StateGraph —— LangGraph 的核心基石

python 复制代码
#!/usr/bin/env python3
"""
Task 3: StateGraph Demo - Shopping Cart
Shows how state persists and accumulates across nodes
"""

from typing import TypedDict, List
from langgraph.graph import StateGraph, START, END

print("\n🛒 STATEGRAPH DEMO - Shopping Cart")
print("=" * 40)

# Define state structure
class CartState(TypedDict):
    items: List[str]
    total: float
    status: str

def add_apple(state: CartState):
    """Add apple to cart - shows state accumulation"""
    print("\nStep 1: Adding apple ($5) to cart...")
    new_items = state["items"] + ["apple"]
    new_total = state["total"] + 5
    print(f"  → State: items={new_items}, total=${new_total}")
    return {
        "items": new_items,
        "total": new_total
    }

def add_banana(state: CartState):
    """Add banana to cart - shows accumulation continues"""
    print("\nStep 2: Adding banana ($3) to cart...")
    new_items = state["items"] + ["banana"]
    new_total = state["total"] + 3
    print(f"  → State: items={new_items}, total=${new_total}")
    return {
        "items": new_items,
        "total": new_total
    }

def checkout(state: CartState):
    """Complete purchase - shows state persistence"""
    print("\nStep 3: Processing checkout...")
    print(f"  → Final items: {state['items']}")
    print(f"  → Final total: ${state['total']}")
    return {
        "status": "paid"
    }

# Build the graph
print("\nBuilding StateGraph workflow...")
workflow = StateGraph(CartState)

# Add nodes
workflow.add_node("add_apple", add_apple)
workflow.add_node("add_banana", add_banana)
workflow.add_node("checkout", checkout)

# Define flow
workflow.set_entry_point("add_apple")
workflow.add_edge("add_apple", "add_banana")
workflow.add_edge("add_banana", "checkout")
workflow.add_edge("checkout", END)

# Compile and run
app = workflow.compile()

# Initial state
initial_state = {
    "items": [],
    "total": 0.0,
    "status": "pending"
}

print(f"\nInitial State: {initial_state}")
print("\nExecuting workflow...")

# Run the workflow
result = app.invoke(initial_state)

# Show final state
print("\n" + "=" * 40)
print("✅ FINAL STATE:")
print(f"  Items: {result['items']}")
print(f"  Total: ${result['total']}")
print(f"  Status: {result['status']}")

print("\n💡 Key Insights:")
print("  • State persisted across all nodes")
print("  • Each node added to the state")
print("  • Previous values were preserved")

# Save completion marker
try:
    with open('/root/stategraph_complete.txt', 'w') as f:
        f.write('StateGraph implementation complete\n')
        f.write(f'Final state: {result}\n')
except:
    pass  # Local testing

LangGraph Shopping Cart 示例完整逐行解读

这份代码是 LangGraph StateGraph 最基础核心演示:状态在节点间持续传递、增量更新,非常适合入门理解 LangGraph 状态流转机制。

核心知识点:StateGraphTypedDict 状态定义、节点函数、边 (Edge)、工作流编译、状态合并规则。

一、头部模块

复制代码
#!/usr/bin/env python3
"""
Task 3: StateGraph Demo - Shopping Cart
Shows how state persists and accumulates across nodes
"""

from typing import TypedDict, List
from langgraph.graph import StateGraph, START, END
  1. #!/usr/bin/env python3:Linux 脚本声明,指定用 python3 执行

  2. 文档字符串:说明演示目标 ------展示状态在多个节点之间持久保存、累积更新

  3. TypedDict:给状态做类型约束(推荐,IDE 智能提示)

  4. StateGraph:LangGraph 核心类,用于构建有状态图工作流

  5. START / END:LangGraph 内置常量,代表图的起点、终点

    print("\n🛒 STATEGRAPH DEMO - Shopping Cart")
    print("=" * 40)

控制台打印分隔标题。


二、状态定义 CartState

复制代码
class CartState(TypedDict):
    items: List[str]
    total: float
    status: str

LangGraph 状态载体定义

  • TypedDict:只定义结构,不实例化类;描述字典里有哪些 key 和对应类型
  • 整个工作流全程共享同一个状态字典
    • items:购物车内商品列表
    • total:总价
    • status:订单状态 pending/paid

⚠️ 重要规则(LangGraph 默认): 节点返回部分状态字典 ,LangGraph 会执行合并更新,不会覆盖整个 state ! 没有返回的字段,保留原有值


三、各个 Node 节点函数

节点函数统一签名:def func(state: CartState) -> dict 入参:当前最新状态;返回:想要更新的状态片段

1. add_apple 节点

复制代码
def add_apple(state: CartState):
    print("\nStep 1: Adding apple ($5) to cart...")
    new_items = state["items"] + ["apple"]
    new_total = state["total"] + 5
    print(f"  → State: items={new_items}, total=${new_total}")
    return {
        "items": new_items,
        "total": new_total
    }

逻辑:

  1. 读取传入 state 里当前 itemstotal
  2. 新建列表(不原地修改原始 state!函数式风格)追加 apple,总价 + 5
  3. 只返回要修改的两个 key
  4. status 没有返回 → LangGraph 保持原来的值不变

最佳实践:不要直接 state["items"].append() 修改入参对象,容易产生副作用。优先构造新值返回。

2. add_banana 节点

复制代码
def add_banana(state: CartState):
    print("\nStep 2: Adding banana ($3) to cart...")
    new_items = state["items"] + ["banana"]
    new_total = state["total"] + 3
    print(f"  → State: items={new_items}, total=${new_total}")
    return {
        "items": new_items,
        "total": new_total
    }

承接上一个节点输出的状态,继续追加商品,总价累加。

3. checkout 结算节点

复制代码
def checkout(state: CartState):
    print("\nStep 3: Processing checkout...")
    print(f"  → Final items: {state['items']}")
    print(f"  → Final total: ${state['total']}")
    return {
        "status": "paid"
    }

重点: 只返回 statusitems、total 完全不改动 LangGraph 自动保留已经累加好的商品和总价,仅更新 status。


四、构建 StateGraph 工作流

复制代码
print("\nBuilding StateGraph workflow...")
workflow = StateGraph(CartState)

实例化图,并绑定状态类型 CartState,告诉图:整个流程流转的数据结构是什么。

复制代码
# Add nodes
workflow.add_node("add_apple", add_apple)
workflow.add_node("add_banana", add_banana)
workflow.add_node("checkout", checkout)
  • add_node(节点名称字符串, 函数)

  • 第一个参数是图内唯一节点标识,用于定义边;第二个是执行函数

    Define flow

    workflow.set_entry_point("add_apple")
    workflow.add_edge("add_apple", "add_banana")
    workflow.add_edge("add_banana", "checkout")
    workflow.add_edge("checkout", END)

  • set_entry_point:图执行起点

  • add_edge(A,B):A 执行完成后,无条件流向 B

  • checkout → END:到达终点,图运行结束

当前流程图: START → add_apple → add_banana → checkout → END

复制代码
app = workflow.compile()

compile():编译图,生成可执行运行时对象 app,之后才能调用 .invoke()


五、初始化状态 & 执行工作流

复制代码
initial_state = {
    "items": [],
    "total": 0.0,
    "status": "pending"
}

初始状态字典,必须完整满足 CartState 结构,作为图执行的起点数据。

复制代码
result = app.invoke(initial_state)

核心执行入口: app.invoke(初始状态)

  1. 将 initial_state 传入图
  2. 按照定义的边顺序依次执行节点
  3. 每个节点执行后,自动合并返回字典更新全局状态
  4. 抵达 END 后,返回最终完整状态 result

六、输出最终状态

复制代码
print("\n" + "=" * 40)
print("✅ FINAL STATE:")
print(f"  Items: {result['items']}")
print(f"  Total: ${result['total']}")
print(f"  Status: {result['status']}")

result = 图跑完之后完整的最终 CartState。

七、最后的文件写入(可选)

复制代码
try:
    with open('/root/stategraph_complete.txt', 'w') as f:
        f.write('StateGraph implementation complete\n')
        f.write(f'Final state: {result}\n')
except:
    pass  # Local testing

异常捕获写法,服务器环境写入标记文件,本地运行路径不存在不会崩溃。


运行输出预期

复制代码
🛒 STATEGRAPH DEMO - Shopping Cart
========================================

Building StateGraph workflow...

Initial State: {'items': [], 'total': 0.0, 'status': 'pending'}

Executing workflow...

Step 1: Adding apple ($5) to cart...
  → State: items=['apple'], total=$5.0

Step 2: Adding banana ($3) to cart...
  → State: items=['apple', 'banana'], total=$8.0

Step 3: Processing checkout...
  → Final items: ['apple', 'banana']
  → Final total: $8.0

========================================
✅ FINAL STATE:
  Items: ['apple', 'banana']
  Total: $8.0
  Status: paid

核心底层原理总结(重点!)

  1. 全局单一状态容器 整个图共享一份状态字典,节点之间依靠这份字典传递信息。
  2. 状态合并规则(默认 StateGraph) 节点返回 {key: value}增量更新,没有返回的键维持原值,不会清空状态。

对比传统 Chain:Chain 经常需要手动在每一步传递所有变量,LangGraph 自动维护。

  1. 节点无副作用范式 推荐不修改入参 state 对象,构造新数据返回;避免并发 / 分支场景出现数据错乱。
  2. 此示例是线性 DAG 顺序执行;在此基础上你可以扩展:
  • 条件分支 add_conditional_edges
  • 循环(Agent 思考循环)
  • 并行节点

拓展思考题

你可以试着修改代码验证机制:

  1. 在 checkout 节点只返回 status,items/total 为什么不会消失?
  2. 如果某节点返回空字典 {},状态会发生什么?
  3. 如果在节点内部 state["items"].append("xxx") 直接原地修改,和构造新列表有什么区别?
相关推荐
uncle_ll1 天前
LangGraph 深度解析:用图结构构建下一代智能代理与多智能体系统
langchain·llm·agent·graph·langgraph
糖果店的幽灵1 天前
大模型测评DeepEval快速入门-RAG指标详解
数据库·人工智能·langgraph·大模型测评·deepeval
糖果店的幽灵2 天前
2026 年最强Obsidian保姆级教程,10分钟打造你的第二大脑
人工智能·langgraph
糖果店的幽灵2 天前
WorkBuddy + 好提示词 = 生产力。43 个场景,复制就能用
人工智能·langgraph
糖果店的幽灵2 天前
langgraph的流式执行
linux·运维·服务器·人工智能·langgraph
一只小bit3 天前
LangGraph 子图使用和房源搜索Agent综合案例实现
机器学习·langchain·llm·langgraph
糖果店的幽灵4 天前
langgraph的 MessagesState 解读
java·开发语言·人工智能·windows·langgraph
辞忧九千七4 天前
MCP 协议完全指南:从原理到 LangGraph 集成,打造即插即用的 AI Agent 工具生态
agent·langgraph·mcp
糖果店的幽灵5 天前
langgraph分支之 - 动态分支(Dynamic Branch)
java·前端·javascript·人工智能·langgraph