@dariomvg/create
vercel-ai-sdktool-callinggeminizodintegracion

Vercel AI SDK — Módulo de Tool Calling

Un módulo autocontenido para tool calling usando el Vercel AI SDK con Google (Gemini) como proveedor. Cubre definición de tools, schemas de tools, ejecución de tools, múltiples tools, resultados de tools, validación de tools y errores de tools.

Es independiente: no depende de los módulos vercel-ai-sdk-text-generation ni vercel-ai-sdk-chat. No usa streaming, por lo que no hay client.ts: actions.ts se llama directamente desde Server Components o Client Components.

Flujo conceptual

AI
 ↓
Tool
 ↓
Database/API
 ↓
Result
 ↓
AI

El modelo decide cuándo llamar a una tool y con qué argumentos. Tu función execute es donde ocurre la llamada real a la Database/API. El resultado vuelve al modelo, que puede llamar a otra tool o producir su respuesta final, hasta TOOL_LOOP_CONFIG.maxSteps rondas.

Dependencias

  • ai — el core del Vercel AI SDK (generateText, tool, isStepCount, y las clases de error relacionadas con tools)
  • @ai-sdk/google — el adaptador del proveedor Google (Gemini)
  • zod — se usa para definir el schema de parámetros de cada tool

Nota de versión: el AI SDK renombró más de una vez su helper para limitar pasos (maxSteps → stepCountIs → isStepCount). Este módulo usa isStepCount. Si tu versión instalada de ai no lo exporta, cambiá el import en service.ts por el que esté disponible en tu versión; el uso (isStepCount(n) pasado a stopWhen) es idéntico en lo demás.

Estructura de archivos

types.ts       ToolDefinition contract, run params/result, tool loop config, errors
tools.ts        Tool registry — register your own tools here
service.ts      Internal logic: builds AI SDK tools, runs the loop, normalizes errors — do not modify
actions.ts      Server Action — import into Server or Client Components
.env.local        Environment variable for the Google API key

Configuración

  1. Definí y registrá tus tools. Cada tool necesita un nombre, una descripción (el modelo la lee para decidir cuándo usarla), un schema de Zod para sus parámetros y una función execute, que es donde llamás a tu Database/API real.

    import { z } from "zod";
    import { registerTool } from "@/lib/ai-tools/tools";
    
    registerTool({
      name: "getOrderStatus",
      description: "Look up the current status of a customer order by its ID.",
      parameters: z.object({
        orderId: z.string().describe("The order ID, e.g. 'ORD-1234'"),
      }),
      execute: async ({ orderId }) => {
        // Replace with your real Database/API call.
        const order = await db.orders.findUnique({ where: { id: orderId } });
        if (!order) throw new Error(`Order ${orderId} not found`);
        return { status: order.status, updatedAt: order.updatedAt };
      },
    });
    

    Registralo durante el inicio de la app, de la misma forma en que registrarías un ConversationStore en el módulo de chat.

  2. Agregá tu API key de Google AI en .env.local. Podés conseguir una en https://aistudio.google.com/apikey

Uso

import { runWithTools } from "@/lib/ai-tools/actions";

const result = await runWithTools({
  prompt: "What's the status of order ORD-1234?",
  system: "You are a helpful customer support assistant.",
});

if (result.success) {
  console.log(result.data.text); // the model's final answer

  for (const call of result.data.toolCalls) {
    console.log(call.toolName, call.args, call.result ?? call.error);
  }
} else {
  console.error(result.error.message);
}

result.data.toolCalls es la traza completa de cada llamada a tools hecha durante la ejecución, en orden: cada entrada tiene un result o un error, nunca ambos. A esto se reducen los "resultados de tools" y los "errores de tools": podés ver exactamente qué pasó en cada paso de la Database/API, no solo el texto final del modelo.

Limitar qué tools están disponibles

Por defecto, todas las tools registradas están disponibles para el modelo. Para restringir una ejecución específica a un subconjunto:

const result = await runWithTools({
  prompt: "What's the status of order ORD-1234?",
  toolNames: ["getOrderStatus"],
});

Si pasás un nombre que no está registrado, la llamada falla con INVALID_REQUEST antes de hacer cualquier llamada al modelo.

Manejo de errores

{
  code:
    | "RATE_LIMITED"
    | "INVALID_REQUEST"
    | "PROVIDER_ERROR"
    | "TOOL_VALIDATION_ERROR"
    | "TOOL_EXECUTION_ERROR"
    | "UNKNOWN",
  message: string,       // safe to show in the UI
  retryAfter?: number,   // seconds, only present for RATE_LIMITED
}
  • TOOL_VALIDATION_ERROR — el modelo llamó a una tool con argumentos que no coinciden con su schema de Zod, o intentó llamar a una tool que no se le habilitó. Esto detiene la ejecución.
  • Un execute fallido (tu llamada a la Database/API lanzando un error) no detiene la ejecución: el AI SDK le devuelve el fallo al modelo para que pueda reintentar, usar otra tool o explicarle el fallo al usuario. Lo vas a ver como una entrada error en el ToolCallTrace de esa tool, no como un fallo de nivel superior de AIResult.

Rate limiting

El mismo limitador de ventana deslizante en memoria que en los otros módulos (RATE_LIMIT_CONFIG en types.ts, por defecto 20 requests/minuto por instancia del servidor), más el manejo normalizado de las respuestas 429 del propio proveedor.

Loop de tools

TOOL_LOOP_CONFIG.maxSteps en types.ts (por defecto 5) limita cuántos viajes de ida y vuelta AI → Tool → AI puede hacer una sola llamada a runWithTools. Subilo si tu caso de uso necesita encadenar más llamadas a tools antes de responder; bajalo para fallar rápido ante loops descontrolados.