IA 7 jul 2026 · 8 min de lectura

Tool calling en producción: el LLM no ejecuta, propone

Yohangel Ramos

Yohangel Ramos

Tech Lead · Senior Fullstack Developer

El error más caro que cometí al meter tool calling en un producto fue mental, no de código: pensaba que el LLM ejecutaba las herramientas. No las ejecuta. El modelo devuelve un objeto JSON que dice "me gustaría llamar a buscarCandidatos con estos argumentos", y ahí termina su trabajo. Quien decide si esa llamada se ejecuta, con qué permisos y qué pasa con el resultado, es tu código. Interiorizar esa frontera —el LLM propone, tu backend dispone— cambió por completo cómo diseño agentes. Dejé de tratar al modelo como un ejecutor autónomo y empecé a tratarlo como un planificador que emite intenciones que yo valido. Este artículo es ese modelo mental y las decisiones de producción que se derivan de él.

La frontera que lo cambia todo

Cuando le das herramientas a un modelo, el ciclo real es: le pasas la petición del usuario y el esquema de las herramientas disponibles; el modelo responde o bien con texto, o bien con una o más tool calls (nombre + argumentos en JSON); tu código ejecuta las que decida ejecutar; le devuelves el resultado al modelo; y el modelo continúa. El LLM nunca toca tu base de datos ni tu API. Es un generador de intenciones estructuradas.

Esa frontera es la mejor noticia de la arquitectura, porque significa que todo el control de seguridad vive en tu lado. El modelo puede pedir borrar un registro; que se borre o no depende de un if tuyo. Tratar la tool call como una solicitud sujeta a autorización, y no como una orden, es lo que separa un agente que puedes poner en producción de una demo que da miedo.

Los esquemas son tu contrato, y el modelo los lee

La calidad de un agente con herramientas depende brutalmente de lo bien descritas que estén las herramientas. El modelo elige qué llamar basándose en el nombre, la descripción y el esquema de parámetros. Descripciones vagas producen llamadas erróneas; descripciones precisas producen llamadas correctas.

const tools = [{
  name: 'buscar_candidatos',
  description: 'Busca candidatos por habilidades y seniority. ' +
    'Úsala solo cuando el usuario pida perfiles concretos, ' +
    'no para preguntas generales sobre el mercado.',
  input_schema: {
    type: 'object',
    properties: {
      skills: { type: 'array', items: { type: 'string' } },
      seniority: { type: 'string', enum: ['junior', 'mid', 'senior'] },
    },
    required: ['skills'],
  },
}];

Ese enum no es decoración: restringe el espacio de salida y hace mucho menos probable que el modelo invente un valor que tu backend no sabe manejar. Cada restricción que pones en el esquema es una clase de bug que eliminas antes de que ocurra. He aprendido a invertir en esquemas estrictos con la misma seriedad con la que diseño una API pública, porque para el modelo eso es exactamente lo que son.

Validar la salida como si viniera de un cliente hostil

Aquí está el punto que más gente se salta. El modelo genera los argumentos como texto, y aunque le des un esquema, no hay garantía dura de que respete tus invariantes de negocio. Puede pasarte un seniority válido según el enum pero un array de skills vacío, o una fecha con formato correcto pero en el pasado.

Por eso valido cada tool call con Zod antes de ejecutarla, con la misma desconfianza que aplicaría a un input de usuario. La tool call es un input de usuario, solo que generado por un modelo. Si no valida, no ejecuto: devuelvo el error al modelo como resultado de la herramienta y dejo que reintente con argumentos corregidos. Ese bucle de "fallaste la validación, aquí está por qué, prueba otra vez" es sorprendentemente eficaz y mantiene el sistema seguro sin intervención humana.

💡 Una tool call es una petición no confiable que resulta venir de un LLM en vez de un navegador. Valídala, autorízala y regístrala exactamente igual que cualquier entrada externa. El modelo no es parte de tu perímetro de confianza.

Efectos secundarios: separa leer de escribir

No todas las herramientas son iguales, y tratarlas como si lo fueran es pedir problemas. Distingo dos categorías con reglas distintas. Las de solo lectura —buscar, consultar, calcular— las ejecuto sin fricción: si el modelo se equivoca de query, el coste es una respuesta pobre, nada irreversible. Las de escritura —crear, actualizar, borrar, enviar— pasan por un filtro mucho más estricto.

Para las de escritura con impacto real, el patrón que me funciona es no darle al modelo la herramienta destructiva directamente, sino una que propone la acción y la deja pendiente de una confirmación explícita. El modelo puede redactar el email; enviarlo requiere un paso que mi código controla, muchas veces con un humano en el lazo. Elegí esta cautela a cambio de agentes menos "mágicos", y volvería a elegirla: un agente que puede mandar mensajes sin supervisión es un incidente esperando su turno.

Por qué este modelo mental escala y el otro no

Cuando piensas que el LLM ejecuta, cada nueva herramienta te da miedo, porque estás ampliando lo que un sistema no determinista puede hacer solo. Cuando entiendes que el LLM solo propone, añadir herramientas es barato: cada una es una intención más que tu código sabe validar, autorizar y ejecutar bajo tus reglas.

El agente deja de ser una caja negra a la que le rezas y pasa a ser un planificador cuyas propuestas atraviesan una capa de control que tú escribiste y entiendes. Toda la creatividad del modelo, ninguna de su capacidad de hacer daño sin permiso. Esa división de responsabilidades no es un detalle de implementación: es la diferencia entre un agente que puedes defender en una revisión de seguridad y uno que no.

Yohangel Ramos

Escrito por Yohangel Ramos

Senior Fullstack Developer y Tech Lead. Construyo con React, Next.js, Nest.js y AWS — y escribo sobre lo que aprendo en el camino.

Hablemos →

Sigue leyendo

IA

Embeddings más baratos: recortar dimensiones y cuantizar sin perder recall

IA

Qué va a pasar con el desarrollo de software: predicciones con fechas (julio 2026)