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 sie 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 komplexere 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 das Abrufen der vom LLM benötigten Informationen jedoch ein einfacher Funktionsaufruf oder eine Datenbanksuche ist, ist der Toolaufruf besser geeignet.

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

  • Berechnungen ausführen, die der LLM nicht zuverlässig selbst abschließen kann.
  • Ein LLM dazu zwingen, unter bestimmten Umständen wörtliche Textausschnitte 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 erläutert. 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 Tool-Aufrufanfrage 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 zum Ausführen eines Prompts erforderlich ist. Die meisten größeren Modelle, die über Web-APIs bereitgestellt werden, wie Gemini und Claude, können dies, aber kleinere und spezialisiertere Modelle 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 letzten beiden der oben genannten Kriterien erfüllt sind. Die generate()-Funktion der Genkit-Instanz führt automatisch die oben beschriebene Tool-Aufrufschleife aus.

Modellunterstützung

Die Unterstützung für Toolaufrufe 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 info.supports.tools an, ob es den Toolaufruf unterstützt.

Tools definieren

Verwenden Sie die defineTool()-Funktion der Genkit-Instanz, um Tooldefinitionen zu schreiben:

import { genkit, z } from 'genkit';
import { googleAI, gemini15Flash } from '@genkit-ai/google-ai';

const ai = genkit({
  plugins: [googleAI()],
  model: gemini15Flash,
});

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

Die Syntax hier sieht genauso aus wie die defineFlow()-Syntax. Allerdings sind alle vier Parameter name, description, inputSchema und outputSchema erforderlich. Achten Sie beim Erstellen einer Tooldefinition besonders auf die Formulierung und Beschreibung dieser Parameter, da sie für die effektive Nutzung der verfügbaren Tools durch den LLM entscheidend sind.

Tools verwenden

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

Generieren

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

Prompt-Datei

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

Toolaufrufe explizit verarbeiten

Standardmäßig ruft Genkit das LLM wiederholt auf, bis alle Toolaufrufe abgeschlossen sind. Wenn Sie mehr Kontrolle über diesen Tool-Aufruf-Loop haben möchten, um beispielsweise eine kompliziertere Logik anzuwenden, legen Sie den Parameter returnToolRequests auf true fest. Jetzt liegt es in Ihrer Verantwortung, dafür zu sorgen, dass alle Toolanfragen erfüllt werden:

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