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

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
| n8n | LangGraph |
|---|---|
| Nodo | Function |
| Workflow | Graph |
| Variables globales | State |
| Condición IF | Conditional 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
- Lee la pregunta del estado
- Hace una heurística tonta:
- Si contiene «quién» o «qué es», decide buscar
- 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())


Ingeniero en Informática, Investigador, me encanta crear cosas o arreglarlas y darles una nueva vida. Escritor y poeta. Más de 20 APPs publicadas y un libro en Amazon.