工具调用(也称为函数调用)是一种结构化方式,可让 LLM 向调用它的应用发出请求。您可以定义要向模型提供的工具,模型会根据需要向您的应用发出工具请求,以便执行您向其提供的提示。
工具调用的用例通常分为以下几个主题:
向 LLM 授予对其未用于训练的信息的访问权限
- 经常变化的信息,例如股票价格或当前天气。
- 特定于应用领域的信息,例如产品信息或用户个人资料。
请注意,这与检索增强生成 (RAG) 有重叠之处,后者也是让 LLM 将事实信息集成到其生成内容中的一种方法。RAG 是一种较为复杂的解决方案,最适合在您有大量信息或与问题最相关的信息模糊不清时使用。另一方面,如果检索 LLM 所需的信息是简单的函数调用或数据库查询,则更适合使用工具调用。
向 LLM 工作流引入一定程度的确定性
- 执行 LLM 无法自行可靠完成的计算。
- 在特定情况下强制 LLM 生成逐字逐句的文本,例如在回答有关应用服务条款的问题时。
在 LLM 发起时执行操作
- 在依托 LLM 的智能家居助理中开灯和关灯
- 在依托 LLM 的餐厅代理中预订餐桌
准备工作
如果您想运行本页中的代码示例,请先完成开始使用指南中的步骤。所有示例都假设您已设置了一个已安装 Genkit 依赖项的项目。
本页介绍了 Genkit 模型抽象的其中一个高级功能,因此在深入探究之前,您应先熟悉使用 AI 模型生成内容页面中的内容。您还应熟悉 Genkit 用于定义输入和输出架构的系统,如流程页面中所述。
工具调用概览
大体上讲,与 LLM 的典型工具调用交互如下所示:
- 调用应用会向 LLM 发出请求,并在提示中包含 LLM 可用于生成响应的工具列表。
- LLM 会生成完整的响应,或生成特定格式的工具调用请求。
- 如果调用方收到完整响应,系统会执行适当的逻辑,并向 LLM 发送包含原始提示或其变体以及工具调用结果的新请求。如果调用方收到工具调用,则会执行适当的逻辑,并向 LLM 发送包含原始提示或其变体以及工具调用结果的新请求。
- LLM 会像第 2 步中所述那样处理新提示。
为此,必须满足以下几项要求:
- 模型必须经过训练,以便在需要时发出工具请求来完成提示。通过 Web 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()
语法完全相同;不过,必须使用 name
、description
、inputSchema
和 outputSchema
这四个参数。编写工具定义时,请特别注意这些参数的措辞和描述性,因为它们对于 LLM 有效利用可用工具至关重要。
使用工具
在提示中添加定义好的工具来生成内容。
生成
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;
}