Saltar al contenido

Tool calling

Tool calling permite que un modelo le pida a tu código que haga algo —buscar un pedido, ejecutar una consulta, llamar a una API— y luego use el resultado en su respuesta. Tú describes las herramientas; el modelo decide cuándo llamarlas y con qué argumentos; tu código las ejecuta y devuelve los resultados. El modelo nunca ejecuta nada por sí mismo.

Usa un modelo cuyo capabilities.tools sea true en la lista de modelos. La mayoría de los modelos de texto actuales cumplen este requisito.

Define una herramienta

Cada herramienta tiene un nombre, una descripción que el modelo lee para decidir cuándo usarla y un JSON Schema para sus argumentos:

const tools = [
  {
    type: "function",
    function: {
      name: "get_weather",
      description: "Current weather for a city.",
      parameters: {
        type: "object",
        properties: {
          city: { type: "string", description: "City name, e.g. Berlin" },
          unit: { type: "string", enum: ["celsius", "fahrenheit"] },
        },
        required: ["city"],
        additionalProperties: false,
      },
    },
  },
];

El ciclo

import OpenAI from "openai";

const client = new OpenAI({ baseURL: "https://api.inferray.com/v1", apiKey: process.env.INFERRAY_API_KEY });

const messages = [{ role: "user", content: "Do I need a jacket in Berlin today?" }];

while (true) {
  const completion = await client.chat.completions.create({ model: "gpt-5.5", messages, tools });
  const message = completion.choices[0].message;
  messages.push(message);

  if (!message.tool_calls?.length) {
    console.log(message.content);
    break;
  }

  for (const call of message.tool_calls) {
    const args = JSON.parse(call.function.arguments);
    const result = await getWeather(args.city, args.unit); // your code
    messages.push({ role: "tool", tool_call_id: call.id, content: JSON.stringify(result) });
  }
}
  1. Envía la conversación y las herramientas.
  2. Si la respuesta tiene tool_calls (y finish_reason es tool_calls), ejecuta cada una.
  3. Agrega el mensaje del asistente y luego un mensaje tool por cada llamada, con el tool_call_id correspondiente.
  4. Vuelve a llamar. Repite hasta que el modelo responda con texto.

Un modelo puede pedir varias llamadas en un mismo turno. Ejecútalas, en paralelo si quieres, y envía todos los resultados antes de la siguiente solicitud.

Decidir si se usa una herramienta

tool_choiceEfecto
"auto" (predeterminado)El modelo decide.
"none"Ninguna herramienta en este turno, aunque estén en la lista.
"required"El modelo debe llamar al menos a una herramienta.
{"type": "function", "function": {"name": "get_weather"}}El modelo debe llamar a esa herramienta.

En el endpoint Messages

El formato Anthropic funciona igual, con otros nombres: las herramientas reciben un input_schema, la respuesta contiene bloques tool_use con un id y input, y tú respondes con un mensaje user que contiene bloques tool_result que hacen referencia a ese tool_use_id. Consulta Anthropic Messages.

En Responses API, las herramientas son {"type": "function", "name": ..., "parameters": ...}, las llamadas llegan como elementos de salida function_call y tú devuelves elementos function_call_output con el call_id.

Consejos

  • Valida los argumentos antes de actuar con ellos. Un modelo puede generar argumentos que cumplen el schema pero no tienen sentido; trátalos como entrada de usuario.
  • Escribe descripciones específicas. La descripción es la única guía del modelo para saber cuándo aplica una herramienta.
  • Las definiciones de herramientas cuentan como tokens de entrada en cada solicitud. Con una lista larga de herramientas, el prompt caching mantiene ese costo bajo.
  • Con streaming, las llamadas a herramientas llegan en fragmentos; consulta streaming.