Dauerhafte Chatsitzungen erstellen

Viele Ihrer Nutzer werden zum ersten Mal über Chatbots mit Large Language Models interagiert haben. LLMs können zwar viel mehr als nur Unterhaltungen simulieren, aber diese Art der Interaktion ist nach wie vor vertraut und nützlich. Auch wenn Ihre Nutzer nicht direkt auf diese Weise mit dem Modell interagieren, ist der konversationsorientierte Prompting-Stil eine leistungsstarke Möglichkeit, die von einem KI-Modell generierte Ausgabe zu beeinflussen.

Um diese Art der Interaktion zu unterstützen, bietet Genkit eine Reihe von Schnittstellen und Abstraktionen, mit denen Sie chatbasierte LLM-Anwendungen einfacher erstellen können.

Hinweis

Bevor Sie diese Seite lesen, sollten Sie sich mit den Inhalten auf der Seite Inhalte mit KI-Modellen generieren vertraut gemacht haben.

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 Genkit bereits als Abhängigkeit in Ihrem Projekt installiert haben.

Grundlagen von Chatsitzungen

Hier ist eine minimale, konsolenbasierte Chatbot-Anwendung:

import { genkit } from "genkit";
import { googleAI, gemini15Flash } from "@genkit-ai/googleai";

import { createInterface } from "node:readline/promises";

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

(async () => {
  const chat = ai.chat();
  console.log("You're chatting with Gemini. Ctrl-C to quit.\n");
  const readline = createInterface(process.stdin, process.stdout);
  while (true) {
    const userInput = await readline.question("> ");
    const { text } = await chat.send(userInput);
    console.log(text);
  }
})();

Eine Chatsitzung mit diesem Programm sieht in etwa so aus:

You're chatting with Gemini. Ctrl-C to quit.

> hi
Hi there! How can I help you today? 

> my name is pavel
Nice to meet you, Pavel! What can I do for you today? 

> what's my name?
Your name is Pavel! I remembered it from our previous interaction. 

Is there anything else I can help you with?

Wie Sie an dieser kurzen Interaktion sehen können, kann das Modell bei seinen Antworten auf eine Nachricht in einer Chatsitzung die bisherige Sitzung nutzen. Das ist möglich, weil Genkit im Hintergrund einige Dinge erledigt:

  • Ruft den Chatverlauf aus dem Speicher ab, falls vorhanden (weitere Informationen zu Persistenz und Speicher finden Sie später)
  • Die Anfrage wird wie bei generate() an das Modell gesendet, aber der Chatverlauf wird automatisch eingeschlossen.
  • Speichert die Modellantwort im Chatverlauf

Modellkonfiguration

Für die Methode chat() gelten größtenteils dieselben Konfigurationsoptionen wie für generate(). So übergeben Sie Konfigurationsoptionen an das Modell:

const chat = ai.chat({
  model: gemini15Pro,
  system:
    "You're a pirate first mate. Address the user as Captain and assist " +
    "them however you can.",
  config: {
    temperature: 1.3,
  },
});

Zustandsorientierte Chatsitzungen

Sie können nicht nur den Nachrichtenverlauf einer Chatsitzung, sondern auch beliebige JavaScript-Objekte speichern. So können Sie den Status strukturierter verwalten, als wenn Sie sich nur auf Informationen im Nachrichtenverlauf verlassen.

Wenn Sie den Status in einer Sitzung einbeziehen möchten, müssen Sie eine Sitzung explizit instanziieren:

interface MyState {
  userName: string;
}

const session = ai.createSession<MyState>({
  initialState: {
    userName: 'Pavel',
  },
});

Sie können dann einen Chat innerhalb der Sitzung starten:

const chat = session.chat();

Wenn du den Sitzungsstatus je nach Verlauf des Chats ändern möchtest, definiere Tools und füge sie deinen Anfragen hinzu:

const changeUserName = ai.defineTool(
  {
    name: 'changeUserName',
    description: 'can be used to change user name',
    inputSchema: z.object({
      newUserName: z.string(),
    }),
  },
  async (input) => {
    await ai.currentSession<MyState>().updateState({
      userName: input.newUserName,
    });
    return 'changed username to ${input.newUserName}';
  }
);
const chat = session.chat({
  model: gemini15Pro,
  tools: [changeUserName],
});
await chat.send('change user name to Kevin');

Sitzungen mit mehreren Threads

Eine einzelne Sitzung kann mehrere Chatthreads enthalten. Jeder Thread hat seinen eigenen Nachrichtenverlauf, aber einen gemeinsamen Sitzungsstatus.

const lawyerChat = session.chat('lawyerThread', {
  system: 'talk like a lawyer',
});
const pirateChat = session.chat('pirateThread', {
  system: 'talk like a pirate',
});

Sitzungsspeicherung (EXPERIMENTELL)

Wenn Sie einen neuen Chat oder eine neue Sitzung initialisieren, wird die Sitzung standardmäßig nur im Arbeitsspeicher gespeichert. Das ist ausreichend, wenn die Sitzung nur für die Dauer einer einzelnen Aufrufung Ihres Programms bestehen bleiben muss, wie im Beispiel-Chatbot am Anfang dieser Seite. Wenn Sie LLM-Chat jedoch in eine Anwendung einbinden, stellen Sie Ihre Logik zur Inhaltsgenerierung in der Regel als zustandslose Web-API-Endpunkte bereit. Damit persistente Chats bei dieser Konfiguration funktionieren, müssen Sie eine Art Sitzungsspeicher implementieren, der den Status über Aufrufe Ihrer Endpunkte hinweg beibehalten kann.

Wenn du einer Chatsitzung dauerhafte Daten hinzufügen möchtest, musst du die SessionStore-Schnittstelle von Genkit implementieren. Hier ist eine Beispielimplementierung, bei der der Sitzungsstatus in einzelnen JSON-Dateien gespeichert wird:

class JsonSessionStore<S = any> implements SessionStore<S> {
  async get(sessionId: string): Promise<SessionData<S> | undefined> {
    try {
      const s = await readFile(`${sessionId}.json`, { encoding: 'utf8' });
      const data = JSON.parse(s);
      return data;
    } catch {
      return undefined;
    }
  }

  async save(sessionId: string, sessionData: SessionData<S>): Promise<void> {
    const s = JSON.stringify(sessionData);
    await writeFile(`${sessionId}.json`, s, { encoding: 'utf8' });
  }
}

Diese Implementierung ist für praktische Bereitstellungen wahrscheinlich nicht geeignet, aber sie veranschaulicht, dass eine Implementierung des Sitzungsspeichers nur zwei Aufgaben erfüllen muss:

  • Sitzungsobjekt anhand der Sitzungs-ID aus dem Speicher abrufen
  • Ein bestimmtes Sitzungsobjekt speichern, das anhand seiner Sitzungs-ID indexiert wird

Nachdem Sie die Schnittstelle für Ihr Speicher-Back-End implementiert haben, übergeben Sie eine Instanz Ihrer Implementierung an die Sitzungskonstruktoren:

// To create a new session:
const session = ai.createSession({
  store: new JsonSessionStore(),
});

// Save session.id so you can restore the session the next time the
// user makes a request.
// If the user has a session ID saved, load the session instead of creating
// a new one:
const session = await ai.loadSession(sessionId, {
    store: new JsonSessionStore(),
});