LangGraph 工具调用集成

从原理→工具集成→从零实现 ReAct Agent,

完整讲清楚 LangGraph 工具调用,

并对比为什么它比 LangChain Agent 更灵活、更好定制。


一、LangGraph 工具调用集成:核心原理

1.1 为什么 LangGraph 更适合做 Agent / 工具调用

LangChain Agent(旧):

  • 黑盒化:initialize_agent 把循环、状态、路由全封装了
  • 流程固定:思考→工具→观察→思考,很难插自定义节点(校验、重试、分支)
  • 状态弱:靠消息链传递,无法自由加字段、做分支判断

LangGraph(新范式):

  • 白盒化:节点、边、状态全由你定义,每一步可控
  • 原生循环:支持任意有环图(ReAct、反思、多轮检索都很自然)
  • 强状态 :全局 State,可随意加字段(loop_counttool_resultsreflection
  • 条件边 :灵活 if/else,想走哪条分支就走哪条

一句话:

LangChain Agent = 预制好的房子;LangGraph = 你自己砌墙、布线、设计格局

1.2 LangGraph 工具调用的核心组件

  1. State(状态):全局共享,存消息、工具结果、计数器等
  2. Tool(工具) :LangChain 标准工具(@tool 装饰器),可无缝复用
  3. Node(节点)
    • llm_node:LLM 思考并决定是否调用工具
    • tool_node:执行工具调用
  4. 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-dotenv

2.2 完整代码(含工具、状态、节点、条件边)

复制代码
import os
from typing import TypedDict, Literal, Sequence, Annotated

from dotenv import load_dotenv
from langchain_core.messages import BaseMessage, HumanMessage
from langchain_core.tools import tool
from langchain_openai import ChatOpenAI
from langgraph.constants import START, END
from langgraph.graph import StateGraph, add_messages
from langgraph.prebuilt import ToolNode

# 加载环境
load_dotenv()

# 定义工具 可任意扩展
@tool
def get_weather(city: str) -> str:
    """获取指定城市的天气"""
    if city == "北京":
        return f"北京:晴,25℃,微风"
    elif city == "上海":
        return f"上海:多云,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]
# tools_zhihu = [convert_to_openai_tool(t) for t in tools]

# 定义 State (强状态 可自由扩展)
class ReActState(TypedDict):
    # messages: Sequence[BaseMessage] # 消息历史
    messages: Annotated[Sequence[BaseMessage], add_messages] # ✅ 明确指定追加模式
    loop_count: int     # 循环次数(防死循环)

# 初始化 LLM 绑定工具
llm = ChatOpenAI(
    api_key=os.getenv("ZHIPU_API_KEY"),
    base_url=os.getenv("ZHIPU_BASE_URL"),
    model=os.getenv("LLM_MODEL"),
    temperature=0
).bind_tools(tools)
# 关键: 绑定工具 让LLM能生成tool_call
# ✅ 智谱唯一能识别的工具绑定方式
# llm_with_tools = llm.bind(tools=tools)

# 定义节点
# 节点1: LLM思考节点
def llm_think(state: ReActState) -> ReActState:
    print(f"\n-- 第 {state['loop_count']} 轮:LLM 思考--")
    message = state["messages"]
    response = llm.invoke(message)
    # 返回新的state:追加AI 消息, 循环次数 + 1
    return {
        "messages": [response], #  # 只返回新消息,LangGraph 自动追加
        "loop_count": state["loop_count"] + 1
    }


# 节点2:工具执行节点 LangGraph 内置 ToolNode 直接用
tool_executor = ToolNode(tools)

# 定义条件路由 核心 决定继续循环还是结束
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"

# 构建图 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()

# 运行测试
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 思考--
→ 结束:无需工具 或 达到最大轮次

 ===== 最终答案 =====
根据查询结果:

**北京今天天气**:晴,25℃

**上海温度**:28℃(比北京高3度)

进程已结束,退出代码为 0

流程:

  1. 第 0 轮:LLM 决定调用 get_weather(北京)
  2. 执行工具 → 拿到北京天气
  3. 第 1 轮:LLM 决定调用 calculator(25,3,+)
  4. 执行工具 → 拿到上海温度
  5. 第 2 轮:LLM 直接回答,无工具调用 → 结束

四、LangGraph vs LangChain Agent:关键差异(为什么更灵活)

4.1 定制节点:想插就插

LangChain Agent:

  • 无法在 "思考→工具" 中间插节点(如 "工具调用前校验参数")

LangGraph:

  • 随便加节点:llm → 校验参数 → 工具执行 → 结果格式化 → llm
  • 示例:加一个 validate_tool_call 节点,检查参数是否合法

4.2 自由状态:想加字段就加

LangChain Agent:

  • 状态固定为消息链,想加 reflectionconfidence 很难

LangGraph:

复制代码
class 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 步:

  1. State 加 reflection 字段
  2. reflect_node:LLM 检查工具结果是否足够
  3. 条件边:反思不合格 → 重新生成工具调用;合格 → 结束

六、langchain 和 langgraph 模块相关版本

langchain 0.3.29

langchain-community 0.3.31

langchain-core 0.3.85

langchain-openai 0.3.35

langchain-text-splitters 0.3.11

langgraph 0.2.56

langgraph-checkpoint 2.1.2

langgraph-sdk 0.1.74

代码关于兼容智普AI做了优化

相关推荐
Chef_Chen1 小时前
Agent-自我反思机制
agent
MATLAB代码顾问1 小时前
【智能优化】无穷优化算法(INFO)原理与Python实现
开发语言·python·算法
SilentSamsara1 小时前
迭代器协议:`__iter__` / `__next__` 的完整执行流程
开发语言·人工智能·python·算法·机器学习
yuanpan1 小时前
Python + psutil 实战:开发一个简易系统监控工具
linux·运维·python
swipe1 小时前
别把 Agent 写成一团 Prompt:用 LangGraph 把多 Agent 系统变成可控状态机
后端·langchain·llm
MATLAB代码顾问2 小时前
【智能优化】鹈鹕优化算法(POA)原理与Python实现
开发语言·python·算法
研究点啥好呢2 小时前
凯捷 自动化测试(Java+Selenium)面试题精选:10道高频考题+答案解析
java·开发语言·python·selenium·测试工具·求职招聘
古茗前端团队2 小时前
Agent Skills 原理及其在中后台页面中的实践
agent
SilentSamsara2 小时前
生成器进阶:`yield from`、协程历史与双向通信
开发语言·python·青少年编程·pycharm