Las llamadas a herramientas, también conocidas como llamadas a función, son una forma estructurada de brindar a los LLM la capacidad de realizar solicitudes a la aplicación que los llamó. Tú defines las herramientas que deseas poner a disposición del modelo, y este hará solicitudes de herramientas a tu app según sea necesario para completar las instrucciones que le des.
Los casos de uso de las llamadas a herramientas suelen incluir algunos temas:
Dar acceso a un LLM a información con la que no se entrenó
- Información que cambia con frecuencia, como el precio de una acción o el clima actual.
- Información específica del dominio de tu app, como la información del producto o los perfiles de usuario.
Ten en cuenta la superposición con la generación mejorada por recuperación (RAG), que también es una forma de permitir que un LLM integre información fáctica en sus generaciones. La RAG es una solución más pesada que es más adecuada cuando tienes una gran cantidad de información o cuando la información más relevante para una instrucción es ambigua. Por otro lado, si la recuperación de la información que necesita el LLM es una llamada a función simple o una búsqueda en la base de datos, las llamadas a herramientas son más apropiadas.
Cómo introducir un grado de determinismo en un flujo de trabajo de LLM
- Realizar cálculos que el LLM no puede completar de forma confiable.
- Forzar a un LLM a generar texto literal en ciertas circunstancias, como cuando se responde una pregunta sobre las condiciones del servicio de una app.
Cómo realizar una acción cuando la inicia un LLM
- Encender y apagar luces en un asistente de casa potenciado por LLM
- Cómo reservar mesas en un agente de restaurantes con LLM
Antes de comenzar
Si quieres ejecutar los ejemplos de código de esta página, primero completa los pasos de la guía Cómo comenzar. En todos los ejemplos, se da por sentado que ya configuraste un proyecto con las dependencias de Genkit instaladas.
En esta página, se analiza una de las funciones avanzadas de la abstracción de modelos de Genkit, por lo que antes de profundizar demasiado, debes familiarizarte con el contenido de la página Cómo generar contenido con modelos de IA. También debes estar familiarizado con el sistema de Genkit para definir esquemas de entrada y salida, que se explica en la página Flujo.
Descripción general de las llamadas a herramientas
En términos generales, así es como se ve una interacción típica de llamada a herramientas con un LLM:
- La aplicación que realiza la llamada le envía una solicitud al LLM y también incluye en la instrucción una lista de herramientas que el LLM puede usar para generar una respuesta.
- El LLM genera una respuesta completa o una solicitud de llamada a la herramienta en un formato específico.
- Si el llamador recibe una respuesta completa, se entrega la solicitud y finaliza la interacción. Sin embargo, si el llamador recibe una llamada a la herramienta, realiza la lógica adecuada y envía una solicitud nueva al LLM que contiene la instrucción original o alguna variación de ella, así como el resultado de la llamada a la herramienta.
- El LLM controla la nueva instrucción como en el paso 2.
Para que esto funcione, se deben cumplir varios requisitos:
- El modelo debe entrenarse para realizar solicitudes de herramientas cuando sea necesario para completar una instrucción. La mayoría de los modelos más grandes que se proporcionan a través de APIs web, como Gemini y Claude, pueden hacerlo, pero los modelos más pequeños y especializados a menudo no pueden. Genkit mostrará un error si intentas proporcionar herramientas a un modelo que no las admite.
- La aplicación que realiza la llamada debe proporcionar definiciones de herramientas al modelo en el formato que espera.
- La aplicación que realiza la llamada debe solicitarle al modelo que genere solicitudes de llamadas a la herramienta en el formato que espera la aplicación.
Llamadas a herramientas con Genkit
Genkit proporciona una sola interfaz para las llamadas a herramientas con modelos que la admiten.
Cada complemento de modelo garantiza que se cumplan los últimos dos de los criterios anteriores, y la función generate()
de la instancia de Genkit realiza automáticamente el bucle de llamadas de herramientas que se describió anteriormente.
Compatibilidad con modelos
La compatibilidad con las llamadas a herramientas depende del modelo, la API del modelo y el complemento de Genkit. Consulta la documentación relevante para determinar si es probable que se admita la llamada a herramientas. Además:
- Genkit mostrará un error si intentas proporcionar herramientas a un modelo que no las admite.
- Si el complemento exporta referencias de modelos, la propiedad
info.supports.tools
indicará si admite llamadas a herramientas.
Definición de herramientas
Usa la función defineTool()
de la instancia de Genkit para escribir definiciones de herramientas:
import { genkit, z } from 'genkit';
import { googleAI } from '@genkitai/google-ai';
const ai = genkit({
plugins: [googleAI()],
model: googleAI.model('gemini-2.0-flash'),
});
const getWeather = ai.defineTool(
{
name: 'getWeather',
description: 'Gets the current weather in a given location',
inputSchema: z.object({
location: z.string().describe('The location to get the current weather for')
}),
outputSchema: z.string(),
},
async (input) => {
// Here, we would typically make an API call or database query. For this
// example, we just return a fixed value.
return `The current weather in ${input.location} is 63°F and sunny.`;
}
);
La sintaxis aquí se ve igual que la sintaxis de defineFlow()
. Sin embargo, los parámetros name
,
description
y inputSchema
son obligatorios. Cuando escribas una definición de herramienta, presta especial atención al lenguaje y la capacidad descriptiva de estos parámetros. Son vitales para que el LLM haga un uso eficaz de las herramientas disponibles.
Uso de herramientas
Incluye herramientas definidas en tus instrucciones para generar contenido.
Generar
const response = await ai.generate({
prompt: 'What is the weather in Baltimore?',
tools: [getWeather],
});
definePrompt
const weatherPrompt = ai.definePrompt(
{
name: 'weatherPrompt',
tools: [getWeather],
},
'What is the weather in {{location}}?'
);
const response = await weatherPrompt({ location: 'Baltimore' });
Archivo de la instrucción
---
system: "Answer questions using the tools you have."
tools: [getWeather]
input:
schema:
location: string
---
What is the weather in {{location}}?
Luego, puedes ejecutar la instrucción en tu código de la siguiente manera:
// assuming prompt file is named weatherPrompt.prompt
const weatherPrompt = ai.prompt('weatherPrompt');
const response = await weatherPrompt({ location: 'Baltimore' });
Chat
const chat = ai.chat({
system: 'Answer questions using the tools you have.',
tools: [getWeather],
});
const response = await chat.send('What is the weather in Baltimore?');
// Or, specify tools that are message-specific
const response = await chat.send({
prompt: 'What is the weather in Baltimore?',
tools: [getWeather],
});
Genkit controlará automáticamente la llamada a la herramienta si el LLM necesita usar la herramienta getWeather
para responder la instrucción.
Definición dinámica de herramientas en el tiempo de ejecución
Al igual que la mayoría de los elementos de Genkit, las herramientas deben definirse de antemano durante la inicialización de tu app. Esto es necesario para que puedas interactuar con tus herramientas desde la IU para desarrolladores de Genkit. Por lo general, esta es la forma recomendada. Sin embargo, hay situaciones en las que la herramienta se debe definir de forma dinámica según la solicitud del usuario.
Puedes definir herramientas de forma dinámica con la función ai.dynamicTool
. Esta función es muy similar al método ai.defineTool
. Sin embargo, el entorno de ejecución de Genkit no realiza un seguimiento de las herramientas dinámicas, por lo que no puedes usar la IU de desarrollador de Genkit para interactuar con ellas. En su lugar, debes pasarlo a la llamada a ai.generate
por
referencia (para herramientas normales, también puedes usar un nombre de herramienta de cadena).
import { genkit, z } from "genkit";
import { googleAI } from "@genkit-ai/googleai";
const ai = genkit({
plugins: [googleAI()],
model: googleAI.model("gemini-2.0-flash"),
});
const weatherFlow = ai.defineFlow("weatherFlow", async () => {
const getWeather = ai.dynamicTool(
{
name: "getWeather",
description: "Gets the current weather in a given location",
inputSchema: z.object({
location: z
.string()
.describe("The location to get the current weather for"),
}),
outputSchema: z.string(),
},
async (input) => {
return `The current weather in ${input.location} is 63°F and sunny.`;
}
);
const { text } = await ai.generate({
prompt: "What is the weather in Baltimore?",
tools: [getWeather],
});
return text;
});
Cuando definas herramientas dinámicas, para especificar los esquemas de entrada y salida, puedes usar Zod como se muestra en el ejemplo anterior o pasar un esquema JSON construido de forma manual.
const getWeather = ai.dynamicTool(
{
name: "getWeather",
description: "Gets the current weather in a given location",
inputJsonSchema: myInputJsonSchema,
outputJsonSchema: myOutputJsonSchema,
},
async (input) => { /* ... */ }
);
Las herramientas dinámicas no requieren la función de implementación. Si no pasas la función, la herramienta se comportará como una interrupción y puedes controlar las llamadas a la herramienta de forma manual:
const getWeather = ai.dynamicTool(
{
name: "getWeather",
description: "Gets the current weather in a given location",
inputJsonSchema: myInputJsonSchema,
outputJsonSchema: myOutputJsonSchema,
}
);
Cómo pausar el bucle de herramientas con interrupciones
De forma predeterminada, Genkit llama al LLM de forma reiterada hasta que se resuelve cada llamada a la herramienta. Puedes pausar la ejecución de forma condicional en situaciones en las que lo desees, por ejemplo:
- Hacerle una pregunta al usuario o mostrarle la IU
- Confirma una acción potencialmente riesgosa con el usuario.
- Solicitar aprobación fuera de banda para una acción
Las interrupciones son herramientas especiales que pueden detener el bucle y devolver el control a tu código para que puedas controlar situaciones más avanzadas. Visita la guía de interrupciones para aprender a usarlas.
Controla de forma explícita las llamadas a herramientas
Si deseas tener control total sobre este bucle de llamada de herramientas, por ejemplo, para aplicar una lógica más complicada, establece el parámetro returnToolRequests
en true
.
Ahora es tu responsabilidad garantizar que se cumplan todas las solicitudes de herramientas:
const getWeather = ai.defineTool(
{
// ... tool definition ...
},
async ({ location }) => {
// ... tool implementation ...
},
);
const generateOptions: GenerateOptions = {
prompt: "What's the weather like in Baltimore?",
tools: [getWeather],
returnToolRequests: true,
};
let llmResponse;
while (true) {
llmResponse = await ai.generate(generateOptions);
const toolRequests = llmResponse.toolRequests;
if (toolRequests.length < 1) {
break;
}
const toolResponses: ToolResponsePart[] = await Promise.all(
toolRequests.map(async (part) => {
switch (part.toolRequest.name) {
case 'specialTool':
return {
toolResponse: {
name: part.toolRequest.name,
ref: part.toolRequest.ref,
output: await getWeather(part.toolRequest.input),
},
};
default:
throw Error('Tool not found');
}
})
);
generateOptions.messages = llmResponse.messages;
generateOptions.prompt = toolResponses;
}