工具呼叫

工具呼叫 (也稱為函式呼叫) 是一種結構化方式,可讓大型語言模型向呼叫它的應用程式提出要求。您可以定義要提供給模型的工具,模型會視需要向應用程式提出工具要求,以便執行您提供的提示。

工具呼叫的用途通常可歸納為幾個主題:

讓大型語言模型存取未用於訓練的資訊

  • 經常變更的資訊,例如股票價格或目前天氣。
  • 應用程式網域專屬資訊,例如產品資訊或使用者個人資料。

請注意,這與檢索增強生成 (RAG) 重疊,後者也是讓 LLM 將事實資訊整合至生成內容的一種方式。RAG 是較為複雜的解決方案,最適合用於大量資訊,或是與提示最相關的資訊模糊不清的情況。另一方面,如果擷取 LLM 所需資訊的操作是簡單的函式呼叫或資料庫查詢,則呼叫工具會更適合。

在 LLM 工作流程中引入一定程度的確定性

  • 執行 LLM 無法可靠完成的計算。
  • 在特定情況下強制 LLM 產生逐字文字,例如在回覆有關應用程式服務條款的問題時。

在 LLM 啟動時執行動作

  • 透過 LLM 技術輔助的家用助理開啟和關閉燈具
  • 在 LLM 輔助的餐廳服務代理中預訂座位

事前準備

如果您想執行本頁的程式碼範例,請先完成「開始使用」指南中的步驟。所有範例都假設您已設定安裝 Genkit 依附元件的專案。

本頁將說明 Genkit 模型抽象化的進階功能之一,因此在深入探討之前,請先熟悉「使用 AI 模型產生內容」頁面中的內容。您也應熟悉 Genkit 的系統,以便定義輸入和輸出結構定義,相關資訊請參閱「流程」頁面。

工具呼叫總覽

大致來說,以下是工具呼叫與大型語言模型互動的典型情況:

  1. 呼叫應用程式會向 LLM 提示要求,並在提示中加入 LLM 可用於產生回應的工具清單。
  2. 大型語言模型會生成完整回應,或以特定格式生成工具呼叫要求。
  3. 如果呼叫端收到完整回應,系統就會執行要求,並結束互動;但如果呼叫端收到工具呼叫,則會執行適當的邏輯,並向 LLM 傳送新要求,其中包含原始提示或某些變化版本,以及工具呼叫的結果。
  4. LLM 會處理新的提示,如步驟 2 所述。

如要使用這項功能,您必須符合下列幾項條件:

  • 模型必須經過訓練,才能在需要完成提示時提出工具要求。大多數透過網路 API 提供的大型模型 (例如 Gemini 和 Claude) 都能執行這項操作,但較小且較專門的模型通常無法執行。如果您嘗試為不支援的模型提供工具,Genkit 就會擲回錯誤。
  • 呼叫端應用程式必須以模型預期的格式,向模型提供工具定義。
  • 呼叫應用程式必須提示模型,以應用程式預期的格式產生工具呼叫要求。

使用 Genkit 呼叫工具

Genkit 提供單一介面,可讓工具呼叫支援的模型。每個模型外掛程式都會確保符合上述最後兩項條件,而 Genkit 例項的 generate() 函式會自動執行先前所述的工具呼叫迴圈。

模型支援

工具呼叫支援取決於模型、模型 API 和 Genkit 外掛程式。請參閱相關說明文件,判斷是否支援工具呼叫。此外:

  • 如果您嘗試為不支援的模型提供工具,Genkit 就會擲回錯誤。
  • 如果外掛程式匯出模型參照,info.supports.tools 屬性會指出是否支援工具呼叫。

定義工具

使用 Genkit 例項的 defineTool() 函式編寫工具定義:

import { genkit, z } from 'genkit';
import { googleAI, gemini15Flash } from '@genkit-ai/google-ai';

const ai = genkit({
  plugins: [googleAI()],
  model: gemini15Flash,
});

const getWeather = ai.defineTool(
  {
    name: 'getWeather',
    description: 'Gets the current weather in a given location',
    inputSchema: z.object({ 
      location: z.string().describe('The location to get the current weather for')
    }),
    outputSchema: z.string(),
  },
  async (input) => {
    // Here, we would typically make an API call or database query. For this
    // example, we just return a fixed value.
    return 'The current weather in ${input.location} is 63°F and sunny.';
  }
);

這裡的語法與 defineFlow() 語法相似,但必須使用四個 namedescriptioninputSchemaoutputSchema 參數。編寫工具定義時,請特別注意這些參數的措辭和描述性,因為這些參數對於大型語言模型有效運用可用的工具至關重要。

使用工具

在提示中加入定義的工具,以便產生內容。

產生

const response = await ai.generate({
  prompt: 'What is the weather in Baltimore?',
  tools: [getWeather],
});

definePrompt

const weatherPrompt = ai.definePrompt(
  {
    name: 'weatherPrompt',
    tools: [getWeather],
  },
  'What is the weather in {{location}}?'
);

const response = await weatherPrompt({ location: 'Baltimore' });

提示檔案

---
system: "Answer questions using the tools you have."
tools: [getWeather]
input:
  schema:
    location: string
---

What is the weather in {{location}}?

接著,您可以在程式碼中執行提示,如下所示:

// assuming prompt file is named weatherPrompt.prompt
const weatherPrompt = ai.prompt('weatherPrompt');

const response = await weatherPrompt({ location: 'Baltimore' });

即時通訊

const chat = ai.chat({
  system: 'Answer questions using the tools you have.',
  tools: [getWeather],
});

const response = await chat.send('What is the weather in Baltimore?');

// Or, specify tools that are message-specific 
const response = await chat.send({
  prompt: 'What is the weather in Baltimore?',
  tools: [getWeather],
});

如果 LLM 需要使用 getWeather 工具來回答提示,Genkit 會自動處理工具呼叫。

明確處理工具呼叫

根據預設,Genkit 會重複呼叫 LLM,直到每個工具呼叫都已解析為止。如要進一步控管這個工具的呼叫迴圈 (例如套用更複雜的邏輯),請將 returnToolRequests 參數設為 true。您現在有責任確保所有工具要求都已滿足:

const getWeather = ai.defineTool(
  {
    // ... tool definition ...
  },
  async ({ location }) => {
    // ... tool implementation ...
  },
);

const generateOptions: GenerateOptions = {
  prompt: "What's the weather like in Baltimore?",
  tools: [getWeather],
  returnToolRequests: true,
};

let llmResponse;
while (true) {
  llmResponse = await ai.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 getWeather(part.toolRequest.input),
            },
          };
        default:
          throw Error('Tool not found');
      }
    })
  );
  generateOptions.messages = llmResponse.messages;
  generateOptions.prompt = toolResponses;
}