Appel de l'outil

L'appel d'outil, également appelé appel de fonction, est un moyen structuré de permettre aux LLM d'envoyer des requêtes à l'application qui les a appelés. Vous définissez les outils que vous souhaitez mettre à la disposition du modèle, et le modèle envoie des requêtes d'outils à votre application si nécessaire pour répondre aux requêtes que vous lui envoyez.

Les cas d'utilisation de l'appel d'outils se répartissent généralement en quelques thèmes:

Accorder à un LLM l'accès à des informations avec lesquelles il n'a pas été entraîné

  • Informations qui changent fréquemment, comme le cours d'une action ou la météo actuelle
  • Informations spécifiques au domaine de votre application, telles que des informations sur les produits ou des profils utilisateur.

Notez le chevauchement avec la génération augmentée par récupération (RAG), qui permet également à un LLM d'intégrer des informations factuelles dans ses générations. Le RAG est une solution plus lourde qui est la plus adaptée lorsque vous disposez d'une grande quantité d'informations ou que les informations les plus pertinentes pour une invite sont ambiguës. En revanche, si un appel de fonction ou une recherche dans la base de données est tout ce qui est nécessaire pour récupérer les informations dont le LLM a besoin, l'appel d'outil est plus approprié.

Introduire un degré de déterminisme dans un workflow de LLM

  • Effectuer des calculs que le LLM ne peut pas effectuer de manière fiable.
  • Forcer un LLM à générer du texte textuel dans certaines circonstances, par exemple pour répondre à une question sur les conditions d'utilisation d'une application.

Effectuer une action lorsqu'elle est lancée par un LLM

  • Allumer et éteindre les lumières dans un assistant à domicile basé sur un LLM
  • Réserver une table dans un agent de restaurant optimisé par LLM

Avant de commencer

Si vous souhaitez exécuter les exemples de code de cette page, suivez d'abord les étapes du guide Premiers pas. Tous les exemples supposent que vous avez déjà configuré un projet avec les dépendances Genkit installées.

Cette page décrit l'une des fonctionnalités avancées de l'abstraction de modèle Genkit. Avant de vous plonger dans les détails, vous devez donc vous familiariser avec le contenu de la page Générer du contenu avec des modèles d'IA. Vous devez également connaître le système de Genkit pour définir des schémas d'entrée et de sortie, qui est décrit sur la page Flux.

Présentation de l'appel d'outils

De manière générale, voici à quoi ressemble une interaction d'appel d'outil avec un LLM:

  1. L'application appelante envoie une requête au LLM et inclut également dans l'invite une liste d'outils que le LLM peut utiliser pour générer une réponse.
  2. Le LLM génère une réponse complète ou une requête d'appel d'outil dans un format spécifique.
  3. Si l'appelant reçoit une réponse complète, la requête est traitée et l'interaction se termine. Toutefois, si l'appelant reçoit un appel d'outil, il exécute la logique appropriée et envoie une nouvelle requête au LLM contenant l'invite d'origine ou une variante de celle-ci, ainsi que le résultat de l'appel d'outil.
  4. Le LLM gère la nouvelle requête comme à l'étape 2.

Pour que cela fonctionne, plusieurs conditions doivent être remplies:

  • Le modèle doit être entraîné pour effectuer des requêtes d'outils lorsqu'il est nécessaire d'exécuter une invite. La plupart des modèles plus volumineux fournis via des API Web telles que Gemini peuvent le faire, mais ce n'est souvent pas le cas des modèles plus petits et plus spécialisés. Genkit génère une erreur si vous essayez de fournir des outils à un modèle qui ne les accepte pas.
  • L'application appelante doit fournir des définitions d'outils au modèle au format attendu.
  • L'application appelante doit inviter le modèle à générer des requêtes d'appel d'outil au format attendu par l'application.

Appel d'outils avec Genkit

Genkit fournit une interface unique pour l'appel d'outils avec les modèles compatibles. Chaque plug-in de modèle s'assure que les deux derniers critères mentionnés dans la section précédente sont remplis, et la fonction genkit.Generate() exécute automatiquement la boucle d'appel d'outil décrite précédemment.

Compatibilité avec les modèles

La compatibilité avec l'appel d'outils dépend du modèle, de l'API du modèle et du plug-in Genkit. Consultez la documentation appropriée pour déterminer si l'appel d'outils est susceptible d'être pris en charge. Autres caractéristiques :

  • Genkit génère une erreur si vous essayez de fournir des outils à un modèle qui ne les accepte pas.
  • Si le plug-in exporte des références de modèle, la propriété ModelInfo.Supports.Tools indique s'il est compatible avec l'appel d'outils.

Outils de définition

Utilisez la fonction genkit.DefineTool() pour écrire des définitions d'outils:

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 syntaxe ici ressemble à celle de genkit.DefineFlow(). Toutefois, vous devez rédiger une description. Faites particulièrement attention au libellé et à la description, car il est essentiel que le LLM décide de l'utiliser de manière appropriée.

Utiliser des outils

Incluez des outils définis dans vos requêtes pour générer du contenu.

Générer

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"}),
)

Fichier de requête

---
system: "Answer questions using the tools you have."
tools: [getWeather]
input:
  schema:
    location: string
---

What is the weather in {{location}}?

Vous pouvez ensuite exécuter l'invite dans votre code comme suit:

// 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 gère automatiquement l'appel de l'outil si le LLM doit utiliser l'outil getWeather pour répondre à l'invite.

Gérer explicitement les appels d'outils

Si vous souhaitez contrôler entièrement cette boucle d'appel d'outil, par exemple pour appliquer une logique plus complexe, définissez l'option WithReturnToolRequests() sur true. Il vous incombe maintenant de vous assurer que toutes les demandes de l'outil sont satisfaites:

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)
}