如何向预构建的 ReAct 代理添加人工参与的流程¶
本教程将展示如何向预构建的 ReAct 代理添加人工参与的流程。请参阅本教程,了解如何开始使用预构建的 ReAct 代理
您可以通过将 interruptBefore: ["tools"]
传递给 createReactAgent
,在调用工具之前添加断点。请注意,您需要使用检查点程序才能使其工作。
设置¶
首先,我们需要安装所需的软件包。
本指南将使用 OpenAI 的 GPT-4o 模型。我们将可选地为 LangSmith tracing 设置我们的 API 密钥,这将为我们提供一流的可观察性。
// process.env.OPENAI_API_KEY = "sk_...";
// Optional, add tracing in LangSmith
// process.env.LANGCHAIN_API_KEY = "ls__..."
// process.env.LANGCHAIN_CALLBACKS_BACKGROUND = "true";
process.env.LANGCHAIN_CALLBACKS_BACKGROUND = "true";
process.env.LANGCHAIN_TRACING_V2 = "true";
process.env.LANGCHAIN_PROJECT = "ReAct Agent with human-in-the-loop: LangGraphJS";
代码¶
现在我们可以使用预构建的 createReactAgent
函数来设置我们的人工参与交互代理
import { ChatOpenAI } from "@langchain/openai";
import { tool } from '@langchain/core/tools';
import { z } from 'zod';
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { MemorySaver } from "@langchain/langgraph";
const model = new ChatOpenAI({
model: "gpt-4o",
});
const getWeather = tool((input) => {
if (['sf', 'san francisco'].includes(input.location.toLowerCase())) {
return 'It\'s always sunny in sf';
} else if (['nyc', 'new york city'].includes(input.location.toLowerCase())) {
return 'It might be cloudy in nyc';
}
else {
throw new Error("Unknown Location");
}
}, {
name: 'get_weather',
description: 'Call to get the current weather in a given location.',
schema: z.object({
location: z.string().describe("Location to get the weather for."),
})
})
// Here we only save in-memory
const memory = new MemorySaver();
const agent = createReactAgent({ llm: model, tools: [getWeather], interruptBefore: ["tools"], checkpointSaver: memory });
用法¶
let inputs = { messages: [{ role: "user", content: "what is the weather in SF california?" }] };
let config = { configurable: { thread_id: "1" } };
let stream = await agent.stream(inputs, {
...config,
streamMode: "values",
});
for await (
const { messages } of stream
) {
let msg = messages[messages?.length - 1];
if (msg?.content) {
console.log(msg.content);
}
if (msg?.tool_calls?.length > 0) {
console.log(msg.tool_calls);
}
console.log("-----\n");
}
what is the weather in SF california?
-----
[
{
name: 'get_weather',
args: { location: 'SF, California' },
type: 'tool_call',
id: 'call_AWgaSjqaYVQN73kL0H4BNn1Q'
}
]
-----
null
输入继续流式传输图。如果我们想编辑工具调用,我们需要更新状态以具有正确的工具调用,然后在应用更新后,我们可以继续。
我们可以尝试恢复,我们将看到一个错误出现
stream = await agent.stream(null, {
...config,
streamMode: "values",
});
for await (
const { messages } of stream
) {
let msg = messages[messages?.length - 1];
if (msg?.content) {
console.log(msg.content);
}
if (msg?.tool_calls?.length > 0) {
console.log(msg.tool_calls);
}
console.log("-----\n");
}
Error: Unknown Location
Please fix your mistakes.
-----
[
{
name: 'get_weather',
args: { location: 'San Francisco, California' },
type: 'tool_call',
id: 'call_MfIPKpRDXRL4LcHm1BxwcSTk'
}
]
-----
让我们展示如何编辑工具调用以搜索“San Francisco”而不是“SF, California” - 因为我们的工具按书面形式将“San Francisco, CA”视为未知位置。我们将更新状态,然后恢复流式传输图,应该看不到任何错误出现。请注意,我们用于 messages
通道的 reducer 仅在使用了具有完全相同 ID 的消息时才会替换消息。因此,我们可以执行 new AiMessage(...)
,而必须直接修改来自 messages
通道的最后一条消息,并确保不编辑其 ID。
// First, lets get the current state
const currentState = await agent.getState(config);
// Let's now get the last message in the state
// This is the one with the tool calls that we want to update
let lastMessage = currentState.values.messages[currentState.values.messages.length - 1]
// Let's now update the args for that tool call
lastMessage.tool_calls[0].args = { location: "San Francisco" }
// Let's now call `updateState` to pass in this message in the `messages` key
// This will get treated as any other update to the state
// It will get passed to the reducer function for the `messages` key
// That reducer function will use the ID of the message to update it
// It's important that it has the right ID! Otherwise it would get appended
// as a new message
await agent.updateState(config, { messages: lastMessage });
{
configurable: {
thread_id: '1',
checkpoint_ns: '',
checkpoint_id: '1ef6638d-bfbd-61d0-8004-2751c8c3f226'
}
}