LangGraph 工具调用实战:构建 ReAct 搜索机器人
在掌握了 LangGraph 的基础入门和 StateGraph 结构后,我们进入进阶阶段——工具调用(Tool Calling)。通过为聊天机器人集成 Tavily 搜索引擎,我们可以实现经典的 ReAct(Reasoning + Acting)模式,让 AI 具备主动获取实时信息的能力。
核心概念
什么是工具调用
工具调用是 LLM 的关键能力之一,它允许模型在推理过程中执行外部操作。其核心流程包括:
- 推理(Reasoning):理解用户意图,判断是否需要外部数据。
- 行动(Acting):调用预定义的工具获取数据。
- 观察(Observation):整合工具返回的结果生成最终回答。
这就是 ReAct 模式的本质。相比纯 LLM,带工具调用的系统能解决知识截止、计算精度不足、无法访问数据库等局限。
| 场景 | 纯 LLM | 带工具调用的 LLM |
|---|---|---|
| 实时信息 | ❌ 知识截止 | ✅ 调用搜索工具 |
| 数学计算 | ❌ 容易出错 | ✅ 调用计算器 |
| 数据库查询 | ❌ 无法访问 | ✅ 调用 SQL 工具 |
架构组件
一个典型的工具调用架构包含以下部分:
- 工具定义:如 TavilySearch、Calculator 等。
- 工具绑定:使用
llm.bind_tools(tools)将工具注入模型上下文。 - 工具节点:负责执行具体的工具调用逻辑。
- 条件路由:判断当前状态是否需要继续调用工具或结束。
- 循环执行:Chatbot ↔ Tools 形成 ReAct 闭环。
环境准备
依赖安装
确保已安装必要的库:
pip install langgraph langchain langchain-openai langchain-community pydantic python-dotenv typing-extensions
配置密钥
创建 .env 文件存储敏感信息,避免硬编码:
# 模型服务 API 密钥
SILICONFLOW_API_KEY=your_api_key_here
# Tavily 搜索引擎 API 密钥
TAVILY_API_KEY=your_tavily_key_here
注意:需自行申请对应的 API Key 并填入。
代码实现
完整代码示例
下面是一个完整的实现,展示了如何构建支持搜索的聊天机器人。
"""
LangGraph 工具调用示例:为聊天机器人添加网页搜索功能
当模型无法凭记忆回答时,自动调用工具查找信息
"""
import warnings
warnings.filterwarnings("ignore", category=DeprecationWarning)
warnings.filterwarnings("ignore", category=UserWarning)
typing Annotated
typing_extensions TypedDict
langgraph.graph StateGraph, START, END
langgraph.graph.message add_messages
langchain_openai ChatOpenAI
langchain_core.messages ToolMessage
langchain_community.tools.tavily_search TavilySearchResults
dotenv load_dotenv
json
os
load_dotenv()
os.getenv():
ValueError()
():
messages: Annotated[, add_messages]
:
() -> :
.tools_by_name = {tool.name: tool tool tools}
():
messages := inputs.get(, []):
message = messages[-]
:
ValueError()
outputs = []
tool_call message.tool_calls:
tool_result = .tools_by_name[tool_call[]].invoke(
tool_call[]
)
outputs.append(
ToolMessage(
content=json.dumps(tool_result, ensure_ascii=),
name=tool_call[],
tool_call_id=tool_call[],
)
)
{: outputs}
():
(state, ):
ai_message = state[-]
messages := state.get(, []):
ai_message = messages[-]
:
ValueError()
(ai_message, ) (ai_message.tool_calls) > :
END
():
graph_builder = StateGraph(State)
llm = ChatOpenAI(
model=,
openai_api_key=os.getenv(),
openai_api_base=,
temperature=
)
tool = TavilySearchResults(max_results=)
tools = [tool]
llm_with_tools = llm.bind_tools(tools)
():
{: [llm_with_tools.invoke(state[])]}
graph_builder.add_node(, chatbot)
tool_node = BasicToolNode(tools=tools)
graph_builder.add_node(, tool_node)
graph_builder.add_edge(START, )
graph_builder.add_conditional_edges(
,
route_tools,
{: , END: END}
)
graph_builder.add_edge(, )
graph_builder.()
():
event graph.stream({: [{: , : user_input}]}):
value event.values():
value:
last_message = value[][-]
(last_message, ) last_message.content:
(last_message, ToolMessage):
(, last_message.content)
():
()
( * )
()
()
graph = create_graph()
:
:
user_input = ()
user_input.lower() [, , ]:
()
stream_graph_updates(graph, user_input)
()
KeyboardInterrupt:
()
Exception e:
()
__name__ == :
main()


