عمليات المقاطعة هي نوع خاص من الأدوات التي يمكنها إيقاف حلقة توليد LLM واستدعاء الأداة مؤقتًا لإعادة التحكّم إليك. عندما تكون مستعدًا، يمكنك استئناف عملية الإنشاء من خلال إرسال ردود تتم معالجتها من خلال نموذج اللغة الضخم (LLM) لإنشاء المزيد من المحتوى.
تندرج الاستخدامات الأكثر شيوعًا للمقاطعات ضمن بضع فئات:
- العنصر البشري في السلسلة: يتيح هذا العنصر لمستخدم الذكاء الاصطناعي التفاعلي clarifying the needed information or confirm the LLM's action قبل اكتماله، ما يضمن أمانًا وثقة أكبر.
- المعالجة غير المتزامنة: بدء مهمة غير متزامنة لا يمكن إكمالها إلا خارج النطاق، مثل إرسال إشعار موافقة إلى أحد المدقّقين أو بدء عملية طويلة الأمد في الخلفية
- الخروج من مهمة مستقلة: توفير طريقة للنموذج لوضع علامة على مهمة باعتبارها مكتملة، في سير عمل قد يكرّر سلسلة طويلة من طلبات أدوات
قبل البدء
تفترض جميع الأمثلة الموثَّقة هنا أنّك سبق لك إعداد مشروع تم تثبيت تبعيات Genkit فيه. إذا كنت تريد تنفيذ رمز برمجي، عليك أولاً إكمال الخطوات الواردة في دليل البدء.
قبل التعمّق في هذه المواضيع، يجب أن تكون على دراية أيضًا بالموضوعات التالية:
- إنشاء محتوى باستخدام نماذج الذكاء الاصطناعي
- نظام Genkit لتحديد مخطّطات الإدخال والإخراج
- الطرق العامة لاستدعاء الأدوات
نظرة عامة على عمليات المقاطعة
بشكل عام، إليك شكل المقاطعة عند التفاعل مع نموذج LLM:
- يطلب تطبيق الاتصال من النموذج اللغوي الكبير (LLM) إجراءً معيّنًا. يتضمّن الطلب قائمة بالأدوات، بما في ذلك أداة واحدة على الأقل للمقاطعة يمكن للنموذج اللغوي الكبير استخدامها لإنشاء ردّ.
- يُنشئ النموذج اللغوي الكبير إما استجابة كاملة أو طلبًا للاتصال بأداة بتنسيق معيّن. بالنسبة إلى LLM، تبدو المكالمة المتداخلة مثل أي مكالمة أخرى للأدوات.
- إذا استدعى نموذج اللغة الكبيرة أداة إيقاف، توقف مكتبة Genkit تلقائيًا عن إنشاء المحتوى بدلاً من إعادة توجيه الردود إلى النموذج على الفور لمعالجتها بشكل إضافي.
- يتحقّق المطوّر ممّا إذا تم إجراء طلب للمقاطعة، وينفّذ أي مهمة مطلوبة لجمع المعلومات اللازمة للردّ على المقاطعة.
- يستأنف المطوّر عملية الإنشاء من خلال إرسال استجابة متعلّقة بالانقطاع إلى النموذج. سيؤدي هذا الإجراء إلى الرجوع إلى الخطوة 2.
تحديد عمليات المقاطعة للردّ اليدوي
إنّ النوع الأكثر شيوعًا من عمليات المقاطعة يسمح لنموذج اللغة المحوسبة الكبير (LLM) بطلب توضيح من العميل، على سبيل المثال من خلال طرح سؤال من نوع "خيارات متعدّدة".
في حالة الاستخدام هذه، استخدِم طريقة defineInterrupt()
في مثيل Genkit:
import { genkit, z } from 'genkit';
import { googleAI, gemini15Flash } from '@genkitai/google-ai';
const ai = genkit({
plugins: [googleAI()],
model: gemini15Flash,
});
const askQuestion = ai.defineInterrupt({
name: 'askQuestion',
description: 'use this to ask the user a clarifying question',
inputSchema: z.object({
choices: z.array(z.string()).describe('the choices to display to the user'),
allowOther: z.boolean().optional().describe('when true, allow write-ins')
}),
outputSchema: z.string()
});
يُرجى العلم أنّ outputSchema
للمقاطعة تتوافق مع بيانات الردّ
التي ستقدّمها بدلاً من العنصر الذي ستتم تعبئته تلقائيًا
بواسطة وظيفة أداة.
استخدام الفواصل
يتم تمرير عمليات المقاطعة إلى صفيف tools
عند إنشاء المحتوى، تمامًا مثل
أنواع الأدوات الأخرى. يمكنك تمرير كلّ من الأدوات العادية والمقاطعات إلى
طلب generate
نفسه:
إنشاء
const response = await ai.generate({
prompt: 'Ask me a movie trivia question.',
tools: [askQuestion],
});
definePrompt
const triviaPrompt = ai.definePrompt(
{
name: 'triviaPrompt',
tools: [askQuestion],
input: {
schema: z.object({subject: z.string()})
},
prompt: 'Ask me a trivia question about {{subject}}
.',
}
);
const response = await triviaPrompt({ subject: 'computer history' });
ملف الطلب
---
tools: [askQuestion]
input:
schema:
partyType: string
---
{{role "system"}}
Use the askQuestion tool if you need to clarify something.
{{role "user"}}
Help me plan a {{partyType}} party next week.
بعد ذلك، يمكنك تنفيذ الطلب في الرمز البرمجي على النحو التالي:
```ts
// assuming prompt file is named partyPlanner.prompt
const partyPlanner = ai.prompt('partyPlanner');
const response = await partyPlanner({ partyType: 'birthday' });
```
دردشة
const chat = ai.chat({
system: 'Use the askQuestion tool if you need to clarify something.',
tools: [askQuestion],
});
const response = await chat.send('make a plan for my birthday party');
يعرض Genkit ردًا فوريًا عند تلقّي طلب أداة إيقاف مؤقت.
الردّ على المقاطعات
إذا تم تمرير مقاطعة واحدة أو أكثر إلى طلب إنشاء المحتوى، عليك التحقّق من الاستجابة للمقاطعات حتى تتمكّن من التعامل معها:
// you can check the 'finishReason' of the response
response.finishReason === 'interrupted'
// or you can check to see if any interrupt requests are on the response
response.interrupts.length > 0
يتمّ الردّ على المقاطعة باستخدام الخيار resume
في مكالمة последئة
generate
، مع التأكّد من إدخال السجلّ الحالي. تحتوي كل أداة على
طريقة .respond()
للمساعدة في إنشاء الردّ.
بعد استئناف النموذج، يعود إلى حلقة الإنشاء، بما في ذلك تنفيذ الأدوات، إلى أن يكتمل أو يتم تشغيل عملية إيقاف أخرى:
let response = await ai.generate({
tools: [askQuestion],
system: 'ask clarifying questions until you have a complete solution',
prompt: 'help me plan a backyard BBQ',
});
while (response.interrupts.length) {
const answers = [];
// multiple interrupts can be called at once, so we handle them all
for (const question in response.interrupts) {
answers.push(
// use the `respond` method on our tool to populate answers
askQuestion.respond(
question,
// send the tool request input to the user to respond
await askUser(question.toolRequest.input)
)
);
}
response = await ai.generate({
tools: [askQuestion],
messages: response.messages,
resume: {
respond: answers
}
})
}
// no more interrupts, we can see the final response
console.log(response.text);
الأدوات التي تتضمّن عمليات إيقاف مؤقت يمكن إعادة تشغيلها
من الأنماط الشائعة الأخرى للمقاطعات الحاجة إلى تأكيد إجراء يقترحه النموذج اللغوي الكبير قبل تنفيذه فعليًا. على سبيل المثال، قد يطلب تطبيق دفعات من المستخدم تأكيد أنواع معيّنة من عمليات التحويل.
في حالة الاستخدام هذه، يمكنك استخدام الطريقة العادية defineTool
لإضافة منطق مخصّص بشأن وقت بدء المقاطعة والإجراءات التي يجب اتّخاذها عند إعادة بدء المقاطعة باستخدام بيانات وصفية إضافية.
تحديد أداة قابلة لإعادة التشغيل
يمكن لكل أداة الوصول إلى مساعدَين خاصَّين في الوسيطة الثانية لتعريف التنفيذ:
interrupt
: عند استدعاء هذه الطريقة، تُلقي نوعًا خاصًا من الاستثناءات التي يتمّ رصدها لإيقاف حلقة الإنشاء مؤقتًا. يمكنك تقديم بيانات وصفية إضافية كعنصر.-
resumed
: عند إعادة تشغيل طلب من عملية إنشاء متوقّفة باستخدام خيار{resume: {restart: ...}}
(راجِع المعلومات أدناه)، يحتوي هذا المساعد على البيانات الوصفية المقدَّمة عند إعادة التشغيل.
على سبيل المثال، إذا كنت بصدد إنشاء تطبيق دفعات، قد تحتاج إلى تأكيد ذلك مع المستخدم قبل إجراء عملية تحويل تتجاوز مبلغًا معيّنًا:
const transferMoney = ai.defineTool({
name: 'transferMoney',
description: 'Transfers money between accounts.',
inputSchema: z.object({
toAccountId: z.string().describe('the account id of the transfer destination'),
amount: z.number().describe('the amount in integer cents (100 = $1.00)'),
}),
outputSchema: z.object({
status: z.string().describe('the outcome of the transfer'),
message: z.string().optional(),
})
}, async (input, {context, interrupt, resumed})) {
// if the user rejected the transaction
if (resumed?.status === "REJECTED") {
return {status: 'REJECTED', message: 'The user rejected the transaction.'};
}
// trigger an interrupt to confirm if amount > $100
if (resumed?.status !== "APPROVED" && input.amount > 10000) {
interrupt({
message: "Please confirm sending an amount > $100.",
});
}
// complete the transaction if not interrupted
return doTransfer(input);
}
في هذا المثال، عند التنفيذ الأول (عندما يكون resumed
غير محدّد)، تحقّق الأداة مما إذا كان المبلغ يتجاوز 100 دولار أمريكي، وتؤدي إلى إيقاف العملية في حال تجاوزه هذا المبلغ. وعند التنفيذ الثاني، تبحث الأداة عن حالة في البيانات الوصفية الجديدة المقدَّمة وتعدّل عملية النقل أو تعرض ردًا بالرفض، وذلك استنادًا إلى ما إذا تمت الموافقة على العملية أو رفضها.
إعادة تشغيل الأدوات بعد انقطاع الاتصال
تمنحك أدوات المقاطعة إمكانية التحكّم الكامل في ما يلي:
- الحالات التي يجب أن يؤدي فيها طلب الأداة الأولي إلى إيقاف مؤقت
- متى يجب استئناف حلقة الإنشاء وما إذا كان يجب استئنافها
- المعلومات الإضافية التي يجب تقديمها إلى الأداة عند استئناف الحملة
في المثال الذي يظهر في القسم السابق، قد يطلب التطبيق من المستخدم confirm the interrupted request للتأكّد من صحة مبلغ النقل:
let response = await ai.generate({
tools: [transferMoney],
prompt: "Transfer $1000 to account ABC123",
});
while (response.interrupts.length) {
const confirmations = [];
// multiple interrupts can be called at once, so we handle them all
for (const interrupt in response.interrupts) {
confirmations.push(
// use the 'restart' method on our tool to provide `resumed` metadata
transferMoney.restart(
interrupt,
// send the tool request input to the user to respond. assume that this
// returns `{status: "APPROVED"}` or `{status: "REJECTED"}`
await requestConfirmation(interrupt.toolRequest.input);
)
);
}
response = await ai.generate({
tools: [transferMoney],
messages: response.messages,
resume: {
restart: confirmations,
}
})
}
// no more interrupts, we can see the final response
console.log(response.text);