فراخوانی ابزار

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

موارد استفاده از فراخوانی ابزار به طور کلی در چند موضوع قرار می گیرند:

دادن دسترسی به LLM به اطلاعاتی که با آن آموزش ندیده است

  • اطلاعاتی که مرتباً در حال تغییر هستند، مانند منوی روزانه رستوران یا وضعیت موجودی فروشگاه.
  • اطلاعات خاص دامنه برنامه شما، مانند اطلاعات محصول.

به همپوشانی با نسل افزوده بازیابی (RAG) توجه کنید، که همچنین راهی برای ادغام اطلاعات واقعی به LLM در نسل‌های خود است. RAG راه حل سنگین تری است که زمانی مناسب تر است که شما حجم زیادی از اطلاعات دارید یا اطلاعاتی که بیشترین ارتباط را با یک اعلان دارد مبهم است. از سوی دیگر، اگر بازیابی اطلاعات مورد نیاز LLM یک فراخوانی ساده تابع یا جستجوی پایگاه داده باشد، فراخوانی ابزار مناسب تر است.

معرفی درجه ای از جبرگرایی در یک گردش کار LLM

  • انجام محاسباتی که LLM نمی تواند خود را به طور قابل اعتماد انجام دهد.
  • مجبور کردن یک LLM برای تولید متن کلمه به کلمه تحت شرایط خاص، مانند هنگام پاسخ دادن به سؤالی در مورد شرایط خدمات یک برنامه.

انجام یک عمل زمانی که توسط یک LLM آغاز شود

  • روشن و خاموش کردن چراغ‌ها در دستیار خانگی مجهز به LLM
  • رزرو میز رزرو در نمایندگی رستوران با قدرت LLM

قبل از شروع

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

این صفحه یکی از ویژگی‌های پیشرفته انتزاع مدل Genkit و تابع Genkit() را مورد بحث قرار می‌دهد، بنابراین قبل از اینکه عمیقاً غواصی کنید، باید با محتوای صفحه تولید محتوا با مدل‌های هوش مصنوعی آشنا شوید. همچنین باید با سیستم Genkit برای تعریف طرحواره های ورودی و خروجی آشنا باشید که در صفحه Flow ها به آن پرداخته شده است.

مروری بر فراخوانی ابزار

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

  1. برنامه فراخوانی LLM را با درخواست درخواست می‌کند و همچنین فهرستی از ابزارهایی را که LLM می‌تواند برای ایجاد پاسخ از آن استفاده کند، در آن درخواست می‌کند.
  2. LLM یا یک پاسخ کامل ایجاد می کند یا یک درخواست فراخوانی ابزار در یک قالب خاص ایجاد می کند.
  3. اگر تماس گیرنده پاسخ کاملی دریافت کند، درخواست برآورده شده و تعامل پایان می یابد. اما اگر تماس گیرنده یک فراخوانی ابزار دریافت کند، هر منطقی را که مناسب است انجام می دهد و درخواست جدیدی را به LLM ارسال می کند که حاوی دستور اصلی یا تغییراتی از آن و همچنین نتیجه فراخوانی ابزار است.
  4. LLM دستور جدید را مانند مرحله 2 مدیریت می کند.

برای انجام این کار، چندین الزام باید رعایت شود:

  • این مدل باید آموزش داده شود تا در مواقعی که برای تکمیل یک درخواست نیاز است، درخواست ابزار را ارائه دهد. اکثر مدل های بزرگتر ارائه شده از طریق API های وب، مانند Gemini و Claude، می توانند این کار را انجام دهند، اما مدل های کوچکتر و تخصصی تر اغلب نمی توانند. اگر بخواهید ابزارهایی را برای مدلی که از آن پشتیبانی نمی کند ارائه دهید، Genkit با خطا مواجه می شود.
  • برنامه فراخوانی باید تعاریف ابزار را در قالبی که انتظار دارد به مدل ارائه دهد.
  • برنامه فراخوانی باید مدل را وادار کند تا درخواست های فراخوانی ابزار را در قالبی که برنامه انتظار دارد ایجاد کند.

تماس ابزار با Genkit

Genkit یک رابط واحد برای فراخوانی ابزار با مدل هایی که از آن پشتیبانی می کنند ارائه می دهد. هر پلاگین مدل تضمین می‌کند که دو مورد آخر از معیارهای بالا برآورده می‌شوند و generate() gene به طور خودکار حلقه فراخوانی ابزار را که قبلا توضیح داده شد انجام می‌دهد.

پشتیبانی از مدل

پشتیبانی از فراخوانی ابزار به مدل، API مدل و پلاگین Genkit بستگی دارد. برای تعیین اینکه آیا فراخوانی ابزار احتمالاً پشتیبانی می شود یا خیر، با اسناد مربوطه مشورت کنید. علاوه بر این:

  • اگر بخواهید ابزارهایی را برای مدلی که از آن پشتیبانی نمی کند ارائه دهید، Genkit با خطا مواجه می شود.
  • اگر افزونه ارجاعات مدل را صادر کند، ویژگی info.supports.tools نشان می دهد که آیا از فراخوانی ابزار پشتیبانی می کند یا خیر.

تعریف ابزار

برای نوشتن تعاریف ابزار از تابع defineTool() استفاده کنید:

const specialToolInputSchema = z.object({ meal: z.enum(["breakfast", "lunch", "dinner"]) });
const specialTool = defineTool(
  {
    name: "specialTool",
    description: "Retrieves today's special for the given meal",
    inputSchema: specialToolInputSchema,
    outputSchema: z.string(),
  },
  async ({ meal }): Promise<string> => {
    // Retrieve up-to-date information and return it. Here, we just return a
    // fixed value.
    return "Baked beans on toast";
  }
);

نحو در اینجا دقیقاً شبیه نحو defineFlow() است. با این حال، هر چهار پارامتر name ، description ، inputSchema و outputSchema مورد نیاز است. هنگام نوشتن تعریف ابزار، به عبارت و توصیفی بودن این پارامترها دقت ویژه ای داشته باشید، زیرا برای LLM برای استفاده موثر از ابزارهای موجود حیاتی هستند.

از جمله ابزارهایی با درخواست های شما

بعد از اینکه ابزارهای خود را تعریف کردید، آنها را در پارامتر tools از generate() مشخص کنید:

const llmResponse = await generate({
  model: gemini15Flash,
  prompt,
  tools: [specialTool],
});

شما می توانید چندین ابزار را در دسترس قرار دهید. LLM ابزارها را در صورت لزوم برای تکمیل درخواست فراخوانی می کند.

کنترل صریح تماس های ابزار

به طور پیش فرض، Genkit به طور مکرر با LLM تماس می گیرد تا زمانی که همه تماس های ابزار حل شود. اگر می خواهید کنترل بیشتری روی حلقه فراخوانی ابزار داشته باشید، برای مثال برای اعمال منطق پیچیده تر، پارامتر returnToolRequests را روی true تنظیم کنید. اکنون این مسئولیت شماست که اطمینان حاصل کنید که تمام درخواست‌های ابزار برآورده شده‌اند:

let generateOptions: GenerateOptions = {
  model: gemini15Flash,
  prompt,
  tools: [specialTool],
  returnToolRequests: true,
};
let llmResponse;
while (true) {
  llmResponse = await generate(generateOptions);
  const toolRequests = llmResponse.toolRequests();
  if (toolRequests.length < 1) {
    break;
  }
  const toolResponses: ToolResponsePart[] = await Promise.all(
    toolRequests.map(async (part) => {
      switch (part.toolRequest.name) {
        case "specialTool":
          return {
            toolResponse: {
              name: part.toolRequest.name,
              ref: part.toolRequest.ref,
              output: await specialTool(specialToolInputSchema.parse(part.toolRequest?.input)),
            },
          };
        default:
          throw Error('Tool not found');
        }
      }));
    generateOptions.history = llmResponse.toHistory();
    generateOptions.prompt = toolResponses;
}