Tool calling
El tool calling es el contrato entre el LLM y el mundo: el modelo devuelve JSON estructurado (nombre + argumentos), el runtime valida contra un schema y ejecuta. Es lo que convierte el texto en acción.
Qué es
El tool calling (también llamado ) es la interfaz por la cual un LLM devuelve, en lugar de (o además de) texto, una llamada de función estructurada: nombre de la herramienta + argumentos en JSON. El runtime la recibe, valida los argumentos contra un schema, ejecuta y devuelve el resultado al contexto.
El modelo nunca ejecuta nada por su cuenta. Solo propone: 'yo llamaría get_weather con { city: 'São Paulo' }'. La ejecución, la autorización, el reintento y la auditoría quedan a cargo del runtime. Olvidar quién ejecuta es el error más caro que aparece en producción.
El schema JSON: el contrato
Cada herramienta se declara al modelo mediante un schema JSON con nombre, descripción y parámetros tipados. El LLM usa ese schema como gramática: conoce el nombre, conoce el formato de los argumentos y usa la descripción para decidir cuándo tiene sentido llamar.
La descripción es la parte más descuidada. El LLM no lee código: lee el string. 'Obtiene el clima de una ciudad' es mejor que 'get_weather', porque el modelo decide cuándo llamar con base en prosa. Los schemas con malas descripciones generan llamadas correctas o erróneas al azar.
{
"name": "get_weather",
"description": "Obtiene la temperatura actual y el pronóstico de los próximos 3 días en una ciudad.",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "Nombre de la ciudad, en portugués o inglés (ej: 'São Paulo', 'Lisbon')."
},
"unit": {
"type": "string",
"enum": ["celsius", "fahrenheit"],
"default": "celsius"
}
},
"required": ["city"]
}
}Validación de argumentos: tu responsabilidad
Cuando el modelo devuelve una llamada de función, el runtime recibe un JSON que puede estar mal: tipo equivocado, campo faltante, valor fuera del enum, string donde debía ir un número. Validar antes de ejecutar es innegociable: es la frontera entre el modelo, que propone, y tu código, que ejecuta con permisos reales.
En Python, Pydantic es el camino estándar: declaras un modelo, llamas a model_validate(model_dump), y Pydantic lanza ValidationError con la lista exacta de campos y el motivo. En TypeScript, el par natural es Zod, con safeParse devolviendo { success, data, error }.
from pydantic import BaseModel, Field, ValidationError
class GetWeatherArgs(BaseModel):
city: str = Field(..., min_length=1)
unit: str = Field("celsius", pattern=r"^(celsius|fahrenheit)$")
def call_tool(name: str, raw_args: dict):
if name != "get_weather":
raise ValueError(f"herramienta desconocida: {name}")
try:
args = GetWeatherArgs.model_validate(raw_args)
except ValidationError as e:
return {"error": "invalid_args", "details": e.errors()}
return fetch_weather(args.city, args.unit)El flujo completo, de punta a punta
La llamada a una herramienta atraviesa cinco etapas, cada una con una respuesta posible y un camino de error distinto. Sin ver las cinco, parece magia, y los bugs no están donde esperas.
1. declaración: la lista de schemas se entrega al LLM junto con el prompt.
2. propuesta: el LLM devuelve tool_calls con name + JSON arguments.
3. validación: el runtime parsea y valida contra el schema; un fallo aquí significa 'el modelo alucinó'; trátalo como error y devuelve el motivo al LLM.
4. ejecución: el runtime llama a la función real (HTTP, DB, comando) con permisos y timeout.
5. observación: el resultado se convierte en un mensaje tool en el contexto; el LLM lo usa para la siguiente decisión.
import Anthropic from '@anthropic-ai/sdk';
import { z } from 'zod';
const GetWeather = z.object({
city: z.string().min(1),
unit: z.enum(['celsius', 'fahrenheit']).default('celsius'),
});
async function run(anthropic: Anthropic, userMessage: string) {
const tools = [{
name: 'get_weather',
description: 'Obtiene el clima actual de una ciudad.',
input_schema: /* shape JSON del schema */,
}];
let msg = await anthropic.messages.create({
model: 'claude-opus-4', max_tokens: 1024, tools,
messages: [{ role: 'user', content: userMessage }],
});
if (msg.stop_reason === 'tool_use') {
const call = msg.content.find((b) => b.type === 'tool_use');
const parsed = GetWeather.safeParse(call.input);
if (!parsed.success) return { error: 'invalid_args', issues: parsed.error.issues };
const result = await fetchWeather(parsed.data.city, parsed.data.unit);
msg = await anthropic.messages.create({
model: 'claude-opus-4', max_tokens: 1024, tools,
messages: [
{ role: 'user', content: userMessage },
{ role: 'assistant',content: msg.content },
{ role: 'user', content: [{ type: 'tool_result', tool_use_id: call.id, content: JSON.stringify(result) }] },
],
});
}
return msg;
}Por qué no se puede omitir la validación
- el modelo puede inventar campos: vio 1000 schemas distintos y no garantiza consistencia
- los tipos están garantizados, los valores no: sabe que 'unit' es un string, pero puede mandar 'celcius' (typo) de vez en cuando
- los enums son la frontera de error más común: el modelo rara vez respeta el enum sin un prompt explícito
- la validación es barata: cuesta microsegundos; una ejecución sin validar puede permitir un orden de ejecución crítico
Puntos fuertes y limitaciones
- fuerte: el schema fuerza estructura; el modelo no necesita 'intentar' producir JSON válido; está produciendo tokens dentro de una gramática
- fuerte: los errores de validación devuelven un mensaje rico al modelo, que casi siempre se corrige en el siguiente turno
- débil: una mala descripción lleva a llamadas correctas o erróneas al azar; escribir un buen schema es trabajo de diseño
- débil: la llamada es opaca para el usuario; si no lee el trace, no sabe qué herramienta se ejecutó
- débil: el paralelismo depende del proveedor; algunos permiten varias tool_calls en una respuesta, otros solo una
conexiones en el mapa
- Agent frameworkshabilitaTool calling
- Tool callinghabla el protocoloMCP - model context protocol
actualizado el 14/10/2026 · fuentes para profundizar · reportar un error
en otros dominios
- Context engineering para agents de códigovibecodinglas herramientas y los permisos deciden lo que el agente puede hacer
- SASTappsecatrapa inyección en el código; aquí el objetivo es el argumento de la herramienta
- Automatización de seguridad y playbooks como códigosecenguna acción disparada por un modelo necesita los mismos frenos que un playbook
Estudia antes
Desbloquea
pon a prueba lo que entendiste
Cargando preguntas…