El ciclo
- Envías la conversación y una lista de herramientas, cada una con nombre, descripción y un JSON Schema para sus parámetros.
- El modelo responde con texto o devuelve una o más llamadas a herramientas con argumentos.
- Tu código valida y ejecuta cada llamada y devuelve los resultados como mensajes de herramienta.
- El modelo usa los resultados para responder o llama a más herramientas.
El modelo nunca ejecuta nada. Eso lo hace tu código y, por tanto, es tu responsabilidad.
Escribir buenas herramientas
- Nombres y descripciones son prompts. Di qué hace la herramienta, cuándo usarla y cuándo no.
- Prefiere pocas herramientas específicas a una genérica
call_api(url, body). - Usa enums, formatos y campos obligatorios en el esquema. Mantén los parámetros planos cuando puedas.
- Devuelve resultados compactos y estructurados. Las respuestas enormes de una API gastan contexto y confunden al modelo.
El scaffolder de OpenAPI a bot genera definiciones de herramientas a partir de una especificación existente como punto de partida.
Valídalo todo
Los argumentos son salida del modelo, así que trátalos como entrada del usuario:
- Valida contra el esquema (Ajv en JavaScript, Pydantic en Python) y rechaza campos desconocidos.
- Comprueba la autorización con la identidad del usuario final, no la del bot: "¿puede esta persona cancelar este pedido?"
- Acota números, limita tamaños de listas y nunca pases argumentos a comandos de shell, cadenas SQL o rutas de archivo sin un tratamiento estricto.
Confirma los efectos secundarios
Separa herramientas de lectura y de escritura. Para todo lo que mueva dinero, borre datos, escriba a otras personas o sea difícil de deshacer:
- Devuelve al usuario una acción pendiente con un resumen y un botón de confirmar (teclado inline en Telegram, botón en Discord o Slack).
- Ejecuta solo cuando el usuario confirme, con una clave de idempotencia para que un doble toque no la ejecute dos veces.
Errores y límites
- Devuelve los errores como resultados que el modelo pueda usar:
{"error": "order_not_found", "hint": "pide al usuario el número de pedido"}. - Limita las llamadas por turno (por ejemplo de 5 a 10) y el tiempo total por turno. Detente y discúlpate en lugar de entrar en bucle.
- Aplica tiempos de espera a cada llamada externa y usa backoff en los reintentos.
- Ejecuta en paralelo las llamadas independientes, pero mantén las escrituras en secuencia salvo que sean realmente independientes.
Observabilidad y pruebas
- Registra el nombre de cada herramienta, los argumentos validados (sin secretos), la duración y el resultado, enlazados a un ID de conversación.
- Crea casos de prueba: "el usuario pide X, se espera la herramienta Y con argumentos Z" y "el usuario pide algo fuera de alcance, no se espera ninguna llamada". Repítelos en cada cambio de modelo o prompt. Consulta pruebas de bots.
- Trata el texto de los resultados como no confiable; páginas web y correos pueden traer instrucciones inyectadas. Consulta defensa contra inyección de prompts.