Ya leíste una docena de posts de "¡los agentes de IA llegaron!" este mes. Anthropic lanzó Managed Agents el 8 de abril. Google sacó ADK. OpenAI empujó su Agents SDK. Cada pitch deck dice "agentes autónomos" como si fuera un hechizo mágico. Pero nunca construiste el loop real que los hace funcionar a todos — las 50 líneas de Python donde un modelo llama a una función, lee el resultado y decide qué hacer después. Sin eso, cada demo de cualquier proveedor se ve igual de impresionante, y no podés distinguir una funcionalidad real de un envoltorio de regalo carísimo.
Por qué "Usá una plataforma y listo" te falla
El movimiento obvio: elegí una plataforma administrada y dejá que se encargue de todo. Pero acá está el problema — estás tercerizando el entendimiento. Managed Agents de Anthropic cobra $0.08 por hora de sesión. El Agents SDK de OpenAI tiene sus propias abstracciones. Google ADK usa flujos basados en grafos. Cada plataforma envuelve el mismo patrón central en distintas opiniones sobre memoria, permisos y facturación — pero si no conocés el patrón en sí, no podés evaluar qué opiniones importan para TU caso de uso. Un análisis de 2024 del MIT Sloan Management Review sobre proyectos empresariales de IA pone la tasa de éxito de piloto a producción para IA agéntica en aproximadamente 5%. El modo de fallo no es el framework. Son los equipos que no entienden qué hay debajo.
Así que vamos a construir la cosa.
La receta: 50 líneas para visión de rayos X
Paso 0: Instalá el SDK
Al 27 de abril de 2026, la última versión del SDK de Python de Anthropic — un kit de herramientas que le permite a tu código Python hablar con el cerebro de Claude — es v0.97.0. Un solo comando:
pip install anthropic
Configurá tu API key — una contraseña secreta que identifica tu cuenta ante los servidores de Anthropic:
export ANTHROPIC_API_KEY="sk-ant-..."
Paso 1: Definí tus herramientas
Las herramientas son funciones que Claude puede pedirte que ejecutes. Las describís usando JSON Schema — un formato estandarizado para decir "esta función recibe estas entradas con estas formas". Claude lee estas descripciones como un menú de restaurante y elige qué pedir.
Insight crítico: las descripciones importan más que los nombres. Claude decide cuándo llamar a una herramienta basándose en lo que dice la descripción. Descripción vaga = comportamiento impredecible.
Acá hay una definición real de herramienta — una consulta de clima y un creador de eventos:
tools = [
{
"name": "get_weather",
"description": "Get current weather for a city. Use when the user asks about weather, temperature, or outdoor conditions.",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name, e.g. 'New York'"},
"units": {"type": "string", "enum": ["celsius", "fahrenheit"]}
},
"required": ["city"]
}
},
{
"name": "create_event",
"description": "Create a calendar event. Use when the user wants to schedule, book, or plan something.",
"input_schema": {
"type": "object",
"properties": {
"title": {"type": "string"},
"start": {"type": "string", "format": "date-time"},
"end": {"type": "string", "format": "date-time"}
},
"required": ["title", "start", "end"]
}
}
]
Ojo: required controla el comportamiento. Omití un campo requerido y mirá cómo Claude se inventa valores. Poné demasiados campos como requeridos y las llamadas válidas se bloquean.
Paso 2: Construí la capa de ejecución
Acá es donde TU código corre. Claude nunca ejecuta nada por sí mismo — envía un pedido educado tipo "por favor corré get_weather con {city: 'Chicago'}", y tu código hace el trabajo real:
def run_tool(name, input_data):
if name == "get_weather":
# En producción, acá llamarías a una API de clima
return {"temp": 72, "condition": "sunny", "city": input_data["city"]}
if name == "create_event":
return {"event_id": "evt_456", "status": "created", "title": input_data["title"]}
return {"error": f"Unknown tool: {name}"}
Paso 3: El loop — donde nace la agencia
Esta es la parte que cada plataforma envuelve en miles de líneas de abstracción. El loop agéntico — el ciclo donde Claude llama herramientas, lee resultados y decide su siguiente movimiento — son aproximadamente 20 líneas:
import json
import anthropic
client = anthropic.Anthropic()
messages = [{"role": "user", "content": "What's the weather in Chicago? If it's nice, schedule a picnic tomorrow at noon."}]
response = client.messages.create(
model="claude-sonnet-4-20250514", max_tokens=1024,
tools=tools, messages=messages
)
while response.stop_reason == "tool_use":
# Claude puede pedir MÚLTIPLES herramientas a la vez — procesá TODAS
tool_results = []
for block in response.content:
if block.type == "tool_use":
result = run_tool(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result)
})
messages.append({"role": "assistant", "content": response.content})
messages.append({"role": "user", "content": tool_results})
response = client.messages.create(
model="claude-sonnet-4-20250514", max_tokens=1024,
tools=tools, messages=messages
)
print(response.content[0].text)
Ese prompt dispara DOS llamadas autónomas a herramientas: primero get_weather (para revisar Chicago), después create_event (para agendar el picnic) — y Claude las encadena sin que vos se lo digas. Este es el momento "ajá": el modelo lee el resultado del clima, decide que está lindo, y llama a la siguiente herramienta por su cuenta.
Cada plataforma de agentes es este loop más opiniones sobre memoria, permisos, facturación y deployment apiladas encima.
Paso 4: Manejo de errores — No te crashees, enseñá
Cuando una herramienta falla, no rompas tu loop. Enviá el error de vuelta con is_error: True para que Claude se adapte — reintente con otra entrada, explique el problema, o pruebe un enfoque diferente:
def run_tool_safe(name, input_data):
try:
return run_tool(name, input_data), False
except Exception as e:
return {"error": str(e)}, True
# Dentro del loop, reemplazá la construcción de tool_results:
result, is_err = run_tool_safe(block.name, block.input)
tool_results.append({
"type": "tool_result",
"tool_use_id": block.id,
"content": json.dumps(result),
"is_error": is_err
})
Claude lee el error y responde de forma inteligente: "Intenté agendar el picnic pero el calendario solo permite eventos en horario laboral. ¿Querés que pruebe el sábado a la mañana?"
Paso 5: Agregá un fusible de seguridad
Un loop descontrolado quema tokens — pequeños pedazos de palabras que Claude procesa, aproximadamente ¾ de una palabra en inglés cada uno — hasta que lo matés. Agregá un contador:
MAX_ITERATIONS = 10
iteration = 0
while response.stop_reason == "tool_use" and iteration < MAX_ITERATIONS:
iteration += 1
# ... mismo cuerpo del loop ...
if iteration >= MAX_ITERATIONS:
print("Loop hit safety limit. Something's probably wrong.")
Ninguna plataforma administrada te va a decir que esto es lo primero que tenés que agregar. Lo manejan en silencio — y te cobran por el privilegio.
Trampas que muerden en producción
1. El bug de "solo la primera herramienta". Claude puede devolver múltiples bloques tool_use en una sola respuesta — por ejemplo, consultando el clima en tres ciudades simultáneamente. Si solo procesás el primer bloque (típico en tutoriales), el modelo se confunde por los resultados faltantes. Síntoma: Claude repite el mismo pedido una y otra vez. Solución: iterá TODOS los bloques, devolvé TODOS los resultados en un solo mensaje. El tutorial oficial llama a esto la progresión de Ring 2 → Ring 3.
2. Inflación de la ventana de contexto. La ventana de contexto — cuánto texto puede "ver" Claude a la vez, como la memoria de trabajo — se llena rápido. Cada llamada a herramienta y resultado se acumula. Una salida verbosa de un comando puede comerse miles de tokens en un solo turno. El Agent SDK maneja la compactación automáticamente; el SDK crudo no. Solución: resumí las salidas grandes antes de retroalimentarlas, o truncá a las partes relevantes.
3. Sin sandbox. Tu función run_tool corre con TUS permisos. Si Claude pide borrar un archivo y tu herramienta obedece, el archivo desaparece. Según el análisis de Momentic, su equipo aprendió esto por las malas en 3 meses de ejecuciones autónomas de agentes: "el sandboxing no es opcional... las cosas se salen de control más rápido de lo que pensás."
4. Campos required faltantes. Si tu schema dice required: ["city"] pero el usuario dice "¿cómo está el clima?", Claude va a inventarse una ciudad en lugar de preguntar. Solución: hacé la descripción explícita — "Si el usuario no especifica una ciudad, preguntale en vez de adivinar."
Qué podés hacer ahora
Tenés un loop agéntico funcional. Cada anuncio de proveedor de acá en adelante se mapea directamente a él. ¿Managed Agents? Es tu loop más checkpointing, monitoreo y recuperación de crashes — por $0.08/hora de sesión. ¿Agents SDK de OpenAI vs Google ADK? Mismo loop, distintas opiniones sobre handoff y flujos basados en grafos.
El próximo pitch de una plataforma aterriza en tu escritorio. En vez de confiar en la demo, preguntás: ¿qué capa de MI loop reemplaza esto — y esa capa es realmente mi cuello de botella?





