Muchos de tus usuarios interactuarán con modelos de lenguaje extenso por primera vez a través de chatbots. Aunque los LLM son capaces de hacer mucho más que simular conversaciones, siguen siendo un estilo de interacción familiar y útil. Incluso cuando tus usuarios no interactúen directamente con el modelo de esta manera, el estilo de indicaciones de conversación es una forma eficaz de influir en el resultado que genera un modelo de IA.
Para admitir este estilo de interacción, Genkit proporciona un conjunto de interfaces y abstracciónes que te permiten compilar aplicaciones de LLM basadas en chat con mayor facilidad.
Antes de comenzar
Antes de leer esta página, debes familiarizarte con el contenido que se explica en la página Cómo generar contenido con modelos de IA.
Si quieres ejecutar los ejemplos de código de esta página, primero completa los pasos de la guía de Cómo comenzar. En todos los ejemplos, se da por sentado que ya instalaste Genkit como dependencia en tu proyecto.
Conceptos básicos de la sesión de chat
Esta es una aplicación de chatbot mínima basada en la consola:
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);
}
})();
Una sesión de chat con este programa se ve como en el siguiente ejemplo:
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?
Como puedes ver en esta breve interacción, cuando envías un mensaje a una sesión de chat, el modelo puede usar la sesión hasta el momento en sus respuestas. Esto es posible porque Genkit hace lo siguiente en segundo plano:
- Recupera el historial de chat, si existe, del almacenamiento (más información sobre la persistencia y el almacenamiento más adelante).
- Envía la solicitud al modelo, como con
generate()
, pero incluye automáticamente el historial de chat. - Guarda la respuesta del modelo en el historial de chat.
Configuración del modelo
El método chat()
acepta la mayoría de las mismas opciones de configuración que generate()
. Para pasar opciones de configuración al modelo, haz lo siguiente:
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,
},
});
Sesiones de chat con estado
Además de conservar el historial de mensajes de una sesión de chat, también puedes conservar cualquier objeto JavaScript arbitrario. De esta manera, puedes administrar el estado de una manera más estructurada y, luego, depender solo de la información del historial de mensajes.
Para incluir el estado en una sesión, debes crear una instancia de una sesión de forma explícita:
interface MyState {
userName: string;
}
const session = ai.createSession<MyState>({
initialState: {
userName: 'Pavel',
},
});
Luego, puedes iniciar un chat dentro de la sesión:
const chat = session.chat();
Para modificar el estado de la sesión según el desarrollo del chat, define las herramientas y, luego, inclúyelas en tus solicitudes:
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');
Sesiones de varios subprocesos
Una sola sesión puede contener varias conversaciones de chat. Cada subproceso tiene su propio historial de mensajes, pero comparten un solo estado de sesión.
const lawyerChat = session.chat('lawyerThread', {
system: 'talk like a lawyer',
});
const pirateChat = session.chat('pirateThread', {
system: 'talk like a pirate',
});
Persistencia de la sesión (EXPERIMENTAL)
Cuando inicializas un chat o una sesión nuevos, se configura de forma predeterminada para almacenar la sesión solo en la memoria. Esto es adecuado cuando la sesión debe persistir solo durante la ejecución de una sola llamada de tu programa, como en el ejemplo de chatbot del principio de esta página. Sin embargo, cuando integres el chat de LLM en una aplicación, por lo general, implementarás tu lógica de generación de contenido como extremos de API web sin estado. Para que los chats persistentes funcionen con esta configuración, deberás implementar algún tipo de almacenamiento de sesión que pueda conservar el estado en todas las invocaciones de tus extremos.
Para agregar persistencia a una sesión de chat, debes implementar la interfaz SessionStore
de Genkit. Este es un ejemplo de implementación que guarda el estado de la sesión en archivos JSON individuales:
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' });
}
}
Es probable que esta implementación no sea adecuada para implementaciones prácticas, pero ilustra que una implementación de almacenamiento de sesiones solo debe realizar dos tareas:
- Cómo obtener un objeto de sesión del almacenamiento con su ID de sesión
- Guarda un objeto de sesión determinado, indexado por su ID de sesión
Una vez que hayas implementado la interfaz para tu backend de almacenamiento, pasa una instancia de tu implementación a los constructores de sesión:
// 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(),
});