Tool calling en AI SDK
El tool calling (también conocido como function calling) permite que los modelos de IA soliciten la ejecución de funciones específicas. Esto permite a los asistentes interactuar con sistemas externos, obtener datos, realizar cálculos y ejecutar acciones en el mundo real.
Lo que permiten las herramientas
- Obtención de datos: Clima, precios de acciones, datos de usuarios en tiempo real
- Cálculos: Matemática compleja o procesamiento de datos
- APIs externas: Interacción con servicios de terceros
- Operaciones en base de datos: Consultar y actualizar datos
- Acciones: Enviar emails, crear eventos de calendario, etc.
Definir herramientas
import { tool } from 'ai';
import { z } from 'zod';
// Define a weather tool
const weatherTool = tool({
description: 'Get the current weather for a location',
parameters: z.object({
location: z.string().describe('The city and state, e.g., San Francisco, CA'),
unit: z.enum(['celsius', 'fahrenheit']).optional().default('fahrenheit'),
}),
execute: async ({ location, unit }) => {
// Call your weather API here
const weather = await fetchWeather(location, unit);
return weather;
},
});
// Define a calculator tool
const calculatorTool = tool({
description: 'Perform mathematical calculations',
parameters: z.object({
expression: z.string().describe('The math expression to evaluate'),
}),
execute: async ({ expression }) => {
// Safely evaluate the expression
const result = evaluateMathExpression(expression);
return { result };
},
});
Usar herramientas con streamText
// app/api/chat/route.ts
import { openai } from '@ai-sdk/openai';
import { streamText, tool } from 'ai';
import { z } from 'zod';
export const maxDuration = 30;
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai('gpt-4-turbo'),
messages,
tools: {
weather: tool({
description: 'Get the current weather for a location',
parameters: z.object({
location: z.string(),
}),
execute: async ({ location }) => {
// Simulate weather API call
return {
location,
temperature: 72,
condition: 'sunny',
};
},
}),
calculator: tool({
description: 'Calculate a math expression',
parameters: z.object({
expression: z.string(),
}),
execute: async ({ expression }) => {
return { result: eval(expression) }; // Use a safe evaluator in production
},
}),
},
});
return result.toDataStreamResponse();
}
Resultados de herramientas en el chat
'use client';
import { useChat } from 'ai/react';
export default function ChatWithTools() {
const { messages, input, handleInputChange, handleSubmit } = useChat();
return (
<div className="max-w-2xl mx-auto p-4">
{messages.map((message) => (
<div key={message.id} className="mb-4">
<strong>{message.role}:</strong>
{/* Display text content */}
{message.content && <p>{message.content}</p>}
{/* Display tool invocations */}
{message.toolInvocations?.map((tool, index) => (
<div key={index} className="bg-gray-100 p-2 rounded mt-2">
<p className="text-sm text-gray-600">
Called: {tool.toolName}
</p>
{tool.state === 'result' && (
<pre className="text-sm">
{JSON.stringify(tool.result, null, 2)}
</pre>
)}
</div>
))}
</div>
))}
<form onSubmit={handleSubmit}>
<input
value={input}
onChange={handleInputChange}
placeholder="Ask about weather or calculate..."
className="w-full p-2 border rounded"
/>
</form>
</div>
);
}
Llamadas de herramientas en varios pasos
Los modelos de IA pueden llamar múltiples herramientas en secuencia para completar tareas complejas:
const result = streamText({
model: openai('gpt-4-turbo'),
messages,
tools: {
searchProducts: tool({
description: 'Search for products in the catalog',
parameters: z.object({
query: z.string(),
maxResults: z.number().optional().default(5),
}),
execute: async ({ query, maxResults }) => {
const products = await searchCatalog(query, maxResults);
return products;
},
}),
getProductDetails: tool({
description: 'Get detailed information about a product',
parameters: z.object({
productId: z.string(),
}),
execute: async ({ productId }) => {
const details = await getProduct(productId);
return details;
},
}),
addToCart: tool({
description: 'Add a product to the shopping cart',
parameters: z.object({
productId: z.string(),
quantity: z.number().default(1),
}),
execute: async ({ productId, quantity }) => {
await addToCart(productId, quantity);
return { success: true, message: 'Added to cart' };
},
}),
},
maxSteps: 5, // Allow up to 5 tool calls
});
Opciones de selección de herramienta
const result = streamText({
model: openai('gpt-4-turbo'),
messages,
tools: { weather, calculator },
// Let the model decide which tools to use (default)
toolChoice: 'auto',
// Force the model to use a specific tool
// toolChoice: { type: 'tool', toolName: 'weather' },
// Require the model to use at least one tool
// toolChoice: 'required',
// Prevent tool usage
// toolChoice: 'none',
});
Manejo de errores de herramientas
const weatherTool = tool({
description: 'Get current weather',
parameters: z.object({
location: z.string(),
}),
execute: async ({ location }) => {
try {
const response = await fetch(
`https://api.weather.com/${location}`
);
if (!response.ok) {
// Return error message for the AI to handle
return {
error: true,
message: `Could not get weather for ${location}`,
};
}
return await response.json();
} catch (error) {
return {
error: true,
message: 'Weather service is unavailable',
};
}
},
});
Server Action con herramientas
// app/actions.ts
'use server';
import { openai } from '@ai-sdk/openai';
import { generateText, tool } from 'ai';
import { z } from 'zod';
export async function askWithTools(prompt: string) {
const { text, toolResults } = await generateText({
model: openai('gpt-4-turbo'),
prompt,
tools: {
getCurrentTime: tool({
description: 'Get the current time',
parameters: z.object({
timezone: z.string().optional().default('UTC'),
}),
execute: async ({ timezone }) => {
return new Date().toLocaleString('en-US', { timeZone: timezone });
},
}),
},
});
return { text, toolResults };
}
Ejemplo real: asistente de IA
// app/api/assistant/route.ts
import { openai } from '@ai-sdk/openai';
import { streamText, tool } from 'ai';
import { z } from 'zod';
export async function POST(req: Request) {
const { messages } = await req.json();
const result = streamText({
model: openai('gpt-4-turbo'),
system: `You are a helpful assistant with access to tools.
Use tools when they would help answer the user's question.
Always explain what you're doing when using tools.`,
messages,
tools: {
searchWeb: tool({
description: 'Search the web for current information',
parameters: z.object({
query: z.string(),
}),
execute: async ({ query }) => {
// Integrate with search API
return await searchWeb(query);
},
}),
createReminder: tool({
description: 'Create a reminder for the user',
parameters: z.object({
title: z.string(),
datetime: z.string(),
priority: z.enum(['low', 'medium', 'high']).optional(),
}),
execute: async ({ title, datetime, priority }) => {
await createReminder({ title, datetime, priority });
return { success: true, message: `Reminder "${title}" created` };
},
}),
sendEmail: tool({
description: 'Send an email on behalf of the user',
parameters: z.object({
to: z.string().email(),
subject: z.string(),
body: z.string(),
}),
execute: async ({ to, subject, body }) => {
await sendEmail({ to, subject, body });
return { success: true, message: `Email sent to ${to}` };
},
}),
},
maxSteps: 3,
});
return result.toDataStreamResponse();
}
Consideraciones de seguridad
- • Valida cuidadosamente todas las entradas con esquemas Zod
- • Nunca confíes en código o expresiones generadas por IA (evita eval)
- • Implementa autorización adecuada para herramientas sensibles
- • Aplica rate limiting para evitar abuso
- • Registra el uso de herramientas para auditoría y depuración
💡 Puntos clave
- • Las herramientas extienden capacidades con acciones reales
- • Define herramientas con descripciones claras y esquemas Zod
- • Usa
maxStepspara interacciones de varios pasos - • Maneja errores de herramientas con gracia para mejor UX
- • Accede a
toolInvocationsen mensajes para mostrar resultados
📚 Más recursos
-
Documentación de tool calling →
Guía completa de herramientas en AI SDK Core.
-
useChat con herramientas →
Integración de herramientas con el hook de chat.