Agentes de IA con Uso de Herramientas: ReAct en Práctica
Construye agentes de IA autónomos que pueden usar herramientas y APIs externas para completar tareas complejas.
Visión General
Un chatbot habla; un agente actúa. Dale a un LLM un conjunto de herramientas — búsqueda, una base de datos, una API — y deja de ser un generador de texto para convertirse en un trabajador que busca en la web, consulta tus tablas, ejecuta código y encadena los resultados en algo que un chatbot simple no puede hacer solo. Para cuando el propio loop falle, el Patrón LLM Fallback es la red de seguridad que conviene conectar primero.
Cuándo Usar
Usa este recurso cuando:
- Construyes asistentes autónomos que necesitan datos en tiempo real
- Creas flujos de trabajo que requieren múltiples llamadas a APIs encadenadas
- Implementas razonamiento sobre fuentes de conocimiento externas
- Diseñas sistemas autocorrectivos que pueden reintentar operaciones fallidas
Solución
Agente con Patrón ReAct (Python)
import openai
import json
from typing import Callable
def agente_react(query: str, tools: dict[str, Callable]) -> str:
messages = [
{"role": "system", "content": "Eres un asistente útil. Usa herramientas cuando sea necesario."},
{"role": "user", "content": query}
]
for _ in range(5): # Máximo de iteraciones
response = openai.chat.completions.create(
model="gpt-4",
messages=messages,
tools=[
{"type": "function", "function": {"name": n, "parameters": {}}}
for n in tools.keys()
]
)
msg = response.choices[0].message
if not msg.tool_calls:
return msg.content
messages.append(msg)
for call in msg.tool_calls:
result = tools[call.function.name](**json.loads(call.function.arguments))
messages.append({
"role": "tool",
"tool_call_id": call.id,
"content": str(result)
})
return "Máximo de iteraciones alcanzado"
Ejemplo de Definición de Herramienta
def buscar_wikipedia(query: str) -> str:
"""Buscar en Wikipedia por un tema."""
# Implementación omitida
return f"Resultados para {query}"
tools = {"buscar_wikipedia": buscar_wikipedia}
resultado = agente_react("¿Quién ganó el Mundial de FIFA 2022?", tools)
Explicación
El patrón ReAct (Razonamiento + Acción) alterna entre:
- Pensamiento: El LLM razona sobre qué hacer a continuación
- Acción: El LLM llama una herramienta con argumentos estructurados
- Observación: El resultado de la herramienta se devuelve como contexto
- Repetir: Hasta que la tarea esté completa
Decisiones clave de diseño:
- Esquemas de herramientas: Usa el formato de function calling de OpenAI para seguridad de tipos
- Límites de iteración: Previene bucles infinitos con un conteo máximo de pasos
- Manejo de errores: Las herramientas deben devolver errores de forma controlada, no fallar
- Ventana de contexto: Resume salidas largas de herramientas para ajustarse a los límites de tokens
Variantes
| Framework | Patrón | Ideal Para |
|---|---|---|
| LangChain Agents | ReAct, Plan-and-Execute | Prototipado rápido |
| AutoGen | Conversación multi-agente | Tareas colaborativas |
| CrewAI | Agentes basados en roles | Flujos de trabajo de negocio |
| Custom | ReAct con registro de herramientas | Sistemas de producción |
Lo que Funciona
- Define interfaces claras de herramientas: Cada herramienta necesita nombre, descripción y esquema JSON
- Limita la cantidad de herramientas: 3-5 herramientas bien diseñadas superan a 20 vagas
- Agrega validación: Verifica argumentos de herramientas antes de ejecutar
- Registra todos los pasos: El razonamiento del agente es opaco; el logging ayuda a depurar
- Implementa timeouts: Las herramientas externas pueden colgarse; establece timeouts generosos
Errores Comunes
- Dar demasiadas herramientas a un agente: Aumenta confusión y tasa de errores
- Faltar manejo de errores: Una llamada a herramienta fallida sin recuperación crashea el loop
- Ignorar límites de tokens: Historiales largos de observaciones agotan la ventana de contexto
- No validar salidas: Los agentes pueden alucinar argumentos de herramientas
- Omitir revisión humana: Los agentes autónomos deben tener interruptores de emergencia
Patrón Plan-and-Execute
import openai
import json
def plan_and_execute(query: str, tools: dict) -> str:
# Paso 1: Generar un plan
plan_response = openai.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "Divide la tarea en pasos. Devuelve un array JSON de pasos."},
{"role": "user", "content": query}
],
response_format={"type": "json_object"}
)
steps = json.loads(plan_response.choices[0].message.content)["steps"]
# Paso 2: Ejecutar cada paso
results = []
for step in steps:
result = agente_react(step, tools)
results.append(result)
# Paso 3: Sintetizar
final = openai.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "Sintetiza los resultados en una respuesta final."},
{"role": "user", "content": f"Query: {query}\nResults: {json.dumps(results)}"}
]
)
return final.choices[0].message.content
Plan-and-Execute separa la planificación de la ejecución. El planner divide la tarea en pasos, cada paso corre por un loop ReAct, y una llamada final sintetiza los resultados. Esto reduce el consumo de tokens porque cada paso tiene una ventana de contexto más pequeña. También habilita ejecución paralela de pasos independientes.
Schemas de Herramientas con JSON Schema
tool_schemas = [
{
"type": "function",
"function": {
"name": "search_database",
"description": "Buscar en la base de datos de productos por nombre o categoría",
"parameters": {
"type": "object",
"properties": {
"query": {
"type": "string",
"description": "Término de búsqueda"
},
"category": {
"type": "string",
"enum": ["electronics", "books", "clothing"],
"description": "Filtro de categoría de producto"
},
"limit": {
"type": "integer",
"minimum": 1,
"maximum": 100,
"default": 10
}
},
"required": ["query"]
}
}
}
]
Los schemas detallados de herramientas mejoran la precisión del agente. Incluye description para cada parámetro — el LLM lee estos para decidir cuándo y cómo llamar la herramienta. Usa enum para valores restringidos, minimum/maximum para rangos numéricos, y required para campos obligatorios. Cuanto más preciso el schema, menos argumentos alucinados.
Gestión de la Ventana de Contexto
def summarize_observations(messages: list, max_tokens: int = 4000) -> list:
"""Resume las salidas de herramientas cuando el contexto crece demasiado."""
total = sum(len(str(m.get("content", ""))) for m in messages)
if total < max_tokens:
return messages
# Mantener system + primer mensaje user, resumir el resto
system = messages[0]
user_query = messages[1]
history = messages[2:]
summary = openai.chat.completions.create(
model="gpt-4",
messages=[
{"role": "system", "content": "Resume las llamadas a herramientas y resultados concisamente."},
{"role": "user", "content": json.dumps([{"role": m["role"], "content": m["content"][:500]} for m in history])}
]
).choices[0].message.content
return [system, user_query, {"role": "system", "content": f"Contexto previo: {summary}"}]
Las ejecuciones largas de agentes acumulan historiales grandes de observaciones que agotan la ventana de contexto. Resume periódicamente manteniendo el system prompt y la query original, luego comprime las salidas de herramientas en un resumen. Alternativamente, usa truncación sliding-window o selección de contexto retrieval-augmented para mantener solo observaciones relevantes.
Orquestación Multi-Agente
def multi_agent_orchestrate(query: str) -> str:
agents = {
'researcher': {
'system': 'You are a research agent. Find information using search tools.',
'tools': ['web_search', 'read_file']
},
'coder': {
'system': 'You are a coding agent. Write and execute code.',
'tools': ['run_python', 'write_file']
},
'reviewer': {
'system': 'You are a review agent. Check code quality and correctness.',
'tools': ['read_file', 'run_tests']
}
}
# Ruta al researcher primero
research = run_agent(agents['researcher'], query)
# Pasa research al coder
code = run_agent(agents['coder'], f"Based on: {research}\nImplement the solution.")
# Review del código
review = run_agent(agents['reviewer'], f"Review this code:\n{code}")
if 'APPROVE' in review:
return code
else:
# Re-ruta al coder con feedback
return run_agent(agents['coder'], f"Fix issues:\n{review}\nOriginal:\n{code}")
La orquestación multi-agente asigna roles especializados a diferentes agentes. Cada agente tiene su propio system prompt y conjunto de herramientas. Un coordinador enruta tareas entre agentes basado en el estado actual. Este patrón funciona bien para flujos de trabajo complejos: investigar → implementar → revisar → desplegar. Mantén la comunicación entre agentes estructurada — pasa contexto como cadenas formateadas o JSON, no historiales sin procesar de mensajes.
Cuándo Evitar
- Preguntas y respuestas simples: Si una sola llamada al LLM responde la pregunta, los agentes añaden latencia y costo innecesarios
- Decisiones de alto riesgo: Diagnóstico médico, asesoría legal, trading financiero — los agentes pueden alucinar argumentos de herramientas
- Sistemas en tiempo real: Los loops de agentes con múltiples llamadas LLM añaden 5-30 segundos de latencia
- Cargas de trabajo sensibles al costo: Cada iteración es una llamada completa al LLM; cinco iteraciones pueden costar varias veces más que una sola llamada.
Solución de Problemas
- Los outputs del modelo son inconsistentes: usa temperature 0 para tareas determinísticas, emplea seed si la API lo soporta y versiona el prompt.
- El prompt injection filtra contexto: separa el input del usuario de las instrucciones del sistema.
- Costos altos de tokens: cachea embeddings, resume contextos largos y elige modelos más pequeños para tareas simples.
- La recuperación devuelve chunks irrelevantes: ajusta tamaño de chunk, overlap y filtros de metadata. Evalúa las métricas de recuperación por separado de la generación.
- Las puntuaciones de evaluación no coinciden con el juicio humano: define rúbricas claras, usa varios evaluadores y registra el desacuerdo. La revisión humana sigue siendo la verdad de referencia.
Lectura Adicional
- OpenAI — Guía de Function Calling — la mecánica del uso de herramientas
- Anthropic — Documentación de Tool Use — el mismo patrón en Claude
- LangChain Agents — la implementación del framework
- ReAct: Synergizing Reasoning and Acting — el paper fundacional del patrón
Preguntas frecuentes
¿Cuál es la diferencia entre RAG y un agente?
RAG recupera documentos y responde una vez. Los agentes pueden tomar múltiples acciones, usar herramientas e iterar hasta cumplir una meta.
¿Cuántas herramientas debería tener un agente?
Comienza con 2-3. La investigación muestra que la precisión cae bruscamente más allá de 5-7 herramientas.
¿Los agentes pueden funcionar sin OpenAI?
Sí. Modelos locales (Llama, Mistral) soportan llamado de herramientas vía formatos de salida estructurada como JSON mode.
¿Cómo manejo fallos en llamadas a herramientas?
Envuelve cada ejecución de herramienta en un try/except. Devuelve mensajes de error como resultados de herramientas para que el agente pueda razonar sobre el fallo y reintentar o intentar una alternativa. Configura un conteo máximo de reintentos para prevenir loops infinitos. Registra el error completo para debugging mientras le das al agente una descripción concisa del error.
¿Cuál es el costo de correr un loop de agente?
Cada iteración es una llamada al LLM. Con GPT-4, un loop de 5 iteraciones con 2000 tokens por llamada cuesta aproximadamente $0.60. Con GPT-4o-mini, el mismo loop cuesta menos de $0.01. Usa modelos más baratos para tareas simples de tool-routing y reserva GPT-4 para razonamiento complejo. Cachea resultados de herramientas para evitar llamadas redundantes.
¿Cómo testeo el comportamiento del agente?
Mockea las respuestas del LLM y llamadas a herramientas en tests unitarios. Para tests de integración, usa un entorno controlado con herramientas stub que devuelven resultados predecibles. Graba traces de producción y replícalas para testear cambios. Evita testear contra APIs en vivo — servicios externos flaky hacen los tests poco confiables.
¿Cuándo debo usar orquestación multi-agente?
Usa multi-agente cuando una tarea tiene fases distintas (investigar, implementar, revisar) que requieren diferentes instrucciones de sistema o sets de herramientas. Para tareas simples, un solo agente con múltiples herramientas es más eficiente y predecible. La orquestación multi-agente añade overhead de coordinación y costo — úsala solo cuando los roles son claramente separables.
Recursos Relacionados
Construir Agentes de IA Autónomos con Uso de Herramientas
Cómo diseñar agentes de IA que autónomamente planifiquen, ejecuten herramientas e iteren hacia objetivos usando ReAct, function calling y arquitecturas de memoria.
RecipeCrea búsqueda semántica con embeddings en Python, JS y Java
Crea un motor de búsqueda semántica con embeddings de texto y similitud vectorial. Incluye ejemplos en Python, JavaScript y Java con FAISS, pgvector y OpenAI.
RecipeBot de Slack con OpenAI: menciones, DMs y memoria
Un bot conversacional de Slack potenciado por OpenAI que responde menciones y mensajes directos, mantiene el historial por usuario y controla el gasto
RecipeChatbot con OpenAI Assistants API: Build, Coste y Deploy
Cómo crear un chatbot de IA usando la OpenAI Assistants API con function calling y file search.
RecipeGenerar Imágenes Programáticamente con Modelos de IA
Cómo crear, editar y optimizar imágenes usando las APIs de DALL-E, Stable Diffusion y Midjourney con prompt engineering, procesamiento por lotes y moderación de contenido.
RecipeAnálisis de Sentimiento con Python y NLTK
Puntúa el sentimiento de texto con NLTK VADER y léxicos personalizados en Python. Clasifica reviews, procesa CSVs y analiza tendencias con ejemplos.