إنشاء جلسات محادثة مستمرة

سيتفاعل العديد من المستخدمين مع النماذج اللغوية الكبيرة للمرة الأولى من خلال محادثات مع برامج الدردشة. على الرغم من أنّ نماذج اللغة الكبيرة قادرة على تنفيذ الكثير من المهام غير محاكاة المحادثات، إلا أنّها تظلّ أسلوب تفاعل مألوفًا ومفيدًا. حتى في حال عدم تفاعل المستخدمين مع النموذج مباشرةً بهذه الطريقة، يشكّل أسلوب الطلب الحواري طريقة فعّالة للتأثير في النتيجة التي ينشئها نموذج الذكاء الاصطناعي.

لدعم هذا الأسلوب من التفاعل، يوفّر Genkit مجموعة من الواجهات والاختصارات التي تسهّل عليك إنشاء تطبيقات النماذج اللغوية الكبيرة المستندة إلى المحادثات.

قبل البدء

قبل قراءة هذه الصفحة، يجب أن تكون على دراية بالمحتوى الذي يتم تناوله في صفحة إنشاء المحتوى باستخدام نماذج الذكاء الاصطناعي.

إذا كنت تريد تنفيذ أمثلة الرموز البرمجية الواردة في هذه الصفحة، عليك أولاً إكمال الخطوات الواردة في دليل البدء. تفترض جميع الأمثلة أنّه سبق أن ثبّت Genkit كتبعية في مشروعك.

أساسيات جلسة المحادثة

في ما يلي تطبيق محادثات آلية بسيط يستند إلى وحدة تحكّم:

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

الاحتفاظ بحالة الجلسة (ميزة تجريبية)

عند بدء محادثة أو جلسة جديدة، يتم ضبطها تلقائيًا لتخزين الجلسة في الذاكرة فقط. يكون ذلك مناسبًا عندما تحتاج الجلسة إلى الاحتفاظ ببياناتها لمدة طلب واحد فقط من برنامجك، كما هو الحال في نموذج الدردشة الآلية من بداية هذه الصفحة. ومع ذلك، عند دمج محادثات الذكاء الاصطناعي اللغوي في أحد التطبيقات، ستنشر عادةً منطق إنشاء المحتوى كنقاط نهاية لواجهة برمجة تطبيقات الويب التي لا تتضمّن حالة. لكي تعمل المحادثات الدائمة بموجب هذا الإعداد، عليك تنفيذ نوع من تخزين الجلسات الذي يمكنه الاحتفاظ بالحالة على مستوى عمليات استدعاء نقاط النهاية.

لإضافة ميزة الاحتفاظ بالبيانات إلى جلسة محادثة، عليك تنفيذ واجهة 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' });
  }
}

من المحتمل أنّ هذا التنفيذ غير مناسب للعمليات العملية، ولكنه يوضّح أنّ تنفيذ مساحة تخزين الجلسة يحتاج فقط إلى تنفيذ مهمتَين:

  • الحصول على عنصر جلسة من مساحة التخزين باستخدام معرّف الجلسة
  • حفظ عنصر جلسة معيّن، مفهرَس بمعرّف الجلسة

بعد تنفيذ واجهة مساحة التخزين في الخلفية، مرِّر مثيلًا من عملية التنفيذ إلى منشئي الجلسات:

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