📖 Day 7 学习页:LangGraph 入门

Day 7:LangGraph 入门——把 ReAct 循环装进"图"里

🎯 今日目标:理解为什么生产级 Agent 都用"图"来组织:状态显式、路由可控、可持久化。 用 LangGraph 的 StateGraph 重写 Day 6 的 Agent(没装库也有模拟器先跑通逻辑)。

📚 本日资源:📝 练习模板 | ✅ 验收脚本

⏱ 今日安排(约 2 小时)

时间内容方式
40min理论学习:图的核心概念 + 与手写循环的对应阅读
50min动手实操:State / Nodes / Router / run_agent编码
30min升级真实库:装 langgraph 重写 build_agent_graph编码

📖 第一步:理论学习

1. 为什么 Day 6 的 while 循环不够用

手写循环 hardcode 了"调 LLM → 执行工具"这一种流转。真实 Agent 需要: 多 Agent 切换、人工审批节点、失败重试分支、断点恢复……全塞进 for 循环就是面条地狱。 图(Graph)把"有哪些步骤"和"步骤间怎么流转"显式声明出来,框架负责执行流转。

2. LangGraph 四个核心概念

概念是什么对应 Day 6 的
State(状态)一个 TypedDict,所有节点共享读写你手写的 steps 列表 + messages
Node(节点)一个函数:读 state → 干活 → 返回 state 更新react_agent 循环体里的一段
Edge(边)固定流转:A 完了必到 B循环体里的先后顺序
Conditional Edge(条件边)路由函数决定下一步去哪if 有 tool_calls: 执行工具 else: 结束
from langgraph.graph import StateGraph, END
from typing import TypedDict, List, Dict

class AgentState(TypedDict):        # ① 状态
    messages: List[Dict]
    step_count: int

def node_call_model(state):         # ② 节点:调 LLM
    response = mock_llm_response(state["messages"])
    return {"messages": state["messages"] + [response],
             "step_count": state["step_count"] + 1}

def node_call_tool(state):          # ② 节点:执行工具
    ...把每个 tool_call 的结果以 role=tool 追加进 messages...

def router(state):                  # ③ 路由函数
    if state["messages"][-1].get("tool_calls"):
        return "call_tool"          # 还有工具要执行
    return "end"                    # 没有了 → 结束

graph = StateGraph(AgentState)      # ④ 组装
graph.add_node("call_model", node_call_model)
graph.add_node("call_tool", node_call_tool)
graph.set_entry_point("call_model")
graph.add_conditional_edges("call_model", router,
    {"call_tool": "call_tool", "end": END})
graph.add_edge("call_tool", "call_model")   # 执行完工具 → 回到模型
app = graph.compile()

3. 手写循环 vs 图(一一对应,帮助理解)

Day 6:  for step in range(max_steps):      Day 7:  图的自动流转
        prompt = build(...)                        node_call_model
        response = llm(prompt)                       │
        if 有 tool_calls:                    router ─┤ call_tool → 回 call_model
            execute + 回传                           └ end → END
        else: return 最终回答

🛠 第二步:动手实操

  1. 先跑模拟器:模板内置 simulate_langgraph_loop(),不需要装库。 完成 TODO 让它正确执行工具并给出最终回答。
  2. 打开模板:day07_practice_template.py:
    • TODO 1.1:AgentState 加 messages / step_count 字段
    • TODO 2.2 / 2.3:工具列表转换 + 执行(Day 4 原题)
    • TODO 4.1 / 4.2:node_call_model / node_call_tool(读 state → 返回更新)
    • TODO 5.1:router_should_continue(有 tool_calls → "call_tool",否则 "end")
    • TODO 7.1:run_agent() —— 装了 langgraph 就 graph.invoke(state),没装降级调模拟器
  3. 升级真实库(推荐):pip install langgraph,把 build_agent_graph() 里的注释展开成真实实现—— 组件函数你都已经写好,组装只需 8 行。
  4. 验收:python day07_practice_validator.py —— 验收会构造 state 逐个调用你的节点函数、 试探你的路由、并端到端跑一遍(回答里必须真的包含工具结果)。

⚠️ 避坑

  • ❌ LangChain 系版本更新快(0.1→0.2→0.3),看文档先对版本;本练习核心是图思想,API 细节随时查
  • ❌ 节点函数直接改传入的 state(原地修改)—— 正确姿势是返回更新字段,由框架合并
  • ❌ 路由返回值和 add_conditional_edges 的映射表对不上 → 图编译完一跑就报错
  • ✅ 先用 mock/模拟器把流转跑对,再换真实 LLM——排查问题时能省一半时间

🔗 延伸资源