Wielu użytkowników po raz pierwszy będzie korzystać z dużych modeli językowych za pomocą chatbotów. Duże modele językowe mogą robić znacznie więcej niż tylko symulować rozmowy, ale nadal są to znane i przydatne style interakcji. Nawet jeśli użytkownicy nie będą w ten sposób bezpośrednio wchodzić w interakcję z modelem, konwersacyjny styl promptów to skuteczny sposób na wpływanie na wyniki generowane przez model AI.
Aby umożliwić tego typu interakcje, Genkit udostępnia zestaw interfejsów i abstrakcji, które ułatwiają tworzenie aplikacji LLM opartych na czacie.
Zanim zaczniesz
Zanim zaczniesz czytać tę stronę, zapoznaj się z treściami na stronie Generowanie treści za pomocą modeli AI.
Jeśli chcesz uruchomić przykłady kodu na tej stronie, najpierw wykonaj czynności opisane w przewodniku Początkujący. We wszystkich przykładach zakładamy, że masz już zainstalowaną bibliotekę Genkit jako zależność w projekcie.
Podstawy sesji czatu
Oto minimalna aplikacja chatbota działająca w konsoli:
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);
}
})();
Sesja czatu z tym programem wygląda mniej więcej tak:
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?
Jak widać na przykładzie tej krótkiej rozmowy, gdy wysyłasz wiadomość do sesji czatu, model może wykorzystać w swoich odpowiedziach informacje z dotychczasowej części sesji. Jest to możliwe, ponieważ Genkit wykonuje kilka czynności w tle:
- Pobiera historię czatu (jeśli istnieje) z miejsca na dane (więcej informacji o trwałości i miejscu na dane znajdziesz poniżej).
- Wysyła żądanie do modelu, tak jak w przypadku
generate()
, ale automatycznie uwzględnia historię czatu. - Zapisywanie odpowiedzi modelu w historii czatu
Konfiguracja modelu
Metoda chat()
obsługuje większość tych samych opcji konfiguracji co metoda generate()
. Aby przekazać opcje konfiguracji modelowi:
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,
},
});
Sesje czatu stanowego
Oprócz trwałego przechowywania historii wiadomości z sesji czatu możesz też przechowywać dowolny obiekt JavaScript. Dzięki temu możesz zarządzać stanem w bardziej uporządkowany sposób niż tylko na podstawie informacji w historii wiadomości.
Aby uwzględnić stan w sesji, musisz jawnie utworzyć instancję sesji:
interface MyState {
userName: string;
}
const session = ai.createSession<MyState>({
initialState: {
userName: 'Pavel',
},
});
Następnie możesz rozpocząć czat w sesji:
const chat = session.chat();
Aby zmienić stan sesji na podstawie przebiegu czatu, zdefiniuj narzędzia i uwzględnij je w swoich żądaniach:
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');
Sesje wielowątkowe
Jedna sesja może zawierać wiele wątków czatu. Każdy wątek ma własną historię wiadomości, ale wszystkie wątki mają ten sam stan sesji.
const lawyerChat = session.chat('lawyerThread', {
system: 'talk like a lawyer',
});
const pirateChat = session.chat('pirateThread', {
system: 'talk like a pirate',
});
Sesja trwała (FUNKCJA EKSPERYMENTALNA)
Gdy inicjujesz nowy czat lub sesję, sesja jest domyślnie przechowywana tylko w pamięci. Jest to odpowiednie rozwiązanie, gdy sesja musi być zachowana tylko na czas wywołania programu, tak jak w przypadku przykładowego chatbota na początku tej strony. Jednak podczas integrowania czatu LLM z aplikacją zwykle wdrażasz logikę generowania treści jako punkty końcowe interfejsu API w sieci bezstanowej. Aby trwałe czaty działały w ramach tej konfiguracji, musisz wdrożyć rodzaj pamięci sesji, który może zachować stan na różnych punktach końcowych.
Aby dodać trwałość do sesji czatu, musisz zaimplementować interfejs SessionStore
Genkit. Oto przykładowa implementacja, która zapisuje stan sesji w poszczególnych plikach JSON:
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' });
}
}
To rozwiązanie prawdopodobnie nie nadaje się do praktycznego wdrożenia, ale pokazuje, że implementacja pamięci sesji musi obejmować tylko 2 zadania:
- Pobieranie obiektu sesji z miejsca na dane za pomocą identyfikatora sesji
- Zapisz dany obiekt sesji, posortowany według identyfikatora sesji
Po zaimplementowaniu interfejsu dla backendu pamięci przechowującej prześlij instancję swojej implementacji do konstruktorów sesji:
// 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(),
});