Unterbrechungen sind eine spezielle Art von Tool, mit dem die LLM-Generierungs- und Tool-Aufrufschleife pausiert werden kann, um die Kontrolle wieder an Sie zurückzugeben. Wenn Sie bereit sind, können Sie die Generierung fortsetzen, indem Sie Antworten senden, die das LLM für die weitere Generierung verarbeitet.
Die häufigsten Verwendungen von Unterbrechungen lassen sich in einige Kategorien unterteilen:
- Human-in-the-Loop: Der Nutzer einer interaktiven KI kann erforderliche Informationen erläutern oder die Aktion der LLM bestätigen, bevor sie abgeschlossen wird. So wird für ein gewisses Maß an Sicherheit und Vertrauen gesorgt.
- Asynchrone Verarbeitung:Starten einer asynchronen Aufgabe, die nur außerhalb des Bandes abgeschlossen werden kann, z. B. das Senden einer Genehmigungsbenachrichtigung an einen menschlichen Prüfer oder das Starten eines langwierigen Hintergrundprozesses.
- Aus einer autonomen Aufgabe aussteigen:Dem Modell wird eine Möglichkeit gegeben, eine Aufgabe in einem Workflow als erledigt zu markieren, der eine lange Reihe von Toolaufrufen durchlaufen kann.
Hinweis
Bei allen hier dokumentierten Beispielen wird davon ausgegangen, dass Sie bereits ein Projekt mit installierten Genkit-Abhängigkeiten eingerichtet haben. Wenn Sie die Codebeispiele auf dieser Seite ausführen möchten, führen Sie zuerst die Schritte in der Anleitung Erste Schritte aus.
Bevor Sie sich näher mit dem Thema befassen, sollten Sie sich mit den folgenden Konzepten vertraut machen:
- Inhalte mit KI-Modellen generieren
- Das Genkit-System zum Definieren von Eingabe- und Ausgabeschemata.
- Allgemeine Methoden zum Aufrufen von Tools.
Unterbrechungen – Übersicht
Im Folgenden wird ein Interrupt bei der Interaktion mit einem LLM allgemein beschrieben:
- Die aufrufende Anwendung sendet eine Anfrage an das LLM. Der Prompt enthält eine Liste von Tools, darunter mindestens eines für eine Unterbrechung, mit der das LLM eine Antwort generieren kann.
- Das LLM generiert entweder eine vollständige Antwort oder eine Tool-Aufrufanfrage in einem bestimmten Format. Für den LLM sieht ein Interruptaufruf wie jeder andere Toolaufruf aus.
- Wenn das LLM ein Unterbrechungstool aufruft, hält die Genkit-Bibliothek die Generierung automatisch an, anstatt die Antworten sofort zur weiteren Verarbeitung an das Modell zurückzugeben.
- Der Entwickler prüft, ob ein Interruptaufruf erfolgt, und führt alle erforderlichen Aufgaben aus, um die für die Interruptantwort erforderlichen Informationen zu erfassen.
- Der Entwickler setzt die Generierung fort, indem er dem Modell eine Unterbrechungsantwort übergibt. Dadurch werden Sie zu Schritt 2 zurückgeleitet.
Unterbrechungen für manuelle Antworten definieren
Bei der häufigsten Art der Unterbrechung kann der LLM vom Nutzer eine Klarstellung anfordern, z. B. durch eine Multiple-Choice-Frage.
Verwenden Sie für diesen Anwendungsfall die Methode defineInterrupt()
der Genkit-Instanz:
import { genkit, z } from 'genkit';
import { googleAI, gemini15Flash } from '@genkitai/google-ai';
const ai = genkit({
plugins: [googleAI()],
model: gemini15Flash,
});
const askQuestion = ai.defineInterrupt({
name: 'askQuestion',
description: 'use this to ask the user a clarifying question',
inputSchema: z.object({
choices: z.array(z.string()).describe('the choices to display to the user'),
allowOther: z.boolean().optional().describe('when true, allow write-ins')
}),
outputSchema: z.string()
});
Die outputSchema
eines Interrupts entspricht den von Ihnen bereitgestellten Antwortdaten und nicht einem Wert, der automatisch von einer Toolfunktion eingefügt wird.
Unterbrechungen verwenden
Unterbrechungen werden beim Generieren von Inhalten wie bei anderen Tools an das tools
-Array übergeben. Du kannst demselben generate
-Aufruf sowohl normale Tools als auch Unterbrechungen übergeben:
generieren
const response = await ai.generate({
prompt: 'Ask me a movie trivia question.',
tools: [askQuestion],
});
definePrompt
const triviaPrompt = ai.definePrompt(
{
name: 'triviaPrompt',
tools: [askQuestion],
input: {
schema: z.object({subject: z.string()})
},
prompt: 'Ask me a trivia question about {{subject}}
.',
}
);
const response = await triviaPrompt({ subject: 'computer history' });
Prompt-Datei
---
tools: [askQuestion]
input:
schema:
partyType: string
---
{{role "system"}}
Use the askQuestion tool if you need to clarify something.
{{role "user"}}
Help me plan a {{partyType}} party next week.
Anschließend können Sie den Prompt in Ihrem Code so ausführen:
```ts
// assuming prompt file is named partyPlanner.prompt
const partyPlanner = ai.prompt('partyPlanner');
const response = await partyPlanner({ partyType: 'birthday' });
```
Chat
const chat = ai.chat({
system: 'Use the askQuestion tool if you need to clarify something.',
tools: [askQuestion],
});
const response = await chat.send('make a plan for my birthday party');
Genkit gibt sofort eine Antwort zurück, wenn ein Interrupt-Tool-Aufruf empfangen wird.
Auf Unterbrechungen reagieren
Wenn Sie Ihrem generate-Aufruf eine oder mehrere Unterbrechungen übergeben haben, müssen Sie die Antwort auf Unterbrechungen prüfen, damit Sie sie verarbeiten können:
// you can check the 'finishReason' of the response
response.finishReason === 'interrupted'
// or you can check to see if any interrupt requests are on the response
response.interrupts.length > 0
Um auf eine Unterbrechung zu reagieren, verwenden Sie die Option resume
bei einem nachfolgenden generate
-Aufruf. Dabei muss der vorhandene Verlauf übergeben werden. Jedes Tool hat eine .respond()
-Methode, die beim Erstellen der Antwort hilft.
Nach der Wiederaufnahme kehrt das Modell in die Generierungsschleife zurück, einschließlich der Toolausführung, bis der Vorgang abgeschlossen ist oder eine weitere Unterbrechung ausgelöst wird:
let response = await ai.generate({
tools: [askQuestion],
system: 'ask clarifying questions until you have a complete solution',
prompt: 'help me plan a backyard BBQ',
});
while (response.interrupts.length) {
const answers = [];
// multiple interrupts can be called at once, so we handle them all
for (const question in response.interrupts) {
answers.push(
// use the `respond` method on our tool to populate answers
askQuestion.respond(
question,
// send the tool request input to the user to respond
await askUser(question.toolRequest.input)
)
);
}
response = await ai.generate({
tools: [askQuestion],
messages: response.messages,
resume: {
respond: answers
}
})
}
// no more interrupts, we can see the final response
console.log(response.text);
Tools mit neustartfähigen Unterbrechungen
Ein weiteres häufiges Muster für Unterbrechungen ist die Notwendigkeit, eine vom LLM vorgeschlagene Aktion zu bestätigen, bevor sie ausgeführt wird. In einer Zahlungs-App kann es beispielsweise erforderlich sein, dass der Nutzer bestimmte Arten von Überweisungen bestätigt.
Für diesen Anwendungsfall können Sie die Standardmethode defineTool
verwenden, um benutzerdefinierte Logik hinzuzufügen, wann eine Unterbrechung ausgelöst werden soll und was passiert, wenn eine Unterbrechung mit zusätzlichen Metadaten erneut gestartet wird.
Neustartbares Tool definieren
Jedes Tool hat im zweiten Argument seiner Implementierungsdefinition Zugriff auf zwei spezielle Helfer:
interrupt
: Wenn diese Methode aufgerufen wird, wird eine spezielle Art von Ausnahme ausgelöst, die abgefangen wird, um die Generierungsschleife anzuhalten. Sie können zusätzliche Metadaten als Objekt angeben.resumed
: Wenn eine Anfrage aus einer unterbrochenen Generierung mit der Option{resume: {restart: ...}}
(siehe unten) fortgesetzt wird, enthält dieser Helfer die beim Neustart bereitgestellten Metadaten.
Wenn Sie beispielsweise eine Zahlungs-App entwickeln, sollten Sie den Nutzer vor einer Überweisung über einen bestimmten Betrag informieren:
const transferMoney = ai.defineTool({
name: 'transferMoney',
description: 'Transfers money between accounts.',
inputSchema: z.object({
toAccountId: z.string().describe('the account id of the transfer destination'),
amount: z.number().describe('the amount in integer cents (100 = $1.00)'),
}),
outputSchema: z.object({
status: z.string().describe('the outcome of the transfer'),
message: z.string().optional(),
})
}, async (input, {context, interrupt, resumed})) {
// if the user rejected the transaction
if (resumed?.status === "REJECTED") {
return {status: 'REJECTED', message: 'The user rejected the transaction.'};
}
// trigger an interrupt to confirm if amount > $100
if (resumed?.status !== "APPROVED" && input.amount > 10000) {
interrupt({
message: "Please confirm sending an amount > $100.",
});
}
// complete the transaction if not interrupted
return doTransfer(input);
}
In diesem Beispiel prüft das Tool bei der ersten Ausführung (wenn resumed
nicht definiert ist), ob der Betrag 100 $überschreitet, und löst bei Überschreitung eine Unterbrechung aus. Bei der zweiten Ausführung sucht es in den neuen bereitgestellten Metadaten nach einem Status und führt die Übertragung aus oder gibt eine Ablehnungsantwort zurück, je nachdem, ob die Transaktion genehmigt oder abgelehnt wurde.
Tools nach Unterbrechung neu starten
Mit Unterbrechungstools haben Sie die vollständige Kontrolle über Folgendes:
- Gibt an, wann eine erste Toolanfrage eine Unterbrechung auslösen soll.
- Wann und ob der Generierungs-Loop fortgesetzt werden soll.
- Welche zusätzlichen Informationen müssen Sie dem Tool bei der Wiederaufnahme zur Verfügung stellen?
Im Beispiel im vorherigen Abschnitt könnte die Anwendung den Nutzer auffordern, die unterbrochene Anfrage zu bestätigen, um sicherzustellen, dass der Überweisungsbetrag korrekt ist:
let response = await ai.generate({
tools: [transferMoney],
prompt: "Transfer $1000 to account ABC123",
});
while (response.interrupts.length) {
const confirmations = [];
// multiple interrupts can be called at once, so we handle them all
for (const interrupt in response.interrupts) {
confirmations.push(
// use the 'restart' method on our tool to provide `resumed` metadata
transferMoney.restart(
interrupt,
// send the tool request input to the user to respond. assume that this
// returns `{status: "APPROVED"}` or `{status: "REJECTED"}`
await requestConfirmation(interrupt.toolRequest.input);
)
);
}
response = await ai.generate({
tools: [transferMoney],
messages: response.messages,
resume: {
restart: confirmations,
}
})
}
// no more interrupts, we can see the final response
console.log(response.text);