1. La herramienta del agente: qué es realmente
En módulos anteriores ya visteis las herramientas desde el lado de Apps SDK — como «funciones de backend» a las que ChatGPT accede a través de tu App. Ahora cambiamos el enfoque: veremos las herramientas con los ojos de un agente en Agents SDK y detallaremos cómo elige qué invocar y qué hacer con los errores.
En un backend tradicional sueles pensar en términos de «endpoint», «método del controlador», «función de servicio». En el mundo de los agentes, la unidad básica de acción pasa a ser la herramienta (tool). Las tools del agente y las mcp-tools son distintas, aunque se solapan en ocasiones.
Hablando estrictamente: una herramienta en el contexto de ChatGPT Agents SDK es la descripción de una función que el modelo puede solicitar ejecutar. El modelo no ejecuta el código por sí mismo; genera una solicitud estructurada (normalmente JSON) y el runtime (tu código, el servidor MCP o Agents SDK) ejecuta esa operación y devuelve el resultado.
En el ecosistema de ChatGPT Agents SDK una herramienta se describe mediante una configuración: tiene name, description y parameters (JSON Schema de los argumentos). El agente ve este conjunto de herramientas, las mantiene en su contexto y, durante su razonamiento, decide qué tool llamar y con qué argumentos.
El agente (o ChatGPT como host) recibe esta lista, la «memoriza» en su contexto y, en el proceso de razonamiento, decide: para qué solicitud del usuario invocar qué herramienta y con qué argumentos. Por eso en las especificaciones se repite la máxima «tools are a contract» — las herramientas son un contrato entre el modelo y tu código, y no simplemente «una función en Python/TS».
Podemos hacer una analogía con una API clásica. La ruta /api/gifts/search es puro sintaxis: URL, método, formato del cuerpo. Pero la tool search_gifts es semántica: «búsqueda de regalos por perfil y presupuesto». La descripción de la herramienta es como un prompt, solo que estructurado y pensado para una LLM, no para una persona.
2. Tipos de herramientas: qué puede hacer un agente LLM
Para no ahogarte en el caos de «funciones que hacen de todo», es útil ver las herramientas como varias categorías típicas. No es una tipificación formal del SDK, sino un enfoque arquitectónico que te ayudará mucho.
En nuestro backend los agentes LLM suelen tener tres fuentes de herramientas.
- Herramientas de negocio locales. Son las que viven en tu backend: acceso a BD, lógica de dominio (filtrado, recomendaciones, scoring). Por ejemplo, para GiftGenius podríamos tener herramientas que extraen productos de su tabla en PostgreSQL o que calculan un scoring personal de «qué tan bien encaja el regalo para esta persona».
- Herramientas MCP. Aquí el servidor MCP actúa como proveedor de herramientas (tools): registra funciones, recursos y prompts y se los entrega al cliente (ChatGPT, agente LLM). A través de MCP, las herramientas pueden llamar APIs externas, trabajar con archivos o proporcionar plantillas de prompts.
- Herramientas de integración. Todo lo que te conecta con el resto del mundo: ACP/commerce (creación de pedido y checkout), envío de emails, webhooks, escritura en la CRM. Estas herramientas (tools) suelen ser más peligrosas porque modifican el estado de sistemas externos, y deben tratarse con especial cuidado en seguridad e idempotencia.
Existe otra clasificación útil — por el tipo de acción. En la investigación sobre herramientas LLM se suelen distinguir: herramientas de obtención de datos (búsqueda, RAG, get_*), herramientas de acciones con efectos secundarios (create_order, send_email), puramente computacionales (calculate_loan) y de sistema/control (handoff_to_human, finish_task).
Para fijarlo, viene bien ver una pequeña tabla.
| Categoría | Ejemplo en GiftGenius | Efecto secundario | Riesgo |
|---|---|---|---|
| Data Retrieval | |
No | Bajo |
| Action / Mutating | |
Sí | Alto |
| Computation | |
No | Medio |
| System / Control | |
No | Lógico |
Desde el punto de vista arquitectónico lo más importante es: las herramientas de solo lectura deben ser numerosas y baratas, mientras que las que modifican estado — escasas, extremadamente cuidadosas, con logs, idempotencia y, a menudo, con confirmación del usuario.
A continuación hablaremos principalmente de herramientas de obtención de datos y de herramientas de acción, porque sobre ellas se construye la lógica de GiftGenius.
3. JSON Schema como contrato entre el modelo y tu código
Ahora profundicemos en cómo se describe una herramienta. En ChatGPT Agents SDK (como en Apps SDK) el formato estándar para describir los parámetros de una herramienta es JSON Schema: describes el tipo object, sus properties, tipos de campos, obligatorios, restricciones, etc.
Es importante entender: JSON Schema aquí no es solo, ni principalmente, para validación. Es parte del prompt para el modelo. En las guías oficiales de OpenAI sobre el diseño de herramientas (tools) se dice explícitamente que la calidad del trabajo del agente depende mucho de lo detallados y inequívocos que sean los campos, sus nombres y comentarios.
Veamos un ejemplo para GiftGenius que ya apareció en los planes del curso.
{
"name": "search_gifts",
"description": "Encuentra regalos según el tipo de destinatario, intereses y presupuesto.",
"parameters": {
"type": "object",
"properties": {
"recipient_type": {
"type": "string",
"description": "Quién es el destinatario del regalo (por ejemplo, 'hombre', 'mujer', 'niño')."
},
"interests": {
"type": "array",
"items": { "type": "string" },
"description": "Intereses clave (deportes, libros, tecnología, etc.)."
},
"budget": {
"type": "number",
"description": "Presupuesto máximo en la moneda del usuario."
}
},
"required": ["recipient_type", "budget"]
}
}
Aquí hay varios puntos importantes.
- Primero, name y description. Para el modelo es la señal principal de cuándo usar esta herramienta. La documentación sobre enrutamiento semántico subraya que la descripción de la herramienta es, de hecho, una API para el modelo: si la llamas func1 y pones «hace algo útil», el modelo honestamente no entenderá cuándo invocarla. Si en cambio usas search_gifts y añades una descripción clara, la elección se vuelve mucho más trivial.
- Segundo, parameters. Los nombres de los campos y sus descripciones son cruciales. Para una LLM recipient_type es mucho más claro que type. Una buena descripción del estilo «Quién es el destinatario del regalo…» le sugiere al modelo que debe introducir ahí el tipo de destinatario, y no, por ejemplo, el formato del envoltorio.
- Tercero, required. No es solo validación de tu lado, sino también una pista para el modelo: intentará rellenar los campos obligatorios y omitirá los opcionales si el contexto no está claro. Esto reduce el número de invocaciones de tools «vacías» o incorrectas.
Las guías oficiales de Apps SDK recomiendan explícitamente: haced herramientas estrechas, de una sola responsabilidad, con nombres y descripciones claros, y evitad herramientas «hazlo todo de regalos» que intentan unificar tareas distintas.
4. Diseñando herramientas de GiftGenius: del esquema al código
Tomemos nuestro GiftGenius y añadamos dos herramientas clave del agente LLM que se necesitarán en casi todos los escenarios:
- suggest_gifts(profile, budget) — devuelve una lista de candidatos;
- get_gift_details(gift_id) — muestra los detalles de un regalo concreto.
Nuestras suggest_gifts y get_gift_details son un ejemplo típico de herramientas de negocio locales de la clasificación anterior, principalmente de la categoría Data Retrieval.
Esquema para suggest_gifts
Empecemos con un JSON Schema limpio y luego mostraremos cómo podría verse en código TypeScript del backend/runtime del agente.
{
"name": "suggest_gifts",
"description": "Selecciona una lista de regalos en función del perfil del destinatario y el presupuesto.",
"parameters": {
"type": "object",
"properties": {
"age": {
"type": "integer",
"minimum": 0,
"maximum": 120,
"description": "Edad del destinatario en años."
},
"relationship": {
"type": "string",
"enum": ["friend", "coworker", "partner", "family"],
"description": "Relación con el destinatario: amigo, colega, pareja, familia."
},
"interests": {
"type": "array",
"items": { "type": "string" },
"description": "Intereses del destinatario (deportes, libros, tecnología, etc.)."
},
"budget": {
"type": "number",
"minimum": 1,
"description": "Presupuesto máximo en la moneda del usuario."
}
},
"required": ["budget"]
}
}
Aquí usamos enum para relationship para que el modelo no invente cadenas arbitrarias como "mal compañero" ni las inserte después en el código. Un diseño cuidadoso del esquema ayuda tanto al modelo (ve las opciones permitidas) como al desarrollador (menos sorpresas en runtime).
Ahora imaginemos que tenemos un servidor MCP en Node.js con un hipotético McpServer. El registro de la herramienta podría verse así:
// ejemplo simplificado de registro de una herramienta en el servidor MCP
server.registerTool(
{
name: "suggest_gifts",
description: "Selecciona regalos según el perfil y el presupuesto.",
inputSchema: suggestGiftsSchema
},
async (input, ctx) => {
const gifts = await findGiftsInDb(input, ctx.userLocale);
return { items: gifts }; // JSON que luego verá el agente
}
);
El código está muy simplificado, pero la lógica se entiende: en un sitio — la descripción del contrato (nombre, descripción, esquema), en otro — la implementación.
Esquema para get_gift_details
La segunda herramienta, necesaria en prácticamente cualquier escaparate:
{
"name": "get_gift_details",
"description": "Obtiene información completa sobre un regalo por su identificador.",
"parameters": {
"type": "object",
"properties": {
"gift_id": {
"type": "string",
"description": "UUID del regalo en la base de GiftGenius."
}
},
"required": ["gift_id"]
}
}
Y un registro similar:
server.registerTool(
{
name: "get_gift_details",
description: "Devuelve información detallada sobre el regalo.",
inputSchema: getGiftDetailsSchema
},
async ({ gift_id }) => {
const gift = await db.gifts.findById(gift_id);
if (!gift) return { notFound: true };
return { gift };
}
);
Fíjate: aquí mostramos de entrada que la herramienta puede devolver notFound: true. Son los brotes de las errores semánticos (de negocio), de los que hablaremos más abajo. El agente podrá ver «regalo no encontrado» y decidir: por ejemplo, probar otro id o sugerir al usuario elegir otro artículo.
5. Cómo el agente elige qué herramienta invocar
Ahora lo más interesante: enrutamiento. En una aplicación web tradicional el routing es rígido: URL → controlador concreto. En el mundo de ChatGPT Apps y agentes la elección de herramienta ocurre de forma semántica y probabilística.
El ciclo a alto nivel puede representarse así:
flowchart TD
U[Mensaje del usuario] --> M["Modelo (agente)"]
M -->|análisis de la solicitud| C{¿Hace falta una tool?}
C -->|no| T[Respuesta de texto]
C -->|sí| S[Selección de herramienta]
S --> K[Formación de argumentos JSON]
K --> R[Ejecución de la herramienta]
R --> M2[El modelo ve el resultado]
M2 --> T2[Respuesta final o siguiente paso]
En cada paso el agente ve varias cosas:
- Primero, instrucciones system (rol del agente, restricciones);
- Segundo, el historial del diálogo;
- Y por último, la lista de herramientas (tools) con sus name, description, inputSchema.
Cuando llega un nuevo mensaje del usuario, el modelo compara el significado de la solicitud con las descripciones de las herramientas (emparejamiento semántico). Si la solicitud es «elige un regalo para un amigo por hasta 50 dólares», la descripción de suggest_gifts suena mucho más relevante que get_gift_details, y el agente muy probablemente elegirá esa.
Las guías oficiales subrayan dos cosas que influyen mucho en la calidad del enrutamiento.
- Primero, hay que evitar herramientas que se solapan en significado: si tienes search_gifts y find_gifts descritas casi igual, el modelo se confundirá.
- Segundo, intenta adherirte al principio de única responsabilidad para la herramienta: una tool — una tarea bien definida, y no «elegir regalos y crear el pedido y enviar el email».
Dentro de distintos agentes LLM hay mecanismos para controlar el modo de selección de herramientas: por ejemplo, «auto» (el modelo decide si necesita herramienta), «required» (hay que invocar la tool sí o sí), «none» (tools desactivadas). Esto ayuda en workflows complejos (multietapa), cuando, por ejemplo, en cierto paso quieres invocar obligatoriamente suggest_gifts y no permitir que el modelo simplemente hable.
Ejemplo de enrutamiento semántico en GiftGenius
Supongamos que nuestro agente tiene al menos dos herramientas: suggest_gifts y get_gift_details.
- El usuario escribe: «Elige un regalo para un colega por hasta 30 dólares; le gustan los juegos de mesa».
- El agente ve que la solicitud contiene el objetivo «elegir un regalo», información sobre el presupuesto e intereses. La descripción de suggest_gifts encaja perfectamente — se invoca esa herramienta.
- La herramienta devuelve una lista de cinco regalos con sus id, nombres y una breve descripción.
- El usuario escribe después: «Cuéntame más sobre la tercera opción». El agente asocia «tercera opción» con el id del resultado anterior, y ahora por significado corresponde la herramienta get_gift_details — se invoca.
Es importante notar: en ninguna parte del código escribiste explícitamente «si en la solicitud hay la palabra “elige”, invoca suggest_gifts». De esto se encarga el propio modelo basándose en tus descripciones y en el historial del diálogo. Tu responsabilidad como desarrollador es hacer que la elección resulte obvia tanto para el modelo como para las personas.
6. Errores de las herramientas: no 500, sino señales para el modelo
¿Recuerdas que en get_gift_details ya mostramos notFound: true? Es un ejemplo de error de negocio que el agente debe ver y procesar con sentido, en lugar de recibir un 500 desnudo.
Ahora vamos a la parte más dolorosa. En un REST‑API normal algo falla en las profundidades del backend — devolvemos 500 Internal Server Error, registramos el stack trace en el log — y que el usuario se las apañe. En el caso de un agente, ese enfoque funciona mal.
Las guías prácticas y materiales de Agents SDK recomiendan tratar los errores de las herramientas como eventos observables, y no simplemente como caídas. A esto a menudo se le llama el patrón «Error as Observation».
Dicho de forma llana, no debes «caerte» sin explicación; debes devolver al modelo una respuesta estructurada que explique qué ha salido mal para que pueda adaptar su comportamiento: reformular la solicitud, preguntar al usuario, probar otra herramienta, etc.
Los tipos de errores suelen dividirse en tres grupos.
- Errores de validación de argumentos. El modelo puede generar parámetros incorrectos: omitir un campo obligatorio, introducir una cadena en lugar de un número, salir de los valores permitidos. Aquí tu esquema y validación deben usarse no solo para lanzar excepciones, sino para responder con sentido: por ejemplo, devolver qué campo es incorrecto y por qué.
- Errores de negocio. Situaciones totalmente esperables como «producto no encontrado», «región no disponible», «presupuesto demasiado bajo para este tipo de regalos». Desde el punto de vista de la API también son errores, pero hay que devolverlos dentro de una respuesta normal — con un código y mensaje claro, no como un crash.
- Errores de sistema. Timeouts de servicios externos, problemas de red, fallos de la base de datos. Aquí al agente normalmente le basta con un mensaje cuidadoso y general del tipo «el servicio no está disponible temporalmente, inténtalo más tarde». Nada de stack traces, nombres de tablas ni otros detalles que el modelo no necesita y que pueden ser peligrosos desde el punto de vista de la seguridad.
Los materiales oficiales de Agents SDK incluso proponen un mecanismo específico, failure_error_function, que permite formar cuidadosamente el texto de error que verá el modelo, en lugar de simplemente lanzar una excepción hacia arriba en la pila.
Estructura de un error «amigable»
En la herramienta del agente (en tu backend) podéis acordar que cualquier error se devuelve, por ejemplo, como un objeto:
type ToolError = {
code: string; // 'VALIDATION_ERROR', 'OUT_OF_STOCK', ...
message: string; // para el modelo
retryable: boolean;
};
Y el resultado de la herramienta — como una unión:
type SuggestGiftsResult =
| {
ok: true;
items: GiftSummary[];
}
| {
ok: false;
error: ToolError;
};
El modelo (o el runtime del agente) verá ese JSON y podrá decidir: si retryable: true, puede intentar de nuevo con pequeños cambios; si es un error de negocio y no reintetable, mejor volver al usuario y explicarle qué ocurrió.
7. Ejemplos: validación, error de negocio y error de sistema
Volvamos a nuestro backend/herramientas del agente y veamos cómo implementar las mismas ideas en código.
Error de validación
Imagina que llega la herramienta suggest_gifts, pero el modelo decide pasar un presupuesto negativo.
async function handleSuggestGifts(input: SuggestGiftsInput)
: Promise<SuggestGiftsResult> {
if (input.budget <= 0) {
return {
ok: false,
error: {
code: "VALIDATION_ERROR",
message: "budget debe ser un número positivo.",
retryable: false
}
};
}
const items = await findGiftsInDb(input);
return { ok: true, items };
}
Aquí conscientemente no lanzamos una excepción, sino que devolvemos un error estructurado. El agente puede replantear la solicitud: quizá decida que se confundió con la moneda y pregunte al usuario o admita que no puede elegir un regalo con ese presupuesto.
Error de negocio
Ahora el ejemplo con get_gift_details. Puede que no exista un regalo con el id indicado.
async function handleGetGiftDetails(input: { gift_id: string }) {
const gift = await db.gifts.findById(input.gift_id);
if (!gift) {
return {
ok: false,
error: {
code: "GIFT_NOT_FOUND",
message: "No se encontró un regalo con ese identificador.",
retryable: false
}
};
}
return { ok: true, gift };
}
En la respuesta del modelo puede aparecer algo como: «Parece que el regalo seleccionado ya no está disponible. ¿Puedo sugerirte algunas alternativas de una categoría similar?». Para ello el agente no necesita ver errores SQL ni stack traces — solo un code y un message comprensibles.
Error de sistema
Por último, un ejemplo de error de sistema. Supón que tu herramienta llama a una API externa de envíos que a veces «se cae».
async function handleEstimateDelivery(input: EstimateDeliveryInput) {
try {
const eta = await callDeliveryApi(input);
return { ok: true, eta_days: eta };
} catch (e) {
return {
ok: false,
error: {
code: "DELIVERY_SERVICE_UNAVAILABLE",
message: "El servicio de entrega no está disponible temporalmente.",
retryable: true
}
};
}
}
El agente puede decidir: «Parece que el servicio de entrega no está disponible ahora. Aun así te mostraré los regalos, pero el tiempo exacto de entrega puede variar. ¿Quieres continuar?».
8. Seguridad e idempotencia de las herramientas (vista rápida desde tools)
La conversación completa sobre seguridad y permisos será un tema aparte, pero las herramientas del agente están tan ligadas a ello que conviene mencionarlo.
Primero, separa herramientas de lectura y de escritura. En descripciones, esquemas y permisos indica explícitamente qué tools solo leen datos y son absolutamente seguras, y cuáles pueden cargar cargos, modificar pedidos, etc. La documentación y los foros sobre escenarios de agentes hablan directamente de la separación entre herramientas ReadOnly y Mutating.
Segundo, para las herramientas que mutan estado, piensa en la idempotencia. El agente o el cliente MCP bien pueden repetir la llamada (por ejemplo, debido a un error de red), y no quieres que create_order cree dos pedidos en lugar de uno. Patrones típicos:
- idempotency‑key que se pasa como argumento de la herramienta;
- comprobar la existencia de la operación antes de ejecutarla;
- separar los pasos en «crear borrador del pedido» y «confirmar pedido».
Todo esto está muy relacionado con cómo diseñas el contrato de la herramienta: si en el JSON Schema no hay un campo para el idempotency‑key, añadir idempotencia después será mucho más doloroso.
9. Una breve mirada a Agents SDK: cómo se ve en el runtime del agente
Esta sección es un breve repaso para quienes vayan a trabajar con un Agents SDK orientado a TypeScript. Aunque la mayor parte del curso es sobre MCP, es útil entender cómo ve herramientas similares el Agents SDK y cómo se ve una tool típica en el runtime.
En la documentación oficial suele describirse una entidad tipo «herramienta funcional»: cualquier función descrita mediante un objeto de configuración (o un helper como tool(...)) y provista de tipos puede convertirse automáticamente en una herramienta para la que el SDK generará JSON Schema y una descripción.
A nivel de concepto es lo mismo que ya hemos comentado: el nombre de la función, sus parámetros y el comentario/description hacen de nombre, esquema y descripción de la herramienta. La diferencia es que el SDK y/o una librería auxiliar de esquemas (por ejemplo, Zod o JSON Schema) hace por ti gran parte del trabajo «mecánico».
Ejemplo hipotético (pseudo‑TypeScript, simplificado):
type Gift = {
id: string;
title: string;
// ...
};
const suggestGifts = tool({
name: "suggest_gifts",
description: "Selecciona una lista de regalos según el tipo de destinatario y el presupuesto.",
parameters: {
type: "object",
properties: {
recipient_type: {
type: "string",
description: "Quién es el destinatario del regalo (por ejemplo, 'hombre', 'mujer', 'niño')."
},
budget: {
type: "number",
description: "Presupuesto máximo en la moneda del usuario."
}
},
required: ["recipient_type", "budget"]
}
}, async (args: { recipient_type: string; budget: number }): Promise<Gift[]> => {
// Dentro — tu lógica de dominio
return findGifts(args.recipient_type, args.budget);
});
El SDK (o tu helper tool) construirá el JSON Schema a partir del objeto parameters y se lo pasará al agente, y el runtime se encargará de la validación y del marshalling de argumentos de ida y vuelta. Conceptualmente, es exactamente lo que hacías manualmente en un servidor MCP con TypeScript, solo que ahora la herramienta está «conectada» directamente al runtime del agente.
Lo importante no es memorizar la sintaxis concreta del helper tool, sino captar la idea: tipado de calidad + description/comentarios nítidos = herramienta de calidad.
Si juntamos todo: una buena herramienta de agente es una función estrecha y bien descrita, con un JSON Schema pensado, una descripción clara para el modelo y un manejo de errores cuidadoso. El enrutamiento semántico funcionará solo si las herramientas no se solapan en significado. Y las operaciones que mutan estado deben ser seguras e idempotentes; de lo contrario, un agente en producción se convertirá rápidamente en una fuente de sorpresas.
10. Errores típicos al diseñar herramientas de agente
Error n.º 1: Herramientas demasiado amplias «do_everything».
A veces apetece meterlo todo en una sola herramienta manage_gifts que busca regalos, muestra detalles, crea el pedido y envía el email. Al modelo esto le cuesta: la descripción se vuelve difusa, el enrutamiento semántico se degrada y el agente empieza a invocar esa herramienta «por si acaso» incluso donde bastaría una búsqueda simple. Mejor dividir las tareas en herramientas separadas con una responsabilidad clara y bien entendida.
Error n.º 2: Herramientas que se solapan en significado.
Si tienes search_gifts y find_gifts, ambas «buscan regalos por intereses», el modelo elegirá entre ellas al azar. El resultado es un comportamiento inestable: solicitudes iguales a veces van a una tool y a veces a la otra. Intenta que cada nombre y descripción ocupen un «nicho» único en el espacio semántico.
Error n.º 3: Descripciones y campos de esquema malos o ausentes.
El nombre func1, la descripción «Does something» y el parámetro data: string — es la manera clásica de hacer un agente torpe. El modelo no es telépata y no puede leer tu código fuente. Se apoya en description, properties y sus description en el esquema. Si no explicas qué es recipient_type, el modelo tendrá que adivinar y se equivocará.
Error n.º 4: Centrarse solo en el happy path e ignorar errores.
Muchas implementaciones de herramientas asumen: «Siempre tendremos argumentos correctos y servicios disponibles». En el mundo real el modelo puede generar parámetros incorrectos, los servicios externos fallan y la base a veces dice «timeout». Si no piensas en los formatos de error ni devuelves al agente un mensaje con sentido, no podrá corregir su comportamiento y o bien caerá en silencio o bien alucinará.
Error n.º 5: Enviar un 500 crudo y un stack trace a la LLM.
En REST‑API solemos registrar el stack trace completo para depurar más rápido. En el contexto de un agente, pasar el stack trace al modelo es a la vez inútil (el modelo no sabe qué es una SQLException en tu biblioteca concreta) y potencialmente peligroso (detalles de implementación innecesarios y, tal vez, información confidencial). Mucho más útil es capturar la excepción, registrar los detalles en el log y enviar al modelo un code y message cuidados.
Error n.º 6: Falta de idempotencia en herramientas que mutan estado.
Una herramienta create_order sin idempotency‑key es una invitación directa a pedidos duplicados, especialmente con fallos de red y reintentos automáticos. Si tu agente opera en un escenario comercial, las herramientas relacionadas con dinero deben diseñarse para que las llamadas repetidas no lleven a cargos adicionales ni duplicados.
Error n.º 7: Guardar secretos y detalles técnicos en el esquema o la descripción.
A veces, por costumbre, el desarrollador escribe en la description: «Por dentro llama al servicio X en https://internal-api.example.com». El modelo no necesita esa información, el usuario menos aún. Los esquemas y descripciones forman parte del prompt, viven en el contexto del modelo, y no se deben colocar allí URLs de servicios internos, nombres de tablas privadas y mucho menos secretos.
Error n.º 8: Pasar a las herramientas cualquier cosa en vez de un conjunto pensado de campos.
Es fácil caer en la tentación de «pasar dentro todo el prompt del usuario como cadena y ya lo resolvemos». Así pierdes el beneficio de estructurar con JSON Schema: el modelo deja de entender qué partes de la solicitud son importantes para la lógica, pierdes validación y previsibilidad. Mejor extraer de la solicitud los campos explícitos (budget, interests, user_location) y describirlos como parte del contrato de la herramienta.
GO TO FULL VERSION