Construir un enrutador multiagente con LangGraph y un agente supervisor
Cómo dividir un agente sobrecargado en especialistas con un supervisor en LangGraph, utilizando el ayudante preconstruido y un StateGraph manual, además del diseño de estados y las trampas de los bucles.
Fuentes: Build a Multi-Agent Router with LangGraph in 30 Minutes
Si se pone a un solo agente frente a un producto real, pronto comienza a hacer demasiado. Si se le pide a un agente que se encargue del soporte al cliente, del seguimiento de pedidos y de los reembolsos, termina siendo mediocre en los tres aspectos. Su instrucción de sistema se convierte en un laberinto de 2,000 palabras con frases como “si el usuario pregunta sobre X, haz Y, pero si también se refiere a Z entonces...”. La solución no es un agente más inteligente, sino varios agentes más pequeños junto con un supervisor que dirige sus acciones. Este es, sin duda, el patrón de producción más utilizado en la IA basada en agentes actualmente, y una versión funcional cabe dentro de un programa breve de LangGraph.
Los problemas con un agente gigante
Digamos que estás creando un asistente que responde preguntas generales, realiza cálculos aritméticos y busca información actual en la web. El diseño tentador sería tener un único agente, una sola instrucción extensa a la que se le adjunten todas las herramientas. A medida que aumentan las herramientas e instrucciones, el modelo pierde la certeza sobre qué herramienta elegir y su razonamiento se vuelve menos preciso. Depurar se convierte en una pesadilla, ya que no es posible determinar por qué eligió la herramienta incorrecta cuando todo está incluido en una sola instrucción.
La solución consiste en dividir las responsabilidades: un agente para las tareas matemáticas, otro para la investigación, y un supervisor que actúa como enrutador, decidiendo qué especialista se encargará de cada parte de la solicitud.
El patrón del supervisor
Imagínese un centro de llamadas. Llama con una pregunta y no lo conectan directamente con el experto. Primero escucha una recepcionista, decide si necesita atención de facturación, soporte técnico o ventas, y luego lo transfiere. La recepcionista es la supervisora y los tres equipos están formados por agentes especializados. La supervisora nunca responde a la pregunta en sí; su único trabajo es elegir a quien debe hacerlo.
Visualmente se ve así:
┌─────────────┐
│ User │
│ Request │
└──────┬──────┘
│
▼
┌───────────────┐
│ Supervisor │
│ (routes task)│
└───────┬───────┘
┌──────┴──────┐
▼ ▼
┌────────────┐ ┌────────────┐
│ Research │ │ Math │
│ Agent │ │ Agent │
└──────┬─────┘ └──────┬─────┘
│ │
└──────┬───────┘
▼
┌───────────────┐
│ Supervisor │
│ (final answer)│
└───────────────┘
El supervisor toma la tarea, la pasa al especialista adecuado, recibe el resultado y luego decide si redirigirla nuevamente o entregarle al usuario la respuesta final.
La versión recomendada, paso a paso
Un punto importante que hay que conocer antes de escribir código: el equipo de LangChain ahora sugiere construir el patrón del supervisor directamente a partir de las llamadas a herramientas, en lugar de depender únicamente de la antigua biblioteca auxiliar langgraph-supervisor, ya que las llamadas a herramientas brindan más control sobre la ingeniería del contexto. A continuación encontrará primero la versión preconstruida rápida y luego una manual, para que quede claro qué ocurre en el proceso.
Paso 1: instalar los paquetes
pip install langgraph langchain-openai langgraph-supervisor
Paso 2: formar a los especialistas
Comience con las importaciones:
from langchain_openai import ChatOpenAI
from langgraph.prebuilt import create_react_agent
El primer especialista se ocupa de las matemáticas, y sus herramientas son dos funciones simples. La suma es la primera:
# Specialist 1: handles math
def add(a: float, b: float) -> float:
"""Add two numbers together."""
return a + b
Luego, la multiplicación:
def multiply(a: float, b: float) -> float:
"""Multiply two numbers together."""
return a * b
Rodea ellos con un agente ReAct que tenga un nombre y una instrucción que limite su función:
math_agent = create_react_agent(
model="openai:gpt-4o",
tools=[add, multiply],
name="math_expert",
prompt="You are a math specialist. Solve numeric problems precisely."
)
El segundo especialista realiza investigaciones. Una de sus herramientas es una función de búsqueda, mostrada aquí de forma simplificada:
# Specialist 2: handles research
def web_search(query: str) -> str:
"""Search the web for current information."""
# In production, replace this with a real search API call
return f"Search results for '{query}': [your real search integration here]"
Abriga eso también en un agente:
research_agent = create_react_agent(
model="openai:gpt-4o",
tools=[web_search],
name="research_expert",
prompt="You are a research specialist. Find accurate, current information."
)
Cada agente tiene exactamente un trabajo y solo las herramientas que ese trabajo requiere, por lo que no hay confusión ni prompts sobrecargados. Los ejemplos utilizan modelos de OpenAI, aunque una alternativa gratuita como Groq o OpenRouter también funcionaría.
Paso 3: crear al supervisor
Importar el asistente:
from langgraph_supervisor import create_supervisor
Luego dele a los dos especialistas, un modelo y una instrucción que le indiquen cuándo usar cada uno:
workflow = create_supervisor(
[research_agent, math_agent],
model=ChatOpenAI(model="gpt-4o"),
prompt=(
"You are a team supervisor managing a research expert and a math expert. "
"For questions requiring current information or web lookups, use research_expert. "
"For anything involving calculation, use math_expert. "
"Route each request to exactly the right specialist."
)
)
Compila el flujo de trabajo en una aplicación ejecutable:
app = workflow.compile()
Paso 4: ejecutarlo
Envía una pregunta de matemáticas:
result = app.invoke({
"messages": [
{"role": "user", "content": "What's 1,847 multiplied by 293?"}
]
})
Y imprima el mensaje final:
print(result["messages"][-1].content)
Esto es lo que sucede en el fondo:
- El supervisor lee la solicitud.
- Ve que se trata de un cálculo y no de una pregunta de investigación.
- Transfiere la tarea a
math_expert. math_expertcalcula la respuesta con su herramientamultiply.- El supervisor recupera el control y devuelve la respuesta.
En el caso de una pregunta de investigación, como los números actuales de empleados en las grandes empresas tecnológicas, el mismo supervisor la dirige a research_expert. El código es idéntico y solo difiere la decisión de enrutamiento, la cual toma la LLM por sí misma.
Qué son realmente las herramientas de transferencia
Esta parte elimina la sensación de magia. El supervisor no utiliza algún mecanismo oculto de LangGraph para enrutar tareas; lo hace mediante llamadas a herramientas, exactamente como cualquier agente que utiliza herramientas comunes. En segundo plano, create_supervisor crea una herramienta de transferencia para cada especialista, con nombres como transfer_to_research_expert y transfer_to_math_expert. El modelo del supervisor considera estas herramientas como elementos que se pueden llamar, sin diferencia alguna con una búsqueda meteorológica; por lo tanto, cuando determina que se necesita investigación, simplemente llama a la función de transferencia. La consecuencia es tranquilizadora: el supervisor no representa en absoluto un concepto nuevo. Se trata del ciclo habitual de los agentes, donde algunas de las herramientas son otros agentes en lugar de llamadas a API.
Construyéndolo manualmente
Si desea tener un control total sobre el enrutamiento, lo cual es recomendable a medida que avanza hacia la producción, aquí está la versión manual basada en un StateGraph sin procesar. Comience con las importaciones:
from typing import Annotated, Sequence, TypedDict
import operator
from langchain_core.messages import BaseMessage
from langgraph.graph import StateGraph, END
Define el estado compartido, que contiene la lista de mensajes y el nombre del siguiente nodo:
class AgentState(TypedDict):
messages: Annotated[Sequence[BaseMessage], operator.add]
next: str
El nodo supervisor examina el mensaje más reciente:
def supervisor_node(state: AgentState):
"""Decide which specialist should act next."""
last_message = state["messages"][-1].content
En producción, la decisión se tomaría mediante una llamada a un LLM. Aquí se reduce a simples verificaciones de palabras clave para que la lógica de enrutamiento siga siendo visible:
# In production, this decision comes from an LLM call —
# simplified here to show the routing logic clearly
if any(word in last_message.lower() for word in ["calculate", "multiply", "add", "sum"]):
return {"next": "math_agent"}
else:
return {"next": "research_agent"}
Cada especialista recibe un nodo que invoca a su agente y luego devuelve el control al supervisor. Primero las matemáticas:
def math_node(state: AgentState):
result = math_agent.invoke(state)
return {"messages": [result], "next": "supervisor"}
Luego, investigue:
def research_node(state: AgentState):
result = research_agent.invoke(state)
return {"messages": [result], "next": "supervisor"}
A continuación, conecte el grafo registrando los nodos:
# Wire the graph together
workflow = StateGraph(AgentState)
workflow.add_node("supervisor", supervisor_node)
workflow.add_node("math_agent", math_node)
workflow.add_node("research_agent", research_node)
Establecer el punto de entrada:
workflow.set_entry_point("supervisor")
Agregue los bordes condicionales que siguen la decisión del supervisor:
workflow.add_conditional_edges(
"supervisor",
lambda state: state["next"],
{"math_agent": "math_agent", "research_agent": "research_agent", "end": END}
)
Envíe a cada especialista de vuelta con el supervisor posteriormente:
workflow.add_edge("math_agent", "supervisor")
workflow.add_edge("research_agent", "supervisor")
Y compilar:
app = workflow.compile()
Es más extenso, pero no hay nada oculto. Puedes ver cómo fluye el estado, cómo se toma cada decisión de enrutamiento y dónde agregar tu propia lógica, como registros, restricciones o condiciones de terminación personalizadas.
La elección de diseño del estado que se deteriora más con el tiempo
Una advertencia basada en la experiencia práctica: el esquema de estado es la decisión más difícil de modificar posteriormente. Es tentador incluir desde el principio todos los campos que se puedan necesitar en un único diccionario plano, abarcando mensajes, contexto del usuario y resultados intermedios. Eso funciona bien con dos agentes. Pero con ocho o diez nodos que leen y escriben en el mismo estado compartido, se vuelve problemático, ya que la verificación de tipos de LangGraph es estricta y desenredar un estado sobrecargado implica modificar cada nodo. Diseña el esquema de forma deliberada desde el primer día, incluso para un sistema con dos agentes. Decide qué necesita realmente leer y escribir cada agente, y mantén todo lo demás fuera del estado compartido.
Un fracaso al que te enfrentarás
Los sistemas de supervisión que llegan a la fase de producción tienden a mostrar este patrón. Imagina que el supervisor delega una tarea; el especialista la completa, pero el supervisor considera que el resultado es insuficiente y lo devuelve. El especialista lo revisa, y la nueva versión resulta incluso peor que la primera. El supervisor sigue insatisfecho y lo envía de vuelta, y a menos que se tome precaución, esto puede repetirse indefinidamente.
La solución es establecer un límite en los envíos y recepciones del supervisor, lo cual puede ser un contador simple en el estado, junto con una condición de parada clara y determinista. La opinión de un LLM sobre si algo es lo suficientemente bueno no constituye una regla de parada fiable por sí sola.
Cuándo no usarlo
Sé honesto respecto a la adecuación. Si el trabajo consiste en una sola recuperación seguida de una generación, como en una pregunta y respuesta típica de estilo RAG, un supervisor es un exceso. La gestión adicional de estados y la sobrecarga de enrutamiento no aportan nada cuando no existe una decisión real que tomar para enrutar. Utiliza el patrón de supervisor una vez que tengas especialistas verdaderamente distintos y una opción de enrutamiento real, y no lo adoptes por defecto.
Resumen
- Un agente sobrecargado deja de funcionar a medida que aumenta la complejidad.
- Un supervisor es un agente enrutador que delega tareas a especialistas.
create_supervisores la ruta rápida y preconstruida.- En el fondo, las transferencias de tarea son simples llamadas a herramientas.
- Un
StateGraphmanual brinda un control total del enrutamiento. - Dos lecciones de la práctica: diseña el esquema de estados temprano y limita los ciclos de revisión.
Leer más
- Equipo Multiagentes Autoreparable en LangGraph: Arquitecto, Probador, Depurador — Construya una máquina de estados en LangGraph con Python en la que un Arquitecto, un Desarrollador, un entorno de pruebas pytest, un Depurador y un Revisor colaboren en un ciclo hasta que las pruebas se completen.
- Triaje de Tiquetes de Soporte Multiaagentes con LangGraph y Ollama — Cree un grafo de triaje de tiquetes con tres agentes utilizando LangGraph: un clasificador, un respondiente y un control humano, que funcione con Ollama local o a través de una API, con solo una línea modificada.