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 una llamada a función o una búsqueda en la base de datos es todo lo que se necesita para recuperar la información que necesita el LLM, 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 completa la solicitud y finaliza la interacción. Sin embargo, si el llamador recibe una llamada de 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 de 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, 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 criterios mencionados en la sección anterior, y la función genkit.Generate()
realiza automáticamente el bucle de llamadas de herramientas que se describió antes.
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
ModelInfo.Supports.Tools
indicará si admite llamadas a herramientas.
Definición de herramientas
Usa la función genkit.DefineTool()
para escribir definiciones de herramientas:
import (
"context"
"log"
"github.com/firebase/genkit/go/ai"
"github.com/firebase/genkit/go/genkit"
"github.com/firebase/genkit/go/plugins/googlegenai"
)
func main() {
ctx := context.Background()
g, err := genkit.Init(ctx,
genkit.WithPlugins(&googlegenai.GoogleAI{}),
genkit.WithDefaultModel("googleai/gemini-2.0-flash"),
)
if err != nil {
log.Fatal(err)
}
getWeatherTool := genkit.DefineTool(
g, "getWeather", "Gets the current weather in a given location",
func(ctx *ai.ToolContext, location string) (string, error) {
// Here, we would typically make an API call or database query. For this
// example, we just return a fixed value.
return fmt.Sprintf("The current weather in %s is 63°F and sunny.", location);
})
}
La sintaxis aquí se ve igual que la sintaxis de genkit.DefineFlow()
. Sin embargo, debes escribir una descripción. Ten especial cuidado con el lenguaje y la descriptividad de la descripción, ya que es fundamental que el LLM decida usarla de manera adecuada.
Uso de herramientas
Incluye herramientas definidas en tus instrucciones para generar contenido.
Generar
resp, err := genkit.Generate(ctx, g,
ai.WithPrompt("What is the weather in San Francisco?"),
ai.WithTools(getWeatherTool),
)
DefinePrompt
weatherPrompt, err := genkit.DefinePrompt(g, "weatherPrompt",
ai.WithPrompt("What is the weather in {{location}}?"),
ai.WithTools(getWeatherTool),
)
if err != nil {
log.Fatal(err)
}
resp, err := weatherPrompt.Execute(ctx,
with.Input(map[string]any{"location": "San Francisco"}),
)
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 named weatherPrompt.prompt exists in ./prompts dir.
weatherPrompt := genkit.LookupPrompt("weatherPrompt")
if weatherPrompt == nil {
log.Fatal("no prompt named 'weatherPrompt' found")
}
resp, err := weatherPrompt.Execute(ctx,
ai.WithInput(map[string]any{"location": "San Francisco"}),
)
Genkit controlará automáticamente la llamada a la herramienta si el LLM necesita usar la herramienta getWeather
para responder la instrucción.
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 la opción WithReturnToolRequests()
en true
. Ahora es tu responsabilidad garantizar que se cumplan todas las solicitudes de herramientas:
getWeatherTool := genkit.DefineTool(
g, "getWeather", "Gets the current weather in a given location",
func(ctx *ai.ToolContext, location string) (string, error) {
// Tool implementation...
})
resp, err := genkit.Generate(ctx, g,
ai.WithPrompt("What is the weather in San Francisco?"),
ai.WithTools(getWeatherTool),
ai.WithReturnToolRequests(true),
)
if err != nil {
log.Fatal(err)
}
parts := []*Part{}
for _, req := range resp.ToolRequests() {
tool := genkit.LookupTool(g, req.Name)
if tool == nil {
log.Fatalf("tool %q not found", req.Name)
}
output, err := tool.RunRaw(ctx, req.Input)
if err != nil {
log.Fatalf("tool %q execution failed: %v", err)
}
parts = append(parts,
ai.NewToolResponsePart(&ai.ToolResponse{
Name: req.Name,
Ref: req.Ref,
Output: output,
}))
}
resp, err = genkit.Generate(ctx, g,
ai.WithMessages(resp.History()..., NewMessage(ai.RoleTool, nil, parts...)),
)
if err != nil {
log.Fatal(err)
}