如何创建工具
本指南假定您熟悉以下概念
在构建自己的代理时,您需要为它提供一个它可以使用的工具列表。虽然 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"
返回工具执行的工件
有时,我们希望将工具执行的某些结果提供给链条或代理中的下游组件,但不想将这些结果暴露给模型本身。例如,如果一个工具返回诸如文档之类的自定义对象,我们可能希望将此输出的一些视图或元数据传递给模型,而不将原始输出传递给模型。同时,我们可能希望能够在其他地方访问此完整输出,例如在后续工具中。
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 中创建自定义工具的几种方法。
接下来,您可能想了解 如何使用聊天模型调用工具。
您还可以查看如何创建您自己的 其他模块的自定义版本。