La proliferación de agentes basados en grandes modelos de lenguaje (LLM) ha traído consigo un problema silencioso pero crítico: la fiabilidad de las llamadas a herramientas externas. Cuando un modelo decide invocar una función —consultar una base de datos, enviar un correo o ejecutar código—, la calidad de esa invocación depende casi enteramente de cómo hayamos definido el esquema de la herramienta. Un esquema ambiguo, incompleto o demasiado permisivo es una invitación abierta a alucinaciones, parámetros inventados y fallos en cascada que rompen la cadena de razonamiento del agente.
El patrón más común en producción sigue siendo Function Calling de OpenAI o la especificación Tools de Anthropic, pero la documentación oficial tiende a mostrar ejemplos mínimos que funcionan en demos, no en entornos reales con datos sucios, usuarios impredecibles y casos frontera. La diferencia entre un prototipo que impresiona en un notebook y un sistema que aguanta tráfico real radica en tres decisiones de diseño: tipado estricto, validación semántica y manejo explícito de errores.
Primero, el tipado. JSON Schema permite definir tipos primitivos, pero la verdadera potencia está en `enum`, `const`, `pattern` y `format`. Si una herramienta espera un código de país ISO 3166-1 alpha-2, no basta con `type: string`; hay que restringirlo a `enum: ["ES", "MX", "AR", ...]`. Lo mismo aplica a fechas (`format: date-time`), correos (`format: email`) o identificadores internos (`pattern: "^usr_[a-z0-9]{12}$"`). Cada restricción añadida reduce el espacio de búsqueda del modelo y elimina una clase entera de errores.
Segundo, la validación semántica. Los esquemas validan sintaxis, no lógica de negocio. Una herramienta de transferencia bancaria puede recibir `amount: 1000` y `currency: "EUR"` sintácticamente correctos, pero el negocio exige que `amount 0`, `currency` esté en la lista de divisas soportadas y el usuario tenga saldo suficiente. La solución no es meter reglas de negocio en el esquema —eso lo vuelve frágil y acopla dominio con interfaz—, sino implementar una capa de validación previa a la ejecución que devuelva errores estructurados al modelo. Así el LLM recibe retroalimentación concreta ("saldo insuficiente", "divisa no soportada") y puede replanificar.
Tercero, el manejo de errores como parte del contrato. La mayoría de esquemas documentan solo el caso feliz. Una herramienta robusta debe declarar en su descripción qué errores puede devolver y con qué estructura: `{"error": "INSUFFICIENT_FUNDS", "message": "Saldo disponible: 50 EUR", "retryable": false}`. Cuando el modelo conoce los modos de fallo posibles, sus reintentos dejan de ser ciegos y empiezan a parecer razonamiento.
Un caso real: un equipo de fintech redujo en un 73% las llamadas fallidas a su API de pagos tras añadir `enum` a los campos de tipo de transacción, `minimum`/`maximum` a importes y una tabla de códigos de error en la descripción de la herramienta. El modelo pasó de inventar tipos como "transferencia_instantanea" a usar exclusivamente "SEPA_INSTANT", "SWIFT" o "INTERNAL".
La lección es clara: el esquema de una herramienta no es metadato administrativo, es la interfaz de programación del modelo. Trátalo con el mismo rigor que una API pública: versionado, changelog, tests de contrato y monitorización de tasas de error por herramienta. En la ingeniería de agentes, la fiabilidad no emerge del modelo, emerge de las restricciones que le imponemos.