
从原理→工具集成→从零实现 ReAct Agent完整讲清楚 LangGraph 工具调用并对比为什么它比 LangChain Agent 更灵活、更好定制。一、LangGraph 工具调用集成核心原理1.1 为什么 LangGraph 更适合做 Agent / 工具调用LangChain Agent旧黑盒化initialize_agent把循环、状态、路由全封装了流程固定思考→工具→观察→思考很难插自定义节点校验、重试、分支状态弱靠消息链传递无法自由加字段、做分支判断LangGraph新范式白盒化节点、边、状态全由你定义每一步可控原生循环支持任意有环图ReAct、反思、多轮检索都很自然强状态全局State可随意加字段loop_count、tool_results、reflection条件边灵活if/else想走哪条分支就走哪条一句话LangChain Agent 预制好的房子LangGraph 你自己砌墙、布线、设计格局1.2 LangGraph 工具调用的核心组件State状态全局共享存消息、工具结果、计数器等Tool工具LangChain 标准工具tool装饰器可无缝复用Node节点llm_nodeLLM 思考并决定是否调用工具tool_node执行工具调用Edge / Conditional Edge线性边llm → tool条件边tool → llm循环或llm → end结束1.3 ReAct 标准流程LangGraph 原生支持用户问题 → LLM 思考 → 是否调用工具 ├─ 否 → 输出答案结束 └─ 是 → 执行工具 → 拿到结果 → 回到 LLM 再思考循环二、从零实现LangGraph ReAct Agent可直接运行2.1 安装依赖pip install -U langgraph langchain-openai python-dotenv2.2 完整代码含工具、状态、节点、条件边import os from dotenv import load_dotenv from typing import TypedDict, Annotated, Sequence, Literal from langchain_core.messages import BaseMessage, HumanMessage, AIMessage, ToolMessage from langchain_core.tools import tool from langchain_openai import ChatOpenAI from langgraph.graph import StateGraph, START, END from langgraph.prebuilt import ToolNode # 加载环境变量 load_dotenv() # -------------------------- 1. 定义工具可任意扩展-------------------------- tool def get_weather(city: str) - str: 获取指定城市的天气 if city 北京: return 北京晴25℃微风 elif city 上海: return 上海多云28℃东南风 else: return f{city}未知仅支持北京/上海 tool def calculator(a: float, b: float, op: str) - float: 计算器支持 - * / if op : return a b elif op -: return a - b elif op *: return a * b elif op /: return a / b if b ! 0 else 除数不能为0 else: return 不支持的运算符 tools [get_weather, calculator] # -------------------------- 2. 定义 State强状态可自由扩展-------------------------- class ReActState(TypedDict): messages: Sequence[BaseMessage] # 消息历史 loop_count: int # 循环次数防死循环 # -------------------------- 3. 初始化 LLM绑定工具-------------------------- llm ChatOpenAI( api_keyos.getenv(OPENAI_API_KEY), modelgpt-3.5-turbo, temperature0 ).bind_tools(tools) # 关键绑定工具让 LLM 能生成 tool_call # -------------------------- 4. 定义节点 -------------------------- # 节点1LLM 思考节点 def llm_think(state: ReActState) - ReActState: print(f\n--- 第 {state[loop_count]} 轮LLM 思考 ---) messages state[messages] response llm.invoke(messages) # 返回新 state追加 AI 消息循环计数1 return { messages: messages [response], loop_count: state[loop_count] 1 } # 节点2工具执行节点LangGraph 内置 ToolNode直接用 tool_executor ToolNode(tools) # -------------------------- 5. 定义条件路由核心决定继续循环还是结束-------------------------- def should_continue(state: ReActState) - Literal[continue, end]: last_msg state[messages][-1] # 终止条件 # 1. LLM 没有生成 tool_call直接回答 # 2. 循环次数 ≥ 5防死循环 if not last_msg.tool_calls or state[loop_count] 5: print(→ 结束无需工具 或 达到最大轮次) return end else: print(→ 继续需要调用工具) return continue # -------------------------- 6. 构建图ReAct 循环-------------------------- builder StateGraph(ReActState) # 添加节点 builder.add_node(llm_think, llm_think) builder.add_node(tool_executor, tool_executor) # 边开始 → LLM 思考 builder.add_edge(START, llm_think) # 边LLM 思考 → 条件判断继续/结束 builder.add_conditional_edges( llm_think, should_continue, { continue: tool_executor, # 继续去执行工具 end: END # 结束直接输出答案 } ) # 边工具执行 → 回到 LLM 思考循环核心 builder.add_edge(tool_executor, llm_think) # 编译图 react_agent builder.compile() # -------------------------- 7. 运行测试 -------------------------- if __name__ __main__: print( LangGraph ReAct Agent 启动 ) # 初始状态用户问题 循环计数0 initial_state { messages: [HumanMessage(content北京今天天气上海比北京高3度上海多少度)], loop_count: 0 } # 调用 Agent result react_agent.invoke(initial_state) # 输出最终答案 print(\n 最终答案 ) print(result[messages][-1].content)三、运行结果解析清晰看到循环 LangGraph ReAct Agent 启动 --- 第 0 轮LLM 思考 --- → 继续需要调用工具 --- 第 1 轮LLM 思考 --- → 继续需要调用工具 --- 第 2 轮LLM 思考 --- → 结束无需工具 或 达到最大轮次 最终答案 上海今天的温度是28℃比北京高3℃。流程第 0 轮LLM 决定调用get_weather(北京)执行工具 → 拿到北京天气第 1 轮LLM 决定调用calculator(25,3,)执行工具 → 拿到上海温度第 2 轮LLM 直接回答无工具调用 → 结束四、LangGraph vs LangChain Agent关键差异为什么更灵活4.1 定制节点想插就插LangChain Agent无法在 “思考→工具” 中间插节点如 “工具调用前校验参数”LangGraph随便加节点llm → 校验参数 → 工具执行 → 结果格式化 → llm示例加一个validate_tool_call节点检查参数是否合法4.2 自由状态想加字段就加LangChain Agent状态固定为消息链想加reflection、confidence很难LangGraphclass ReActState(TypedDict): messages: Sequence[BaseMessage] loop_count: int reflection: str # 可加反思结果 confidence: float # 可加置信度 tool_results: dict # 可加工具结果缓存4.3 复杂分支轻松实现LangGraph 可做多工具并行调用工具失败重试最多 3 次不同工具结果走不同分支人工介入审批human-in-the-loop五、扩展给 ReAct 加 “反思”更高级只需 3 步State 加reflection字段加reflect_nodeLLM 检查工具结果是否足够条件边反思不合格 → 重新生成工具调用合格 → 结束