इंटरप्ट का इस्तेमाल करके जनरेशन को रोकना

इंटरप्ट एक खास तरह का टूल है. यह एलएलएम जनरेशन और टूल कॉलिंग लूप को रोक सकता है, ताकि कंट्रोल आपके पास वापस आ सके. जब आप तैयार हों, तब जनरेशन को फिर से शुरू किया जा सकता है. इसके लिए, एलएलएम को जवाब भेजें, ताकि वह आगे के जनरेशन के लिए उन्हें प्रोसेस कर सके.

आम तौर पर, इंटरप्ट का इस्तेमाल इन कैटगरी में किया जाता है:

  • मानव-इन-लूप: इंटरैक्टिव एआई के उपयोगकर्ता को ज़रूरी जानकारी देने या एलएलएम की कार्रवाई पूरी होने से पहले उसकी पुष्टि करने की सुविधा देना. इससे सुरक्षा और भरोसे को बढ़ावा मिलता है.
  • असाइनमेंट को अलग-अलग प्रोसेस करना: असाइनमेंट को अलग-अलग प्रोसेस करने की सुविधा, जिसे सिर्फ़ अलग से पूरा किया जा सकता है. जैसे, समीक्षक को अनुमति की सूचना भेजना या लंबे समय तक चलने वाली बैकग्राउंड प्रोसेस शुरू करना.
  • ऑटोनॉमस टास्क से बाहर निकलना: मॉडल को एक ऐसा तरीका देना जिससे वह किसी ऐसे वर्कफ़्लो में टास्क को 'पूरा हुआ' के तौर पर मार्क कर सके जिसमें टूल कॉल की लंबी सीरीज़ शामिल हो सकती है.

शुरू करने से पहले

यहां दिए गए सभी उदाहरणों में यह माना गया है कि आपने पहले ही Genkit की डिपेंडेंसी इंस्टॉल करके कोई प्रोजेक्ट सेट अप कर लिया है. अगर आपको इस पेज पर दिए गए कोड के उदाहरण चलाने हैं, तो पहले शुरू करें गाइड में दिया गया तरीका अपनाएं.

ज़्यादा जानकारी के लिए, आपको इन कॉन्सेप्ट के बारे में भी पता होना चाहिए:

रुकावटों के बारे में खास जानकारी

हाई लेवल पर, एलएलएम के साथ इंटरैक्ट करते समय, रुकावट इस तरह दिखती है:

  1. कॉल करने वाला ऐप्लिकेशन, एलएलएम को अनुरोध भेजता है. प्रॉम्प्ट में टूल की एक सूची शामिल होती है. इसमें कम से कम एक ऐसा टूल भी होता है जिसका इस्तेमाल एलएलएम, जवाब जनरेट करने के लिए कर सकता है.
  2. एलएलएम, किसी खास फ़ॉर्मैट में पूरा जवाब या टूल कॉल का अनुरोध जनरेट करता है. एलएलएम के लिए, इंटरप्ट कॉल किसी भी दूसरे टूल कॉल की तरह दिखता है.
  3. अगर एलएलएम किसी इंटरप्ट टूल को कॉल करता है, तो Genkit लाइब्रेरी, जवाबों को तुरंत मॉडल को भेजने के बजाय, जनरेशन को अपने-आप रोक देती है, ताकि अतिरिक्त प्रोसेसिंग की जा सके.
  4. डेवलपर यह जांच करता है कि कोई रुकावट वाला कॉल किया गया है या नहीं. साथ ही, रुकावट वाले जवाब के लिए ज़रूरी जानकारी इकट्ठा करने के लिए, ज़रूरी काम करता है.
  5. डेवलपर, मॉडल को इंटरप्ट रिस्पॉन्स भेजकर जनरेशन को फिर से शुरू करता है. इस कार्रवाई से, आपको दूसरे चरण पर वापस ले जाया जाता है.

मैन्युअल तरीके से जवाब देने की सुविधा के दौरान होने वाले रुकावटों के बारे में जानकारी

आम तौर पर, इंटरप्ट करने की सुविधा की मदद से एलएलएम, उपयोगकर्ता से जानकारी मांग सकता है. उदाहरण के लिए, कई विकल्पों में से किसी एक को चुनने के लिए सवाल पूछकर.

इस इस्तेमाल के उदाहरण के लिए, Genkit इंस्टेंस के defineInterrupt() तरीके का इस्तेमाल करें:

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

किसी रुकावट का जवाब देने के लिए, अगले generate कॉल पर resume विकल्प का इस्तेमाल किया जाता है. साथ ही, यह पक्का किया जाता है कि मौजूदा इतिहास को पास किया जाए. जवाब बनाने में मदद करने के लिए, हर टूल पर .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 डॉलर से ज़्यादा है या नहीं. अगर रकम 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);