Notas prácticas: El mejor framework de agentes en 2026: LangGraph vs OpenAI Agents
Guía práctica paso a paso: El mejor framework de agentes en 2026: LangGraph vs OpenAI Agents: contratos, verificaciones y espacios de código listos para usar para los equipos que implementan este patrón.
Esta guía reconstruye el proceso desde las materias primas hasta un sistema funcional para: El mejor framework de agentes en 2026: LangGraph vs OpenAI Agents SDK vs Claude Agent SDK. El enfoque está en pasos operativos, verificaciones explícitas y código que se puede incorporar directamente a un repositorio sin necesidad de adivinar la intención. Para obtener una visión general, defina las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Registre los tiempos de ejecución y el costo en tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de una demostración a entornos compartidos.
Las tres primitivas
Al trabajar con The Three Primitives, anote primero el contrato: las entradas requeridas, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema. Haga un punto de control después de los pasos costosos. La función de reanudación no debe volver a facturar la misma llamada al LLM cuando un operador intente nuevamente un nodo posterior.
Una creencia que se abandonará en 2025
Al trabajar en “Una creencia a descartar para 2025”, anote primero el contrato: los datos necesarios, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Documente junto con ello el camino óptimo y el camino de recuperación. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no de mejoras posteriores. Haga un punto de control después de los pasos costosos. Resume no debe volver a facturar la misma llamada al LLM cuando un operador vuelve a intentar un nodo posterior.
# 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."
Presentamos Meridian
Al trabajar en Introducing Meridian, anote primero el contrato: los datos de entrada requeridos, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando un paso falla, el fallo debe apuntar a una única responsabilidad y no a un proceso complicado. Haga una verificación después de los pasos costosos. El sistema de reanudación no debe volver a facturar la misma llamada al LLM cuando un operador intenta nuevamente un nodo posterior. Al trabajar en Introducing Meridian, anote primero el contrato: los datos de entrada requeridos, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Registre los tiempos y el costo en tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de la versión de demostración a entornos compartidos.
Carga de trabajo 1: Voz y transmisión en tiempo real
Carga de trabajo 1: La transmisión por voz y en tiempo real funciona mejor cuando se trata como una superficie medible. Capture una transcripción de referencia, un caso de fallo y la nota de reversión antes de ampliar el alcance. Mantenga la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el grafo. Mantenga el estado del grafo plano y tipado. Los bloques anidados ocultan qué nodo escribió qué campo y provocan interrupciones en la continuación después de las interrupciones.
# 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())
Carga de trabajo 2: Orquestación duradera multiagente con HITL
Workload 2: La orquestación multiagente duradera con HITL funciona mejor cuando se trata como una superficie medible. Capture una transcripción ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Documente tanto el camino óptimo como el camino de recuperación juntos. Las reintentos, los controles humanos y el manejo de mensajes no entregados forman parte del producto, no son mejoras posteriores. Mantenga el estado del grafo plano y tipado; los bloques anidados ocultan qué nodo escribió qué campo y provocan interrupciones en la continuación después de las interrupciones.
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)
Workload 3: Centrado en la programación y en archivos y shell
Trabajo 3: Las tareas relacionadas con la programación y centradas en archivos y shells funcionan mejor cuando se tratan como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando un paso falla, el fallo debe apuntar a una sola responsabilidad y no a un proceso complicado. Mantenga el estado de los gráficos simple y tipado. Los bloques anidados ocultan qué nodo escribió qué campo y causan interrupciones en la continuación del proceso. Trabajo 3: Las tareas relacionadas con la programación y centradas en archivos y shells funcionan mejor cuando se tratan como una superficie medible. Capture un registro ideal, un caso de fallo y la nota de reversión antes de ampliar el alcance. Registre los tiempos y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando el proceso pasa de una demostración a entornos compartidos.
# 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)
Carga de trabajo 4: Orquestación de herramientas con alto uso de MCP
Para la Carga de trabajo 4: Orquestación de herramientas con alto uso de MCP, se deben definir las entradas, el responsable de cada paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. La configuración debe mantenerse fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos confidenciales y las banderas de funcionalidad deben estar en un único lugar que los operadores puedan auditar sin necesidad de leer todo el sistema. Se debe autenticar en la pasarela y volver a autorizar en el plano de datos. Un token portador por sí solo no constituye un límite entre tenencias.
La matriz de decisiones
Para la matriz de decisiones, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Documente tanto la ruta óptima como la ruta de recuperación. Las reintentos, los controles humanos y el manejo de correos no entregados forman parte del producto, no son mejoras posteriores. Incluya la aprobación humana en aquellos casos que impliquen gastos o cambios en los datos de producción. La configuración en tiempo de compilación no equivale a la completitud del proceso empresarial.
Sobre CrewAI
En On CrewAI, defina las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea desde un punto de control conocido sin tener que adivinar el estado oculto. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando una tarea falla, el error debe indicar una única responsabilidad y no un proceso complicado. Incluya la aprobación humana en aquellas acciones que implican gastos o modificaciones en datos de producción. La conexión durante la compilación no equivale a una solución completa para el negocio. En On CrewAI, defina las entradas, el responsable de la tarea y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar la tarea desde un punto de control conocido sin tener que adivinar el estado oculto. Registre los tiempos de ejecución y el costo en tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando la tarea pasa de un entorno de demostración a uno compartido.
La verdadera elección
Al trabajar en The Real Choice, anote primero el contrato: los datos necesarios, la señal de éxito y qué ocurre en caso de fallo parcial. Esa lista de verificación mantiene honestas las futuras modificaciones del código. Guarde la configuración fuera del código de la aplicación. Los archivos de entorno, los almacenes de datos secretos y las banderas de funcionalidad deben estar en un lugar donde los operadores puedan auditarlos sin tener que leer todo el sistema.
Lista de verificación operativa
La lista de verificación operativa funciona mejor cuando se trata como una superficie medible. Capture una transcripción de referencia, un caso de fallo y la nota de reversión antes de ampliar el alcance.
Considere esta etapa como un contrato entre los datos de entrada y los resultados validados. Asigne nombres a los artefactos, defina las comprobaciones de éxito y rechace cualquier completación parcial silenciosa.
Mantenga el estado del grafo plano y tipado. Los bloques anidados ocultan qué nodo escribió qué campo y provocan interrupciones en la continuación del proceso tras las interrupciones.
Añada una prueba de funcionamiento que ejerza la ruta crítica en los procesos de integración continua utilizando fixtures, y no APIs pagadas en tiempo real, siempre que lo permitan los presupuestos.
Registre los tiempos de ejecución y el costo de tokens o consultas junto con los resultados funcionales. Tener visibilidad del costo desde el principio evita facturas inesperadas cuando la ruta pasa de una versión de demostración a entornos compartidos.
Mantenga el estado del grafo plano y tipado. Los bloques anidados ocultan qué nodo escribió qué campo y provocan interrupciones en la continuación del proceso tras las interrupciones.
Antes de promocionar la solución, congele las versiones, capture una transcripción de referencia para la ruta crítica y confirme los pasos para revertir cambios. Los entornos compartidos requieren límites de uso, verificaciones de asignación y un responsable claro para la rotación de credenciales secretas. Prefiera una fiabilidad sencilla a demostraciones ingeniosas pero puntuales.
Nota de lote para 2c64e0b378d9: mantener las claves del proveedor fuera del repositorio, establecer un límite para los tokens por sesión y almacenar las transcripciones junto a los archivos de evaluación para que los cambios posteriores en el modelo sigan siendo comparables.
La nota de refuerzo 0 funciona mejor cuando se trata como una superficie medible. Capture una transcripción de referencia, un caso de fallo y la nota de reversión antes de ampliar el alcance. Prefiera unidades pequeñas y verificables en lugar de scripts extensos. Cuando falla un paso, el fallo debe apuntar a una única responsabilidad y no a un proceso complicado.
Detalle de refuerzo 0/821: mida el tiempo de ejecución, la clase del error y el consumo de tokens para esta nota, y luego decida si mantener el cambio basándose en un conjunto fijo de preguntas en lugar de en anécdotas.
Para la nota de reforzamiento 1, defina las entradas, el responsable del paso y los criterios de finalización antes de modificar el código. Los operadores deben poder volver a ejecutar el paso a partir de un punto de control conocido sin tener que adivinar el estado oculto. Registre los tiempos de ejecución y el costo en tokens o consultas junto con los resultados funcionales. La visibilidad temprana de los costos evita facturas inesperadas cuando el proceso pasa de entornos de demostración a entornos compartidos.
Detalle de reforzamiento 1/821: mida el tiempo de ejecución, la clase del error y el gasto en tokens para esta nota, y luego decida si mantener el cambio basándose en un conjunto fijo de preguntas en lugar de en observaciones anecdóticas.
Lecturas relacionadas
- Notas prácticas: Construir un enrutador multi-agente con LangGraph en 30 minutos — Guía paso a paso de las Notas prácticas: Construir un enrutador multi-agente con LangGraph en 30 minutos: contratos, verificaciones y espacios para código listo para usar para los equipos que implementan este patrón.
- Notas prácticas: Construir un equipo multi-agente autoreparable con LangGraph — Guía paso a paso de las Notas prácticas: Construir un equipo multi-agente autoreparable con LangGraph: contratos, verificaciones y espacios para código listo para usar para los equipos que implementan este patrón.
- Notas prácticas: Rastreo de agentes LangGraph en Agent Engine — Guía paso a paso de las Notas prácticas: Rastreo de agentes LangGraph en Agent Engine: contratos, verificaciones y espacios para código listo para usar para los equipos que implementan este patrón.
- Notas prácticas: LangGraph vs. Google ADK en 2026. Parte 1: Dos métodos diferentes — Guía paso a paso de las Notas prácticas: LangGraph vs. Google ADK en 2026. Parte 1: Dos métodos diferentes: contratos, verificaciones y espacios para código listo para usar para los equipos que implementan este patrón.