توقف تولید با استفاده از وقفه

وقفه ها نوع خاصی از ابزار هستند که می توانند حلقه فراخوانی نسل و ابزار LLM را متوقف کنند تا کنترل را به شما بازگرداند. وقتی آماده شدید، می توانید با ارسال پاسخ هایی که LLM برای نسل های بعدی پردازش می کند، تولید را از سر بگیرید .

رایج ترین کاربردهای وقفه ها به چند دسته تقسیم می شوند:

  • Human-in-the-Loop: به کاربر یک هوش مصنوعی تعاملی را قادر می‌سازد تا اطلاعات مورد نیاز را روشن کند یا عملکرد LLM را قبل از تکمیل آن تأیید کند، که معیاری از ایمنی و اطمینان را ارائه می‌کند.
  • پردازش ناهمگام: شروع یک کار ناهمزمان که فقط می تواند خارج از باند تکمیل شود، مانند ارسال اعلان تأیید به یک بازبین انسانی یا شروع یک فرآیند پس زمینه طولانی مدت.
  • خروج از یک کار مستقل: ارائه روشی به مدل برای علامت گذاری یک کار به عنوان کامل، در جریان کاری که ممکن است از طریق یک سری طولانی از فراخوانی ابزار تکرار شود.

قبل از شروع

همه نمونه‌های مستند شده در اینجا فرض می‌کنند که شما قبلاً پروژه‌ای را با وابستگی‌های Genkit نصب کرده‌اید. اگر می خواهید نمونه کدهای موجود در این صفحه را اجرا کنید، ابتدا مراحل راهنمای Get Start را کامل کنید.

قبل از غواصی بیش از حد عمیق، باید با مفاهیم زیر نیز آشنا باشید:

بررسی اجمالی وقفه ها

در سطح بالا، این چیزی است که یک وقفه هنگام تعامل با یک LLM به نظر می رسد:

  1. برنامه فراخوانی LLM را با درخواست درخواست می کند. اعلان شامل فهرستی از ابزارها، شامل حداقل یکی برای وقفه است که LLM می تواند برای تولید پاسخ از آن استفاده کند.
  2. LLM یا یک پاسخ کامل یا یک درخواست فراخوانی ابزار در یک قالب خاص ایجاد می کند. برای LLM، یک تماس وقفه مانند هر تماس ابزار دیگری به نظر می رسد.
  3. اگر LLM یک ابزار وقفه را فراخوانی کند، کتابخانه Genkit به‌جای اینکه بلافاصله پاسخ‌ها را برای پردازش اضافی به مدل برگرداند، به‌طور خودکار تولید را متوقف می‌کند.
  4. توسعه دهنده بررسی می کند که آیا یک تماس وقفه برقرار شده است یا خیر، و هر کاری را که برای جمع آوری اطلاعات مورد نیاز برای پاسخ وقفه لازم است انجام می دهد.
  5. توسعه دهنده با ارسال یک پاسخ وقفه به مدل، تولید را از سر می گیرد. این عمل باعث بازگشت به مرحله 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);

ابزارهایی با وقفه های قابل راه اندازی مجدد

یکی دیگر از الگوهای رایج برای وقفه ها، نیاز به تایید عملی است که LLM قبل از اجرای واقعی آن پیشنهاد می کند. به عنوان مثال، یک برنامه پرداخت ممکن است از کاربر بخواهد که انواع خاصی از نقل و انتقالات را تأیید کند.

برای این مورد استفاده، می‌توانید از روش استاندارد 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 دلار بیشتر است یا خیر، و در این صورت یک وقفه ایجاد می کند. در اجرای دوم، به دنبال وضعیتی در فراداده جدید ارائه شده می‌گردد و بسته به تایید یا رد شدن، انتقال را انجام می‌دهد یا پاسخ رد را برمی‌گرداند.

پس از وقفه، ابزارها را مجدداً راه اندازی کنید

ابزارهای وقفه به شما کنترل کامل بر موارد زیر را می دهد:

  1. زمانی که یک درخواست ابزار اولیه باید یک وقفه ایجاد کند.
  2. چه زمانی و آیا باید حلقه تولید را از سر گرفت.
  3. چه اطلاعات اضافی برای ارائه به ابزار هنگام از سرگیری.

در مثال نشان داده شده در بخش قبل، برنامه ممکن است از کاربر بخواهد تا درخواست قطع شده را تأیید کند تا مطمئن شود مبلغ انتقال درست است:

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