跳到主要内容

Agent 设计模式——6 种生产级模式深度解析

2026 年,Azure、Redis、LangChain、Anthropic 等官方文档都收录了 Agent 设计模式。掌握这些模式,意味着你不再"只会调用 API",而是能根据业务场景选择正确的架构。Gartner 预测 2026 年底 40% 的企业应用将嵌入 AI Agent,而失败率高达 40%——选错模式是主因之一

前置知识

  • LangGraph 基础(状态图、节点、条件边)
  • MCP 协议概念
  • 工具调用原理

核心概念

6 大模式全景

模式核心机制适合场景复杂度
ReAct思考 → 行动 → 观察 → 循环需要多步推理和工具调用的任务★★☆
Reflection生成 → 反思 → 修正需要高准确率的代码/文档生成★★☆
Plan-and-Execute先拆分子任务 → 逐个执行复杂多步骤任务(如调研报告)★★★
Router分类 → 路由到专业 Agent多领域客服、多技能问答★★☆
Human-in-the-LoopAgent 执行 → 人工审核 → 继续金融审批、医疗决策、内容审核★★★
Handoff专业 Agent 互相交接任务跨部门协作、复杂工作流★★★★

1. ReAct 模式(Reasoning + Acting)

ReAct 是最基础的 Agent 模式,核心思想:让模型在每一步行动前先思考,再行动,再观察结果,循环往复

ReAct 循环详解

每一步包含三个要素:

要素说明示例
Thought推理:"我现在需要做什么?""我需要先搜索用户信息,然后查订单状态"
Action行动:调用工具/函数search_user(name="张三")
Observation观察:工具返回的结果{"id": 123, "level": "VIP"}

LangGraph 实现

from langgraph.graph import StateGraph, END
from typing import TypedDict, Annotated
import operator

class ReActState(TypedDict):
query: str # 用户原始问题
thoughts: list[str] # 思考链
actions: list[str] # 行动记录
observations: list # 观察结果
answer: str # 最终答案

def agent_step(state: ReActState) -> dict:
"""ReAct 核心:根据当前状态决定下一步。"""
query = state["query"]
history = "\n".join(
f"Thought: {t}\nAction: {a}\nObservation: {o}"
for t, a, o in zip(
state["thoughts"], state["actions"], state["observations"]
)
)

# 调用 LLM 决定下一步
prompt = f"""你是一个智能助手。基于以下信息决定下一步行动。

问题:{query}
{history}

请用 JSON 格式返回:
{{"thought": "你的思考", "action": "工具名或'answer'", "input": "工具输入"}}
"""
response = llm_json_mode.invoke([{"role": "user", "content": prompt}])
return response

def tool_step(state: ReActState) -> dict:
"""执行工具并记录结果。"""
last_action = state["actions"][-1]
last_input = state["thoughts"][-1] # 简化:用 thought 作为输入

tools = {
"search_user": search_user,
"get_orders": get_orders,
"calculate_refund": calculate_refund,
}

if last_action in tools:
result = tools[last_action](last_input)
else:
result = f"错误:未知工具 {last_action}"

return {
"observations": state["observations"] + [str(result)],
}

def should_continue(state: ReActState) -> str:
"""判断是继续循环还是返回答案。"""
# 从最后一次 thought 中判断是否已经有了答案
last_thought = state["thoughts"][-1] if state["thoughts"] else ""

# 超过最大循环次数
if len(state["actions"]) >= 5:
return "answer"

# Agent 认为已经完成
if "answer" in last_thought.lower():
return "answer"

return "tool"

# 构建 ReAct 图
graph = StateGraph(ReActState)
graph.add_node("agent", agent_step)
graph.add_node("tool", tool_step)

graph.set_entry_point("agent")
graph.add_conditional_edges("agent", should_continue, {
"tool": "tool",
"answer": END,
})
graph.add_edge("tool", "agent")

app = graph.compile()

# 运行
result = app.invoke({
"query": "张三的订单有退款吗?",
"thoughts": [],
"actions": [],
"observations": [],
"answer": "",
})

ReAct 的优缺点

优点缺点
实现简单,适合快速原型循环次数不可预测
可解释性强(思考链可见)长循环容易跑偏
天然支持工具调用缺乏全局规划

2. Reflection 模式(自检自修复)

Reflection 模式让 Agent 生成输出后先自我检查,发现错误后自动修正——类似于程序员的 Code Review 自动化。

Reflection 的两种实现方式

方式一:单 Agent 自我反思

class ReflectionState(TypedDict):
task: str
draft: str
feedback: str
final_output: str
iteration: int

MAX_REFLECTION_ROUNDS = 3

def generate(state: ReflectionState) -> dict:
"""生成初稿或修正稿。"""
if not state["draft"]:
# 第一次生成
prompt = f"完成以下任务:{state['task']}"
else:
# 基于反馈修正
prompt = f"""任务:{state['task']}

初稿:{state['draft']}

评审意见:{state['feedback']}

请根据评审意见修正。"""

draft = llm.invoke([{"role": "user", "content": prompt}]).content
return {"draft": draft, "iteration": state["iteration"] + 1}

def reflect(state: ReflectionState) -> dict:
"""自我反思——检查输出质量。"""
prompt = f"""你是一位资深审核员。请评审以下内容:

任务:{state['task']}
内容:{state['draft']}

请从以下维度评分并给出意见:
1. 准确性(事实是否正确)
2. 完整性(是否覆盖所有要求)
3. 清晰度(是否易于理解)
4. 格式(是否符合规范)

返回 JSON:
{"score": "1-10", "passed": "true/false", "feedback": "具体意见"}
"""
result = llm_json_mode.invoke([{"role": "user", "content": prompt}])
return {"feedback": result.get("feedback", ""), "_score": result.get("score", 0), "_passed": result.get("passed", False)}

def should_reflect(state: ReflectionState) -> str:
"""决定是否继续反思循环。"""
if state["iteration"] >= MAX_REFLECTION_ROUNDS:
return "done"
if state.get("_passed", False):
return "done"
return "reflect"

graph = StateGraph(ReflectionState)
graph.add_node("generate", generate)
graph.add_node("reflect", reflect)

graph.set_entry_point("generate")
graph.add_edge("generate", "reflect")
graph.add_conditional_edges("reflect", should_reflect, {
"reflect": "generate",
"done": END,
})

app = graph.compile()

方式二:双 Agent 生成器+审核器

# 生成器 Agent
generator = Agent(
model="gpt-4o",
system_prompt="你是一位资深 Python 工程师,负责编写高质量代码。",
)

# 审核器 Agent(更严格)
reviewer = Agent(
model="gpt-4o",
system_prompt="""你是一位资深技术主管,负责 Code Review。
审核标准:
1. 代码是否正确(无 bug)
2. 是否遵循最佳实践(PEP 8、类型注解)
3. 是否有边界情况未处理
4. 是否有效率问题

返回格式:
- score: 1-10
- passed: true/false(≥8 分通过)
- issues: 具体问题列表
- suggestions: 改进建议
""",
)

def code_with_review(task: str) -> dict:
"""生成代码并自动评审。"""
# 生成
code = generator.run(task).content

# 评审
review = reviewer.run(f"评审以下代码:\n```python\n{code}\n```").content

# 如果不合格,让生成器重新生成
parsed_review = parse_review(review)
if not parsed_review["passed"]:
code = generator.run(f"{task}\n\n上次代码的问题:{parsed_review['issues']}\n请修正。").content

return {"code": code, "review": review}

Reflection 的生产价值

指标不使用 Reflection使用 Reflection
代码 bug 率15-20%5-8%
文档完整度60%90%
测试覆盖率40%75%
额外 token 成本-+30-50%(但质量提升 >100%)

3. Plan-and-Execute 模式(先计划后执行)

对于复杂任务,先制定完整计划,再按步骤执行——避免 ReAct 的"盲目探索"问题

适用场景

场景为什么需要 Plan-and-Execute
写调研报告需要:确定大纲 → 搜索每个章节资料 → 写作 → 审核
开发完整功能需要:设计 → 建模 → 编码 → 测试 → 部署
数据分析报告需要:获取数据 → 清洗 → 分析 → 可视化 → 结论

LangGraph 实现

class PlanState(TypedDict):
task: str
plan: list[dict] # 计划步骤列表
plan_step_index: int # 当前执行到第几步
results: list[str] # 每个步骤的结果
final_output: str

def planner(state: PlanState) -> dict:
"""制定任务计划。"""
prompt = f"""将以下任务分解为可执行的步骤。

任务:{state['task']}

要求:
1. 每个步骤独立、具体、可执行
2. 标注每个步骤需要的工具
3. 步骤之间有明确的输入输出关系

返回 JSON 数组,每个步骤包含:
[{"step": "步骤描述", "tool": "需要的工具名", "depends_on": "依赖的步骤编号"}]
"""
plan = llm_json_mode.invoke([{"role": "user", "content": prompt}])
return {"plan": plan, "plan_step_index": 0, "results": []}

def executor(state: PlanState) -> dict:
"""执行当前步骤。"""
idx = state["plan_step_index"]
current_step = state["plan"][idx]

# 收集依赖的结果
context = ""
for dep_idx in current_step.get("depends_on", []):
context += f"步骤 {dep_idx} 结果:{state['results'][dep_idx]}\n"

prompt = f"""执行以下步骤:
{current_step['step']}

任务背景:{state['task']}
{context}

请执行并返回结果。"""

result = llm.invoke([{"role": "user", "content": prompt}]).content

# 如果需要调用工具
tool_name = current_step.get("tool")
if tool_name:
tool_result = execute_tool(tool_name, result)
result = f"{result}\n工具结果:{tool_result}"

return {
"results": state["results"] + [result],
"plan_step_index": idx + 1,
}

def synthesizer(state: PlanState) -> dict:
"""汇总所有步骤的结果。"""
results_summary = "\n".join(
f"步骤 {i+1}: {r[:200]}..." for i, r in enumerate(state["results"])
)

prompt = f"""任务:{state['task']}

所有步骤的执行结果:
{results_summary}

请汇总为最终报告。"""

final_output = llm.invoke([{"role": "user", "content": prompt}]).content
return {"final_output": final_output}

def should_continue_plan(state: PlanState) -> str:
"""判断是继续执行下一步还是汇总。"""
if state["plan_step_index"] >= len(state["plan"]):
return "synthesize"
return "execute"

graph = StateGraph(PlanState)
graph.add_node("plan", planner)
graph.add_node("execute", executor)
graph.add_node("synthesize", synthesizer)

graph.set_entry_point("plan")
graph.add_edge("plan", "execute")
graph.add_conditional_edges("execute", should_continue_plan, {
"execute": "execute",
"synthesize": "synthesize",
})
graph.add_edge("synthesize", END)

app = graph.compile()

ReAct vs Plan-and-Execute 对比

维度ReActPlan-and-Execute
规划方式逐步决定(无全局计划)先制定完整计划
适合任务探索性、不确定性强结构化、可分解
可控性低(可能陷入循环)高(步骤固定)
Token 消耗不可预测可预测(步骤数 × 每步 token)
调试难度高(循环链路复杂)低(每步独立)

4. Router 模式(智能分类路由)

Router 模式将输入分类后路由到不同的专业 Agent——避免一个 Agent 干所有事

Router 的两种实现

方式一:LLM 分类器

from langgraph.graph import StateGraph, END
from typing import TypedDict, Literal

class RouterState(TypedDict):
query: str
category: str
answer: str

def router(state: RouterState) -> Literal["tech", "business", "customer_service", "creative"]:
"""基于 LLM 的分类路由函数。"""
prompt = f"""将以下问题分类为以下类别之一:
- tech:技术问题(代码、架构、部署、算法)
- business:业务问题(市场策略、运营、财务、竞争分析)
- customer_service:客服问题(产品使用、退款、投诉、FAQ)
- creative:创意问题(写作、设计、营销文案)

问题:{state['query']}

只返回类别名称,不要解释。"""

category = llm.invoke([{"role": "user", "content": prompt}]).content.strip().lower()

if category in ["tech", "business", "customer_service", "creative"]:
return category
return "tech" # 默认

def tech_agent(state: RouterState) -> dict:
answer = tech_llm.invoke([{"role": "user", "content": state["query"]}]).content
return {"answer": answer}

def business_agent(state: RouterState) -> dict:
answer = business_llm.invoke([{"role": "user", "content": state["query"]}]).content
return {"answer": answer}

def customer_service_agent(state: RouterState) -> dict:
answer = cs_llm.invoke([{"role": "user", "content": state["query"]}]).content
return {"answer": answer}

def creative_agent(state: RouterState) -> dict:
answer = creative_llm.invoke([{"role": "user", "content": state["query"]}]).content
return {"answer": answer}

graph = StateGraph(RouterState)
graph.add_node("router", router)
graph.add_node("tech", tech_agent)
graph.add_node("business", business_agent)
graph.add_node("customer_service", customer_service_agent)
graph.add_node("creative", creative_agent)

graph.set_entry_point("router")
graph.add_conditional_edges("router", router, {
"tech": "tech",
"business": "business",
"customer_service": "customer_service",
"creative": "creative",
})
graph.add_edge("tech", END)
graph.add_edge("business", END)
graph.add_edge("customer_service", END)
graph.add_edge("creative", END)

app = graph.compile()

方式二:置信度路由(Confidence-based Routing)

def confidence_router(state: RouterState) -> str:
"""基于置信度的路由——如果不确定,交给更通用的 Agent。"""
prompt = f"""问题:{state['query']}

1. 分类:tech / business / customer_service / creative
2. 置信度:0.0-1.0(你对分类的确定程度)

返回 JSON:{"category": "...", "confidence": 0.0}"""

result = llm_json_mode.invoke([{"role": "user", "content": prompt}])
category = result["category"]
confidence = result["confidence"]

# 置信度低于阈值,路由到通用 Agent
if confidence < 0.7:
return "general"
return category

# 低置信度时路由到一个更强大的通用 Agent
graph.add_node("general", general_agent)
# ... 在 add_conditional_edges 中加入 "general": "general"

Router 的生产考量

维度LLM 分类器规则分类器混合分类器
准确率高(85-95%)中(60-80%)最高(95%+)
速度慢(+500ms)极快(小于 1ms)快(规则优先)
成本每次 +$0.001$0规则命中 $0
维护成本中(规则膨胀)

混合分类器推荐实现:先用规则匹配关键词(如"退款"→客服),未命中再用 LLM 分类。


5. Human-in-the-Loop 模式(人工审核)

在关键节点引入人工审核——让 AI 提效,让人类把关

三级风险审核

class HITLState(TypedDict):
query: str
agent_output: str
risk_level: str # "low" / "medium" / "high"
human_approval: bool
human_feedback: str
final_output: str

def assess_risk(state: HITLState) -> dict:
"""评估输出内容的风险等级。"""
# 规则层:快速判断
high_risk_keywords = ["退款", "赔偿", "法律", "起诉", "医疗", "诊断", "用药"]
if any(kw in state["agent_output"] for kw in high_risk_keywords):
return {"risk_level": "high"}

# LLM 层:语义判断
prompt = f"""评估以下回复的风险等级。

问题:{state['query']}
回复:{state['agent_output']}

风险等级:
- low:普通问答、信息查询
- medium:建议、推荐、可能影响用户决策
- high:法律/医疗/金融建议、赔偿承诺、敏感信息

返回 JSON:{"risk_level": "low/medium/high", "reason": "原因"}"""

result = llm_json_mode.invoke([{"role": "user", "content": prompt}])
return {"risk_level": result["risk_level"]}

def human_review_gate(state: HITLState) -> dict:
"""人工审核闸——实际生产中通过 UI/API 接入。"""
# 在实际生产中,这里会通过 API 通知人工审核
# 人工在 Web UI 中查看 agent_output 并决定 approve/reject + 修改意见

# 模拟人工审核
print(f"\n=== 人工审核 ===")
print(f"问题:{state['query']}")
print(f"Agent 回复:{state['agent_output']}")
print(f"风险等级:{state['risk_level']}")
print(f"是否通过?(y/n): ", end="")

approval = input().strip().lower() == "y"
feedback = ""
if not approval:
feedback = input("请给出修改意见:")

return {
"human_approval": approval,
"human_feedback": feedback,
}

def should_require_human_review(state: HITLState) -> str:
"""判断是否需要人工审核。"""
if state["risk_level"] == "low":
return "auto_approve"
return "human_review"

def apply_human_feedback(state: HITLState) -> dict:
"""根据人工反馈修正输出。"""
if state["human_approval"]:
return {"final_output": state["agent_output"]}
else:
# Agent 根据反馈重新生成
prompt = f"""问题:{state['query']}

之前的回复:{state['agent_output']}

人工审核意见:{state['human_feedback']}

请根据意见修改回复。"""

new_output = llm.invoke([{"role": "user", "content": prompt}]).content
return {"final_output": new_output}

graph = StateGraph(HITLState)
graph.add_node("agent", agent_node)
graph.add_node("risk_assessment", assess_risk)
graph.add_node("human_review", human_review_gate)
graph.add_node("apply_feedback", apply_human_feedback)

graph.set_entry_point("agent")
graph.add_edge("agent", "risk_assessment")
graph.add_conditional_edges("risk_assessment", should_require_human_review, {
"auto_approve": END,
"human_review": "human_review",
})
graph.add_edge("human_review", "apply_feedback")
graph.add_edge("apply_feedback", END)

app = graph.compile()

HITL 的生产实现模式

模式说明适用场景
Approval GateAgent 生成后等人工批准内容发布、代码合并
Confidence Routing低置信度路由到人工客服、医疗初诊
Interrupt & Edit人工中途介入修改复杂写作、代码开发
Post-Hoc Review先执行后抽查低风险批量任务

6. Handoff 模式(多智能体交接)

不同专业 Agent 之间传递任务——让最擅长的人(Agent)做对应的事

LangGraph Supervisor + Worker 实现

from langgraph.graph import StateGraph, END
from typing import TypedDict, Literal

class HandoffState(TypedDict):
query: str
subtasks: list[dict]
current_task_index: int
task_results: list[str]
final_output: str

def supervisor(state: HandoffState) -> dict:
"""协调者:拆解任务、分配 Worker、汇总结果。"""
if not state["subtasks"]:
# 第一次运行——拆解任务
prompt = f"""将以下任务分解为子任务,每个子任务分配给合适的专家。

任务:{state['query']}

专家列表:
- devops_agent:部署、运维、Docker、K8s、CI/CD
- coding_agent:写代码、调试、测试
- docs_agent:写文档、教程、API 文档
- security_agent:安全审计、漏洞扫描

返回 JSON 数组:
[{"task": "子任务描述", "assignee": "专家名"}]
"""
subtasks = llm_json_mode.invoke([{"role": "user", "content": prompt}])
return {"subtasks": subtasks, "current_task_index": 0, "task_results": []}
else:
# 汇总所有 Worker 结果
results_summary = "\n".join(
f"任务 {i+1}{state['subtasks'][i]['assignee']}):{r[:300]}..."
for i, r in enumerate(state["task_results"])
)

prompt = f"""原始任务:{state['query']}

所有子任务完成结果:
{results_summary}

请汇总为最终回复。"""

final = llm.invoke([{"role": "user", "content": prompt}]).content
return {"final_output": final}

def devops_worker(state: HandoffState) -> dict:
task = state["subtasks"][state["current_task_index"]]
result = devops_llm.invoke([{"role": "user", "content": f"执行:{task['task']}"}]).content
return {
"task_results": state["task_results"] + [result],
"current_task_index": state["current_task_index"] + 1,
}

def coding_worker(state: HandoffState) -> dict:
task = state["subtasks"][state["current_task_index"]]
result = coding_llm.invoke([{"role": "user", "content": f"执行:{task['task']}"}]).content
return {
"task_results": state["task_results"] + [result],
"current_task_index": state["current_task_index"] + 1,
}

def docs_worker(state: HandoffState) -> dict:
task = state["subtasks"][state["current_task_index"]]
result = docs_llm.invoke([{"role": "user", "content": f"执行:{task['task']}"}]).content
return {
"task_results": state["task_results"] + [result],
"current_task_index": state["current_task_index"] + 1,
}

def route_to_worker(state: HandoffState) -> str:
"""路由到对应的 Worker。"""
idx = state["current_task_index"]
if idx >= len(state["subtasks"]):
return "supervisor" # 所有任务完成,回到 supervisor 汇总

assignee = state["subtasks"][idx]["assignee"]
return f"{assignee}_worker"

graph = StateGraph(HandoffState)
graph.add_node("supervisor", supervisor)
graph.add_node("devops_worker", devops_worker)
graph.add_node("coding_worker", coding_worker)
graph.add_node("docs_worker", docs_worker)

graph.set_entry_point("supervisor")
graph.add_conditional_edges("supervisor", route_to_worker, {
"devops_worker": "devops_worker",
"coding_worker": "coding_worker",
"docs_worker": "docs_worker",
"supervisor": "supervisor",
})
graph.add_conditional_edges("devops_worker", route_to_worker, {
"devops_worker": "devops_worker",
"coding_worker": "coding_worker",
"docs_worker": "docs_worker",
"supervisor": "supervisor",
})
graph.add_conditional_edges("coding_worker", route_to_worker, {
"devops_worker": "devops_worker",
"coding_worker": "coding_worker",
"docs_worker": "docs_worker",
"supervisor": "supervisor",
})
graph.add_conditional_edges("docs_worker", route_to_worker, {
"devops_worker": "devops_worker",
"coding_worker": "coding_worker",
"docs_worker": "docs_worker",
"supervisor": "supervisor",
})

app = graph.compile()

Handoff vs Router 的区别

维度RouterHandoff
任务数量一个 → 一个 Agent一个 → 多个 Agent 依次/并行
信息传递不传递Worker 结果汇总给 Supervisor
适合场景"这个问题归谁管?""这件事需要多人合作"
复杂度低(单层分类)高(编排、状态管理)

工程视角

模式选择决策树

用户的任务是什么?

├─ 简单、单次问答?
│ └─→ 直接 LLM(不需要 Agent)

├─ 需要调用工具、多步推理?
│ ├─ 步骤可预先规划?
│ │ └─→ Plan-and-Execute
│ └─ 步骤不可预知、需要探索?
│ └─→ ReAct

├─ 需要高质量输出、可自我修正?
│ └─→ Reflection

├─ 涉及多个专业领域?
│ ├─ 先分类,每个请求一个领域?
│ │ └─→ Router
│ └─ 单个请求需要多个领域合作?
│ └─→ Handoff

└─ 涉及高风险操作、需要人工把关?
└─→ Human-in-the-Loop
(可叠加到以上任何模式)

组合使用模式

生产中往往多个模式叠加使用

Router(分类)→ ReAct(执行)→ Reflection(自检)→ HITL(审核)→ 输出
组合说明场景
Router + ReAct分类后各自用 ReAct 执行多领域客服
Plan-and-Execute + Reflection每步执行后自检代码生成
ReAct + HITL多步推理后人工审核金融审批
Handoff + Reflection每个 Worker 输出后自检跨部门协作
Router + Handoff + HITL分类 → 多 Agent 合作 → 审核复杂工单

各模式的性能特征

模式平均延迟Token 成本准确率提升调试难度
直接 LLM~500ms1x基准
ReAct (3 步)~1500ms3-5x+10-20%
Reflection (1 轮)~1000ms2-3x+15-30%
Plan-and-Execute (5 步)~2500ms5-8x+20-40%
Router~700ms1.5-2x+15-25%
HITL不定2-4x+30-50%
Handoff (3 Workers)~3000ms5-10x+25-50%

面试视角

Q: ReAct 和 Plan-and-Execute 怎么选?

满分回答

  • 任务可分解、步骤固定 → Plan-and-Execute(如:数据清洗 → 分析 → 可视化)
  • 任务不可预知、需要探索 → ReAct(如:"帮我查一下这个 bug 的原因")
  • 简单判断:如果人能写出明确步骤清单 → Plan-and-Execute;如果不能 → ReAct
  • 生产建议:混合使用——Planner 制定高层计划,每步用 ReAct 执行

Q: Reflection 模式的 token 成本增加值得吗?

满分回答

  • 数据:Reflection 增加 ~30-50% token 成本,但错误率降低 50-70%
  • 对于面向用户的场景(客服、文档),值得——一个错误回答的损失远超 token 成本
  • 对于内部工具(代码生成),值得——bug 修复成本随时间指数增长
  • 优化策略:只对关键输出 Reflection;用轻量模型做 Reflection(如 GPT-4o-mini)

Q: 什么时候必须用 Human-in-the-Loop?

满分回答

  • 法律/金融/医疗领域的建议或决策——AI 无法律主体资格
  • 涉及用户数据删除、资金操作——需要用户确认
  • 内容发布——防止 AI 生成不当内容
  • 实现方式:三级风险(低自动、中审核、高人工),不要一刀切

Q: 6 大模式中哪个最难调试?为什么?

满分回答

  • Handoff 最难调试——原因:
    • 跨 Agent 信息传递可能丢失或变形
    • Supervisor 的汇总可能歪曲 Worker 的意图
    • 失败定位困难(是哪个 Worker 的问题?还是 Supervisor 的问题?)
  • 调试方法:
    • 每个 Worker 的输入输出必须记录(Langfuse Trace)
    • Supervisor 的拆解逻辑要有单元测试
    • 用 mock Worker 隔离测试编排逻辑

实战环节:构建一个智能客服系统

目标

综合运用 Router、ReAct、Reflection、HITL 4 种模式,构建一个生产级客服 Agent。

环境要求

  • Python 3.12+
  • uv add langgraph langchain-openai pydantic
  • OpenAI API key

步骤

1. 创建客服 Router

from langgraph.graph import StateGraph, END
from typing import TypedDict, Literal
from openai import OpenAI
import json

client = OpenAI()

class CustomerServiceState(TypedDict):
query: str
category: str
answer: str
risk_level: str
needs_human: bool

def classify(query: str) -> str:
"""分类:技术问题 / 账单问题 / 退款请求 / 投诉 / 一般咨询。"""
resp = client.chat.completions.create(
model="gpt-4o-mini",
messages=[{"role": "user", "content": f"""将以下客服问题分类:
{query}

类别:tech_query / billing_query / refund_request / complaint / general
只返回类别名。"""}],
)
return resp.choices[0].message.content.strip()

def route(state: CustomerServiceState) -> Literal["tech", "billing", "refund", "complaint", "general"]:
category = classify(state["query"])
return {
"tech_query": "tech",
"billing_query": "billing",
"refund_request": "refund",
"complaint": "complaint",
"general": "general",
}.get(category, "general")

def generate_answer(prompt: str) -> str:
resp = client.chat.completions.create(
model="gpt-4o",
messages=[{"role": "user", "content": prompt}],
)
return resp.choices[0].message.content

def tech_agent(state: CustomerServiceState) -> dict:
answer = generate_answer(f"""你是技术支持。回答以下技术问题。
问题:{state['query']}

产品知识库:
- API 速率限制:1000 次/小时
- 支持 REST 和 GraphQL
- 文档地址:docs.example.com
""")
return {"answer": answer}

def billing_agent(state: CustomerServiceState) -> dict:
answer = generate_answer(f"""你是账单客服。回答以下账单问题。
问题:{state['query']}

规则:
- 不能承诺具体金额
- 可以解释计费规则
- 引导用户查看账单详情页
""")
return {"answer": answer}

def refund_agent(state: CustomerServiceState) -> dict:
answer = generate_answer(f"""你是退款客服。处理以下退款请求。
请求:{state['query']}

规则:
- 7 天内可申请
- 使用量 <10% 可全额退款
- 超过 7 天只能转余额
- 回答后标记需要人工审核(risk_level=high)
""")
return {"answer": answer, "risk_level": "high"}

def complaint_agent(state: CustomerServiceState) -> dict:
answer = generate_answer(f"""你是投诉处理专员。处理以下投诉。
投诉:{state['query']}

规则:
- 先道歉
- 记录问题
- 承诺 24 小时内回复
- 标记需要人工审核(risk_level=high)
""")
return {"answer": answer, "risk_level": "high"}

def general_agent(state: CustomerServiceState) -> dict:
answer = generate_answer(f"""回答以下一般问题。
问题:{state['query']}
""")
return {"answer": answer}

def assess_risk(state: CustomerServiceState) -> dict:
"""评估回答风险。"""
risk = state.get("risk_level", "low")
return {"risk_level": risk, "needs_human": risk == "high"}

def build_graph():
graph = StateGraph(CustomerServiceState)

graph.add_node("tech", tech_agent)
graph.add_node("billing", billing_agent)
graph.add_node("refund", refund_agent)
graph.add_node("complaint", complaint_agent)
graph.add_node("general", general_agent)
graph.add_node("risk_assessment", assess_risk)

graph.set_entry_point("route") # 需要先定义 route 节点
graph.add_node("route", route)

graph.add_conditional_edges("route", route, {
"tech": "tech",
"billing": "billing",
"refund": "refund",
"complaint": "complaint",
"general": "general",
})

for node in ["tech", "billing", "refund", "complaint", "general"]:
graph.add_edge(node, "risk_assessment")

# 高风险需要人工
graph.add_conditional_edges("risk_assessment", lambda s: "human" if s["needs_human"] else "end", {
"human": END, # 实际生产中标记为 pending human review
"end": END,
})

return graph.compile()

# 运行
app = build_graph()

# 测试不同场景
test_queries = [
"API 返回 502 错误怎么办?", # → tech
"这个月账单为什么比上个月多?", # → billing
"我要退款,刚买 3 天还没怎么用", # → refund + HITL
"你们的服务太差了!", # → complaint + HITL
"你们公司成立几年了?", # → general
]

for q in test_queries:
print(f"\n{'='*50}")
print(f"问题:{q}")
result = app.invoke({
"query": q, "category": "", "answer": "",
"risk_level": "", "needs_human": False,
})
print(f"回答:{result['answer']}")
print(f"风险:{result['risk_level']} | 需人工:{result['needs_human']}")

2. 加入 Reflection 自检

在 tech_agent 和 billing_agent 后面加入 Reflection 节点:

def reflection_check(state: CustomerServiceState) -> dict:
"""Reflection 自检——检查回答是否准确、完整、无幻觉。"""
resp = client.chat.completions.create(
model="gpt-4o-mini", # 用轻量模型做 Reflection
messages=[{"role": "user", "content": f"""审核以下客服回答。

问题:{state['query']}
回答:{state['answer']}

审核标准:
1. 是否直接回答了问题(没有回避)
2. 是否有事实错误
3. 是否遗漏关键信息
4. 是否有不当承诺

返回 JSON:
{{"passed": true/false, "issues": "问题列表或空数组", "corrected": "修正后的回答(如有问题)"}}
"""}],
)
result = json.loads(resp.choices[0].message.content)

if result["passed"]:
return {"answer": state["answer"]}
else:
return {"answer": result["corrected"]}

# 在 graph 中加入:
# graph.add_node("reflection", reflection_check)
# 在每个 agent 节点和 risk_assessment 之间加入 reflection

验证成功

  • Router 能正确分类 5 种问题类型
  • tech 和 billing 回答准确、无需人工
  • refund 和 complaint 自动标记为高风险、需人工
  • Reflection 能发现回答中的事实错误并修正
  • 整个流程在 3 秒内完成(不含人工审核等待)

思考题

  1. 如果 Router 分类错误(如把技术问题误分类为账单问题),如何增加"再分类"机制?
  2. 在 Reflection 环节,用 GPT-4o-mini 做审核和用 GPT-4o 有什么区别?成本差异和准确率差异分别是多少?
  3. 如何把 HITL 对接到真实的工单系统(如 Zendesk、Jira Service Desk)?

上一阶段:← 检查清单与面试 | 下一阶段:评估与可观测性 →