03|Langgraph | 从入门到实战 | 状态机与智能路由
1. Langgraph状态机:智能工作流的核心引擎
当你第一次听说"状态机"这个词时,可能会联想到老式自动售货机的机械结构——投币、选择商品、出货,每个步骤都严格遵循预设流程。但在Langgraph的世界里,状态机(State)更像是一个智能管家,它不仅能记住当前对话的所有细节,还能根据情况动态调整服务流程。
1.1 TypedDict状态机的魔法口袋
想象你有个神奇口袋,里面装着对话的所有记忆碎片。在Langgraph中,这个口袋就是TypedDict定义的状态机。让我们用实际代码来看看这个口袋长什么样:
from typing_extensions import TypedDict, Annotated
from typing import List
import operator
class ConversationState(TypedDict):
user_query: str # 用户最新提问
history: Annotated[List[str], operator.add] # 累积的对话历史
current_step: str # 当前执行阶段
decision_point: bool # 是否需要分支判断
这个状态机设计有几个精妙之处:
- Annotated类型配合operator.add实现了自动列表追加,不用手动维护历史记录
- 明确的类型标注让IDE能智能提示,减少编码错误
- 每个字段都像口袋里的独立隔层,存放不同类型的对话信息
我在实际项目中发现,良好的状态机设计要遵循"三不原则":
- 不遗漏关键信息(如用户意图)
- 不混淆数据类型(明确str/list/dict)
- 不过度设计(只保留必要状态)
1.2 状态流转的三种模式
状态机在工作流中流转时,常见三种模式:
线性流转就像火车沿轨道行驶:
workflow.add_edge("step1", "step2")
workflow.add_edge("step2", "step3")
条件分支如同高速公路的立交桥:
def should_continue(state):
if "?" in state["user_query"]:
return "knowledge_search"
return "direct_answer"
workflow.add_conditional_edges(
"classify",
should_continue,
{"knowledge_search": "search_node", "direct_answer": "answer_node"}
)
循环迭代则像洗碗机的清洗循环:
def check_quality(state):
if state["answer_quality"] > 0.8:
return END
return "improve_step"
workflow.add_conditional_edges(
"generate",
check_quality,
{"improve_step": "improve_node", END: END}
)
实测一个电商客服场景:当用户询问"这件衣服怎么洗"时,状态机先后经历:
用户输入 -> 意图识别 -> 知识检索 -> 生成回答 -> 质量检查 -> [循环优化] -> 最终回复
2. 智能路由:让工作流学会"见机行事"
去年我帮一家律所设计合同审查系统时,发现律师们最头疼的是处理不同类型的法律条款。传统工作流需要手动选择模板,而智能路由(Conditional Edges)让系统能自动识别条款类型并跳转到对应处理节点。
2.1 add_conditional_edges方法详解
这个方法的强大之处在于它把决策逻辑从代码中解放出来。看个实际例子:
def route_intent(state):
"""根据查询内容路由到不同处理节点"""
query = state["user_query"].lower()
if "多少钱" in query:
return "price_check"
elif "怎么用" in query:
return "tutorial"
elif "故障" in query:
return "troubleshoot"
return "general_qa"
workflow.add_conditional_edges(
"classify",
route_intent,
{
"price_check": "price_node",
"tutorial": "tutorial_node",
"troubleshoot": "tech_support_node",
"general_qa": "qa_node"
}
)
这里有三个关键点需要注意:
- 路由函数应该保持纯净(不修改状态)
- 返回值必须完全匹配预设的分支名称
- 建议为未知情况设置默认分支
2.2 动态路由的进阶技巧
技巧一:LLM辅助决策 当简单规则不够用时,可以让LLM参与决策:
from langchain_core.prompts import PromptTemplate
router_prompt = PromptTemplate.from_template("""
分析以下用户问题最适合的处理方式:
问题:{query}
可选方案:
- 价格查询(price)
- 使用教程(tutorial)
- 故障排查(error)
- 一般咨询(general)
只需返回上述括号内的英文单词""")
def llm_router(state):
chain = router_prompt | llm
return chain.invoke({"query": state["user_query"]}).strip()
技巧二:多条件组合
def complex_router(state):
if state["user_level"] == "vip" and "投诉" in state["user_query"]:
return "vip_service"
elif state["urgency"] > 0.7:
return "fast_response"
return "normal_process"
技巧三:概率路由
import random
def prob_router(state):
rand = random.random()
if rand < 0.6:
return "main_path"
elif rand < 0.9:
return "alternative_path"
return "experimental_path"
3. 实战:构建智能客服路由系统
让我们用真实案例串联所学知识。假设要为一个3C电商构建客服系统,需要处理:产品咨询、订单查询、退换货、技术支持等场景。
3.1 系统架构设计
首先定义状态机结构:
class CustomerServiceState(TypedDict):
user_input: str # 原始用户输入
intent: str # 识别出的意图
user_profile: dict # 用户画像
dialog_history: Annotated[List, operator.add] # 对话历史
current_response: str # 当前节点生成的回复
satisfaction: float # 用户满意度预测
然后构建工作流骨架:
builder = StateGraph(CustomerServiceState)
# 定义节点
builder.add_node("receive_input", receive_input)
builder.add_node("classify_intent", classify_intent)
builder.add_node("handle_inquiry", handle_inquiry)
builder.add_node("check_order", check_order)
builder.add_node("process_return", process_return)
builder.add_node("tech_support", tech_support)
builder.add_node("evaluate_satisfaction", evaluate_satisfaction)
# 设置入口
builder.set_entry_point("receive_input")
# 添加固定路径
builder.add_edge("receive_input", "classify_intent")
builder.add_edge("evaluate_satisfaction", END)
# 添加条件路由
def intent_router(state):
intents = {
"产品咨询": "handle_inquiry",
"订单状态": "check_order",
"退换货": "process_return",
"技术支持": "tech_support"
}
return intents.get(state["intent"], "handle_inquiry")
builder.add_conditional_edges(
"classify_intent",
intent_router,
{
"handle_inquiry": "handle_inquiry",
"check_order": "check_order",
"process_return": "process_return",
"tech_support": "tech_support"
}
)
# 添加循环检查
def satisfaction_check(state):
if state["satisfaction"] < 0.6:
return "classify_intent" # 重新路由
return "end_conversation"
builder.add_conditional_edges(
"handle_inquiry",
satisfaction_check
)
# 其他节点同理...
workflow = builder.compile()
3.2 关键节点实现示例
以技术支持的节点为例:
def tech_support(state):
# 从知识库检索解决方案
kb_result = retrieve_from_knowledgebase(state["user_input"])
if kb_result:
response = format_kb_response(kb_result)
else:
# 没有匹配方案时转人工
response = escalate_to_human(state)
# 更新状态
return {
"current_response": response,
"dialog_history": [("system", response)]
}
3.3 调试技巧分享
在开发过程中,我总结了这些调试方法:
- 状态快照:在每个节点打印state内容
print(f"当前状态:{state}")
- 可视化流程:生成流程图检查路由逻辑
Image(workflow.get_graph().draw_mermaid_png())
- 测试用例集:覆盖各种边界情况
test_cases = [
("手机多少钱", "price_check"),
("怎么连接WiFi", "tutorial"),
("开不了机", "troubleshoot"),
("你好", "general_qa")
]
- 性能监控:记录每个节点的执行时间
import time
def timed_node(state):
start = time.time()
# ...节点逻辑
print(f"执行耗时:{time.time()-start:.2f}s")
return result
4. 高级模式:嵌套工作流与分布式状态
当系统复杂度增加时,单一状态机可能变得臃肿。这时可以采用嵌套工作流模式,就像俄罗斯套娃一样。
4.1 嵌套工作流实现
# 子工作流:订单处理
order_builder = StateGraph(OrderState)
order_builder.add_node("verify", verify_order)
order_builder.add_node("update", update_status)
order_builder.set_entry_point("verify")
order_builder.add_edge("verify", "update")
order_workflow = order_builder.compile()
# 主工作流
main_builder = StateGraph(MainState)
main_builder.add_node("order_subflow", order_workflow)
4.2 状态分片技巧
对于大型应用,可以采用状态分片:
class UserState(TypedDict):
basic_info: dict
preferences: dict
class DialogState(TypedDict):
current_intent: str
history: list
class SystemState(TypedDict):
user: UserState
dialog: DialogState
service: dict
这种架构的优势在于:
- 不同团队可以并行开发不同状态模块
- 减少不必要的状态传递
- 更细粒度的权限控制
4.3 性能优化实践
在处理高并发请求时,我总结了几点经验:
- 状态压缩:定期清理历史记录
def clean_history(state):
if len(state["history"]) > 5:
state["history"] = state["history"][-5:]
- 懒加载:延迟加载大资源
def load_on_demand(state):
if "big_data" not in state:
state["big_data"] = load_from_db()
- 缓存策略:复用中间结果
from functools import lru_cache
@lru_cache(maxsize=100)
def expensive_computation(query):
# ...耗时计算
- 异步处理:非阻塞式执行
async def async_node(state):
result = await call_external_api()
return {"api_result": result}
更多推荐



所有评论(0)