Toolaufrufe

Der Toolaufruf, auch Funktionsaufruf genannt, ist eine strukturierte Methode, mit der LLMs Anfragen an die Anwendung zurücksenden können, die sie aufgerufen hat. Sie definieren die Tools, die Sie dem Modell zur Verfügung stellen möchten. Das Modell sendet dann bei Bedarf Toolanfragen an Ihre App, um die von Ihnen gegebenen Prompts zu erfüllen.

Die Anwendungsfälle für Toolaufrufe lassen sich in der Regel in einige Themen unterteilen:

LLM Zugriff auf Informationen gewähren, mit denen er nicht trainiert wurde

  • Häufig ändernde Informationen wie Aktienkurse oder das aktuelle Wetter
  • Informationen, die für Ihre App-Domain spezifisch sind, z. B. Produktinformationen oder Nutzerprofile.

Beachten Sie die Überschneidung mit der Retrieval-Augmented Generation (RAG), bei der ein LLM auch Fakten in seine Generierungen einbinden kann. Die RAG-Methode ist eine umfangreichere Lösung, die am besten geeignet ist, wenn Sie eine große Menge an Informationen haben oder die für einen Prompt relevantesten Informationen mehrdeutig sind. Wenn hingegen ein Funktionsaufruf oder eine Datenbanksuche ausreicht, um die für das LLM erforderlichen Informationen abzurufen, ist der Toolaufruf besser geeignet.

Ein gewisses Maß an Determinismus in einen LLM-Workflow einführen

  • Berechnungen ausführen, die das LLM nicht zuverlässig selbst abschließen kann.
  • Ein LLM dazu zwingen, unter bestimmten Umständen wörtliche Textpassagen zu generieren, z. B. bei der Beantwortung einer Frage zu den Nutzungsbedingungen einer App.

Ausführung einer Aktion, die von einem LLM initiiert wurde

  • Lampen über einen LLM-gestützten Smart-Home-Assistenten ein- und ausschalten
  • Tischreservierungen über einen Restaurant-Agenten mit LLM vornehmen

Hinweis

Wenn Sie die Codebeispiele auf dieser Seite ausführen möchten, führen Sie zuerst die Schritte in der Anleitung Erste Schritte aus. Bei allen Beispielen wird davon ausgegangen, dass Sie bereits ein Projekt mit installierten Genkit-Abhängigkeiten eingerichtet haben.

Auf dieser Seite wird eine der erweiterten Funktionen der Genkit-Modellabstraktion beschrieben. Bevor Sie sich also näher damit befassen, sollten Sie sich mit den Inhalten auf der Seite Inhalte mit KI-Modellen generieren vertraut machen. Außerdem sollten Sie mit dem System von Genkit zum Definieren von Eingabe- und Ausgabeschemata vertraut sein. Weitere Informationen finden Sie auf der Seite Abläufe.

Aufruf von Tools

Im Folgenden wird eine typische Interaktion zwischen einem Tool und einem LLM dargestellt:

  1. Die aufrufende Anwendung sendet dem LLM eine Anfrage und enthält im Prompt auch eine Liste der Tools, die das LLM zum Generieren einer Antwort verwenden kann.
  2. Das LLM generiert entweder eine vollständige Antwort oder eine Toolaufrufanfrage in einem bestimmten Format.
  3. Wenn der Aufrufer eine vollständige Antwort erhält, wird die Anfrage erfüllt und die Interaktion endet. Wenn der Aufrufer jedoch einen Toolaufruf erhält, wird die entsprechende Logik ausgeführt und eine neue Anfrage an das LLM gesendet, die den ursprünglichen Prompt oder eine Variante davon sowie das Ergebnis des Toolaufrufs enthält.
  4. Der LLM verarbeitet den neuen Prompt wie in Schritt 2.

Damit dies funktioniert, müssen mehrere Anforderungen erfüllt sein:

  • Das Modell muss so trainiert werden, dass es Toolanfragen stellt, wenn dies für die Ausführung eines Prompts erforderlich ist. Die meisten größeren Modelle, die über Web-APIs wie Gemini bereitgestellt werden, können dies, kleinere und spezialisiertere Modelle jedoch oft nicht. Genkit gibt einen Fehler zurück, wenn Sie versuchen, einem Modell Tools zur Verfügung zu stellen, die es nicht unterstützt.
  • Die aufrufende Anwendung muss dem Modell Tooldefinitionen im erwarteten Format zur Verfügung stellen.
  • Die aufrufende Anwendung muss das Modell auffordern, Toolaufrufanfragen im von der Anwendung erwarteten Format zu generieren.

Toolaufrufe mit Genkit

Genkit bietet eine einzige Schnittstelle für den Toolaufruf mit Modellen, die dies unterstützen. Jedes Modell-Plug-in sorgt dafür, dass die beiden im vorherigen Abschnitt genannten Kriterien erfüllt sind. Die Funktion genkit.Generate() führt dann automatisch die oben beschriebene Schleife zum Aufrufen des Tools aus.

Modellunterstützung

Die Unterstützung für den Toolaufruf hängt vom Modell, der Modell-API und dem Genkit-Plug-in ab. Lesen Sie in der entsprechenden Dokumentation nach, ob der Aufruf von Tools wahrscheinlich unterstützt wird. Außerdem gilt:

  • Genkit gibt einen Fehler zurück, wenn Sie versuchen, einem Modell Tools zur Verfügung zu stellen, die es nicht unterstützt.
  • Wenn das Plug-in Modellreferenzen exportiert, gibt die Eigenschaft ModelInfo.Supports.Tools an, ob es den Toolaufruf unterstützt.

Tools definieren

Verwenden Sie die genkit.DefineTool()-Funktion, um Tooldefinitionen zu schreiben:

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

Die Syntax hier sieht genauso aus wie die genkit.DefineFlow()-Syntax. Sie müssen jedoch eine Beschreibung hinzufügen. Achten Sie besonders auf die Formulierung und Beschreibung, da es für das LLM entscheidend ist, sie richtig zu verwenden.

Tools verwenden

Fügen Sie Ihrem Prompt Tools hinzu, um Inhalte zu generieren.

resp, err := genkit.Generate(ctx, g,
    ai.WithPrompt("What is the weather in San Francisco?"),
    ai.WithTools(getWeatherTool),
)
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"}),
)
---
system: "Answer questions using the tools you have."
tools: [getWeather]
input:
  schema:
    location: string
---

What is the weather in {{location}}?

Anschließend können Sie den Prompt in Ihrem Code so ausführen:

// 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 verarbeitet den Toolaufruf automatisch, wenn das LLM das Tool getWeather verwenden muss, um den Prompt zu beantworten.

Toolaufrufe explizit verarbeiten

Wenn Sie die volle Kontrolle über diesen Tool-Aufruf-Loop haben möchten, um beispielsweise eine kompliziertere Logik anzuwenden, legen Sie die Option WithReturnToolRequests() auf true fest. Jetzt liegt es in Ihrer Verantwortung, dafür zu sorgen, dass alle Toolanfragen erfüllt werden:

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