ToolNode 是一个 LangChain Runnable,它以图形状态(带有消息列表)作为输入,并使用工具调用的结果输出状态更新。它被设计为与 LangGraph 预构建的 ReAct 代理一起开箱即用,但也可以与任何 StateGraph 一起工作,只要它的状态有一个带有reducer的message key(参见 MessagesState)。from langchain_core.messages import AIMessage
from langchain_core.tools import tool
from langgraph.prebuilt import ToolNode
@tool
def get_weather(location: str):
"""Call to get the current weather."""
if location.lower() in ["sf", "san francisco"]:
return "It's 60 degrees and foggy."
else:
return "It's 90 degrees and sunny."
@tool
def get_coolest_cities():
"""Get a list of coolest cities"""
return "nyc, sf"
tools = [get_weather, get_coolest_cities]
tool_node = ToolNode(tools)
ToolNode 使用消息列表对graph状态进行操作。它要求列表中的最后一条消息是带有 tool_calls 参数的 AIMessage。message_with_single_tool_call = AIMessage(
content="",
tool_calls=[
{
"name": "get_weather",
"args": {"location": "sf"},
"id": "tool_call_id",
"type": "tool_call",
}
],
)
print(tool_node.invoke({"messages": [message_with_single_tool_call]}))
{'messages': [ToolMessage(content="It's 60 degrees and foggy.", name='get_weather', tool_call_id='tool_call_id')]}
注意,通常我们不需要手动创建 AIMessage,它将由任何支持工具调用的 LangChain 聊天模型自动生成。如果将多个工具调用传递给 AIMessage 的 tool_calls 参数,还可以使用 ToolNode 进行并行工具调用:message_with_multiple_tool_calls = AIMessage(
content="",
tool_calls=[
{
"name": "get_coolest_cities",
"args": {},
"id": "tool_call_id_1",
"type": "tool_call",
},
{
"name": "get_weather",
"args": {"location": "sf"},
"id": "tool_call_id_2",
"type": "tool_call",
},
],
)
print(tool_node.invoke({"messages": [message_with_multiple_tool_calls]}))
{'messages':
[ToolMessage(content='nyc, sf', name='get_coolest_cities', tool_call_id='tool_call_id_1'),
ToolMessage(content="It's 60 degrees and foggy.", name='get_weather', tool_call_id='tool_call_id_2')]}
我们通常会使用到一个叫做 bind_tools的方法:from langchain_ollama import ChatOllama
import base_conf
model_with_tools = (ChatOllama(base_url=base_conf.base_url,
model=base_conf.model_name)
.bind_tools(tools))
print(model_with_tools.invoke("what's the weather in sf?").tool_calls)
[{'name': 'get_weather', 'args': {'location': 'sf'}, 'id': 'ba41aa58-1d28-4228-bd9f-44fce328cf8c', 'type': 'tool_call'}]
如你所见,聊天模型生成的 AI 消息已经填充了 tool_calls,因此我们可以直接将其传递给 ToolNodetool_node.invoke({"messages": [model_with_tools.invoke("what's the weather in sf?")]})
{'messages': [ToolMessage(content="It's 60 degrees and foggy.", name='get_weather', tool_call_id='a433fe97-736f-4518-b8c4-c930767ea99f')]}
接下来,让我们看看如何在 LangGraph 图表中使用 ToolNode。让我们设置 ReAct agent的graph实现。该代理将一些查询作为输入,然后反复调用工具,直到它有足够的信息来解决查询。我们基本沿用上面定义好的一些代码from typing import Literal
from langgraph.graph import StateGraph, MessagesState, START, END
def should_continue(state: MessagesState):
messages = state["messages"]
last_message = messages[-1]
if last_message.tool_calls:
return "tools"
return END
def call_model(state: MessagesState):
messages = state["messages"]
response = model_with_tools.invoke(messages)
return {"messages": [response]}
workflow = StateGraph(MessagesState)
# Define the two nodes we will cycle between
workflow.add_node("agent", call_model)
workflow.add_node("tools", tool_node)
workflow.add_edge(START, "agent")
workflow.add_conditional_edges("agent", should_continue, ["tools", END])
workflow.add_edge("tools", "agent")
app = workflow.compile()
for chunk in app.stream(
{"messages": [("human", "what's the weather in sf?")]}, stream_mode="values"
):
chunk["messages"][-1].pretty_print()
================================ Human Message =================================
what's the weather in sf?
================================== Ai Message ==================================
Tool Calls:
get_weather (0969a8d8-490e-4c2d-bbaa-fda07bdd917d)
Call ID: 0969a8d8-490e-4c2d-bbaa-fda07bdd917d
Args:
location: sf
================================= Tool Message =================================
Name: get_weather
It's 60 degrees and foggy.
================================== Ai Message ==================================
The current weather in SF is 60 degrees with some fog.
for chunk in app.stream(
{"messages": [("human", "what's the weather in the coolest cities?")]},
stream_mode="values",
):
chunk["messages"][-1].pretty_print()
================================ Human Message =================================
what's the weather in the coolest cities?
================================== Ai Message ==================================
Tool Calls:
get_coolest_cities (6e1f1592-d214-40c8-929d-e6476d2881bc)
Call ID: 6e1f1592-d214-40c8-929d-e6476d2881bc
Args:
================================= Tool Message =================================
Name: get_coolest_cities
nyc, sf
================================== Ai Message ==================================
Tool Calls:
get_weather (1c308e8a-026a-4ed0-9e12-3d2512b477ac)
Call ID: 1c308e8a-026a-4ed0-9e12-3d2512b477ac
Args:
location: New York City
get_weather (a725f375-5150-4ab9-af97-eb8d3b039073)
Call ID: a725f375-5150-4ab9-af97-eb8d3b039073
Args:
location: San Francisco
================================= Tool Message =================================
Name: get_weather
It's 60 degrees and foggy.
================================== Ai Message ==================================
The weather in the coolest cities, New York City and San Francisco, is as follows:
- In New York City, it's currently 90 degrees with clear skies and sunny conditions.
- In San Francisco, it's a more comfortable 60 degrees with some fog.
Stay cool out there!
ToolNode 还可以处理工具执行期间的错误。可以通过设置 handle_tool_errors=True(默认启用)来启用/禁用此功能。