跳至主要内容

如何创建工具

先决条件

本指南假定您熟悉以下概念

在构建自己的代理时,您需要为它提供一个它可以使用的工具列表。虽然 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 中创建自定义工具的几种方法。

接下来,您可能想了解 如何使用聊天模型调用工具

您还可以查看如何创建您自己的 其他模块的自定义版本


此页面对您有帮助吗?


您也可以留下详细的反馈 在 GitHub 上.