การสร้างเซสชันการแชทแบบถาวร

ผู้ใช้จํานวนมากจะโต้ตอบกับโมเดลภาษาขนาดใหญ่เป็นครั้งแรกผ่านแชทบ็อต แม้ว่า LLM จะทำได้มากกว่าการจําลองการสนทนา แต่ก็ยังเป็นการโต้ตอบรูปแบบที่คุ้นเคยและมีประโยชน์ แม้ว่าผู้ใช้จะไม่โต้ตอบกับโมเดลโดยตรงด้วยวิธีนี้ แต่พรอมต์แบบการสนทนาก็เป็นวิธีที่มีประสิทธิภาพในการส่งผลต่อเอาต์พุตที่โมเดล AI สร้างขึ้น

Genkit มีชุดอินเทอร์เฟซและข้อมูลทั่วไปที่ช่วยให้สร้างแอปพลิเคชัน LLM ที่อิงตามแชทได้ง่ายขึ้น เพื่อรองรับรูปแบบการโต้ตอบนี้

ก่อนเริ่มต้น

ก่อนอ่านหน้านี้ คุณควรทำความคุ้นเคยกับเนื้อหาที่ครอบคลุมในหน้าการสร้างเนื้อหาด้วยโมเดล AI

หากต้องการเรียกใช้ตัวอย่างโค้ดในหน้านี้ ให้ทําตามขั้นตอนในคู่มือการเริ่มต้นใช้งานก่อน ตัวอย่างทั้งหมดจะถือว่าคุณได้ติดตั้ง Genkit ไว้เป็น Dependency ในโปรเจ็กต์แล้ว

ข้อมูลเบื้องต้นเกี่ยวกับเซสชันการแชท

แอปพลิเคชันแชทบ็อตแบบคอนโซลที่เรียบง่ายมีดังนี้

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

เซสชันการแชทกับโปรแกรมนี้จะมีลักษณะดังตัวอย่างต่อไปนี้

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?

ดังที่คุณเห็นจากการโต้ตอบสั้นๆ นี้ เมื่อคุณส่งข้อความไปยังเซสชันการแชท โมเดลจะใช้เซสชันที่ผ่านมาในการตอบกลับได้ ซึ่งเป็นไปได้เนื่องจาก Genkit ทําสิ่งต่อไปนี้อยู่เบื้องหลัง

  • ดึงข้อมูลประวัติการแชท (หากมี) จากพื้นที่เก็บข้อมูล (ดูข้อมูลเพิ่มเติมเกี่ยวกับการจัดเก็บข้อมูลและพื้นที่เก็บข้อมูลในภายหลัง)
  • ส่งคําขอไปยังโมเดลเช่นเดียวกับ generate() แต่รวมประวัติการแชทโดยอัตโนมัติ
  • บันทึกคำตอบของโมเดลลงในประวัติการแชท

การกำหนดค่าโมเดล

วิธีการ chat() ยอมรับตัวเลือกการกำหนดค่าส่วนใหญ่เดียวกับ generate() วิธีส่งตัวเลือกการกําหนดค่าไปยังโมเดล

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

เซสชันการแชทที่มีสถานะ

นอกจากการเก็บรักษาประวัติข้อความของเซสชันการแชทแล้ว คุณยังเก็บรักษาออบเจ็กต์ JavaScript ใดก็ได้ ซึ่งจะช่วยให้คุณจัดการสถานะได้อย่างเป็นระเบียบมากขึ้นกว่าการอาศัยข้อมูลในประวัติข้อความเพียงอย่างเดียว

หากต้องการรวมสถานะไว้ในเซสชัน คุณต้องสร้างอินสแตนซ์เซสชันอย่างชัดเจน ดังนี้

interface MyState {
  userName: string;
}

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

จากนั้นคุณสามารถเริ่มแชทภายในเซสชันได้โดยทำดังนี้

const chat = session.chat();

หากต้องการแก้ไขสถานะเซสชันตามลักษณะการพูดคุย ให้กําหนดเครื่องมือและรวมไว้ในคําขอ

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

เซสชันแบบหลายเธรด

เซสชันเดียวอาจมีชุดข้อความแชทหลายชุด โดยแต่ละชุดข้อความจะมีประวัติข้อความของตัวเอง แต่แชร์สถานะเซสชันเดียวกัน

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

การรักษาเซสชันไว้ (เวอร์ชันทดลอง)

เมื่อคุณเริ่มต้นแชทหรือเซสชันใหม่ ระบบจะกำหนดค่าให้จัดเก็บเซสชันไว้ในหน่วยความจำเท่านั้นโดยค่าเริ่มต้น ซึ่งเพียงพอเมื่อเซสชันต้องคงอยู่ตลอดระยะเวลาการเรียกใช้โปรแกรมเพียงครั้งเดียว ดังตัวอย่างแชทบ็อตจากตอนต้นของหน้านี้ อย่างไรก็ตาม เมื่อผสานรวมแชท LLM เข้ากับแอปพลิเคชัน คุณมักจะติดตั้งใช้งานตรรกะการสร้างเนื้อหาเป็นปลายทางแบบไม่มีสถานะของ Web API หากต้องการให้แชทถาวรทำงานภายใต้การตั้งค่านี้ คุณจะต้องติดตั้งใช้งานพื้นที่เก็บข้อมูลเซสชันบางประเภทที่สามารถเก็บสถานะไว้ได้ตลอดการเรียกใช้ปลายทาง

หากต้องการเพิ่มการคงอยู่ในเซสชันการแชท คุณต้องติดตั้งใช้งานอินเทอร์เฟซ SessionStore ของ Genkit ตัวอย่างการใช้งานที่บันทึกสถานะเซสชันไปยังไฟล์ 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' });
  }
}

การใช้งานนี้อาจไม่เพียงพอสําหรับการใช้งานจริง แต่แสดงให้เห็นว่าการใช้งานพื้นที่เก็บข้อมูลเซสชันต้องทํางาน 2 อย่างเท่านั้น

  • รับออบเจ็กต์เซสชันจากพื้นที่เก็บข้อมูลโดยใช้รหัสเซสชัน
  • บันทึกออบเจ็กต์เซสชันที่ระบุ โดยจัดทําดัชนีตามรหัสเซสชัน

เมื่อติดตั้งใช้งานอินเทอร์เฟซสําหรับแบ็กเอนด์พื้นที่เก็บข้อมูลแล้ว ให้ส่งอินสแตนซ์ของการใช้งานไปยังตัวสร้างเซสชัน ดังนี้

// 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(),
});