No hace falta un framework enorme. Con la API de Anthropic y 80 líneas de Python podés construir un agente que razona, usa herramientas y mantiene contexto entre turnos. Esta guía es el camino más corto al primer agente funcional.
"Un agente no es un chatbot con mejor prompt. Es un sistema que toma decisiones sobre qué herramientas usar y cuándo parar."
Si alguna vez pagaste por una herramienta de IA que hacía exactamente lo que necesitabas, pero luego cambió de precio, desapareció o no se adaptaba a tu caso específico, esta guía es para ti. Antes de escribir una sola línea, necesitas tener claro el modelo mental correcto. Un agente no es simplemente "Claude con más instrucciones". La diferencia fundamental está en el loop de ejecución: un agente llama al modelo, evalúa si necesita usar una herramienta, la ejecuta, y vuelve a llamar al modelo con el resultado — hasta que decide que terminó.
La Claude API soporta esto nativamente con tool use (también llamado function calling). Le describes herramientas al modelo en formato JSON, y Claude decide autónomamente cuándo y cómo usarlas. Tu código solo necesita manejar el loop.
Necesitás Python 3.9+ y la SDK oficial de Anthropic. Nada más. No hace falta LangChain, LlamaIndex ni ningún framework extra para este primer agente.
# 1. Crear entorno virtual python -m venv agente-env source agente-env/bin/activate # Mac/Linux agente-env\Scripts\activate # Windows # 2. Instalar la SDK de Anthropic pip install anthropic # 3. Setear tu API key (obtenela en console.anthropic.com) export ANTHROPIC_API_KEY="sk-ant-..." # Verificar que funciona python -c "import anthropic; print('SDK lista ✓')"
.env con python-dotenv. Si la pushás a GitHub por accidente, Anthropic la desactiva automáticamente — pero es un dolor de cabeza evitable.
El modelo recomendado para agentes en 2026 es claude-sonnet-4-6. Tiene el mejor balance entre capacidad de razonamiento, velocidad y costo. Para agentes que necesitan razonamiento complejo o múltiples pasos encadenados, considerá claude-opus-4-7.
claude-haiku-4-5 — demasiado rápido para razonamiento profundo, tiende a saltear pasos en cadenas de tools complejas.
claude-sonnet-4-6 — razona bien, usa tools correctamente, velocidad aceptable, costo manejable.
💡 En Expertos AI Builder usamos esto para el agente de investigación de mercado de nuestros clientes. En lugar de pagar $200/mes por una herramienta SaaS, el cliente tiene su propio agente personalizado corriendo en su máquina, con sus herramientas específicas.
Las herramientas son funciones Python normales, pero con una descripción en JSON que le dice a Claude qué hacen y qué parámetros aceptan. La calidad de esta descripción impacta directamente en qué tan bien el modelo decide cuándo usarlas.
Para este ejemplo construimos un agente con 3 herramientas: buscar información en la web, leer un archivo y escribir un archivo. Es suficiente para tareas de investigación y síntesis reales.
# tools.py — Definición de herramientas para el agente import os import json import urllib.request # ── Esquemas JSON que Claude lee ────────────────────── TOOLS = [ { "name": "web_search", "description": """Busca información actualizada en la web. Usá esta herramienta cuando necesites datos que pueden haber cambiado recientemente o que no tenés en contexto.""", "input_schema": { "type": "object", "properties": { "query": { "type": "string", "description": "Consulta de búsqueda. Sé específico." } }, "required": ["query"] } }, { "name": "read_file", "description": "Lee el contenido de un archivo local.", "input_schema": { "type": "object", "properties": { "path": { "type": "string", "description": "Ruta al archivo a leer." } }, "required": ["path"] } }, { "name": "write_file", "description": "Escribe contenido en un archivo. Crea el archivo si no existe.", "input_schema": { "type": "object", "properties": { "path": { "type": "string" }, "content": { "type": "string", "description": "Texto a guardar." } }, "required": ["path", "content"] } } ] # ── Implementaciones reales ──────────────────────────── def web_search(query: str) -> str: # DuckDuckGo Instant Answer API (sin key, gratis) url = f"https://api.duckduckgo.com/?q={urllib.parse.quote(query)}&format=json&no_html=1" with urllib.request.urlopen(url) as r: data = json.loads(r.read()) abstract = data.get("AbstractText", "") related = [t["Text"] for t in data.get("RelatedTopics", [])[:3] if "Text" in t] return abstract or "\n".join(related) or "Sin resultados encontrados." def read_file(path: str) -> str: if not os.path.exists(path): return f"Error: el archivo '{path}' no existe." with open(path, "r", encoding="utf-8") as f: return f.read() def write_file(path: str, content: str) -> str: with open(path, "w", encoding="utf-8") as f: f.write(content) return f"Archivo guardado en '{path}' ({len(content)} caracteres)." # Mapa para ejecutar tools por nombre TOOL_MAP = { "web_search": lambda **kw: web_search(kw["query"]), "read_file": lambda **kw: read_file(kw["path"]), "write_file": lambda **kw: write_file(kw["path"], kw["content"]), }
description. Invierte tiempo en escribir descripciones precisas. Incluye cuándo usarla y cuándo NO. Un ejemplo: "NO uses esta herramienta si ya tienes la información en el contexto de la conversación."
El corazón del agente es un loop while simple. Llamás a Claude, revisás si quiere usar una herramienta, la ejecutás, añadís el resultado al historial, y volvés a llamar. El loop termina cuando Claude responde con stop_reason == "end_turn" — es decir, cuando decide que terminó.
stop_reason == "tool_use", hay tool_use blocks en el response. Si es "end_turn", terminaste.tool_result al historial.# agent.py — Loop principal del agente import anthropic from tools import TOOLS, TOOL_MAP client = anthropic.Anthropic() def run_agent(user_message: str, system: str = "") -> str: messages = [{"role": "user", "content": user_message}] while True: response = client.messages.create( model="claude-sonnet-4-6", max_tokens=4096, system=system, tools=TOOLS, messages=messages, ) # Agente terminó — devolver texto final if response.stop_reason == "end_turn": return response.content[0].text # Procesar tool calls tool_results = [] for block in response.content: if block.type == "tool_use": tool_fn = TOOL_MAP.get(block.name) result = tool_fn(**block.input) if tool_fn else "Tool no encontrada." print(f" 🔧 {block.name}({block.input}) → {str(result)[:80]}...") tool_results.append({ "type": "tool_result", "tool_use_id": block.id, "content": str(result), }) # Añadir al historial: respuesta del asistente + resultados messages.append({"role": "assistant", "content": response.content}) messages.append({"role": "user", "content": tool_results}) # Correr el agente if __name__ == "__main__": resultado = run_agent( "Buscá información sobre Claude Sonnet 4.6, " "resumila en 3 puntos y guardala en resumen.txt" ) print("\n✅ Agente terminó:", resultado)
if iterations > 10: break. Un agente mal configurado puede entrar en un loop infinito de tool calls que consume tokens (y plata) rápidamente. 10 iteraciones es suficiente para el 95% de los casos.
El system prompt de un agente no es el mismo que el de un chatbot. Acá no describes "cómo hablar" — describes cómo razonar: qué herramientas tiene disponibles y cuándo usarlas, cómo manejar errores, cuándo pedir clarificación y cuándo proceder.
Sé explícito con los límites: "No ejecutes acciones destructivas sin confirmar con el usuario."
Pide razonamiento explícito: "Antes de usar una herramienta, explica en una oración por qué la necesitas."
Definí el formato de respuesta final: El agente debe saber cómo terminar. Sin esto, puede ser verbose innecesariamente.
No repitas lo que ya está en el tool schema: Evitá redundancia. Si la description de la tool ya explica cuándo usarla, no lo repitas en el system.
Este es el agente completo en un solo archivo. Cópialo, configura tu API key, y tienes un agente funcional en minutos.
import anthropic # Cliente oficial de la API de Anthropic import json # Para manejar las respuestas de las herramientas # Inicializar el cliente con la API key del entorno client = anthropic.Anthropic() # Definir las herramientas disponibles para el agente tools = [ { "name": "buscar_informacion", "description": "Busca información relevante en internet sobre un tema", "input_schema": { "type": "object", "properties": { "query": { "type": "string", "description": "El término o pregunta a buscar" } }, "required": ["query"] # El campo query es obligatorio } }, { "name": "guardar_resultado", "description": "Guarda el resultado final en un archivo de texto", "input_schema": { "type": "object", "properties": { "contenido": {"type": "string"}, "nombre_archivo": {"type": "string"} }, "required": ["contenido", "nombre_archivo"] } } ] def ejecutar_herramienta(nombre: str, parametros: dict) -> str: """Ejecuta la herramienta solicitada y retorna el resultado como string""" if nombre == "buscar_informacion": # En producción, aquí iría la llamada real a una API de búsqueda return f"Resultados encontrados para '{parametros['query']}': [resultado simulado]" elif nombre == "guardar_resultado": with open(parametros["nombre_archivo"], "w", encoding="utf-8") as f: f.write(parametros["contenido"]) # Guardar en disco return f"Archivo '{parametros['nombre_archivo']}' guardado correctamente" return "Herramienta no reconocida" def correr_agente(tarea: str, max_iteraciones: int = 10) -> str: """ Ejecuta el loop del agente hasta completar la tarea o alcanzar el límite. Retorna el resultado final como string. """ mensajes = [{"role": "user", "content": tarea}] # Historial de conversación for iteracion in range(max_iteraciones): print(f"[Iteración {iteracion + 1}]") # Llamar a la API de Claude con las herramientas disponibles respuesta = client.messages.create( model="claude-sonnet-4-6", # Modelo a usar max_tokens=4096, # Máximo de tokens en la respuesta tools=tools, # Herramientas disponibles messages=mensajes # Historial de la conversación ) # Verificar si Claude terminó de razonar if respuesta.stop_reason == "end_turn": texto_final = next( (b.text for b in respuesta.content if hasattr(b, "text")), "Tarea completada." ) return texto_final # Retornar respuesta final # Si Claude quiere usar una herramienta if respuesta.stop_reason == "tool_use": mensajes.append({"role": "assistant", "content": respuesta.content}) resultados_herramientas = [] for bloque in respuesta.content: if bloque.type == "tool_use": print(f" → Usando herramienta: {bloque.name}") resultado = ejecutar_herramienta(bloque.name, bloque.input) resultados_herramientas.append({ "type": "tool_result", "tool_use_id": bloque.id, # ID para correlacionar la respuesta "content": resultado }) # Agregar resultados al historial para que Claude continúe mensajes.append({"role": "user", "content": resultados_herramientas}) return "Límite de iteraciones alcanzado." # Fallback si no termina # Punto de entrada if __name__ == "__main__": resultado = correr_agente("Investiga las mejores prácticas de prompting para Claude y guarda un resumen en resumen.txt") print(f"\nResultado final:\n{resultado}")
Usá este prompt para que Claude te ayude a diseñar el sistema prompt y las herramientas de tu agente específico. Antes de escribir código, primero diseñá la arquitectura.
Necesito diseñar un agente con la Claude API para el siguiente caso de uso: [DESCRIPCIÓN DEL AGENTE: qué debe hacer, quién lo va a usar, en qué contexto] Ayudame a diseñar: 1. HERRAMIENTAS (tools): - Listá las herramientas mínimas necesarias - Para cada una: nombre, descripción precisa, parámetros con tipos - Indicá cuándo usarla y cuándo NO 2. SYSTEM PROMPT: - Rol del agente en una oración - Proceso de trabajo (pasos numerados) - Límites y restricciones explícitas - Formato de respuesta final 3. CASOS LÍMITE: - Qué pasa si una herramienta falla - Qué pasa si el usuario pide algo fuera del scope - Cuándo debe pedir clarificación vs proceder 4. PROMPT DE PRUEBA: - Dame 3 inputs de prueba que cubran el caso principal, un caso límite y un caso de error Contexto técnico: Python, SDK oficial de Anthropic, modelo claude-sonnet-4-6. Formato: sé específico y directo. Código donde sea útil.
Ejemplo de resultado
Agente iniciado correctamente. He analizado la tarea: necesito buscar información sobre el tema X, procesarla y generar un resumen. Comenzaré con la búsqueda. [Iteración 1] → Usando herramienta: buscar_informacion con query='mejores prácticas prompting Claude'
Mi agente con Claude API está [PROBLEMA: no usando las tools / usando la tool equivocada / entrando en loop / respondiendo antes de terminar]. Este es mi system prompt actual: [SYSTEM PROMPT] Estas son las tools que definí: [DEFINICIÓN JSON DE TOOLS] Este es el input que falla: [INPUT DE PRUEBA] Este es el output actual (o el historial de tool calls): [OUTPUT / HISTORIAL] Diagnosticá qué está mal y decime exactamente qué cambiar. Priorizá cambios en las descriptions de las tools antes de tocar el system prompt.
Ejemplo de resultado
Diagnóstico: el problema está en la descripción de tu tool web_search. Al decir "busca información" sin especificar cuándo NO usarla, Claude la llama en cada iteración aunque ya tenga los datos en contexto. Cambio recomendado: agrega "NO uses esta herramienta si la información ya está disponible en el historial de conversación." Eso solo debería resolver el loop.
🏢 Si tienes una agencia
Construye agentes personalizados para tus clientes como parte de tu oferta de servicio premium. Un agente de research, uno de generación de reportes, uno de monitoreo de competencia. Entregables que el cliente no puede obtener en ningún SaaS.
🛍️ Si vendes productos o servicios
Un agente que revisa tu inbox de soporte cada mañana, clasifica los tickets por urgencia y redacta las primeras respuestas. Reduces el tiempo de atención al cliente en un 60% sin perder personalización.
🎬 Si eres creador de contenido
Un agente que analiza tus métricas de la semana, identifica qué contenido funcionó mejor y genera 5 ideas de videos para la próxima semana basadas en tus propios datos de rendimiento.
Con el agente base funcionando, estos son los próximos pasos naturales.
Prompt caching: Cacheá el system prompt con cache_control: {"type": "ephemeral"} para ahorrar hasta 90% del costo en conversaciones largas.
Streaming: Usá client.messages.stream() para mostrar la respuesta en tiempo real mientras el agente trabaja.
Memoria persistente: Guardá el historial de messages en un archivo JSON entre sesiones para que el agente recuerde conversaciones anteriores.
Logging estructurado: Loguiá cada tool call con timestamp, inputs, outputs y tokens usados. Te va a salvar en el debugging.
MCP servers: Conectá el agente a MCP servers para darle acceso a bases de datos, APIs externas o tu propio file system con permisos granulares.
En la comunidad tienes el workshop completo, plantillas y soporte directo.
VER LA COMUNIDAD →Todas las guías son gratis. Construidas con Claude Code, publicadas para la comunidad.
Ver todas las guías