1. 引言:为什么需要不同的Agent架构
在第1章中,我们建立了对AI智能体(AI Agent)的基本认知:智能体是一个能够感知环境、自主决策、执行行动并持续循环直到完成目标的系统。如果把大语言模型(LLM)比作"大脑",那么架构就是大脑与手脚之间的"神经系统"——它决定了智能体如何思考、何时行动、如何反馈。
💡 生活比喻:架构之于智能体,就像"工作流程"之于一家公司。同样是接到客户订单,路边小吃店老板一个人就能从接单、做饭到收钱全包;而大型连锁餐厅则需要前台、后厨、配送、财务多个岗位配合。规模不同,“流程"就不同。智能体架构也是如此——任务简单就用简单流程,任务复杂才需要复杂流程。
现实世界中的任务复杂度千差万别。一个"把今天的天气告诉我"的请求,与"帮我调研三家竞品并输出对比报告"的任务,所需的推理深度、工具调用次数、错误恢复能力完全不在一个量级。如果对所有任务都套用最复杂的架构,不仅浪费token、增加延迟,还会因链条过长而放大幻觉风险;反之,若对复杂任务只用单次LLM调用,又必然力不从心。
⚠️ 常见误区:很多初学者一上来就想搭"多Agent协作系统”,结果发现简单的翻译任务也被拆成七八次调用,既慢又贵。架构不是越复杂越好,而是越匹配越好。
因此,架构选型的本质是在"能力上限"与"成本/复杂度"之间寻找平衡点。本章将带你从最简单的单次调用出发,逐级演进到ReAct、Plan-and-Execute、Reflection,直至多Agent协作,让你在面对具体需求时能够做出合理的工程决策。
2. 架构演进路线图(从简单到复杂)
我们可以把智能体架构按"自主性"和"复杂度"划分为五个层级:
| 层级 |
架构名称 |
核心特征 |
典型适用场景 |
| Level 1 |
单次LLM调用 |
一次提示,一次回答 |
翻译、摘要、简单问答 |
| Level 2 |
ReAct |
思考-行动-观察循环 |
工具调用、信息检索 |
| Level 3 |
Plan-and-Execute |
先规划再分步执行 |
多步骤复杂任务 |
| Level 4 |
Reflection |
自我反思与迭代改进 |
代码生成、写作优化 |
| Level 5 |
多Agent协作 |
角色分工协同 |
大型项目、研究任务 |
💡 一图记五层:可以把它想象成"做事的人"在升级——Level 1 是"问一句答一句的客服";Level 2 是"边查资料边回答的助理";Level 3 是"先列清单再逐项做的项目经理";Level 4 是"做完自己检查改错的工匠";Level 5 是"分工合作的项目团队"。
演进的内在逻辑是:每解决上一层的瓶颈,就诞生下一层架构。单次调用无法使用工具,于是有了ReAct;ReAct缺乏全局规划容易"走偏",于是有了Plan-and-Execute;后者产出质量依赖单次生成,于是加入Reflection做迭代打磨;当任务规模超出单Agent承载能力时,便走向多Agent协作。
⚠️ 注意:这五层不是"替换"关系,而是"叠加"关系。高级架构内部往往嵌套着低级架构,例如 Plan-and-Execute 的执行器内部就常常使用 ReAct。理解了这一点,你才能灵活组合,而不是死记硬背。
3. Level 1:单次LLM调用(最简单的Agent)
3.1 生活比喻
Level 1 就像自动售货机:你投币(输入提示),它出货(给出回答),一次完成,没有后续动作。它不会"再去仓库找货",也不会"问你要不要加购"。简单、直接、可预测。
严格来说,单次LLM调用算不上完整的"智能体"——它没有循环、没有工具、没有状态。但它是所有更复杂架构的原子单元,理解它能帮你认清"何时真的需要升级架构"。
3.2 这段代码做了什么
下面这段代码实现一个"中英互译"小程序:先告诉LLM"你是翻译官,只输出译文",再把待翻译文本作为用户消息发给它,最后取出回复内容返回。整个过程只调用一次API,没有任何循环或工具。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
|
# file: level1_single_call.py
# 单次LLM调用示例:中英互译
import os
from openai import OpenAI
# 初始化客户端,API Key从环境变量读取(避免硬编码泄露密钥)
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
def translate(text: str, direction: str = "zh2en") -> str:
"""根据方向完成中英互译"""
# 根据方向决定源语言和目标语言
src, dst = ("中文", "英文") if direction == "zh2en" else ("英文", "中文")
# 构造系统提示,限定LLM的角色与输出格式
system_prompt = f"你是一个专业翻译,负责将{src}翻译成{dst},只输出译文。"
# 单次调用:一次system + 一次user,得到一次response
response = client.chat.completions.create(
model="gpt-5.4", # 模型名可按你账号可用的模型替换
messages=[
{"role": "system", "content": system_prompt}, # 设定角色
{"role": "user", "content": text}, # 用户输入
],
temperature=0.3, # 低温度让翻译更稳定、少发挥
)
# choices[0].message.content 即模型生成的文本
return response.choices[0].message.content.strip()
if __name__ == "__main__":
print(translate("人工智能正在改变软件开发的范式。", "zh2en"))
# 输出示例:Artificial intelligence is changing the paradigm of software development.
|
💡 小贴士:temperature 控制"随机性"。翻译这类要求稳定的任务用 00.3;写诗、起标题等需要创意的任务可调到 0.71.0。
⚠️ 注意事项:务必把 API Key 放在环境变量里,不要直接写进代码再提交到 GitHub,否则会被爬虫盗用导致账单爆炸。
3.3 为什么选这个架构(对比分析)
| 维度 |
Level 1 单次调用 |
Level 2+ 更复杂架构 |
| 实现难度 |
极低,十几行代码 |
中到高 |
| 延迟 |
一次API往返,最快 |
多次调用,明显变慢 |
| 成本 |
最省token |
成倍增加 |
| 能力 |
不能用工具、不能多步推理 |
可查资料、可分步、可反思 |
适用场景:输入输出明确、无需外部信息、单步即可完成。
局限性:无法调用工具(如搜索、计算器)、无法处理需要多轮推理的任务、无法根据中间结果调整策略。一旦你的任务需要"先查再答"或"分步走",就该升级到Level 2了。
4. Level 2:ReAct架构(思考-行动-观察循环)
4.1 生活比喻
ReAct 就像你查字典做作业:遇到一道题(用户问题),你不是立刻写答案,而是先想"我需要先查这个词的意思"(Thought → Action),查完看到解释(Observation),再想"现在我能答题了吗?"——不能就再查一次,能了就写下最终答案(Final Answer)。“先想、再做、再看结果"不断循环,这就是 ReAct。
4.2 原理图解
ReAct(Reasoning + Acting)由Yao等人于2022年提出,核心思想是让LLM交替输出"思考"和"行动”,并在行动后获取"观察"结果反馈给LLM,形成闭环:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
用户输入
│
▼
┌─────────────────────────────┐
│ LLM 推理:Thought → Action │ ← 循环开始
└─────────────────────────────┘
│ Action(如 search("天气"))
▼
┌─────────────────────────────┐
│ 工具执行 / 环境反馈 │
└─────────────────────────────┘
│ Observation(如 "北京 25℃ 晴")
▼
┌─────────────────────────────┐
│ LLM 再推理:是否已能回答? │
└─────────────────────────────┘
│
├── 否 → 回到循环顶部
└── 是 → 输出 Final Answer
|
关键点在于:LLM本身不直接执行工具,它只生成"行动指令";执行由外部代码完成,结果再注入回对话。这种"思考-行动-观察"的文本协议让LLM在无需微调的情况下获得工具使用能力。
⚠️ 注意:这里有个容易混淆的点——LLM 输出的是"文本形式的指令"(比如字符串 Action: search),真正去调用 search() 函数的是我们写的 Python 代码。LLM 只负责"决定用什么工具、传什么参数",不负责"动手"。
4.3 这段代码做了什么
下面用纯Python(不依赖LangChain)实现一个完整ReAct智能体。它注册了两个工具:计算器和搜索;然后用一段提示词告诉LLM"请按 Thought/Action/Action Input 的格式输出";主循环里每次拿到LLM输出就用正则解析出动作,执行对应工具,再把观察结果塞回对话让LLM继续推理,直到它给出 Final Answer 或达到步数上限。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
|
# file: level2_react_agent.py
# ReAct架构智能体:纯Python实现,不依赖LangChain
import os
import re
from openai import OpenAI
# 初始化客户端,密钥从环境变量读取
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
# ---------- 工具定义 ----------
def calculator(expression: str) -> str:
"""简易计算器,仅支持四则运算"""
try:
# 用正则限制字符集,防止恶意注入(如导入os)
if not re.match(r"^[\d\s\+\-\*/\.\(\)]+$", expression):
return "错误:表达式包含非法字符"
# 字符集已限定,此处eval相对安全
return str(eval(expression))
except Exception as e:
return f"计算出错:{e}"
def search(query: str) -> str:
"""模拟搜索工具(真实场景可接入搜索API)"""
# 这里用一个字典假装是搜索引擎的返回
fake_db = {
"北京天气": "北京今日 25℃,晴,微风",
"上海天气": "上海今日 28℃,多云",
"Python版本": "Python最新稳定版为 3.13",
}
return fake_db.get(query.strip(), f"未找到关于'{query}'的信息")
# 工具注册表:名称 -> (函数, 描述)
# 描述会拼进提示词,让LLM知道有哪些工具可用
TOOLS = {
"calculator": (calculator, "四则运算计算器,输入数学表达式,如 3*8+2"),
"search": (search, "信息搜索工具,输入关键词查询天气、常识等"),
}
# ---------- ReAct 提示模板 ----------
REACT_PROMPT = """你是一个使用ReAct模式工作的智能体。
可用工具:
{tool_descriptions}
请严格按以下格式输出,每一步用关键词分隔:
Thought: 你的思考过程
Action: 工具名称
Action Input: 工具输入参数(字符串)
当你已得到足够信息可以回答用户问题时,输出:
Thought: 我已经可以回答了
Final Answer: 最终答案
问题:{question}
"""
def build_tool_description() -> str:
"""构造工具说明文本,拼成提示词的一部分"""
lines = []
for name, (_, desc) in TOOLS.items():
lines.append(f"- {name}: {desc}")
return "\n".join(lines)
def parse_action(text: str):
"""从LLM输出中解析出 Action 和 Action Input,或 Final Answer"""
# 用正则匹配各关键字后的内容
action_match = re.search(r"Action:\s*(.+)", text)
input_match = re.search(r"Action Input:\s*(.+)", text)
final_match = re.search(r"Final Answer:\s*([\s\S]+)", text)
# 优先判断是否已给出最终答案
if final_match:
return "final", final_match.group(1).strip()
if action_match and input_match:
return action_match.group(1).strip(), input_match.group(1).strip()
return None, None # 格式不符时返回None,由主循环兜底处理
def react_agent(question: str, max_steps: int = 5) -> str:
"""ReAct主循环:思考-行动-观察,直到得出答案或步数耗尽"""
messages = [
{"role": "system", "content": REACT_PROMPT.format(
tool_descriptions=build_tool_description(), # 注入工具清单
question=question, # 注入用户问题
)},
]
for step in range(max_steps):
# 1. LLM推理:生成 Thought + Action
resp = client.chat.completions.create(
model="gpt-5.4",
messages=messages,
temperature=0.2, # 低温度让格式更稳定
)
output = resp.choices[0].message.content
print(f"\n===== Step {step + 1} =====")
print(output)
# 2. 解析动作(要么是工具调用,要么是final)
action, action_input = parse_action(output)
# 3. 若给出最终答案,结束循环
if action == "final":
return action_input
# 4. 执行工具
if action in TOOLS:
tool_fn, _ = TOOLS[action] # 取出对应函数
observation = tool_fn(action_input) # 真正"动手"执行
print(f"Observation: {observation}")
# 把LLM的输出和观察结果都塞回对话,供下一轮推理
messages.append({"role": "assistant", "content": output})
messages.append({"role": "user", "content": f"Observation: {observation}"})
else:
# 工具名不存在时提示LLM重新选择
messages.append({"role": "assistant", "content": output})
messages.append({"role": "user", "content": f"Observation: 工具'{action}'不存在,请从可用工具中选择。"})
return "达到最大步数,未能得出答案。"
if __name__ == "__main__":
# 测试:计算并搜索的组合任务
answer = react_agent("北京今天多少度?如果把这个温度乘以2再加10是多少?")
print(f"\n最终答案:{answer}")
|
运行后你将看到智能体先调用 search 查询北京天气,再用 calculator 计算 25*2+10=60,最终给出答案。整个过程无需微调,完全靠提示工程与文本协议驱动。
💡 小贴士:max_steps 是必备的"安全气囊"。没有它,一旦LLM陷入"查了又查"的死循环,你的API账单会一路飙升。生产环境建议设 5~10 步。
⚠️ 注意事项:示例中的 calculator 用了 eval。虽然前面用正则限制了字符集,但 eval 始终有风险。生产环境请改用 ast.literal_eval 或专门的数学解析库(如 numexpr、sympy)。
4.4 适用场景与局限性
适用场景:需要调用工具、信息检索、简单多步推理。
局限性:
- 缺乏全局规划:每一步只看上一步结果,容易在长链任务中"走偏"或陷入循环;
- 错误传播:某步观察错误会污染后续推理;
- 步数失控:需要外部
max_steps 兜底,否则可能无限循环。
4.5 调试与排错小贴士
ReAct 智能体最常见的故障是"格式不对"——LLM 没有按 Thought/Action/Action Input 的关键字输出,导致 parse_action 解析失败。排查时可关注三点:第一,把每一步的原始输出打印出来,肉眼检查格式;第二,提示词里加一句"严格按格式输出,不要加多余解释"并给出示例;第三,若模型支持 Function Calling,可改用结构化调用代替文本协议,稳定性会高很多。
另一个高频问题是"工具名拼错"。LLM 可能输出 Calculator(大写)或 compute(同义词),而注册表里只有小写 calculator。解决方法是在 parse_action 里做大小写归一化和别名映射,或当工具不存在时把可用清单再提示一遍,让模型自我纠正。
💡 小贴士:调试时把 temperature 临时调到 0,能减少随机性,更容易复现问题。问题定位后再调回原值。
5. Level 3:Plan-and-Execute架构
5.1 生活比喻
Plan-and-Execute 就像出差前的行程规划:你不会到了机场才想"先飞哪、住哪、见谁",而是出发前先列一张清单——1.订机票 2.订酒店 3.联系客户 4.准备资料——然后逐项执行。中途如果航班取消,你就修订后续计划(Replan)。“先想清楚要做哪些事,再一件件做”,这就是它和 ReAct 的根本区别。
5.2 Planner + Executor分离
Plan-and-Execute的核心改进是先规划、再执行。它把"想清楚要做哪些子任务"和"逐个完成子任务"解耦:
- Planner:一次性生成有序的子任务列表(计划);
- Executor:依次执行每个子任务,可使用ReAct或单次调用;
- Replanner(可选):执行中如遇意外,可动态修订剩余计划。
这种"谋定而后动"的方式显著提升了长任务的稳定性。
5.3 这段代码做了什么
下面实现一个简化版 Plan-and-Execute。plan() 让LLM把任务拆成JSON数组形式的子任务清单;execute() 逐个执行子任务并把已完成的上下文带进去;最后再让LLM把所有子任务结果汇总成最终答案。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
|
# file: level3_plan_execute.py
# Plan-and-Execute架构智能体
import os
import json
from openai import OpenAI
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
PLANNER_PROMPT = """你是一个任务规划器。请将用户任务拆分为有序的子任务列表。
每个子任务应可独立执行,粒度适中(不多于5个子任务)。
仅输出JSON数组,不要其他文字,格式如:
["子任务1", "子任务2"]
用户任务:{task}
"""
EXECUTOR_PROMPT = """你是一个任务执行器。请完成以下子任务。
你可以使用如下已知能力:搜索、计算、翻译、写作。
若需要外部信息,可基于常识合理假设并在结果中标注"假设"。
仅输出执行结果,不要解释过程。
子任务:{subtask}
上下文(已完成结果):{context}
"""
def plan(task: str) -> list:
"""生成子任务计划:让LLM输出JSON数组"""
resp = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": PLANNER_PROMPT.format(task=task)}],
temperature=0.2, # 规划阶段低温度,让拆解更稳定
)
raw = resp.choices[0].message.content.strip()
try:
return json.loads(raw) # 把JSON文本解析成Python列表
except json.JSONDecodeError:
# 解析失败则退化为单任务,保证不崩
return [task]
def execute(subtask: str, context: str) -> str:
"""执行单个子任务,带上已完成结果作为上下文"""
resp = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": EXECUTOR_PROMPT.format(
subtask=subtask, context=context
)}],
temperature=0.3,
)
return resp.choices[0].message.content.strip()
def plan_execute_agent(task: str) -> str:
"""Plan-and-Execute主流程:规划→执行→汇总"""
# 1. 规划:拆出子任务清单
subtasks = plan(task)
print(f"计划:{subtasks}")
# 2. 依次执行,并累积上下文(后面的子任务能看到前面的结果)
context_parts = []
for i, st in enumerate(subtasks, 1):
result = execute(st, "\n".join(context_parts))
context_parts.append(f"[{i}] {st} -> {result}") # 拼进上下文
print(f"执行[{i}]:{st}\n结果:{result}\n")
# 3. 汇总:让LLM把所有子任务结果整理成最终答案
summary_prompt = f"请根据以下子任务结果,回答原始任务:\n原始任务:{task}\n子任务结果:\n" + "\n".join(context_parts)
resp = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": summary_prompt}],
temperature=0.3,
)
return resp.choices[0].message.content.strip()
if __name__ == "__main__":
print(plan_execute_agent("帮我调研Python和Rust在Web开发中的优劣,并给出学习建议。"))
|
💡 小贴士:让LLM输出JSON时,加一句"仅输出JSON,不要其他文字"能大幅提高解析成功率。如果模型支持 response_format={"type": "json_object"},用它会更加稳。
⚠️ 注意事项:Planner 拆出的子任务可能粒度不均——有时太粗(一个子任务啥都包了),有时太碎(拆成20条)。可以通过提示词约束"3~5个、每个可独立完成"来缓解。
5.4 与ReAct对比
| 维度 |
ReAct |
Plan-and-Execute |
| 规划方式 |
边走边看,逐步决策 |
先全局规划,再分步执行 |
| 上下文窗口压力 |
全程累积,易超长 |
子任务隔离,可裁剪上下文 |
| 错误恢复 |
较弱,依赖单步反思 |
较强,可Replan修订计划 |
| LLM调用次数 |
与步数1:1 |
规划1次 + 执行N次 + 汇总1次 |
| 适用任务长度 |
短至中等(2-6步) |
中至长(5-15步) |
| 实现复杂度 |
中 |
中高 |
简单经验:步数≤5且任务动态性强 → ReAct;步数>5且可预先拆解 → Plan-and-Execute。
💡 混合玩法:实际工程中,Plan-and-Execute 的 Executor 往往内部就是一个 ReAct 智能体——先用规划拿到清单,再让 ReAct 逐项执行并查资料。这种"外层规划、内层反应"的组合,兼顾了全局视野和局部灵活性,是生产环境最常见的搭配之一。
6. Level 4:Reflection/Self-Critique架构
6.1 生活比喻
Reflection 就像写作文先打草稿再自己改:第一稿写完不直接交,而是回头读一遍,发现"这段没说清、那个例子不贴切",改完再读,直到满意为止。在智能体里,“写作文"的角色叫 Generator,“挑毛病"的角色叫 Critic,两者循环直到通过审查。
6.2 自我反思与迭代改进
Reflection架构让智能体在产出结果后自我审视,发现不足并迭代改进,直到满足质量标准或达到上限。它通常由两个角色构成:
- Generator(生成器):产出初始结果;
- Critic(评审器):对结果打分并提出改进建议;
- 循环:Generator根据Critic反馈重新生成。
这在代码生成、技术写作等"质量可判定"的场景中效果尤为显著。
⚠️ 注意:Critic 必须有明确的"合格标准”(比如输出 PASS),否则会无限挑刺、永远停不下来。同时 Critic 自己也是LLM,可能误判——所以最好限制迭代次数(如3轮)。
6.3 这段代码做了什么
下面以"生成Python函数"为例:generate() 负责写代码(或根据反馈改代码),critique() 负责审查并给出意见(合格就回 PASS)。主循环里先生成、再审查,若审查通过就停,否则带着反馈重新生成,最多迭代3轮。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
# file: level4_reflection.py
# Reflection架构智能体:代码生成与自我改进
import os
from openai import OpenAI
client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))
GENERATOR_PROMPT = """你是一个Python工程师。请根据需求生成代码。
若收到改进建议,请据此修订代码并输出完整版本。
需求:{requirement}
上一版代码:
{previous_code}
改进建议:
{feedback}
只输出Python代码,不要解释。
"""
CRITIC_PROMPT = """你是一个严格的代码审查员。请审查以下代码:
需求:{requirement}
代码:
{code}
请从以下维度评审:正确性、健壮性、可读性、边界处理。
若代码已合格,输出:PASS
否则输出具体改进建议(不超过3条)。
"""
def generate(requirement: str, previous_code: str, feedback: str) -> str:
"""生成器:产出或修订代码"""
resp = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": GENERATOR_PROMPT.format(
requirement=requirement,
previous_code=previous_code or "(无)", # 首轮没有上一版
feedback=feedback or "(无)", # 首轮没有反馈
)}],
temperature=0.4, # 略高温度,鼓励多样化尝试
)
return resp.choices[0].message.content.strip()
def critique(requirement: str, code: str) -> str:
"""评审器:检查并给出反馈(合格返回PASS)"""
resp = client.chat.completions.create(
model="gpt-5.4",
messages=[{"role": "user", "content": CRITIC_PROMPT.format(
requirement=requirement, code=code
)}],
temperature=0.2, # 审查要严格稳定,用低温度
)
return resp.choices[0].message.content.strip()
def reflection_agent(requirement: str, max_iterations: int = 3) -> str:
"""Reflection主循环:生成→评审→改进,直到通过或达上限"""
code = "" # 上一版代码,首轮为空
feedback = "" # 评审反馈,首轮为空
for i in range(max_iterations):
# 1. 生成/修订代码
code = generate(requirement, code, feedback)
print(f"\n--- 第{i+1}轮代码 ---\n{code}\n")
# 2. 评审
feedback = critique(requirement, code)
print(f"评审反馈:{feedback}\n")
# 3. 通过则退出循环
if "PASS" in feedback:
print("代码通过审查。")
break
return code
if __name__ == "__main__":
req = "写一个函数,输入整数列表,返回其中第二大的数。要求处理空列表、单元素列表等边界情况。"
final_code = reflection_agent(req)
print(f"\n最终代码:\n{final_code}")
|
💡 小贴士:Generator 和 Critic 最好用不同的提示词甚至不同的模型/温度,避免"自己审自己"时互相迁就、挑不出毛病。让 Critic 角色"严格、挑剔"是关键。
适用场景:代码生成、文档撰写、翻译润色等有明确质量标准的任务。
局限性:评审器本身可能误判;迭代会成倍增加token消耗;对"开放性创意"任务效果不稳定(创意没有唯一正确答案,Critic 难以判定"合格”)。
6.4 适用边界再强调
Reflection 不是万能药。对于"写一首关于秋天的诗"这类开放性任务,Critic 很难给出客观的合格标准,迭代往往变成"个人品味拉锯战",反而越改越平庸。它的甜区是有可验证标准的任务:代码能跑通且测试通过、翻译忠实原文、文档覆盖指定要点。在这些场景下,Critic 的反馈是具体且可执行的,迭代才有意义。
⚠️ 注意事项:别让 Reflection 成本失控。每多一轮迭代,token 消耗约翻倍。建议先用2轮验证收益,再决定是否加大迭代上限。
7. Level 5:多Agent协作架构(概述)
7.1 生活比喻
多Agent协作就像公司里不同岗位的人配合做事:一个项目来了,项目经理拆活、派给前端、后端、测试,大家各干各的又互相交接,最后由项目经理汇总交付。没有谁全包,但通过分工和沟通把大事做成。
当任务规模进一步扩大——例如"完成一份行业研究报告"涉及资料搜集、数据分析、图表绘制、报告撰写等多个专业环节——单Agent的上下文与角色定位都会捉襟见肘。这时引入多Agent协作架构:每个Agent专注一个角色,通过结构化的消息传递协同完成整体任务。
7.2 常见协作模式
常见协作模式包括:
- 串行流水线:Agent A → B → C,前者输出作为后者输入;就像工厂流水线,上一道工序的成品是下一道的原料。
- 层级委派:一个Manager Agent拆解任务并分发给Worker Agents,再汇总结果;就像经理派活给组员再收作业。
- 辩论/投票:多个Agent对同一问题各自作答,通过比较择优;就像请多位专家各写一版方案再投票。
- 对等协作:Agent间双向通信,动态协商分工(如AutoGen的GroupChat);就像圆桌会议上大家自由讨论、自发认领任务。
💡 小贴士:多Agent不是"越多越好"。每多一个Agent,通信开销、协调难度、调试成本都会上升。能用一个Agent搞定的,就别拆成三个。
⚠️ 注意事项:多Agent系统最怕"死循环"——A等B回复、B等A确认,谁都不动。务必设计好"谁听谁的"、设置超时和最大轮数兜底。
多Agent协作的工程细节(角色设计、通信协议、状态管理、死锁避免)将在第9章深入展开,本章仅作概念性铺垫。
8. 架构选型决策树
面对一个新任务,如何选择合适的架构?可参考如下决策路径:
| 步骤 |
判断条件 |
推荐架构 |
| 1 |
任务可一步完成、无需工具? |
是 → Level 1 单次调用 |
| 2 |
需要调用工具,但步数≤5? |
是 → Level 2 ReAct |
| 3 |
步数>5或可预先拆解为子任务? |
是 → Level 3 Plan-and-Execute |
| 4 |
产出有明确质量标准、可迭代改进? |
是 → Level 4 Reflection |
| 5 |
任务涉及多个专业领域、需角色分工? |
是 → Level 5 多Agent协作 |
💡 一句话口诀:能一步就一步,要工具用ReAct,步骤多先规划,要质量加反思,跨领域就分工。
实践中的几点经验:
- 从简单架构起步:先用Level 1/2跑通,再按需升级,避免过度设计;
- 混合使用:Plan-and-Execute的Executor子步骤可内部采用ReAct;Reflection可叠加在任何架构之上;
- 成本敏感时优先降级:Reflection和多Agent会成倍增加调用次数,线上服务务必评估ROI;
- 可观测性是底线:无论哪种架构,务必记录每一步的输入输出与工具调用,便于调试与回归。
⚠️ 注意事项:架构选型不是一次性决定。任务会演化、模型会升级、预算会变。每隔一段时间回头评估"现在的架构还合适吗",是工程上的好习惯。
小结
本章沿着"从简单到复杂"的主线,系统梳理了智能体架构的五个层级:
- Level 1 单次调用是原子单元,像自动售货机,适合无工具的简单任务;
- Level 2 ReAct通过"思考-行动-观察"循环赋予LLM工具使用能力,像查字典做作业;
- Level 3 Plan-and-Execute先规划后执行,像出差前列行程单,提升长任务稳定性;
- Level 4 Reflection引入自我审视,像写完作文自己改,实现质量迭代;
- Level 5 多Agent协作通过角色分工应对大规模任务,像团队协作完成项目。
每种架构都有其适用边界,没有"最好"的架构,只有"最合适"的架构。工程上的关键能力不是会写复杂代码,而是能根据任务特征做出恰当的取舍。记住口诀:能简不繁、按需升级、混合搭配、成本可控。
下一章预告
本章所有架构都以LLM作为推理核心,但我们一直把它当作"黑盒"调用。第3章:LLM核心引擎将打开这个黑盒,深入探讨:
- LLM的提示工程进阶技巧(few-shot、CoT、结构化输出);
- 函数调用(Function Calling)与ReAct的关系与取舍;
- 流式输出、上下文窗口管理、token成本优化;
- 如何为不同架构选择合适的模型与参数。
理解了引擎本身,你才能在后续章节中更从容地驾驭各类智能体架构。我们第3章见。