一种常见用例是从工具内部更新graph state。例如,在客户支持应用程序中,可能希望在对话开始时查找客户帐号或 ID。要从工具更新graph state,可以从tool返回 Command(update={"my_custom_key": "foo", "messages": [...]}):@tool
def lookup_user_info(tool_call_id: Annotated[str, InjectedToolCallId], config: RunnableConfig):
"""使用此工具查找用户信息,以便更好地回答他们的问题。"""
user_info = get_user_info(config)
return Command(
update={
"user_info": user_info,
# 更新消息历史记录
"messages": [ToolMessage("成功查找用户信息", tool_call_id=tool_call_id)]
}
)
首先,让我们定义用于查找用户信息的工具。我们将使用一个简单的实现,即使用字典简单地查找用户信息:USER_INFO = [
{"user_id": "1", "name": "张三", "location": "北京"},
{"user_id": "2", "name": "李四", "location": "成都"},
]
USER_ID_TO_USER_INFO = {info["user_id"]: info for info in USER_INFO}
from langgraph.prebuilt.chat_agent_executor import AgentState
from langgraph.types import Command
from langchain_core.tools import tool
from langchain_core.tools.base import InjectedToolCallId
from langchain_core.messages import ToolMessage
from langchain_core.runnables import RunnableConfig
from typing_extensions import Any, Annotated
class State(AgentState):
# 由工具更新
user_info: dict[str, Any]
@tool
def lookup_user_info(
tool_call_id: Annotated[str, InjectedToolCallId], config: RunnableConfig
):
"""使用此工具查找用户信息,以便更好地回答他们的问题。"""
user_id = config.get("configurable", {}).get("user_id")
if user_id is None:
raise ValueError("请提供用户ID")
if user_id not in USER_ID_TO_USER_INFO:
raise ValueError(f"未找到用户'{user_id}'")
user_info = USER_ID_TO_USER_INFO[user_id]
return Command(
update={
# 更新状态键
"user_info": user_info,
# 更新消息历史
"messages": [
ToolMessage(
"成功查找用户信息", tool_call_id=tool_call_id
)
],
}
)
现在让我们加点料:在状态从工具更新后,我们将根据状态值对用户做出不同的响应。为了实现这一点,让我们定义一个函数,该函数将根据图形状态动态构建系统提示。每次调用 LLM 时都会调用它,并且函数输出将传递给 LLM:def state_modifier(state: State):
user_info = state.get("user_info")
if user_info is None:
return state["messages"]
system_msg = (
f"用户名是{user_info['name']}。用户住在{user_info['location']}"
)
return [{"role": "system", "content": system_msg}] + state["messages"]
from langgraph.prebuilt import create_react_agent
from langchain_ollama import ChatOllama
import base_conf
model = ChatOllama(base_url=base_conf.base_url, model=base_conf.model_name, temperature=0)
agent = create_react_agent(
model,
# 传递可以更新状态的工具
[lookup_user_info],
state_schema=State,
# 传递动态提示函数
state_modifier=state_modifier,
)
for chunk in agent.stream(
{"messages": [("user", "我是用户,这周我该做什么?")]},
# provide user ID in the config
{"configurable": {"user_id": "1"}},
):
print(chunk)
print("\n")
{'agent': {'messages': [AIMessage(content='', additional_kwargs={}, response_metadata={'model': 'qwen2.5:7b', 'created_at': '2025-01-08T06:39:47.488317Z', 'done': True, 'done_reason': 'stop', 'total_duration': 3534691667, 'load_duration': 22909042, 'prompt_eval_count': 162, 'prompt_eval_duration': 799000000, 'eval_count': 60, 'eval_duration': 2710000000, 'message': Message(role='assistant', content='', images=None, tool_calls=None)}, id='run-3909aefc-f875-49f6-952e-9f24290f3780-0', tool_calls=[{'name': 'lookup_user_info', 'args': {}, 'id': '17f1dc87-07fd-4261-8c35-f554fbce7fcd', 'type': 'tool_call'}], usage_metadata={'input_tokens': 162, 'output_tokens': 60, 'total_tokens': 222})]}}
{'tools': {'user_info': {'user_id': '1', 'name': '张三', 'location': '北京'}, 'messages': [ToolMessage(content='成功查找用户信息', name='lookup_user_info', id='45207262-0344-41a4-a28d-ce33a4927d44', tool_call_id='17f1dc87-07fd-4261-8c35-f554fbce7fcd')]}}
{'agent': {'messages': [AIMessage(content='您好!根据您的个人信息,您最近在学习编程。如果您愿意的话,这周您可以尝试完成一些小项目来巩固所学知识,或者参加在线课程进一步提升技能。此外,您还可以阅读相关书籍或文章以拓宽视野。\n\n另外,您还提到了对摄影感兴趣。如果时间允许,您可以利用周末的时间去户外拍摄风景照片,提高自己的摄影技巧。\n\n当然,这些建议仅供参考,您可以根据个人兴趣和实际情况进行调整。希望这些建议能帮助到您!', additional_kwargs={}, response_metadata={'model': 'qwen2.5:7b', 'created_at': '2025-01-08T06:39:53.329455Z', 'done': True, 'done_reason': 'stop', 'total_duration': 5823573375, 'load_duration': 9685875, 'prompt_eval_count': 194, 'prompt_eval_duration': 854000000, 'eval_count': 108, 'eval_duration': 4957000000, 'message': Message(role='assistant', content='您好!根据您的个人信息,您最近在学习编程。如果您愿意的话,这周您可以尝试完成一些小项目来巩固所学知识,或者参加在线课程进一步提升技能。此外,您还可以阅读相关书籍或文章以拓宽视野。\n\n另外,您还提到了对摄影感兴趣。如果时间允许,您可以利用周末的时间去户外拍摄风景照片,提高自己的摄影技巧。\n\n当然,这些建议仅供参考,您可以根据个人兴趣和实际情况进行调整。希望这些建议能帮助到您!', images=None, tool_calls=None)}, id='run-984dfe37-7aa0-4133-bd20-ccf92cef88dc-0', usage_metadata={'input_tokens': 194, 'output_tokens': 108, 'total_tokens': 302})]}}
当然了,你还可以试着把{"configurable": {"user_id": "1"}}改为2试试。可以看到,我们的tool实际上充当了一个修改 state 状态的 node。