Skip to content

Lección 03

Tool use: dale superpoderes al chatbot

Tu bot deja de inventar y empieza a consultar APIs reales. Implementamos tool calling con Claude y el patrón loop completo.


La diferencia entre un demo y un producto

Sin tool use, el bot inventa. Le preguntas el tiempo en Madrid y te lo dirá (mal).

Con tool use, el bot mira. Le preguntas el tiempo y llama al endpoint de tu API meteorológica, recibe el JSON real y te lo cuenta.

Cómo funciona en Claude

  1. Defines un array de tools con nombre, descripción y esquema JSON de los parámetros.
  2. Se lo pasas a messages.create junto con la conversación.
  3. Claude puede decidir llamar a una herramienta. En vez de devolver text, devuelve un tool_use con los argumentos.
  4. ejecutas la función en tu servidor.
  5. Envías el resultado como un mensaje con role: "user" y content tipo tool_result.
  6. Claude lee el resultado y responde al usuario en lenguaje natural.

Es un loop. Hasta que Claude no devuelva stop_reason: "end_turn", sigues el bucle.

Ejemplo: herramienta de clima

1. Define la herramienta

const tools: Anthropic.Tool[] = [
  {
    name: "get_weather",
    description: "Obtiene el clima actual de una ciudad.",
    input_schema: {
      type: "object",
      properties: {
        city: { type: "string", description: "Nombre de la ciudad, ej. 'Madrid'." },
      },
      required: ["city"],
    },
  },
];

2. La implementación real

async function getWeather(city: string) {
  const res = await fetch(
    `https://wttr.in/${encodeURIComponent(city)}?format=j1`,
  );
  const data = await res.json();
  const cur = data.current_condition[0];
  return {
    city,
    temperature: cur.temp_C + "°C",
    description: cur.lang_es?.[0]?.value ?? cur.weatherDesc[0].value,
    humidity: cur.humidity + "%",
  };
}

3. El loop

async function chat(userMessages: Anthropic.MessageParam[]) {
  const messages = [...userMessages];

  while (true) {
    const res = await client.messages.create({
      model: "claude-opus-4-7",
      max_tokens: 1024,
      tools,
      messages,
    });

    if (res.stop_reason === "end_turn") {
      const text = res.content.find((c) => c.type === "text");
      return text?.type === "text" ? text.text : "";
    }

    if (res.stop_reason === "tool_use") {
      messages.push({ role: "assistant", content: res.content });

      const results: Anthropic.ToolResultBlockParam[] = [];
      for (const block of res.content) {
        if (block.type !== "tool_use") continue;

        if (block.name === "get_weather") {
          const input = block.input as { city: string };
          const data = await getWeather(input.city);
          results.push({
            type: "tool_result",
            tool_use_id: block.id,
            content: JSON.stringify(data),
          });
        }
      }

      messages.push({ role: "user", content: results });
      continue;
    }

    return "";
  }
}

Probarlo

const reply = await chat([
  { role: "user", content: "¿Qué tiempo hace ahora en Buenos Aires y en Madrid?" },
]);
console.log(reply);
// → "En Buenos Aires hace 14°C con cielo despejado. En Madrid hace 22°C con sol."

Claude llama a get_weather dos veces (una por ciudad) en paralelo, recibe los resultados, y compone la respuesta.

Diseño de herramientas — reglas que duelen aprenderlas tarde

  • Descripciones honestas: si tu herramienta falla a veces, dilo. El modelo decidirá si llamarla.
  • Nombres explícitos: search_products, no search.
  • Parámetros enumerados cuando puedas. sort: "price_asc" | "price_desc" es mejor que sort: string.
  • Devuelve JSON estructurado, no texto plano. El modelo lo procesa mejor.
  • Sin secrets en description ni en el esquema. Va al modelo en cada turno.

Lo que sigue

Tu bot ya recuerda y puede consultar el mundo real. En la siguiente lección lo envolvemos en una UI tipo ChatGPT con streaming de tokens.


NIVEL 2

Reto Pro

Reto Pro de esta lección

Misma idea, sin pistas, evaluada por tests automáticos.

Desbloquear Modo Pro · 29 € Pago único · acceso de por vida · sin suscripción
NIVEL 3

Hard Mode

Hard Mode

Variante extrema del reto. Tiempo límite y restricciones adicionales.

Desbloquear Modo Pro · 29 € Pago único · acceso de por vida · sin suscripción