系列简介:从零搭建一个多 Agent AI 助手,覆盖原理、实现、部署全链路。不讲空话,每篇都有可运行的代码。
项目地址:github.com/CodeMomentY…
本篇目标:理解 Agent 的三种工作模式,知道什么场景用哪种。
前言
大家好,我是一名前端工程师。都说前端“已死”,那与其担心被 AI 替代,不如打入敌人内部,于是我开始折腾 Agent 开发。
折腾下来发现,Agent 的核心不是算法,而是“工程能力”(怎么设计架构、怎么串联服务、怎么把 LLM 的能力落地成产品)。这些恰好是我们擅长的事。
这个系列记录我从零搭建多 Agent 系统的完整过程。只聊技术知识和设计思路,代码交给 AI 写。如果你也想从应用层切入 AI,希望这个系列对你有帮助。
读完本篇你将学到:
- Agent 的三种经典工作模式(范式);
- 每种范式的核心思想和适用场景;
- 三种范式的代码实现对比;
- 什么时候该用哪种,什么时候组合使用;
背景与动机
上一篇我们搞清楚了 Agent 的本质:LLM + 工具 + 循环。但“循环”具体怎么循环,其实有不同的策略。
打个比方:你接到一个任务“帮我规划一次北京三日游”。
- 方式 A:边想边做。先查天气,看到晴天,那就安排户外景点,再查景点,发现故宫周一闭馆,那换一个...一步步推进。
- 方式 B:先规划再执行。先列出三天的大纲(Day1 历史、Day2 自然、Day3 美食),然后逐个填充细节。
- 方式 C:做完检查一遍。先生成一版计划,然后自己审视“有没有遗漏?时间安排合理吗?”,不满意就修改。
这三种方式对应 Agent 的三大范式:ReAct、Plan-and-Solve、Reflection。
核心概念
我们对比一下这三种范式的流程:
用一张表来总结一下:
| ReAct | Plan-and-Solve | Reflection | |
|---|---|---|---|
| 核心思想 | 边想边做 | 先规划后执行 | 做完自检 |
| 循环方式 | 思考→行动→观察→思考... | 规划→执行步骤1→执行步骤2... | 生成→反思→修改→再反思... |
| 优势 | 灵活,能应对意外 | 有条理,不遗漏 | 质量高,能自我修正 |
| 劣势 | 可能跑偏 | 规划错了全盘皆输 | 慢(多次 LLM 调用) |
| 适合场景 | 简单查询、工具调用 | 复杂多步任务 | 写作、代码生成 |
| 类比 | 即兴发挥 | 写提纲再写文章 | 写完改稿 |
动手实现
ReAct 范式:边想边做
ReAct 是最常用的范式,上一篇我们其实已经实现了。核心就是 Thought → Action → Observation 的循环:
"""
ReAct 范式:边想边做
适合:需要调用工具获取信息的场景
"""
REACT_PROMPT = """你是一个助手,请按以下格式思考和行动:
Thought: 我需要做什么
Action: 工具名(参数)
Observation: 工具返回的结果
... (重复直到有足够信息)
Thought: 我现在可以回答了
Answer: 最终回答
"""
def react_agent(user_input):
messages = [{"role": "system", "content": REACT_PROMPT}]
messages.append({"role": "user", "content": user_input})
for _ in range(5): # 最多 5 轮
response = call_llm(messages)
if "Action:" in response:
# 解析并执行工具
tool_result = execute_tool(response)
messages.append({"role": "assistant", "content": response})
messages.append({"role": "user", "content": f"Observation: {tool_result}"})
elif "Answer:" in response:
return response.split("Answer:")[-1].strip()
return "处理超时"
特点:每一步都能看到中间过程,灵活应对意外情况。但如果任务复杂(比如需要 10 个步骤),可能会跑偏。
Plan-and-Solve 范式:先规划后执行
先让 LLM 列出计划,再逐步执行。适合复杂的多步任务:
"""
Plan-and-Solve 范式:先规划后执行
适合:复杂多步任务(旅行规划、研究报告)
"""
PLAN_PROMPT = """请先制定计划,再逐步执行。
格式:
Plan:
1. 第一步做什么
2. 第二步做什么
3. 第三步做什么
然后逐步执行每一步。
"""
def plan_and_solve_agent(user_input):
# 阶段 1:生成计划
plan_response = call_llm([
{"role": "system", "content": PLAN_PROMPT},
{"role": "user", "content": user_input}
])
steps = parse_plan(plan_response) # 提取步骤列表
# 阶段 2:逐步执行
results = []
for step in steps:
result = call_llm([
{"role": "system", "content": "请执行以下任务步骤"},
{"role": "user", "content": f"任务:{step}\n已有信息:{results}"}
])
results.append(result)
# 阶段 3:整合结果
final = call_llm([
{"role": "system", "content": "请整合以下信息,生成最终回答"},
{"role": "user", "content": str(results)}
])
return final
特点:有条理,适合"帮我写一份报告"这种需要结构化输出的任务。但如果第一步规划错了,后面全跟着错。
Reflection 范式:做完自检
生成回答后让 LLM 自我检查,不满意就修改。适合对质量要求高的场景:
"""
Reflection 范式:生成 + 自我反思
适合:写作、代码生成等需要高质量输出的场景
"""
def reflection_agent(user_input, max_rounds=3):
# 第一次生成
draft = call_llm([
{"role": "system", "content": "你是一个写作助手"},
{"role": "user", "content": user_input}
])
for round in range(max_rounds):
# 反思:检查质量
critique = call_llm([
{"role": "system", "content": "请严格评审以下内容,指出问题。如果质量够好,回复'PASS'"},
{"role": "user", "content": f"原始需求:{user_input}\n\n当前内容:\n{draft}"}
])
if "PASS" in critique:
return draft # 质量够了
# 根据反馈修改
draft = call_llm([
{"role": "system", "content": "请根据反馈修改内容"},
{"role": "user", "content": f"当前内容:\n{draft}\n\n反馈:\n{critique}"}
])
return draft # 达到最大轮次
特点:输出质量高,但每多一轮反思就多两次 LLM 调用(一次评审 + 一次修改),速度慢、成本高。
效果对比
问同一个问题“帮我写一段产品介绍”,三种范式的表现:
| 范式 | LLM 调用次数 | 耗时 | 输出质量 |
|---|---|---|---|
| ReAct | 1 次 | ~3 秒 | 一般 |
| Plan-and-Solve | 3-4 次 | ~10 秒 | 较好 |
| Reflection | 5-7 次 | ~20 秒 | 最好 |
组合使用:Plan + ReAct + Reflect
实际项目中,三种范式经常组合。比如“帮我规划北京三日游并写成攻略”:
看一下代码实现:
"""
三范式组合:Plan 拆任务 → ReAct 执行每步 → Reflect 检查质量
"""
def combined_agent(user_input):
# 阶段 1:Plan(拆解任务)
plan = call_llm([
{"role": "system", "content": "请将任务拆解为 3-5 个步骤"},
{"role": "user", "content": user_input}
])
steps = parse_plan(plan)
# 阶段 2:ReAct(逐步执行,每步可调工具)
results = []
for step in steps:
result = react_agent(step) # 复用上面的 ReAct 逻辑
results.append(result)
# 阶段 3:Reflect(整合并自检)
draft = call_llm([
{"role": "system", "content": "请整合以下信息,生成完整攻略"},
{"role": "user", "content": str(results)}
])
# 自检一轮
critique = call_llm([
{"role": "system", "content": "检查攻略是否完整,有无遗漏"},
{"role": "user", "content": draft}
])
if "PASS" not in critique:
draft = call_llm([
{"role": "system", "content": "根据反馈修改"},
{"role": "user", "content": f"{draft}\n\n反馈:{critique}"}
])
return draft
这就是我们后面搭建多 Agent 时用的思路——dispatcher 做 Plan(判断走哪些 Agent),各 Agent 内部用 ReAct(调工具),写作类任务可以加 Reflect。
刨根问底
| 序号 | 问题 |
|---|---|
| 1️⃣ | Q:实际项目中只用一种范式吗? |
| A:不是。实际项目经常组合使用。比如:天气查询用 ReAct(简单,调一次工具就够了);深度研究用 Plan-and-Solve(先规划子任务,再逐个执行);写文案可以加 Reflection(生成后自检修改)。 | |
| 2️⃣ | Q:怎么决定用哪种范式? |
| A:看任务复杂度。一两步就能完成 → ReAct;需要多步骤、有明确结构 → Plan-and-Solve;对输出质量要求高、允许慢一点 → Reflection。 | |
| 3️⃣ | Q:Reflection 会不会无限循环? |
| A:会,所以必须加 max_rounds 限制。而且有时候 LLM 的“评审员”和“写作者”是同一个模型,可能会陷入“改来改去越改越差”的情况。所以实际使用中 2-3 轮就够了。 |
本篇小结
- Agent 有三种经典工作模式:ReAct(边想边做)、Plan-and-Solve(先规划后执行)、Reflection(做完自检);
- 没有最好的范式,只有最适合的——根据任务复杂度和质量要求选择;
- 实际项目中经常组合使用多种范式;
- 核心差异在于"循环的策略"不同,底层都是 LLM + 工具;
写在最后
三种范式看起来是三种“技术方案”,但本质是三种“思维方式”。ReAct 像是敏捷开发(快速迭代、随时调整)、Plan-and-Solve 像是瀑布模型(先设计后实现);Reflection 像是 Code Review(写完回头审视)。
选范式和选开发流程一样,没有万能解,只有取舍。
下一篇预告:有了范式的认知,接下来我们用 LangGraph 框架搭建一个真正的多 Agent 系统——多个 Agent 各司其职,dispatcher 动态路由,支持串行和并行执行。