如何在工具内流式传输事件¶
如果您的 LangGraph 图需要使用调用 LLM(或任何其他 LangChain Runnable
对象 - 其他图、LCEL 链、检索器等)的工具,您可能希望从底层的 Runnable
流式传输事件。本指南展示了如何执行此操作。
设置¶
npm install @langchain/langgraph @langchain/anthropic @langchain/core zod
process.env.ANTHROPIC_API_KEY = 'YOUR_API_KEY'
定义图和工具¶
我们将使用预建的 ReAct 代理作为本指南的示例
在 [11]
已复制!
import { z } from "zod";
import { tool } from "@langchain/core/tools";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { ChatAnthropic } from "@langchain/anthropic";
const model = new ChatAnthropic({
model: "claude-3-5-sonnet-20240620",
temperature: 0,
});
const getItems = tool(
async (input, config) => {
const template = ChatPromptTemplate.fromMessages([
[
"human",
"Can you tell me what kind of items i might find in the following place: '{place}'. " +
"List at least 3 such items separating them by a comma. And include a brief description of each item..",
],
]);
const modelWithConfig = model.withConfig({
runName: "Get Items LLM",
tags: ["tool_llm"],
});
const chain = template.pipe(modelWithConfig);
const result = await chain.invoke(input, config);
return result.content;
},
{
name: "get_items",
description: "Use this tool to look up which items are in the given place.",
schema: z.object({
place: z.string().describe("The place to look up items for. E.g 'shelf'"),
}),
}
);
import { z } from "zod"; import { tool } from "@langchain/core/tools"; import { ChatPromptTemplate } from "@langchain/core/prompts"; import { ChatAnthropic } from "@langchain/anthropic"; const model = new ChatAnthropic({ model: "claude-3-5-sonnet-20240620", temperature: 0, }); const getItems = tool( async (input, config) => { const template = ChatPromptTemplate.fromMessages([ [ "human", "Can you tell me what kind of items i might find in the following place: '{place}'. " + "List at least 3 such items separating them by a comma. And include a brief description of each item..", ], ]); const modelWithConfig = model.withConfig({ runName: "Get Items LLM", tags: ["tool_llm"], }); const chain = template.pipe(modelWithConfig); const result = await chain.invoke(input, config); return result.content; }, { name: "get_items", description: "Use this tool to look up which items are in the given place.", schema: z.object({ place: z.string().describe("The place to look up items for. E.g 'shelf'"), }), } );
我们在工具内的 LLM 可运行对象中添加了一个自定义标签 (tool_llm
)。这将允许我们过滤从已编译图 (agent
) 可运行对象(如下)流式传输的事件。
在 [12]
已复制!
import { createReactAgent } from "@langchain/langgraph/prebuilt";
const agent = createReactAgent({
llm: model,
tools: [getItems],
});
import { createReactAgent } from "@langchain/langgraph/prebuilt"; const agent = createReactAgent({ llm: model, tools: [getItems], });
从图中流式传输事件¶
在 [20]
已复制!
let finalEvent;
for await (const event of agent.streamEvents(
{
messages: [
[
"human",
"what items are on the shelf? You should call the get_items tool.",
],
],
},
{
version: "v2",
},
{
includeTags: ["tool_llm"],
}
)) {
if ("chunk" in event.data) {
console.dir({
type: event.data.chunk._getType(),
content: event.data.chunk.content,
})
}
finalEvent = event;
}
let finalEvent; for await (const event of agent.streamEvents( { messages: [ [ "human", "what items are on the shelf? You should call the get_items tool.", ], ], }, { version: "v2", }, { includeTags: ["tool_llm"], } )) { if ("chunk" in event.data) { console.dir({ type: event.data.chunk._getType(), content: event.data.chunk.content, }) } finalEvent = event; }
{ type: 'ai', content: 'Here' } { type: 'ai', content: ' are three items you might' } { type: 'ai', content: ' find on a shelf,' } { type: 'ai', content: ' along with brief' } { type: 'ai', content: ' descriptions:\n\n1.' } { type: 'ai', content: ' Books' } { type: 'ai', content: ': Boun' } { type: 'ai', content: 'd collections of printe' } { type: 'ai', content: 'd pages' } { type: 'ai', content: ' containing' } { type: 'ai', content: ' various' } { type: 'ai', content: ' forms' } { type: 'ai', content: ' of literature, information' } { type: 'ai', content: ', or reference' } { type: 'ai', content: ' material.\n\n2.' } { type: 'ai', content: ' Picture' } { type: 'ai', content: ' frames: Decorative' } { type: 'ai', content: ' borders' } { type: 'ai', content: ' used to display an' } { type: 'ai', content: 'd protect photographs, artwork' } { type: 'ai', content: ', or other visual memor' } { type: 'ai', content: 'abilia.\n\n3' } { type: 'ai', content: '. Pot' } { type: 'ai', content: 'ted plants: Small' } { type: 'ai', content: ' indoor' } { type: 'ai', content: ' plants in' } { type: 'ai', content: ' containers, often used for' } { type: 'ai', content: ' decoration or to add a' } { type: 'ai', content: ' touch of nature to indoor' } { type: 'ai', content: ' spaces.' }
让我们检查最后一个事件以获取代理的最终消息列表。
在 [21]
已复制!
const finalMessage = finalEvent?.data.output;
console.dir(
{
type: finalMessage._getType(),
content: finalMessage.content,
tool_calls: finalMessage.tool_calls,
},
{ depth: null }
);
const finalMessage = finalEvent?.data.output; console.dir( { type: finalMessage._getType(), content: finalMessage.content, tool_calls: finalMessage.tool_calls, }, { depth: null } );
{ type: 'ai', content: 'Here are three items you might find on a shelf, along with brief descriptions:\n' + '\n' + '1. Books: Bound collections of printed pages containing various forms of literature, information, or reference material.\n' + '\n' + '2. Picture frames: Decorative borders used to display and protect photographs, artwork, or other visual memorabilia.\n' + '\n' + '3. Potted plants: Small indoor plants in containers, often used for decoration or to add a touch of nature to indoor spaces.', tool_calls: [] }
您可以看到 ToolMessage
的内容与我们在上面流式传输的输出相同。