在构建复杂 AI 工作流时,静态流程往往无法满足实际业务需求。我在使用 LangGraph 开发多轮对话系统时,最大的挑战就是如何让 Agent 能够根据不同条件动态选择执行路径——这正是条件分支的核心价值所在。本文将深入讲解 LangGraph 中的条件路由(Conditional Edge)与循环控制(Loop),并通过 HolySheep AI 作为示例 API,演示完整的工程实践。
平台选型对比:HolySheep vs 官方 API vs 其他中转站
| 对比维度 | HolySheep AI | 官方 API | 其他中转站 |
|---|---|---|---|
| 美元汇率 | ¥1 = $1(无损) | ¥7.3 = $1 | ¥6.5-8.0 = $1 |
| 国内延迟 | <50ms(直连) | 200-500ms | 80-300ms |
| 充值方式 | 微信/支付宝/银行卡 | 国际信用卡 | 参差不齐 |
| Claude Sonnet 4.5 | $15/MTok | $15/MTok | $12-18/MTok |
| GPT-4.1 | $8/MTok | $8/MTok | $7-12/MTok |
| DeepSeek V3.2 | $0.42/MTok | $0.42/MTok | $0.35-0.6/MTok |
| 注册福利 | 送免费额度 | 无 | 部分有 |
从我的实际项目经验来看,使用 HolySheep AI 后,同样的预算能多支撑 85% 以上的 API 调用量,特别适合需要大量测试条件分支逻辑的开发者。如果你是国内开发者,立即注册 HolySheep AI 可以避免繁琐的跨境支付问题。
LangGraph 条件分支核心概念
LangGraph 的控制流分为两种模式:
- 条件分支(Conditional Edge):根据节点输出动态决定下一个执行哪个节点
- 循环控制(Loop):通过 while 循环实现多轮迭代,直到满足退出条件
为什么需要条件分支?
在我的一个客服 Agent 项目中,需要根据用户意图分发到不同的处理模块:
- 查询订单 → 订单模块
- 申请退款 → 退款模块
- 投诉建议 → 人工客服
- 闲聊寒暄 → 对话模块
这种 if-else 逻辑在 LangGraph 中通过 conditional_edges 实现,让工作流具备真正的决策能力。
实战代码:构建条件路由工作流
环境准备
pip install langgraph langchain-openai langchain-core
配置 HolySheep AI(国内直连,延迟 <50ms)
import os
os.environ["OPENAI_API_KEY"] = "YOUR_HOLYSHEEP_API_KEY"
os.environ["OPENAI_API_BASE"] = "https://api.holysheep.ai/v1"
基础条件分支实现
from langgraph.graph import StateGraph, END
from typing import TypedDict, Literal
定义状态类型
class RouterState(TypedDict):
user_input: str
intent: str
response: str
意图识别函数(使用 HolySheep API)
def intent_classifier(state: RouterState) -> RouterState:
"""根据用户输入判断意图"""
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-4.1",
api_key="YOUR_HOLYSHEEP_API_KEY",
base_url="https://api.holysheep.ai/v1"
)
prompt = f"判断用户意图,只能返回以下之一:order/refund/complaint/chat\n用户输入:{state['user_input']}"
result = llm.invoke(prompt)
state["intent"] = result.content.strip().lower()
return state
各模块处理函数
def order_handler(state: RouterState) -> RouterState:
state["response"] = "📦 您的订单编号:ORD-2024-00187,当前状态:已发货"
return state
def refund_handler(state: RouterState) -> RouterState:
state["response"] = "💰 退款申请已提交,预计3个工作日到账"
return state
def complaint_handler(state: RouterState) -> RouterState:
state["response"] = "📞 人工客服将在24小时内联系您"
return state
def chat_handler(state: RouterState) -> RouterState:
state["response"] = "😊 您好,有什么可以帮您的?"
return state
路由函数 - 条件分支核心
def route_based_on_intent(state: RouterState) -> Literal["order_node", "refund_node", "complaint_node", "chat_node"]:
"""根据意图路由到对应节点"""
intent = state.get("intent", "chat")
route_map = {
"order": "order_node",
"refund": "refund_node",
"complaint": "complaint_node"
}
return route_map.get(intent, "chat_node")
构建图
graph = StateGraph(RouterState)
添加节点
graph.add_node("classify", intent_classifier)
graph.add_node("order_node", order_handler)
graph.add_node("refund_node", refund_handler)
graph.add_node("complaint_node", complaint_handler)
graph.add_node("chat_node", chat_handler)
设置入口
graph.set_entry_point("classify")
添加条件分支(核心语法)
graph.add_conditional_edges(
"classify",
route_based_on_intent,
{
"order_node": "order_node",
"refund_node": "refund_node",
"complaint_node": "complaint_node",
"chat_node": "chat_node"
}
)
所有处理节点结束后结束
for node in ["order_node", "refund_node", "complaint_node", "chat_node"]:
graph.add_edge(node, END)
编译并测试
app = graph.compile()
测试用例
test_inputs = [
{"user_input": "我想查一下我的订单", "intent": "", "response": ""},
{"user_input": "商品坏了要退款", "intent": "", "response": ""},
{"user_input": "服务态度太差要投诉", "intent": "", "response": ""}
]
for input_data in test_inputs:
result = app.invoke(input_data)
print(f"输入: {input_data['user_input']}")
print(f"意图: {result['intent']} → 响应: {result['response']}")
print("-" * 50)
带循环的多轮对话系统
在实际项目中,我经常需要实现多轮对话循环。下面的代码展示了如何用 while 循环让 Agent 持续交互,直到用户明确结束:
from langgraph.graph import StateGraph, END, START
from typing import Annotated
import operator
class ConversationState(TypedDict):
messages: Annotated[list, operator.add]
should_continue: bool
turn_count: int
def chat_node(state: ConversationState) -> ConversationState:
"""对话节点 - 每次交互增加轮次计数"""
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="claude-sonnet-4.5",
api_key="YOUR_HOLYSHEEP_API_KEY",
base_url="https://api.holysheep.ai/v1"
)
# 获取历史消息
history = state["messages"]
response = llm.invoke(history)
state["messages"].append({"role": "assistant", "content": response.content})
state["turn_count"] += 1
return state
def should_continue(state: ConversationState) -> Literal["continue", "end"]:
"""
循环退出条件判断
- 对话超过10轮自动结束
- 用户输入'再见'结束
"""
# 检查最后一条用户消息
if state["turn_count"] >= 10:
return "end"
messages = state["messages"]
if messages and messages[-1].get("role") == "user":
user_msg = messages[-1].get("content", "").lower()
if "再见" in user_msg or "结束" in user_msg or "退出" in user_msg:
return "end"
return "continue"
构建循环工作流
loop_graph = StateGraph(ConversationState)
loop_graph.add_node("chat", chat_node)
loop_graph.set_entry_point(START)
条件循环边 - 实现 while 循环
loop_graph.add_conditional_edges(
"chat",
should_continue,
{
"continue": "chat", # 循环回自身
"end": END # 退出循环
}
)
loop_app = loop_graph.compile()
运行多轮对话
initial_state = {
"messages": [{"role": "user", "content": "你好,帮我推荐一本书"}],
"should_continue": True,
"turn_count": 0
}
print("=== 开始多轮对话(最多10轮)===\n")
for step in loop_app.stream(initial_state):
node_name = list(step.keys())[0]
node_state = step[node_name]
print(f"[轮次 {node_state.get('turn_count', 0)}] {node_name}")
if node_state.get("messages"):
last_msg = node_state["messages"][-1]
print(f" {last_msg['role']}: {last_msg['content'][:100]}...")
print()
高级技巧:条件边中使用 LLM 做决策
在我开发一个复杂的审批流程时,纯代码的条件判断不够灵活,于是我在条件边中直接调用 LLM 来决定路由方向:
from langgraph.prebuilt import ToolNode, tools_condition
from langchain_core.tools import tool
@tool
def approve_request(request_id: str) -> str:
"""批准请求"""
return f"请求 {request_id} 已批准"
@tool
def reject_request(request_id: str) -> str:
"""拒绝请求"""
return f"请求 {request_id} 已拒绝"
@tool
def escalate_to_manager(request_id: str) -> str:
"""升级给经理处理"""
return f"请求 {request_id} 已升级到经理"
tools = [approve_request, reject_request, escalate_to_manager]
def llm_routing_decision(state: dict) -> str:
"""
使用 LLM 做路由决策
根据请求内容金额和类型决定处理路径
"""
from langchain_openai import ChatOpenAI
llm = ChatOpenAI(
model="gpt-4.1",
api_key="YOUR_HOLYSHEEP_API_KEY",
base_url="https://api.holysheep.ai/v1"
)
request_text = state.get("request_text", "")
prompt = f"""分析以下请求,决定处理方式:
- 如果金额 <1000元且是常规采购:返回 "small_request"
- 如果金额 1000-10000元:返回 "medium_request"
- 如果金额 >10000元:返回 "large_request"
- 如果是敏感类型(人事、财务):返回 "sensitive_request"
请求内容:{request_text}
只返回一个分类标签"""
decision = llm.invoke(prompt)
return decision.content.strip().lower()
路由映射
def route_decision(decision: str) -> str:
route_map = {
"small_request": "small_node",
"medium_request": "medium_node",
"large_request": "large_node",
"sensitive_request": "sensitive_node"
}
return route_map.get(decision, "default_node")
实战经验分享
在我使用 LangGraph 构建企业级 AI 工作流的一年多时间里,有几点经验特别想分享给刚入门的开发者:
第一,选择稳定的 API 供应商至关重要。我之前使用官方 API 时,高峰期的延迟波动经常导致我的条件分支超时,特别是那些需要多轮 LLM 调用的复杂路由逻辑。切换到 HolySheep AI 后,国内直连的 <50ms 延迟让整个工作流流畅很多,而且汇率优势(¥1=$1)让我在调试阶段可以大胆测试各种分支路径,而不用担心费用。
第二,条件分支的路由函数必须返回值在映射表中存在。这是我踩过最多次的坑——当 LLM 返回的意图不在预设的 route_map 中时,整个图会抛出 KeyError。解决方案是在路由函数中用 .get(intent, "default_node") 兜底。
第三,循环退出条件要设上界。我第一次实现多轮对话时忘记设置最大轮次,导致用户触发了一个 bug 后对话陷入了无限循环。使用 HolySheep AI 的低价优势,我建议在调试阶段就设置合理的轮次上限(比如 10-20 轮),避免意外开销。
常见报错排查
错误 1:KeyError in conditional_edges 路由映射
# ❌ 错误写法
def route_intent(state):
return state["intent"] # 可能返回不在映射表中的值
graph.add_conditional_edges(
"classify",
route_intent,
{"order": "order_node", "refund": "refund_node"} # 如果返回 "complaint" 会报错
)
✅ 正确写法 - 添加兜底默认值
def route_intent(state):
route_map = {
"order": "order_node",
"refund": "refund_node",
"complaint": "complaint_node"
}
return route_map.get(state["intent"], "default_node") # 兜底
graph.add_conditional_edges(
"classify",
route_intent,
{
"order_node": "order_node",
"refund_node": "refund_node",
"complaint_node": "complaint_node",
"default_node": "default_node" # 需要包含兜底节点
}
)
错误 2:循环节点未设置退出条件导致超时
# ❌ 危险写法 - 可能无限循环
def should_loop(state):
# 只检查是否继续,没有上限
return "continue" if not state["done"] else "end"
✅ 正确写法 - 强制退出机制
def should_loop(state):
MAX_TURNS = 20
# 检查轮次上限
if state.get("turn_count", 0) >= MAX_TURNS:
print(f"⚠️ 达到最大轮次 {MAX_TURNS},强制退出")
return "end"
# 检查用户是否主动结束
messages = state.get("messages", [])
if messages and "再见" in messages[-1].get("content", ""):
return "end"
return "continue"
错误 3:API 认证失败或 base_url 配置错误
# ❌ 常见错误配置
os.environ["OPENAI_API_BASE"] = "https://api.openai.com/v1" # 错误!
os.environ["OPENAI_API_KEY"] = "sk-xxxx" # 使用了错误的 key 格式
✅ HolySheep AI 正确配置
import os
os.environ["OPENAI_API_BASE"] = "https://api.holysheep.ai/v1"
os.environ["OPENAI_API_KEY"] = "YOUR_HOLYSHEEP_API_KEY"
如果是 Claude 模型,直接用相同 base_url
llm = ChatOpenAI(
model="claude-sonnet-4.5",
api_key="YOUR_HOLYSHEEP_API_KEY", # 与 OpenAI 使用相同的 key
base_url="https://api.holysheep.ai/v1"
)
错误 4:状态传递丢失问题
# ❌ 错误:直接覆盖状态而不是更新
def bad_node(state):
return {"user_input": "new input"} # 丢失了其他字段!
✅ 正确:保持状态连续性
def good_node(state):
new_state = state.copy() # 或 state | {"new_field": "value"}
new_state["processed"] = True
return new_state
或者在节点内直接修改
def best_node(state: RouterState) -> RouterState:
state["processed"] = True
state["response"] = "处理完成"
return state
错误 5:conditional_edges 路由函数类型错误
# ❌ 错误:返回了状态对象而不是字符串
def wrong_route(state):
return state # 返回了整个状态,类型不对
✅ 正确:返回字符串路由键
def correct_route(state) -> str:
return state.get("next_action", "default")
或者使用 Literal 类型提示
from typing import Literal
def typed_route(state) -> Literal["node_a", "node_b", "node_c"]:
return state["route_key"]
性能与成本优化建议
在我优化 LangGraph 工作流时,发现几个显著影响成本和响应速度的点:
- 减少 LLM 调用次数:条件判断尽量用简单代码逻辑,只有复杂的语义理解才调用 LLM
- 选择性价比模型:意图分类、简单路由等场景使用 DeepSeek V3.2($0.42/MTok),仅在真正需要高质量输出时用 Claude Sonnet 4.5($15/MTok)
- 批量处理:对于不相关的请求,使用并发执行减少总等待时间
- 缓存复用:对于相同的条件分支路径,可以缓存中间结果
使用 HolySheep AI 的汇率优势(¥1=$1),我在生产环境中日均调用量约 5000 次,月度费用控制在 ¥800 以内,相比官方 API 节省超过 85% 成本。
总结
LangGraph 的条件分支和循环控制为构建智能 AI 工作流提供了强大的表达能力。通过本文的讲解,你应该已经掌握了:
- 如何设计条件路由函数并处理边界情况
- 如何实现带退出条件的循环工作流
- 如何避免 5 种最常见的错误
- 如何在 HolySheep AI 上实现稳定、低延迟的接入
如果你还没体验过 HolySheheep AI 的优势,强烈建议立即注册,利用首月赠送的免费额度开始你的 LangGraph 项目。国内直连 + 微信支付宝充值 + 无损汇率,让 AI 工作流开发不再受制于网络和成本问题。
完整的示例代码已在上文提供,你可以直接复制运行。如果有任何问题,欢迎在评论区交流!
👉 免费注册 HolySheep AI,获取首月赠额度