Cuando desplegamos un agente para automatizar informes desde un sistema SCADA en un cliente del sector energético, los primeros días transcurrieron sin problemas. Luego empezaron los fallos silenciosos: el agente llamaba a la herramienta correcta, pero enviaba los argumentos en el formato incorrecto — un número donde se esperaba una cadena, null donde se esperaba un valor. ¿El resultado? La herramienta devolvía un error, el agente lo ignoraba y seguía adelante como si nada. El informe se generaba, parecía correcto, pero las cifras eran inexactas. Tardamos varios días en encontrar la causa.
Tool calling — la llamada a herramientas y sistemas externos mediante un LLM — es la capacidad fundamental de cualquier agente en producción. Y al mismo tiempo su mayor fuente de fallos silenciosos. Este artículo se centra en patrones concretos: cómo diseñar esquemas de herramientas, validar argumentos, gestionar errores y construir lógica de reintento que funcione en condiciones reales.
Por qué falla el tool calling — no de la forma que usted cree
Cuando los desarrolladores investigan la falta de fiabilidad de los agentes, suelen buscar la causa en el modelo. Razonamiento deficiente, inferencia insuficiente, comprensión errónea de la tarea. En la práctica hemos comprobado que la mayoría de los incidentes en producción tienen otra causa: mal diseño del esquema de herramienta, validación de argumentos inexistente, errores de herramienta sin gestionar.
Los cuatro patrones de fallo más frecuentes que observamos:
- El agente llama a la herramienta equivocada — porque las descripciones de las herramientas son demasiado similares, vagas o no discriminantes
- El agente llama a la herramienta correcta con los argumentos incorrectos — porque el esquema no describe con precisión qué valores son válidos
- El agente ignora el error de la herramienta — porque nadie gestionó el caso en que la herramienta devuelve una excepción
- El agente entra en un bucle de reintento — porque la lógica de reintento no está limitada y carece de backoff exponencial
Ninguno de estos problemas está relacionado con la inteligencia del modelo. Todos se pueden resolver a nivel de ingeniería. Y todos se repiten independientemente de la arquitectura de agente utilizada.
Diseño del esquema de herramienta: precisión antes que brevedad
El esquema de herramienta es lo que el agente ve cuando decide qué llamar. Si el esquema es impreciso, el agente adivina — y adivinar en un sistema determinista es un problema.
Reglas básicas de diseño de esquemas que funcionan en la práctica:
El nombre de la herramienta debe ser verbo de acción + objeto. get_sensor_reading es correcto. sensor es incorrecto. data es muy incorrecto. El LLM se orienta por el nombre — si los nombres de dos herramientas suenan parecidos, el agente las confundirá independientemente de la calidad de la descripción.
La descripción debe distinguir cuándo usar la herramienta y cuándo no. No basta con escribir "devuelve datos del sensor". Escriba: "Llama solo cuando necesites valores en vivo de un dispositivo concreto por ID. No usar para datos históricos — para eso está get_sensor_history." La negación explícita es igual de importante que la descripción positiva.
Cada parámetro debe tener tipo, descripción y ejemplo. No es suficiente sensor_id: string. Escriba: "ID del sensor en el formato PLANT_ZONE_NNN, p. ej. A_LINE1_042. Nunca introduzca solo el número sin el prefijo." El modelo no inferirá el formato — hay que mostrárselo.
Marque los parámetros opcionales de forma explícita — e indique cuál es el valor predeterminado y qué ocurre si se omiten. Sin esto el agente genera null de forma repetida o asume un valor incorrecto.
Ejemplo de esquema antes y después:
# Antes (esquema típico deficiente)
{
"name": "sensor_data",
"description": "Gets sensor data",
"parameters": {
"id": {"type": "string"},
"from": {"type": "string"},
"to": {"type": "string"}
}
}
# Después (esquema de producción)
{
"name": "get_sensor_reading",
"description": "Reads current live value from a field sensor.
Use ONLY for real-time values. For historical ranges use get_sensor_history instead.
Returns {value, unit, timestamp, status}. Throws SensorOfflineError if device unreachable.",
"parameters": {
"sensor_id": {
"type": "string",
"description": "Sensor identifier in format PLANT_ZONE_NNN, e.g. A_LINE1_042"
},
"unit": {
"type": "string",
"enum": ["raw", "normalized"],
"description": "Output unit type. Default: 'raw'",
"default": "raw"
}
},
"required": ["sensor_id"]
}La diferencia no está en la elegancia — está en el porcentaje de llamadas correctas con argumentos válidos que realiza el agente. En la práctica: corrigiendo los esquemas redujimos la tasa de llamadas incorrectas en más de la mitad sin ningún cambio en el modelo.
Validación de argumentos: no hay que fiarse del modelo
Aunque el esquema sea bueno, el modelo genera ocasionalmente argumentos que son sintácticamente válidos pero semánticamente incorrectos. from_date: "2026-13-45" es una cadena válida, pero una fecha inválida. count: -5 es un número válido, pero no tiene sentido.
Validar los argumentos antes de la llamada real a la herramienta es una obligación, no una optimización.
Tres capas de validación que recomendamos:
1. Validación por JSON Schema — la capa más sencilla. Compruebe que el agente ha enviado el tipo correcto para cada parámetro. La mayoría de los frameworks (LangGraph, LangChain) lo hacen automáticamente si tiene el esquema, pero una capa explícita es más segura.
2. Validación de dominio — verificación de que los valores tienen sentido en el contexto de su dominio. Fechas en un rango razonable, IDs en el formato correcto, valores numéricos en un rango válido. Esto debe programarlo usted mismo — ningún framework genérico lo hará por usted.
3. Integridad referencial — verificación de que la entidad referenciada existe. sensor_id: "A_LINE1_042" debe comprobarse contra el registro real de sensores — el modelo no tiene forma de saber qué IDs son válidos.
Cuando la validación falle, no lance solo una excepción. Devuelva un mensaje de error estructurado que le diga al modelo *qué* fue incorrecto y *cómo* corregirlo:
# Incorrecto
raise ValueError("Invalid sensor_id")
# Correcto
return {
"error": "INVALID_ARGUMENT",
"parameter": "sensor_id",
"received": "A_LINE_42",
"message": "Format must be PLANT_ZONE_NNN. Did you mean A_LINE1_042?",
"hint": "Call list_sensors() to get valid IDs for this plant"
}Este mensaje de error es la entrada al siguiente paso del agente — cuanto más informativo sea, mayor es la probabilidad de que el agente se autocorrija sin necesidad de escalar innecesariamente.
Gestión de errores: los errores de herramienta son una situación normal, no una excepción
Uno de los mayores problemas conceptuales que observamos en los agentes en producción: el código fue escrito para el happy path. Cuando la herramienta devuelve un error, el agente se comporta de forma impredecible — o se bloquea, o continúa con un estado erróneo.
La realidad en producción: las herramientas fallan. Las APIs tienen interrupciones. Las bases de datos están temporalmente no disponibles. Los sistemas SCADA devuelven timeout. Estos no son edge cases — son eventos habituales en entornos industriales.
Patrón básico de gestión de errores para cada herramienta:
def call_tool_safely(tool_fn, args, max_retries=3):
for attempt in range(max_retries):
try:
result = tool_fn(**args)
return {"status": "ok", "data": result}
except TransientError as e:
if attempt == max_retries - 1:
return {
"status": "error",
"type": "TRANSIENT",
"message": str(e),
"hint": "Service temporarily unavailable, retry later"
}
time.sleep(2 ** attempt) # exponential backoff
except PermanentError as e:
return {
"status": "error",
"type": "PERMANENT",
"message": str(e),
"hint": "Do not retry. Escalate to human operator."
}
except Exception as e:
return {
"status": "error",
"type": "UNKNOWN",
"message": str(e),
"hint": "Unexpected error. Log and escalate."
}Principios clave:
- Distinga errores transitorios de permanentes. Un timeout es un error transitorio (reintento). Un error de autorización es permanente (no reintentar, escalar). El modelo debe saber qué hacer a continuación.
- Backoff exponencial — no una pausa fija. Cada reintento espera el doble (1 s, 2 s, 4 s...). Evita la sobrecarga de los sistemas durante las interrupciones.
- Número máximo de reintentos — siempre limitado. Sin límite, el agente puede entrar en un bucle infinito. En la práctica: una tasa de reintento del 12 % aproximadamente es habitual en sistemas en producción — si no la controla, puede duplicar el total de llamadas y los costes.
- Mensaje de error estructurado — el agente debe recibir información sobre el tipo de error y el paso siguiente recomendado.
Puede leer más sobre las consecuencias en costes de la lógica de reintento en el artículo sobre los costes del agente de IA en producción.
Idempotencia: la condición de fiabilidad olvidada
Cuando un agente reintenta la llamada a una herramienta, debe ser seguro llamarla varias veces con los mismos argumentos. Si no lo es — tiene un problema.
Llamada idempotente: llamar a get_sensor_reading(sensor_id="A_LINE1_042") varias veces devuelve el mismo valor (o equivalente) sin efecto secundario. Seguro para reintentar.
Llamada no idempotente: llamar a create_work_order(equipment_id="P-042", type="inspection") varias veces crea múltiples órdenes de trabajo. Una catástrofe con reintento.
Regla para sistemas en producción: toda herramienta que realice escritura, mutación o acción con efecto secundario debe estar protegida contra llamadas duplicadas.
Patrones de protección:
Clave de idempotencia — el agente genera una clave única para cada tarea y la envía con la llamada. El backend registra la clave y una segunda llamada con la misma clave devuelve el resultado de la primera sin volver a ejecutar la acción:
def create_work_order(equipment_id, type, idempotency_key):
existing = db.find_by_key(idempotency_key)
if existing:
return existing # Devolvemos el resultado anterior
result = actually_create_work_order(equipment_id, type)
db.store(idempotency_key, result)
return resultComprobación de estado antes de la acción — antes de una operación de escritura, verificar si el estado ya corresponde al objetivo. Si ya existe una orden de trabajo para el equipo P-042 para hoy, no crear una nueva. Esto es más sencillo que la clave de idempotencia y adecuado para dominios de negocio con unicidad natural.
Documentación explícita en el esquema — toda herramienta con efecto secundario debe tener en su descripción: "Esta acción es irreversible / crea un registro. Llama solo si estás seguro de que las condiciones están cumplidas." El modelo que recibe esta información actúa con más cautela.
Por qué el agente llama a la herramienta equivocada — y cómo reducirlo
Uno de los problemas más desconcertantes: el agente llama de forma consistente a tool_A en lugar de tool_B a pesar de que la correcta es tool_B. Las causas son varias y cada una tiene una solución diferente.
Nombres y descripciones demasiado similares. Si tiene get_equipment_data y fetch_equipment_info, el agente confundirá estas herramientas. Solución: revise todo el conjunto de herramientas y compruebe que los nombres y las descripciones son inequívocamente diferenciadores. Si dos colegas no pueden distinguirlas sin leer el código, el modelo tampoco podrá.
Demasiadas herramientas a la vez. Los LLM tienen una capacidad de atención limitada. Cuando le presenta al agente 30 herramientas en un solo prompt, la probabilidad de una selección incorrecta aumenta. Patrón de solución: toolset routing — el agente primero elige un grupo de herramientas (p. ej. "herramientas de sensor" vs "herramientas de informes") y luego selecciona la concreta de ese grupo. Esto está relacionado con el protocolo MCP — los servidores actúan como grupos naturales de herramientas.
Contexto ausente en el prompt. Si el system prompt no le dice al agente en qué contexto está trabajando, el modelo adivina la herramienta adecuada a partir del historial de la conversación. El contexto explícito en el system prompt — "Trabajas en el sistema de gestión de producción, no en el sistema de RR. HH." — reduce los errores de selección de herramienta.
Sesgo de entrenamiento del modelo. Algunos modelos tienen datos de entrenamiento que favorecen ciertos patrones de llamada. Si el agente llama de forma repetida a la herramienta incorrecta a pesar de tener el esquema correcto, pruebe a cambiar el nombre de la herramienta — a veces incluso eso ayuda.
Lógica de reintento: cinco reglas que salvarán la producción
El reintento es una parte inseparable del tool calling fiable. Pero un reintento mal implementado es peor que ningún reintento — puede convertir una interrupción transitoria en un fallo en cascada.
Regla 1: Reintentar solo errores transitorios. HTTP 503 (Service Unavailable) y timeout son transitorios. HTTP 400 (Bad Request) y 403 (Forbidden) son permanentes — el reintento no ayudará, solo malgastará recursos.
Regla 2: Backoff exponencial con jitter. Una pausa fija (reintento cada segundo) sobrecarga el sistema durante una interrupción. El backoff exponencial con jitter aleatorio (±20 %) distribuye la carga:
delay = min(base_delay * (2 ** attempt) + random.uniform(0, 0.3), max_delay)Regla 3: Límite absoluto de intentos. Tres intentos suelen ser suficientes. Cinco es el máximo. Más reintentos → mayor riesgo de retry storm (todos los agentes reintentando el sistema caído al mismo tiempo).
Regla 4: Circuit breaker para interrupciones repetidas. Si una herramienta determinada falla varias veces seguidas, "desconéctela" temporalmente y devuelva todas las llamadas siguientes inmediatamente como CIRCUIT_OPEN. Tras el período de cooldown, permita una llamada de prueba. Esto también protege sus sistemas backend.
Regla 5: Acción de fallback. Cuando tanto el reintento como el circuit breaker fallan, ¿qué hace el agente? ¿Escala al operador humano, continúa sin esa información, o se detiene? Toda herramienta crítica debe tener definida una estrategia de fallback. Sin ella, el agente es impredecible ante un fallo — lo que es la motivación directa para los HITL gates.
Testing del tool calling antes de producción
La fiabilidad del tool calling no se puede verificar solo con pruebas manuales del happy path. Algunos patrones de testing que recomendamos:
Mock toolset testing — cree versiones mock de todas las herramientas que devuelvan distintas combinaciones de respuestas: éxito, error transitorio, error permanente, salida malformada. Ejecute el agente contra estos mocks y observe el comportamiento.
Boundary testing de argumentos — pruebe manualmente qué argumentos genera el modelo para entradas límite: cadena vacía, valores null, números extremos, fechas en el pasado o en el futuro. El esquema debe excluir explícitamente estos casos o el agente fallará en ellos de forma repetida.
Chaos testing — con cierta probabilidad (p. ej. 20 %) inyecte un error en la herramienta durante la prueba. Verifica que la lógica de reintento y el comportamiento de fallback funcionan en la práctica, no solo en unit tests.
Revisión de trazas — para el despliegue en producción es imprescindible la observabilidad y el tracing. Cada llamada a una herramienta debe registrarse con argumentos, resultado, latencia y el error si lo hubiera. Sin esto no sabrá ni por dónde empezar a buscar cuando se produzca un incidente en producción.
Preguntas frecuentes
¿Cuántas herramientas puede tener un agente a la vez?
En la práctica: por encima de 15–20 herramientas en un solo contexto la fiabilidad de la selección se deteriora notablemente. La solución es el toolset routing o los servidores MCP — el agente primero elige el grupo de herramientas correcto y luego la herramienta concreta de ese grupo. Si tiene 50+ herramientas, la navegación jerárquica es una necesidad, no una optimización.
¿Qué hacer si el agente genera argumentos alucinados — valores que no existen?
Dos pasos: primero, el esquema debe mostrar explícitamente el formato de los valores válidos, incluidos ejemplos. Segundo, la validación debe comprobar la existencia de las entidades referenciadas (p. ej. sensor_id contra el registro) y devolver un error estructurado con pistas sobre cómo encontrar los valores válidos. Adicionalmente: una herramienta list_available_X() (p. ej. list_sensors()) ayuda al agente a buscar por sí mismo los IDs válidos sin alucinar.
¿Es seguro dejar que el agente ejecute acciones irreversibles de forma automática?
Depende del contexto. Para acciones de bajo riesgo (lectura de datos, generación de informes) la automatización total es correcta. Para acciones irreversibles (crear pedidos, modificar configuraciones, enviar mensajes) recomendamos una puerta HITL explícita — el agente propone la acción, el operador humano la aprueba. La Ley de IA de la UE a partir de agosto de 2026 exige supervisión humana para sistemas de IA de alto riesgo — esto implica directamente HITL para acciones con consecuencias potencialmente graves.
¿Cuál es la forma más rápida de reducir la tasa de llamadas erróneas?
En la práctica el mayor efecto lo produce corregir los esquemas de herramientas — concretamente descripciones discriminantes, ejemplos de valores válidos y delimitación negativa explícita ("esto no usarlo para..."). El segundo gran efecto viene de reducir el número de herramientas en un solo contexto. Estos dos cambios no requieren modificar el modelo ni la arquitectura.
¿Cómo monitorizar la calidad del tool calling en producción?
Registre cada llamada con: timestamp, tool_name, argumentos (sin PII), status (ok/error), tipo de error, latencia, número de intento. Monitorice la tasa de errores por herramienta — si una herramienta tiene una tasa de error 3× superior a la media, es una señal para auditar el esquema. Herramientas como Langfuse (self-hostable) o LangSmith lo permiten sin necesidad de infraestructura de observabilidad propia.
Conclusión
*El tool calling es el lugar donde empieza la mayoría de los problemas de fiabilidad de los agentes — y al mismo tiempo donde pueden resolverse de forma pura a nivel de ingeniería, sin cambiar el modelo. Esquemas bien diseñados, validación de argumentos, gestión de errores estructurada y lógica de reintento acotada convierten un agente impredecible en una herramienta operable. Si está a punto de desplegar un agente en producción o está resolviendo problemas de fiabilidad con un sistema existente, estaremos encantados de evaluar su caso concreto — diseñaremos las herramientas, las validaciones y la gestión de errores para su entorno.*
