LangGraph, OpenAI Agents SDK o Claude Agent SDK: Asignar la primitiva al trabajo.
Cuatro cargas de trabajo de ejemplo, voz, reembolsos duraderos, migración de código y operaciones MCP, muestran qué framework de agente es adecuado en cada caso, con notas sobre el efecto de bloqueo, durabilidad y tiempo real.
Fuentes: The Best Agent Framework in 2026: LangGraph vs OpenAI Agents SDK vs Claude Agent SDK
Las comparaciones en 2026 siguen centrándose en tres marcos de trabajo para agentes, y cada uno se basa en una idea central diferente. LangGraph es un entorno de ejecución de grafos en el que los nodos son funciones sencillas y las aristas determinan las transiciones. El SDK de OpenAI Agents gira en torno a la transferencia de tareas, donde un agente pasa el trabajo a otro a través de sesiones tipadas, con soporte nativo para MCP. El SDK de Claude Agent es el inesperado: le proporciona al agente una computadora, ya que Anthropic lo desarrolló sobre la ejecución de bash, escritura de archivos y ganchos, convencidos de que un agente capaz necesita un shell real.
La elección adecuada depende de algo que las comparaciones arquitectónicas rara vez consideran: ¿qué tipo de tarea está realizando el agente?
Las tres primitivas
LangGraph está orientado a flujos de trabajo con estado. Se declara un esquema de estado, y un objeto tipado se desplaza a través del grafo desde el primer nodo hasta el último. Dado que los puntos de control guardan ese estado en cada nodo, una ejecución puede reanudarse tras una interrupción o tras esperar una aprobación humana manteniendo su contexto intacto. La función create_agent, que se incluyó con LangChain 1.0, disponible de forma general el 22 de octubre de 2025, es solo una fachada sobre este entorno de ejecución, lo que pone fin al antiguo debate entre LangChain y LangGraph.
El SDK OpenAI Agents cuenta con nueve componentes básicos, entre ellos Agents, Handoffs, Tools, Guardrails, Sessions y Realtime. Su unidad atómica es un agente que transfiere una tarea a otro. La independencia de proveedores llegó en 2025 con el soporte para más de 100 modelos a través de LiteLLM. MCP es un tipo de herramienta de primera clase, y la función de voz viene integrada de forma nativa en la familia de modelos gpt-realtime-2.
El Claude Agent SDK se basa en un entorno de shell. Su conjunto de herramientas incluye Bash, Read, Write, Edit, Glob y Grep, además de ganchos de ciclo de vida denominados PreToolUse, PostToolUse y Stop, y subagentes que se ejecutan en ventanas de contexto separadas e aisladas. Anthropic cambió el nombre de Claude Code SDK a finales de 2025 porque esta plataforma también sirve para investigaciones avanzadas, creación de videos y toma de notas, no solo para programación. Solo se permiten modelos Claude, aunque Bedrock, Vertex y Azure Foundry pueden alojarlo.
Una creencia de 2025 que dejará de ser válida
Una suposición común del año pasado es que el OpenAI Agents SDK obliga al uso de modelos de OpenAI. Eso está desactualizado desde hace unos quince meses. El repositorio oficial admite la API OpenAI Responses, así como aproximadamente 100 otros modelos a través de las integraciones LiteLLM y Any-LLM.
# Install: pip install "openai-agents[litellm]"
# Env: export GEMINI_API_KEY=...
import os
from agents import Agent, Runner, function_tool
from agents.extensions.models.litellm_model import LitellmModel
@function_tool
def current_time_utc() -> str:
"""Return the current UTC time as an ISO-8601 string."""
from datetime import datetime, timezone
return datetime.now(timezone.utc).isoformat(timespec="seconds")
# OpenAI Agents SDK using Gemini via LiteLLM. No OpenAI key required.
gemini_model = LitellmModel(
model="gemini/gemini-2.5-pro",
api_key=os.environ["GEMINI_API_KEY"],
)
agent = Agent(
name="time-agent",
instructions="Answer time questions using the current_time_utc tool.",
model=gemini_model,
tools=[current_time_utc],
)
result = Runner.run_sync(agent, "What is the current UTC time?")
print(result.final_output)
# -> "The current UTC time is 2026-07-06T14:32:11+00:00."
La creación de LitellmModel con un nombre de modelo Gemini demuestra que el framework dirige la comunicación fuera del ecosistema de OpenAI, y el decorador @function_tool funciona de manera idéntica independientemente del modelo subyacente. Las rutas que no pertenecen a OpenAI se documentan según los mejores esfuerzos posibles, siendo la paridad de funciones variable según el proveedor. Al no existir límites estrictos en los modelos, los frameworks compiten por sus primitivas arquitectónicas.
Una empresa de pruebas con cuatro agentes
Tomemos una empresa fintech de tamaño medio, llamémosla Meridian, que cuenta con cuatro agentes en fase de desarrollo en equipos separados.
- Un agente de soporte por voz que resuelve consultas de facturación por teléfono.
- Un flujo de trabajo de reembolso con múltiples agentes que verifica reglas contra el fraude antes de pasar el caso a finanzas.
- Un agente interno de migración de código que recorre un gran repositorio en Java, aplica transformaciones sintácticas y abre solicitudes de integración.
Los cuatro entornos de desarrollo mostrados indican qué framework es adecuado para cada uno.
Carga de trabajo uno: voz y transmisión en tiempo real
El equipo encargado de la voz trabaja con un límite estricto de latencia, inferior a 500 ms para la transmisión, y debe gestionarse la interrupción de usuarios. El proceso de conversión de voz a texto, seguido de un modelo de texto que genera voz, es demasiado lento, ya que cada salto en la red añade retraso.
El SDK OpenAI Agents es adecuado. El modelo gpt-realtime-2 transmite tokens de audio de forma nativa, y RealtimeAgent aprovecha esa capacidad. Ni LangGraph ni el Claude Agent SDK ofrecían una funcionalidad nativa en tiempo real a este nivel a mediados de 2026.
# Install: pip install openai-agents
# Env: export OPENAI_API_KEY=...
import asyncio
from agents import function_tool
from agents.realtime import RealtimeAgent, RealtimeRunner
@function_tool
def lookup_billing_balance(account_id: str) -> str:
"""Return the current outstanding balance for an account."""
# In production, this hits the billing service. Here it is a stub.
return "42.17 USD outstanding as of 2026-07-06."
voice_agent = RealtimeAgent(
name="meridian-billing-voice",
instructions=(
"You are Meridian's billing voice assistant. Answer politely, briefly. "
"Confirm the account_id before disclosing any balance."
),
tools=[lookup_billing_balance],
)
async def main():
runner = RealtimeRunner(
starting_agent=voice_agent,
config={"model_settings": {"model_name": "gpt-realtime-2.1"}},
)
# session handles the audio stream and tool calls
session = await runner.run()
async with session:
# Wire the audio input source here via sounddevice or pyaudio
async for event in session:
if event.type == "history_updated":
# The item contains the finalized transcript once the turn ends
print(f"History updated with item: {event.item}")
elif event.type == "error":
print(f"Error: {event.error}")
break
asyncio.run(main())
RealtimeAgent y RealtimeSession se encargan de las transmisiones de audio entrantes y salientes, así como del bucle de llamadas a herramientas; las herramientas declaradas con @function_tool se ejecutan en una sesión en tiempo real de la misma manera que en un agente de texto. El framework hace visible el bucle de eventos, mientras que el estado de WebSocket permanece oculto.
Hacer esto en LangGraph o en el Claude Agent SDK implicaría escribir código personalizado para WebSocket, implementar detección de actividad de voz y lidiar con semánticas complejas de interrupciones, lo que convierte un proyecto de agente en uno de pipeline de medios. Si la política de la empresa exige utilizar Claude o Gemini como modelo de voz, la situación cambia. Anthropic añadió capacidades en tiempo real más tarde, por lo que quienes lean este texto después de mediados de 2026 deberían verificar la paridad de funciones.
Carga de trabajo dos: orquestación duradera con aprobación humana
El flujo de reembolso requiere una verificación de fraude seguida de una aprobación financiera, una espera para la revisión humana en reembolsos superiores a $500, y una decisión final que se registra en Postgres. Debe resistir caídas del servidor y gestionar pausas asincrónicas por parte de los usuarios sin perder el contexto.
LangGraph es adecuado. Los puntos de control combinados con la primitiva de interrupción proporcionan exactamente el flujo de control que necesitan los procesos empresariales de larga duración. Los equipos de producción respaldan esta arquitectura: Uber informa haber ahorrado aproximadamente 21,000 horas de trabajo de desarrolladores al utilizar LangGraph en sus sistemas AutoCover y Validator, mientras que LinkedIn publicó un artículo sobre un árbol de memoria semántica jerárquica para su herramienta Hiring Assistant, cuyo diseño de supervisor y subagente se aborda por separado en las presentaciones técnicas de LangChain.
from typing import TypedDict, Literal
from langgraph.graph import StateGraph, START, END
from langgraph.checkpoint.memory import MemorySaver
from langgraph.types import interrupt, Command
from langchain_google_genai import ChatGoogleGenerativeAI
# LangGraph is provider-agnostic. Here it uses Gemini.
llm = ChatGoogleGenerativeAI(model="gemini-2.5-pro", temperature=0)
class RefundState(TypedDict):
order_id: str
amount_usd: float
customer_reason: str
fraud_risk: Literal["low", "medium", "high"] | None
finance_decision: Literal["approved", "denied"] | None
human_review_needed: bool
def fraud_check(state: RefundState) -> RefundState:
"""Run the LLM-backed fraud check against the customer's stated reason."""
prompt = (
f"Assess fraud risk for refund of ${state['amount_usd']:.2f}. "
f"Customer reason: {state['customer_reason']!r}. "
"Respond with one word: low, medium, or high."
)
verdict = llm.invoke(prompt).content.strip().lower()
if verdict not in {"low", "medium", "high"}:
verdict = "high" # fail-closed on ambiguous LLM output
return {**state, "fraud_risk": verdict}
def finance_approval(state: RefundState) -> RefundState:
"""Above $500 or medium risk, pause for a human. Otherwise auto-approve."""
needs_human = state["amount_usd"] > 500 or state["fraud_risk"] in {"medium", "high"}
if needs_human:
# Pause the graph. On resume, interrupt returns the human's decision.
human_decision = interrupt({
"order_id": state["order_id"],
"amount_usd": state["amount_usd"],
"fraud_risk": state["fraud_risk"],
"prompt": "Approve (yes/no)?",
})
return {**state, "human_review_needed": True, "finance_decision": human_decision}
return {**state, "human_review_needed": False, "finance_decision": "approved"}
# Build the graph
graph = StateGraph(RefundState)
graph.add_node("fraud_check", fraud_check)
graph.add_node("finance_approval", finance_approval)
graph.add_edge(START, "fraud_check")
graph.add_conditional_edges(
"fraud_check",
lambda s: "finance_approval" if s["fraud_risk"] != "high" else END,
)
graph.add_edge("finance_approval", END)
# Checkpointer. For production, swap MemorySaver for PostgresSaver.
compiled = graph.compile(checkpointer=MemorySaver())
# Run it. Interrupt fires on the $850 refund and the graph pauses.
config = {"configurable": {"thread_id": "order-4291"}}
result = compiled.invoke(
{
"order_id": "4291",
"amount_usd": 850.00,
"customer_reason": "arrived damaged, no photo",
"fraud_risk": None,
"finance_decision": None,
"human_review_needed": False,
},
config=config,
)
# Later, a human reviewer says yes. Resume with Command.
final = compiled.invoke(Command(resume="approved"), config=config)
El patrón de pausa y reanudación demuestra una ejecución duradera en el código. Al llamar a interrupt() dentro del nodo de aprobación financiera, el estado actual se escribe en el checkpointer, y el sistema podría apagarse en ese momento. Horas después, un comando con la opción de reanudación establecida en “aprobado” continúa desde el punto donde se detuvo bajo el mismo ID de hilo, sin volver a ejecutar la verificación de fraude.
Existe una advertencia relacionada con la durabilidad. El entorno de ejecución de código abierto guarda el estado en MemorySaver, que se encuentra en la memoria del proceso. Para una verdadera recuperación en caso de fallo bajo carga, se necesita la plataforma LangGraph respaldada por Postgres, o un MemorySaver personalizado.
El SDK de OpenAI Agents ofrece Sesiones para el estado de la conversación y Agents Sandbox para trabajos a largo plazo, pero no existe nada comparable a la creación de puntos de control a nivel de nodo en un grafo arbitrario. El SDK de Claude Agent almacena localmente el estado de la sesión en formato JSONL, o utiliza Agents Gestionados para garantizar durabilidad en la nube, a costa de los modelos exclusivos de Claude. Por ahora, LangGraph es quien se encarga de la orquestación duradera.
Trabajo tres: tareas con archivos y shell
El agente de migración del equipo de experiencia de desarrollador debe recorrer un repositorio en Java de 400,000 líneas, aplicar cambios sintácticos, ejecutar pruebas unitarias y abrir solicitudes de integración. Eso implica leer y editar archivos, ejecutar comandos de shell y reaccionar ante errores del compilador. Bash y Edit constituyen casi todo el trabajo a realizar.
El Claude Agent SDK se corresponde directamente con esto, ya que la filosofía de Anthropic es proporcionar a los agentes una computadora. Cuenta con herramientas nativas para Bash, Read, Write, Edit, Glob y Grep, y sus ganchos funcionan como una superficie de control. Un gancho PreToolUse puede imponer restricciones contra comandos destructivos, mientras que un gancho PostToolUse puede ejecutar formateadores o analizadores de código. Los subagentes dividen el trabajo de transformación en contextos aislados, de modo que un largo registro de errores del compilador entregado a un subagente no contamina la ventana del agente principal.
# Install: pip install claude-agent-sdk
# Env: export ANTHROPIC_API_KEY=...
import anyio
from claude_agent_sdk import (
ClaudeSDKClient,
ClaudeAgentOptions,
AgentDefinition,
HookMatcher,
)
# PreToolUse hook: block Bash calls that look like rm -rf
async def block_dangerous_bash(input_data, tool_use_id, context):
if input_data.get("tool_name") == "Bash":
cmd = input_data.get("tool_input", {}).get("command", "")
if "rm -rf" in cmd or "rm -rf" in cmd:
return {
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "rm -rf blocked by policy",
}
}
return {}
# Subagent: runs in isolated context to lint one file
lint_agent = AgentDefinition(
description="Run linters on a single file and return a concise report.",
prompt=(
"You are the lint subagent. Given a file path, run the project's linter "
"on it and return a one-paragraph summary of failures. Do not fix anything."
),
tools=["Bash", "Read"], # Note: tools is deprecated in favor of skills in recent SDKs
)
options = ClaudeAgentOptions(
system_prompt=(
"You are Meridian's code migration agent. Walk the target directory, "
"apply the migration, run tests, and open a PR. Prefer small commits."
),
allowed_tools=["Bash", "Read", "Write", "Edit", "Glob", "Grep"],
hooks={"PreToolUse": [HookMatcher(hooks=[block_dangerous_bash])]},
agents={"lint": lint_agent},
# resume="mig-run-2026-07-06-01", # uncomment to resume a prior session
)
async def main():
async with ClaudeSDKClient(options=options) as client:
await client.query(
"Migrate services/payments/ from Java 17 to Java 21. "
"For every file you touch, delegate to the `lint` subagent afterward. "
"Do NOT commit or open PRs yet. Stop after changes are on disk."
)
async for message in client.receive_response():
print(message)
anyio.run(main)
La lista allowed_tools define el entorno del agente. Los ganchos ofrecen una estructura de control que se encuentra dentro del bucle del agente y no alrededor de él: un gancho PreToolUse se ejecuta antes de que se utilice una herramienta, y una decisión de denegación detiene la llamada de inmediato. El subagente lint cuenta con sus propias herramientas y ventana de contexto. Las versiones recientes del SDK deprecian el campo tools en AgentDefinition en favor de skills, aunque sigue funcionando. La línea comentada del resumen ilustra cómo restaurar el estado de la sesión desde archivos JSONL en el disco local.
En LangGraph, estas primitivas de shell tendrían que escribirse como funciones personalizadas de Python. Los agentes Sandbox del SDK de OpenAI se ejecutan en contenedores, lo cual es similar en arquitectura, pero el conjunto de primitivas no está nombrado ni expuesto de la misma manera centrada en archivos. El problema es el encierro del modelo: un equipo con una regla estricta contra el encierro en la capa del modelo no puede utilizar el SDK de Claude Agent y debe recurrir a LangGraph al reconstruir las primitivas de bash y edición por sí mismo.
Trabajo cuatro: orquestación intensiva con MCP
El panel de control del equipo de la plataforma responde a una sola pregunta introducida por un ingeniero. Detrás de esto, el agente obtiene errores de Sentry, tickets de Linear, incidentes de PagerDuty y registros de usuarios de Postgres. Casi todo su esfuerzo se dedica a coordinar los servidores MCP de terceros, y muy poco a compilar la respuesta.
Aquí, el OpenAI Agents SDK y el Claude Agent SDK están empatados. En ambos, MCP es un componente fundamental y los servidores funcionan como funciones locales. LangGraph también puede utilizar MCP, pero a mediados de 2026 hacerlo requiere más código genérico, y los equipos suelen encapsular los servidores en herramientas por sí mismos. La diferencia decisiva entre estos dos líderes es una restricción secundaria.
- Elige el OpenAI Agents SDK para el seguimiento de procesos propios, normas estrictas y la transferencia de tareas a subagentes especializados, o cuando resulte atractivo enrutar tareas simples de síntesis a proveedores más económicos a través de LiteLLM.
- Elige el Claude Agent SDK para el ciclo de vida de los complementos, un aislamiento estricto de los subagentes y la fiabilidad en el uso de herramientas de Claude.
Los envoltorios API personalizados para herramientas SaaS comunes consumen tiempo de ingeniería. El estándar MCP estandariza el contexto y el descubrimiento de herramientas, de modo que el framework solo necesita mantenerse al margen, y ambos SDKs admiten este patrón de forma nativa.
Resumen por tipo de trabajo
- Voz en tiempo real con intervención simultánea: OpenAI Agents SDK.
- Flujos multiagente duraderos con aprobación humana: LangGraph.
- Trabajos de migración de archivos, shells y código: Claude Agent SDK.
- Orquestación intensiva con MCP: OpenAI Agents SDK o Claude Agent SDK.
Una nota sobre CrewAI
Muchos lectores esperan encontrar a CrewAI en una comparación como esta. Al verificarlo, la evidencia relativa a su versión actual, la adopción de Flows y los estudios de caso empresariales no fue tan sólida como la de los otros tres, por lo que se dejó fuera en lugar de completar el artículo con fuentes menos fiables.
La verdadera elección
Cuatro agentes terminaron integrados en tres frameworks: los agentes de voz y de plataforma en el OpenAI SDK, el flujo de reembolsos en LangGraph y el agente de migración en el Claude Agent SDK. Discutir cuál framework es el mejor es enfoque erróneo. La tarea consiste en alinear la primitiva central de cada framework con las características del trabajo a realizar.
La próxima ronda probablemente reabrirá el debate sobre la durabilidad, ya que LangGraph Platform compite con los Managed Agents de Anthropic. LangGraph podría obtener primitivas en tiempo real de primera categoría, o bien Anthropic podría abrir su SDK a otros proveedores de modelos. Hasta entonces, las primitivas determinan la arquitectura.
Leer más
- Construir un enrutador multi-agente con LangGraph y un agente supervisor — Cómo dividir un agente sobrecargado en especialistas con la ayuda de un supervisor en LangGraph, utilizando el asistente preconstruido y un StateGraph manual, además del diseño de estados y las trampas comunes en los bucles.
- Equipo multi-agente autoreparable en LangGraph: Arquitecto, Probador, Depurador — Construir 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 colaboran y realizan bucles hasta que las pruebas se aprueben.