Construir un agente con LangGraph sin conexión LLM tutorial básico

Tiempo de lectura: 3 minutos

Hoy vamos a construir un agente con LangGraph y Python sin usar LLM cómo ejemplo de un tutorial básico.

Casa ventana azul - pexels

Nuestro agente hará lo siguiente:

Recibe una pregunta del usuario

Decide si necesita buscar info (simulado)

Responde con o sin búsqueda

Guarda estado entre nodos

Lo primero que haremos es instalar la librería:

pip install langgraph langchain openai

Concepto clave de LangGraph

n8nLangGraph
NodoFunction
WorkflowGraph
Variables globalesState
Condición IFConditional edges

Ahora vamos a usar este ejemplo:

from typing import TypedDict
from langgraph.graph import StateGraph, END

# 1 Definir el estado global
class AgentState(TypedDict):
    question: str
    needs_search: bool
    answer: str


# 2️ NODO: decidir si buscar
def decide_search(state: AgentState):
    question = state["question"]
    needs_search = "quién" in question.lower() or "qué es" in question.lower()
    print("Decide buscar:", needs_search)
    return {"needs_search": needs_search}


# 3️ NODO: búsqueda fake (simulada)
def search_node(state: AgentState):
    print("Buscando info...")
    fake_info = "LangGraph es una librería de grafos para agentes de IA."
    return {"answer": f"Encontré esto: {fake_info}"}


# 4️ NODO: responder sin búsqueda
def answer_direct(state: AgentState):
    return {"answer": "No necesito buscar, te respondo con mi conocimiento base."}


# 5️ Crear el grafo
builder = StateGraph(AgentState)

builder.add_node("decide_search", decide_search)
builder.add_node("search", search_node)
builder.add_node("direct_answer", answer_direct)

# Flujo inicial
builder.set_entry_point("decide_search")

# Condición tipo IF
builder.add_conditional_edges(
    "decide_search",
    lambda state: "search" if state["needs_search"] else "direct_answer",
)

# Finales
builder.add_edge("search", END)
builder.add_edge("direct_answer", END)

graph = builder.compile()


# 6️ Ejecutar
if __name__ == "__main__":
    result = graph.invoke({"question": "¿Qué es LangGraph?"})
    print("\n Resultado final:")
    print(result)

Y ahora voy a explicar uno por uno cada punto:

Definir el estado global

class AgentState(TypedDict):
    question: str
    needs_search: bool
    answer: str

Qué es el State en LangGraph

Es el objeto que viaja entre nodos.
Como las variables globales del workflow en n8n.

Ejemplo real:

state = {
  "question": "¿Qué es LangGraph?",
  "needs_search": True,
  "answer": "texto"
}

Por qué TypedDict

Porque LangGraph necesita saber:

  • Qué keys puede haber
  • Para hacer merging de estados
  • Para debugging y validación

No es obligatorio, pero muy recomendado.

Nodo 1: decidir si buscar

def decide_search(state: AgentState):
    question = state["question"]
    needs_search = "quién" in question.lower() or "qué es" in question.lower()
    print("Decide buscar:", needs_search)
    return {"needs_search": needs_search}

Qué es un nodo en LangGraph

Un nodo = una función Python pura.

Siempre:

  • Recibe state
  • Devuelve un dict parcial del state

Qué hace este nodo

  1. Lee la pregunta del estado
  2. Hace una heurística tonta:
    • Si contiene «quién» o «qué es», decide buscar
  3. Devuelve solo:
{"needs_search": True/False}

LangGraph mergea automáticamente esto con el estado global.

Nodo 2: búsqueda fake

def search_node(state: AgentState):
    print("Buscando info...")
    fake_info = "LangGraph es una librería de grafos para agentes de IA."
    return {"answer": f"Encontré esto: {fake_info}"}

Importante

Este nodo simula un tool (como Google Search, RAG, DB).

En un sistema real aquí iría:

  • Web search
  • Vector DB
  • API externa
  • scraping

Devuelve solo:

{"answer": "..."}

Nodo 3: responder sin búsqueda

def answer_direct(state: AgentState):
    return {"answer": "No necesito buscar, te respondo con mi conocimiento base."}

Nodo simple que responde directamente.

En un agente real sería un LLM call.

Crear el grafo

builder = StateGraph(AgentState)

Qué es builder

Es el editor del workflow.

Le dices:

  • Qué estado global tendrá
  • Qué nodos existen
  • Cómo se conectan

Registrar nodos

builder.add_node("decide_search", decide_search)
builder.add_node("search", search_node)
builder.add_node("direct_answer", answer_direct)

Formato:

add_node("nombre_del_nodo", funcion)

Es igual a crear nodos en n8n visualmente.

Nodo inicial (entry point)

builder.set_entry_point("decide_search")

Esto define:

👉 Por dónde empieza el workflow

En n8n sería el trigger node.

9) Condicional (IF)

builder.add_conditional_edges(
    "decide_search",
    lambda state: "search" if state["needs_search"] else "direct_answer",
)

Esto es CLAVE.

Qué hace

Después de decide_search, ejecuta esta función:

lambda state: ...

Si needs_search == True → va al nodo "search"
Si no → va al nodo "direct_answer"

Mental model n8n

Es literalmente:

IF needs_search
   → search
ELSE
   → direct_answer

Nodos finales

builder.add_edge("search", END)
builder.add_edge("direct_answer", END)

Esto significa:

Después de search → terminar
Después de direct_answer → terminar

Si no lo pones, LangGraph no sabe cuándo parar.

11) Compilar el grafo

graph = builder.compile()

Esto convierte el builder en:

Un grafo ejecutable (runtime engine)

Ejecutar

result = graph.invoke({"question": "¿Qué es LangGraph?"})

Qué hace invoke

  • Crea el state inicial
  • Ejecuta nodos en orden
  • Va saltando condicionales
  • Mergea estados
  • Devuelve el estado final

Estado inicial

{"question": "¿Qué es LangGraph?"}

LangGraph irá añadiendo:

  • needs_search
  • answer

Resultado final

print(result)

Devuelve algo como:

{
 'question': '¿Qué es LangGraph?',
 'needs_search': True,
 'answer': 'Encontré esto: LangGraph es una librería...'
}

Y para visualizar el grafo:

with open("summary_workflow.png", "wb") as f:
    f.write(graph.get_graph().draw_mermaid_png())
Grafo de ejemplo langgraph

Deja un comentario