如何创建工具
本指南假设您熟悉以下概念
在构建自己的代理时,您需要为它提供一个它可以使用的工具列表。虽然 LangChain 包含一些预建的工具,但使用使用自定义逻辑的工具通常更有用。本指南将引导您完成创建自定义工具的一些方法。
这里最大的区别是第一个函数需要一个包含多个输入字段的对象,而第二个函数只接受一个包含单个字段的对象。一些较旧的代理只适用于需要单个输入的函数,因此了解这种区别很重要。
LangChain 提供了一些方法来构建用于不同应用程序的工具。下面我将展示创建工具的两种最常见方法,以及您可能在何处使用它们。
工具模式
仅在 @langchain/core
版本 0.2.19 及更高版本中可用。
创建工具最简单的方法是通过 StructuredToolParams
模式。LangChain 中支持工具调用的每个聊天模型都接受通过此模式将工具绑定到模型。此模式只有三个字段
name
- 工具的名称。schema
- 工具的模式,用 Zod 对象定义。description
(可选) - 工具的描述。
此模式不包含与工具配对的函数,因此它只应在生成的输出不需要作为输入参数传递给函数的情况下使用。
import { z } from "zod";
import { StructuredToolParams } from "@langchain/core/tools";
const simpleToolSchema: StructuredToolParams = {
name: "get_current_weather",
description: "Get the current weather for a location",
schema: z.object({
city: z.string().describe("The city to get the weather for"),
state: z.string().optional().describe("The state to get the weather for"),
}),
};
tool
函数
仅在 @langchain/core
版本 0.2.7 及更高版本中可用。
该 tool
包装函数是一种将 JavaScript 函数转换为工具的便捷方法。它需要函数本身以及一些定义工具的附加参数。您应该在 StructuredToolParams
工具调用结果工具时执行函数的情况下使用它。最重要的是
- 工具的
name
,LLM 将它用作上下文以及引用工具 - 可选的,但建议的
description
,LLM 将它用作上下文以了解何时使用工具 - 一个
schema
,它定义工具输入的形状
tool
函数将返回 StructuredTool
类的实例,因此它与 LangChain 库中所有现有的工具调用基础设施兼容。
import { z } from "zod";
import { tool } from "@langchain/core/tools";
const adderSchema = z.object({
a: z.number(),
b: z.number(),
});
const adderTool = tool(
async (input): Promise<string> => {
const sum = input.a + input.b;
return `The sum of ${input.a} and ${input.b} is ${sum}`;
},
{
name: "adder",
description: "Adds two numbers together",
schema: adderSchema,
}
);
await adderTool.invoke({ a: 1, b: 2 });
"The sum of 1 and 2 is 3"
DynamicStructuredTool
您也可以使用 DynamicStructuredTool
类来声明工具。这是一个例子 - 注意工具必须始终返回字符串!
import { DynamicStructuredTool } from "@langchain/core/tools";
import { z } from "zod";
const multiplyTool = new DynamicStructuredTool({
name: "multiply",
description: "multiply two numbers together",
schema: z.object({
a: z.number().describe("the first number to multiply"),
b: z.number().describe("the second number to multiply"),
}),
func: async ({ a, b }: { a: number; b: number }) => {
return (a * b).toString();
},
});
await multiplyTool.invoke({ a: 8, b: 9 });
"72"
DynamicTool
对于需要仅接受单个输入的工具的旧代理,您可以将相关参数传递给 DynamicTool
类。这在与仅支持接受单个输入的工具的旧代理一起工作时很有用。在这种情况下,不需要模式
import { DynamicTool } from "@langchain/core/tools";
const searchTool = new DynamicTool({
name: "search",
description: "look things up online",
func: async (_input: string) => {
return "LangChain";
},
});
await searchTool.invoke("foo");
"LangChain"
返回工具执行的工件
有时,我们会希望将工具执行的某些结果传递给链或代理中的下游组件,但又不想将其暴露给模型本身。例如,如果一个工具返回自定义对象,例如 Documents,我们可能希望将有关此输出的一些视图或元数据传递给模型,而不将原始输出传递给模型。同时,我们可能希望能够在其他地方访问此完整输出,例如在下游工具中。
Tool 和 ToolMessage
接口使我们能够区分工具输出中专为模型设计的部分 (ToolMessage.content
) 和专为模型外部使用设计的其他部分 (ToolMessage.artifact
)。
此功能在 @langchain/core>=0.2.16
中添加。请确保你的软件包已更新。
如果你想让你的工具区分消息内容和其他结果,我们需要做三件事:
- 在定义工具时,将
response_format
参数设置为"content_and_artifact"
。 - 确保我们返回一个
[content, artifact]
元组。 - 使用
ToolCall
(类似于工具调用模型生成的那些)调用工具,而不是直接使用所需的模式。
以下是一个示例,展示了它的工作方式。首先,创建一个新工具
import { z } from "zod";
import { tool } from "@langchain/core/tools";
const randomIntToolSchema = z.object({
min: z.number(),
max: z.number(),
size: z.number(),
});
const generateRandomInts = tool(
async ({ min, max, size }) => {
const array: number[] = [];
for (let i = 0; i < size; i++) {
array.push(Math.floor(Math.random() * (max - min + 1)) + min);
}
return [
`Successfully generated array of ${size} random ints in [${min}, ${max}].`,
array,
];
},
{
name: "generateRandomInts",
description: "Generate size random ints in the range [min, max].",
schema: randomIntToolSchema,
responseFormat: "content_and_artifact",
}
);
如果你直接使用工具参数调用我们的工具,你将只得到输出的 content
部分
await generateRandomInts.invoke({ min: 0, max: 9, size: 10 });
"Successfully generated array of 10 random ints in [0, 9]."
但是,如果你使用 ToolCall
调用我们的工具,你将得到一个 ToolMessage
,其中包含 Tool
生成的内容和结果。
await generateRandomInts.invoke({
name: "generateRandomInts",
args: { min: 0, max: 9, size: 10 },
id: "123", // required
type: "tool_call",
});
ToolMessage {
lc_serializable: true,
lc_kwargs: {
content: "Successfully generated array of 10 random ints in [0, 9].",
artifact: [
7, 7, 1, 4, 8,
4, 8, 3, 0, 9
],
tool_call_id: "123",
name: "generateRandomInts",
additional_kwargs: {},
response_metadata: {}
},
lc_namespace: [ "langchain_core", "messages" ],
content: "Successfully generated array of 10 random ints in [0, 9].",
name: "generateRandomInts",
additional_kwargs: {},
response_metadata: {},
id: undefined,
tool_call_id: "123",
artifact: [
7, 7, 1, 4, 8,
4, 8, 3, 0, 9
]
}
相关
现在你已经了解了一些在 LangChain 中创建自定义工具的方法。
接下来,你可能想了解 如何使用聊天模型调用工具。
你也可以查看如何创建你自己的 其他模块的自定义版本。