调用工具¶
工具封装了一个可调用函数及其输入模式。它们可以传递给兼容的聊天模型,让模型决定是否调用工具并确定合适的参数。
定义工具¶
使用@tool装饰器定义一个基本工具
API 参考:tool
from langchain_core.tools import tool
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
运行工具¶
工具符合Runnable 接口,这意味着您可以使用invoke
方法运行工具
如果工具以type="tool_call"
调用,它将返回一个ToolMessage
tool_call = {
"type": "tool_call",
"id": "1",
"args": {"a": 42, "b": 7}
}
multiply.invoke(tool_call) # returns a ToolMessage object
输出
在代理中使用¶
要创建工具调用代理,您可以使用预构建的create_react_agent
API 参考: tool | create_react_agent
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet",
tools=[multiply]
)
agent.invoke({"messages": [{"role": "user", "content": "what's 42 x 7?"}]})
在工作流中使用¶
如果您正在编写自定义工作流,则需要
- 向聊天模型注册工具
- 如果模型决定使用,则调用工具
使用model.bind_tools()
将工具注册到模型。
API 参考: init_chat_model
from langchain.chat_models import init_chat_model
model = init_chat_model(model="claude-3-5-haiku-latest")
model_with_tools = model.bind_tools([multiply])
LLM 会自动判断是否需要调用工具,并处理使用适当参数调用工具的情况。
扩展示例: 将工具附加到聊天模型
from langchain_core.tools import tool
from langchain.chat_models import init_chat_model
@tool
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
model = init_chat_model(model="claude-3-5-haiku-latest")
model_with_tools = model.bind_tools([multiply])
response_message = model_with_tools.invoke("what's 42 x 7?")
tool_call = response_message.tool_calls[0]
multiply.invoke(tool_call)
ToolNode¶
要在自定义工作流中执行工具,请使用预构建的ToolNode
或实现您自己的自定义节点。
ToolNode
是一个专门用于在工作流中执行工具的节点。它提供以下功能:
- 支持同步和异步工具。
- 并发执行多个工具。
- 处理工具执行期间的错误(
handle_tool_errors=True
,默认启用)。更多详细信息请参见处理工具错误。
ToolNode
对 MessagesState
进行操作
- 输入:
MessagesState
,其中最后一条消息是包含tool_calls
参数的AIMessage
。 - 输出:
MessagesState
已更新,包含执行工具后产生的ToolMessage
。
API 参考: ToolNode
from langgraph.prebuilt import ToolNode
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."
def get_coolest_cities():
"""Get a list of coolest cities"""
return "nyc, sf"
tool_node = ToolNode([get_weather, get_coolest_cities])
tool_node.invoke({"messages": [...]})
单个工具调用
from langchain_core.messages import AIMessage
from langgraph.prebuilt import ToolNode
# Define tools
@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_node = ToolNode([get_weather])
message_with_single_tool_call = AIMessage(
content="",
tool_calls=[
{
"name": "get_weather",
"args": {"location": "sf"},
"id": "tool_call_id",
"type": "tool_call",
}
],
)
tool_node.invoke({"messages": [message_with_single_tool_call]})
多个工具调用
from langchain_core.messages import AIMessage
from langgraph.prebuilt import ToolNode
# Define tools
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."
def get_coolest_cities():
"""Get a list of coolest cities"""
return "nyc, sf"
tool_node = ToolNode([get_weather, get_coolest_cities])
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",
},
],
)
tool_node.invoke({"messages": [message_with_multiple_tool_calls]}) # (1)!
ToolNode
将并行执行这两个工具
与聊天模型一起使用
from langchain.chat_models import init_chat_model
from langgraph.prebuilt import ToolNode
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_node = ToolNode([get_weather])
model = init_chat_model(model="claude-3-5-haiku-latest")
model_with_tools = model.bind_tools([get_weather]) # (1)!
response_message = model_with_tools.invoke("what's the weather in sf?")
tool_node.invoke({"messages": [response_message]})
- 使用
.bind_tools()
将工具模式附加到聊天模型
在工具调用代理中使用
这是一个使用ToolNode
从头开始创建工具调用代理的示例。您也可以使用 LangGraph 的预构建代理。
from langchain.chat_models import init_chat_model
from langgraph.prebuilt import ToolNode
from langgraph.graph import StateGraph, MessagesState, START, END
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_node = ToolNode([get_weather])
model = init_chat_model(model="claude-3-5-haiku-latest")
model_with_tools = model.bind_tools([get_weather])
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]}
builder = StateGraph(MessagesState)
# Define the two nodes we will cycle between
builder.add_node("call_model", call_model)
builder.add_node("tools", tool_node)
builder.add_edge(START, "call_model")
builder.add_conditional_edges("call_model", should_continue, ["tools", END])
builder.add_edge("tools", "call_model")
graph = builder.compile()
graph.invoke({"messages": [{"role": "user", "content": "what's the weather in sf?"}]})
{
'messages': [
HumanMessage(content="what's the weather in sf?"),
AIMessage(
content=[{'text': "I'll help you check the weather in San Francisco right now.", 'type': 'text'}, {'id': 'toolu_01A4vwUEgBKxfFVc5H3v1CNs', 'input': {'location': 'San Francisco'}, 'name': 'get_weather', 'type': 'tool_use'}],
tool_calls=[{'name': 'get_weather', 'args': {'location': 'San Francisco'}, 'id': 'toolu_01A4vwUEgBKxfFVc5H3v1CNs', 'type': 'tool_call'}]
),
ToolMessage(content="It's 60 degrees and foggy."),
AIMessage(content="The current weather in San Francisco is 60 degrees and foggy. Typical San Francisco weather with its famous marine layer!")
]
}
工具定制¶
要更精细地控制工具行为,请使用@tool
装饰器。
参数描述¶
从文档字符串自动生成描述
API 参考:tool
from langchain_core.tools import tool
@tool("multiply_tool", parse_docstring=True)
def multiply(a: int, b: int) -> int:
"""Multiply two numbers.
Args:
a: First operand
b: Second operand
"""
return a * b
显式输入模式¶
使用args_schema
定义模式
API 参考:tool
from pydantic import BaseModel, Field
from langchain_core.tools import tool
class MultiplyInputSchema(BaseModel):
"""Multiply two numbers"""
a: int = Field(description="First operand")
b: int = Field(description="Second operand")
@tool("multiply_tool", args_schema=MultiplyInputSchema)
def multiply(a: int, b: int) -> int:
return a * b
工具名称¶
使用第一个参数覆盖默认工具名称(函数名称)
API 参考:tool
from langchain_core.tools import tool
@tool("multiply_tool")
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
上下文管理¶
LangGraph 中的工具有时需要上下文数据,例如仅运行时参数(例如用户 ID 或会话详细信息),这些参数不应由模型控制。LangGraph 提供了三种管理此类上下文的方法
类型 | 使用场景 | 可变 | 生命周期 |
---|---|---|---|
配置 | 静态的、不可变的运行时数据 | ❌ | 单次调用 |
短期记忆 | 调用期间动态变化的数据 | ✅ | 单次调用 |
长期记忆 | 持久的、跨会话数据 | ✅ | 跨多个会话 |
配置¶
当您拥有工具所需的不可变运行时数据(例如用户标识符)时,请使用配置。您可以通过RunnableConfig
在调用时传递这些参数,并在工具中访问它们
API 参考: tool | RunnableConfig
from langchain_core.tools import tool
from langchain_core.runnables import RunnableConfig
@tool
def get_user_info(config: RunnableConfig) -> str:
"""Retrieve user information based on user ID."""
user_id = config["configurable"].get("user_id")
return "User is John Smith" if user_id == "user_123" else "Unknown user"
# Invocation example with an agent
agent.invoke(
{"messages": [{"role": "user", "content": "look up user info"}]},
config={"configurable": {"user_id": "user_123"}}
)
扩展示例: 在工具中访问配置
from langchain_core.runnables import RunnableConfig
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
def get_user_info(
config: RunnableConfig,
) -> str:
"""Look up user info."""
user_id = config["configurable"].get("user_id")
return "User is John Smith" if user_id == "user_123" else "Unknown user"
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_user_info],
)
agent.invoke(
{"messages": [{"role": "user", "content": "look up user information"}]},
config={"configurable": {"user_id": "user_123"}}
)
短期记忆¶
短期记忆维护在单次执行期间会变化的动态状态。
要访问(读取)工具内部的图状态,您可以使用特殊的参数注解 — InjectedState
API 参考: tool | InjectedState | create_react_agent | AgentState
from typing import Annotated, NotRequired
from langchain_core.tools import tool
from langgraph.prebuilt import InjectedState, create_react_agent
from langgraph.prebuilt.chat_agent_executor import AgentState
class CustomState(AgentState):
# The user_name field in short-term state
user_name: NotRequired[str]
@tool
def get_user_name(
state: Annotated[CustomState, InjectedState]
) -> str:
"""Retrieve the current user-name from state."""
# Return stored name or a default if not set
return state.get("user_name", "Unknown user")
# Example agent setup
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_user_name],
state_schema=CustomState,
)
# Invocation: reads the name from state (initially empty)
agent.invoke({"messages": "what's my name?"})
使用返回Command
的工具来更新user_name
并附加确认消息
API 参考: Command | ToolMessage | tool | InjectedToolCallId
from typing import Annotated
from langgraph.types import Command
from langchain_core.messages import ToolMessage
from langchain_core.tools import tool, InjectedToolCallId
@tool
def update_user_name(
new_name: str,
tool_call_id: Annotated[str, InjectedToolCallId]
) -> Command:
"""Update user-name in short-term memory."""
return Command(update={
"user_name": new_name,
"messages": [
ToolMessage(f"Updated user name to {new_name}", tool_call_id=tool_call_id)
]
})
重要
如果您想使用返回Command
并更新图状态的工具,您可以使用预构建的create_react_agent
/ ToolNode
组件,或者实现您自己的工具执行节点,该节点收集工具返回的Command
对象并返回它们的列表,例如:
长期记忆¶
使用长期记忆在对话中存储用户特定或应用程序特定的数据。这对于聊天机器人等应用程序非常有用,您可以在其中记住用户偏好或其他信息。
要使用长期记忆,您需要:
要访问存储中的信息
API 参考: RunnableConfig | tool | StateGraph | get_store
from langchain_core.runnables import RunnableConfig
from langchain_core.tools import tool
from langgraph.graph import StateGraph
from langgraph.config import get_store
@tool
def get_user_info(config: RunnableConfig) -> str:
"""Look up user info."""
# Same as that provided to `builder.compile(store=store)`
# or `create_react_agent`
store = get_store()
user_id = config["configurable"].get("user_id")
user_info = store.get(("users",), user_id)
return str(user_info.value) if user_info else "Unknown user"
builder = StateGraph(...)
...
graph = builder.compile(store=store)
访问长期记忆
from langchain_core.runnables import RunnableConfig
from langchain_core.tools import tool
from langgraph.config import get_store
from langgraph.prebuilt import create_react_agent
from langgraph.store.memory import InMemoryStore
store = InMemoryStore() # (1)!
store.put( # (2)!
("users",), # (3)!
"user_123", # (4)!
{
"name": "John Smith",
"language": "English",
} # (5)!
)
@tool
def get_user_info(config: RunnableConfig) -> str:
"""Look up user info."""
# Same as that provided to `create_react_agent`
store = get_store() # (6)!
user_id = config["configurable"].get("user_id")
user_info = store.get(("users",), user_id) # (7)!
return str(user_info.value) if user_info else "Unknown user"
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[get_user_info],
store=store # (8)!
)
# Run the agent
agent.invoke(
{"messages": [{"role": "user", "content": "look up user information"}]},
config={"configurable": {"user_id": "user_123"}}
)
InMemoryStore
是一种将数据存储在内存中的存储。在生产环境中,您通常会使用数据库或其他持久存储。请查阅[存储文档][../reference/store.md)以获取更多选项。如果您使用 LangGraph Platform 进行部署,该平台将为您提供生产就绪的存储。- 在此示例中,我们使用
put
方法向存储写入一些示例数据。有关更多详细信息,请参阅BaseStore.put API 参考。 - 第一个参数是命名空间。这用于将相关数据分组。在本例中,我们使用
users
命名空间来分组用户数据。 - 命名空间中的键。此示例使用用户 ID 作为键。
- 我们希望为给定用户存储的数据。
get_store
函数用于访问存储。您可以在代码的任何地方调用它,包括工具和提示。此函数返回创建代理时传递给代理的存储。get
方法用于从存储中检索数据。第一个参数是命名空间,第二个参数是键。这将返回一个StoreValue
对象,其中包含值和有关值的元数据。store
被传递给代理。这使得代理在运行工具时可以访问存储。您还可以使用get_store
函数从代码的任何地方访问存储。
要更新存储中的信息
API 参考: RunnableConfig | tool | StateGraph | get_store
from langchain_core.runnables import RunnableConfig
from langchain_core.tools import tool
from langgraph.graph import StateGraph
from langgraph.config import get_store
@tool
def save_user_info(user_info: str, config: RunnableConfig) -> str:
"""Save user info."""
# Same as that provided to `builder.compile(store=store)`
# or `create_react_agent`
store = get_store()
user_id = config["configurable"].get("user_id")
store.put(("users",), user_id, user_info)
return "Successfully saved user info."
builder = StateGraph(...)
...
graph = builder.compile(store=store)
更新长期记忆
from typing_extensions import TypedDict
from langchain_core.tools import tool
from langgraph.config import get_store
from langgraph.prebuilt import create_react_agent
from langgraph.store.memory import InMemoryStore
store = InMemoryStore() # (1)!
class UserInfo(TypedDict): # (2)!
name: str
@tool
def save_user_info(user_info: UserInfo, config: RunnableConfig) -> str: # (3)!
"""Save user info."""
# Same as that provided to `create_react_agent`
store = get_store() # (4)!
user_id = config["configurable"].get("user_id")
store.put(("users",), user_id, user_info) # (5)!
return "Successfully saved user info."
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[save_user_info],
store=store
)
# Run the agent
agent.invoke(
{"messages": [{"role": "user", "content": "My name is John Smith"}]},
config={"configurable": {"user_id": "user_123"}} # (6)!
)
# You can access the store directly to get the value
store.get(("users",), "user_123").value
InMemoryStore
是一种将数据存储在内存中的存储。在生产环境中,您通常会使用数据库或其他持久存储。请查阅存储文档以获取更多选项。如果您使用 LangGraph Platform 进行部署,该平台将为您提供生产就绪的存储。UserInfo
类是一个TypedDict
,它定义了用户信息结构。LLM 将使用它根据模式格式化响应。save_user_info
函数是一个工具,允许代理更新用户信息。这对于用户希望更新其个人资料信息的聊天应用程序非常有用。get_store
函数用于访问存储。您可以在代码的任何地方调用它,包括工具和提示。此函数返回创建代理时传递给代理的存储。put
方法用于将数据存储在存储中。第一个参数是命名空间,第二个参数是键。这将把用户信息存储在存储中。user_id
在配置中传递。这用于识别正在更新其信息的用户。
高级工具功能¶
即时返回¶
使用return_direct=True
立即返回工具结果,而无需执行额外的逻辑。
这对于不应触发进一步处理或工具调用的工具非常有用,允许您将结果直接返回给用户。
扩展示例: 在预构建代理中使用 return_direct
from langchain_core.tools import tool
from langgraph.prebuilt import create_react_agent
@tool(return_direct=True)
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[add]
)
agent.invoke(
{"messages": [{"role": "user", "content": "what's 3 + 5?"}]}
)
不使用预构建组件
如果您正在构建自定义工作流且不依赖create_react_agent
或ToolNode
,您还需要实现控制流来处理return_direct=True
。
强制使用工具¶
如果您需要强制使用某个特定工具,您需要在模型级别使用bind_tools
方法中的tool_choice
参数进行配置。
通过 tool_choice 强制使用特定工具
@tool(return_direct=True)
def greet(user_name: str) -> int:
"""Greet user."""
return f"Hello {user_name}!"
tools = [greet]
configured_model = model.bind_tools(
tools,
# Force the use of the 'greet' tool
tool_choice={"type": "tool", "name": "greet"}
)
扩展示例: 在代理中强制使用工具
要强制代理使用特定工具,您可以在model.bind_tools()
中设置tool_choice
选项
from langchain_core.tools import tool
@tool(return_direct=True)
def greet(user_name: str) -> int:
"""Greet user."""
return f"Hello {user_name}!"
tools = [greet]
agent = create_react_agent(
model=model.bind_tools(tools, tool_choice={"type": "tool", "name": "greet"}),
tools=tools
)
agent.invoke(
{"messages": [{"role": "user", "content": "Hi, I am Bob"}]}
)
避免无限循环
强制使用工具而没有停止条件可能会创建无限循环。请使用以下保护措施之一:
- 将工具标记为[
return_direct=True
](#immediate-return)以在执行后结束循环。 - 设置
recursion_limit
以限制执行步骤的数量。
工具选择配置
tool_choice
参数用于配置模型在决定调用工具时应使用哪个工具。当您希望确保某个特定工具始终用于特定任务,或者希望覆盖模型根据其内部逻辑选择工具的默认行为时,这会很有用。
请注意,并非所有模型都支持此功能,并且确切的配置可能因您使用的模型而异。
禁用并行调用¶
对于受支持的提供商,您可以通过model.bind_tools()
方法设置parallel_tool_calls=False
来禁用并行工具调用
扩展示例: 在预构建代理中禁用并行工具调用
from langchain.chat_models import init_chat_model
def add(a: int, b: int) -> int:
"""Add two numbers"""
return a + b
def multiply(a: int, b: int) -> int:
"""Multiply two numbers."""
return a * b
model = init_chat_model("anthropic:claude-3-5-sonnet-latest", temperature=0)
tools = [add, multiply]
agent = create_react_agent(
# disable parallel tool calls
model=model.bind_tools(tools, parallel_tool_calls=False),
tools=tools
)
agent.invoke(
{"messages": [{"role": "user", "content": "what's 3 + 5 and 4 * 7?"}]}
)
处理错误¶
LangGraph 通过预构建的ToolNode 组件提供内置的工具执行错误处理,该组件既可独立使用,也可在预构建代理中使用。
默认情况下,ToolNode
会捕获工具执行期间引发的异常,并将其作为带有错误状态的ToolMessage
对象返回。
from langchain_core.messages import AIMessage
from langgraph.prebuilt import ToolNode
def multiply(a: int, b: int) -> int:
if a == 42:
raise ValueError("The ultimate error")
return a * b
# Default error handling (enabled by default)
tool_node = ToolNode([multiply])
message = AIMessage(
content="",
tool_calls=[{
"name": "multiply",
"args": {"a": 42, "b": 7},
"id": "tool_call_id",
"type": "tool_call"
}]
)
result = tool_node.invoke({"messages": [message]})
输出
{'messages': [
ToolMessage(
content="Error: ValueError('The ultimate error')\n Please fix your mistakes.",
name='multiply',
tool_call_id='tool_call_id',
status='error'
)
]}
禁用错误处理¶
要直接传播异常,请禁用错误处理
禁用错误处理后,工具引发的异常将向上传播,需要显式管理。
自定义错误消息¶
通过将handle_tool_errors
设置为字符串来提供自定义错误消息
tool_node = ToolNode(
[multiply],
handle_tool_errors="Can't use 42 as the first operand, please switch operands!"
)
示例输出
{'messages': [
ToolMessage(
content="Can't use 42 as the first operand, please switch operands!",
name='multiply',
tool_call_id='tool_call_id',
status='error'
)
]}
代理中的错误处理¶
预构建代理(create_react_agent
)中的错误处理利用了ToolNode
API 参考:create_react_agent
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=[multiply]
)
# Default error handling
agent.invoke({"messages": [{"role": "user", "content": "what's 42 x 7?"}]})
要在预构建代理中禁用或自定义错误处理,请显式传递一个已配置的ToolNode
custom_tool_node = ToolNode(
[multiply],
handle_tool_errors="Cannot use 42 as a first operand!"
)
agent_custom = create_react_agent(
model="anthropic:claude-3-7-sonnet-latest",
tools=custom_tool_node
)
agent_custom.invoke({"messages": [{"role": "user", "content": "what's 42 x 7?"}]})
处理大量工具¶
随着可用工具数量的增长,您可能希望限制 LLM 选择的范围,以减少 token 消耗并帮助管理 LLM 推理中的错误源。
为了解决这个问题,您可以通过在运行时使用语义搜索检索相关工具来动态调整模型可用的工具。
请参阅langgraph-bigtool
预构建库以获取即用型实现。
预置工具¶
LLM 提供商工具¶
您可以通过将包含工具规格的字典传递给create_react_agent
的tools
参数来使用模型提供商的预构建工具。例如,要使用 OpenAI 的web_search_preview
工具
API 参考:create_react_agent
from langgraph.prebuilt import create_react_agent
agent = create_react_agent(
model="openai:gpt-4o-mini",
tools=[{"type": "web_search_preview"}]
)
response = agent.invoke(
{"messages": ["What was a positive news story from today?"]}
)
请查阅您所使用的特定模型的文档,以了解哪些工具可用以及如何使用它们。
LangChain 工具¶
此外,LangChain 支持广泛的预构建工具集成,用于与 API、数据库、文件系统、Web 数据等进行交互。这些工具扩展了代理的功能,并实现了快速开发。
您可以在LangChain 集成目录中浏览可用集成的完整列表。
一些常用的工具类别包括:
- 搜索: Bing、SerpAPI、Tavily
- 代码解释器: Python REPL、Node.js REPL
- 数据库:SQL、MongoDB、Redis
- 网络数据: 网页抓取和浏览
- API: OpenWeatherMap、NewsAPI 等
这些集成可以使用上面示例中所示的相同tools
参数进行配置并添加到您的代理中。