跳至主要内容

如何将可运行对象转换为工具

先决条件

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

为了方便起见,接受字符串或对象输入的 可运行对象 可以使用 asTool 方法转换为工具,该方法允许为参数指定名称、描述和附加架构信息。

在本指南中,我们将演示如何使用此方法将 LangChain 可运行对象 转换为可由代理、链或聊天模型使用的工具。

兼容性

此功能需要 @langchain/core>=0.2.16。请参阅 升级指南

asTool

工具对通用可运行对象有一些额外的要求

  • 它们的输入被限制为可序列化的,特别是字符串和对象;
  • 它们包含指示如何和何时使用它们的名称和描述;
  • 它们包含一个详细的 schema 属性,用于描述其参数。也就是说,虽然工具(作为 可运行对象)可能接受单个对象输入,但用于填充对象的特定键和类型信息应在 schema 字段中指定。

因此,asTool() 方法需要这些附加信息才能从可运行对象创建工具。以下是一个基本示例

import { RunnableLambda } from "@langchain/core/runnables";
import { z } from "zod";

const schema = z.object({
a: z.number(),
b: z.array(z.number()),
});

const runnable = RunnableLambda.from((input: z.infer<typeof schema>) => {
return input.a * Math.max(...input.b);
});

const asTool = runnable.asTool({
name: "My tool",
description: "Explanation of when to use the tool.",
schema,
});

asTool.description;
Explanation of when to use the tool.
await asTool.invoke({ a: 3, b: [1, 2] });
6

也支持接受字符串输入的可运行对象

const firstRunnable = RunnableLambda.from<string, string>((input) => {
return input + "a";
});

const secondRunnable = RunnableLambda.from<string, string>((input) => {
return input + "z";
});

const runnable = firstRunnable.pipe(secondRunnable);
const asTool = runnable.asTool({
name: "append_letters",
description: "Adds letters to a string.",
schema: z.string(),
});

asTool.description;
Adds letters to a string.
await asTool.invoke("b");
baz

在代理中

下面,我们将将 LangChain 可运行对象作为工具并入 代理 应用程序。我们将使用以下内容进行演示

  • 文档 检索器
  • 一个简单的 RAG 链,允许代理将相关查询委托给它。

我们首先实例化一个支持 工具调用 的聊天模型

按照 RAG 教程,我们首先构建一个检索器

import { ChatOpenAI } from "@langchain/openai";

const llm = new ChatOpenAI({ model: "gpt-3.5-turbo-0125", temperature: 0 });

import { Document } from "@langchain/core/documents";
import { MemoryVectorStore } from "langchain/vectorstores/memory";
import { OpenAIEmbeddings } from "@langchain/openai";

const documents = [
new Document({
pageContent:
"Dogs are great companions, known for their loyalty and friendliness.",
}),
new Document({
pageContent: "Cats are independent pets that often enjoy their own space.",
}),
];

const vectorstore = await MemoryVectorStore.fromDocuments(
documents,
new OpenAIEmbeddings()
);

const retriever = vectorstore.asRetriever({
k: 1,
searchType: "similarity",
});

接下来,我们创建一个预构建的 LangGraph 代理 并为其提供工具

import { createReactAgent } from "@langchain/langgraph/prebuilt";

const tools = [
retriever.asTool({
name: "pet_info_retriever",
description: "Get information about pets.",
schema: z.string(),
}),
];

const agent = createReactAgent({ llm: llm, tools });

const stream = await agent.stream({
messages: [["human", "What are dogs known for?"]],
});

for await (const chunk of stream) {
// Log output from the agent or tools node
if (chunk.agent) {
console.log("AGENT:", chunk.agent.messages[0]);
} else if (chunk.tools) {
console.log("TOOLS:", chunk.tools.messages[0]);
}
console.log("----");
}
AGENT: AIMessage {
"id": "chatcmpl-9m9RIN1GQVeXcrVdp0lNBTcZFVHb9",
"content": "",
"additional_kwargs": {
"tool_calls": [
{
"id": "call_n30LPDbegmytrj5GdUxZt9xn",
"type": "function",
"function": "[Object]"
}
]
},
"response_metadata": {
"tokenUsage": {
"completionTokens": 17,
"promptTokens": 52,
"totalTokens": 69
},
"finish_reason": "tool_calls"
},
"tool_calls": [
{
"name": "pet_info_retriever",
"args": {
"input": "dogs"
},
"type": "tool_call",
"id": "call_n30LPDbegmytrj5GdUxZt9xn"
}
],
"invalid_tool_calls": [],
"usage_metadata": {
"input_tokens": 52,
"output_tokens": 17,
"total_tokens": 69
}
}
----
TOOLS: ToolMessage {
"content": "[{\"pageContent\":\"Dogs are great companions, known for their loyalty and friendliness.\",\"metadata\":{}}]",
"name": "pet_info_retriever",
"additional_kwargs": {},
"response_metadata": {},
"tool_call_id": "call_n30LPDbegmytrj5GdUxZt9xn"
}
----
AGENT: AIMessage {
"id": "chatcmpl-9m9RJ3TT3ITfv6R0Tb7pcrNOUtnm8",
"content": "Dogs are known for being great companions, known for their loyalty and friendliness.",
"additional_kwargs": {},
"response_metadata": {
"tokenUsage": {
"completionTokens": 18,
"promptTokens": 104,
"totalTokens": 122
},
"finish_reason": "stop"
},
"tool_calls": [],
"invalid_tool_calls": [],
"usage_metadata": {
"input_tokens": 104,
"output_tokens": 18,
"total_tokens": 122
}
}
----

LangSmith 跟踪 显示了上述运行背后的工作原理。

更进一步,我们甚至可以从完整的 RAG 链 中创建工具

import { StringOutputParser } from "@langchain/core/output_parsers";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { RunnableSequence } from "@langchain/core/runnables";

const SYSTEM_TEMPLATE = `
You are an assistant for question-answering tasks.
Use the below context to answer the question. If
you don't know the answer, say you don't know.
Use three sentences maximum and keep the answer
concise.

Answer in the style of {answer_style}.

Context: {context}`;

const prompt = ChatPromptTemplate.fromMessages([
["system", SYSTEM_TEMPLATE],
["human", "{question}"],
]);

const ragChain = RunnableSequence.from([
{
context: (input, config) => retriever.invoke(input.question, config),
question: (input) => input.question,
answer_style: (input) => input.answer_style,
},
prompt,
llm,
new StringOutputParser(),
]);

下面,我们再次调用代理。请注意,代理在 tool_calls 中填充了必要的参数

const ragTool = ragChain.asTool({
name: "pet_expert",
description: "Get information about pets.",
schema: z.object({
context: z.string(),
question: z.string(),
answer_style: z.string(),
}),
});

const agent = createReactAgent({ llm: llm, tools: [ragTool] });

const stream = await agent.stream({
messages: [["human", "What would a pirate say dogs are known for?"]],
});

for await (const chunk of stream) {
// Log output from the agent or tools node
if (chunk.agent) {
console.log("AGENT:", chunk.agent.messages[0]);
} else if (chunk.tools) {
console.log("TOOLS:", chunk.tools.messages[0]);
}
console.log("----");
}
AGENT: AIMessage {
"id": "chatcmpl-9m9RKY2nAa8LeGoBiO7N1SR4nAoED",
"content": "",
"additional_kwargs": {
"tool_calls": [
{
"id": "call_ukzivO4jRn1XdDpuVTI6CvtU",
"type": "function",
"function": "[Object]"
}
]
},
"response_metadata": {
"tokenUsage": {
"completionTokens": 30,
"promptTokens": 63,
"totalTokens": 93
},
"finish_reason": "tool_calls"
},
"tool_calls": [
{
"name": "pet_expert",
"args": {
"context": "pirate",
"question": "What are dogs known for?",
"answer_style": "short"
},
"type": "tool_call",
"id": "call_ukzivO4jRn1XdDpuVTI6CvtU"
}
],
"invalid_tool_calls": [],
"usage_metadata": {
"input_tokens": 63,
"output_tokens": 30,
"total_tokens": 93
}
}
----
TOOLS: ToolMessage {
"content": "Dogs are known for their loyalty, companionship, and ability to provide emotional support to their owners.",
"name": "pet_expert",
"additional_kwargs": {},
"response_metadata": {},
"tool_call_id": "call_ukzivO4jRn1XdDpuVTI6CvtU"
}
----
AGENT: AIMessage {
"id": "chatcmpl-9m9RMwAEc14TTKtitq3CH2x9wpGik",
"content": "A pirate would say that dogs are known for their loyalty, companionship, and ability to provide emotional support to their owners.",
"additional_kwargs": {},
"response_metadata": {
"tokenUsage": {
"completionTokens": 26,
"promptTokens": 123,
"totalTokens": 149
},
"finish_reason": "stop"
},
"tool_calls": [],
"invalid_tool_calls": [],
"usage_metadata": {
"input_tokens": 123,
"output_tokens": 26,
"total_tokens": 149
}
}
----

有关上述运行,请参阅此 LangSmith 跟踪 以查看内部工作原理。


此页面是否有用?


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