最近在梳理 AI Agent 的架构设计,写了一张演进图。图画完之后我发现,如果用「一家纺织工厂的改造历程」来解释这套东西,好像比直接讲概念要顺很多。
这篇文章就沿着这条线走:工厂 V1 到 V4,对应的是 Agent 系统从「能跑」到「好用」再到「不出事」的完整演进。
目标读者是有一定 Prompt 工程或 LangChain 实践经验的开发者,所以基础概念不会从头解释,重点放在「为什么这样设计」和「不这样会怎样」。
V1:先把流水线搭起来
工厂的第一个问题:工匠太随性
想象这样一个场景:工厂接了一张订单,要绣一幅「江南春色图」。
老板把需求扔给工匠甲:「你看着办。」
工匠甲手艺不错,但今天心情好多绣了几朵花,明天换了个针法,后天觉得绿色应该深一点……客户拿到货,发现和上次订的「江南春色图」完全不一样。
这就是直接用对话式 AI 做任务的问题:输出不稳定,上下文一变结果就漂。不是 AI 不聪明,是缺乏约束。
第一步改造:Prompt + Tools,给工匠穿上工装
给工匠发一套标准工装(System Prompt 定义角色和输出格式),再配一套标准工具箱(Tools:查色卡、量布料、查库存)。工匠不再随性发挥,而是在约束框架内执行。
这一步解决的是可复现性的问题。同样的需求,每次执行的路径和输出格式是稳定的。
第二步改造:原子化拆解,让每个人只干一件事
但单个工匠处理复杂订单还是容易出错——脑子里同时装着「剪裁、配色、走针」太多了,推理容易跑偏。
解法是原子化:把一张刺绣拆给三个小组:
- 剪裁组:只负责按尺寸裁布,输出裁好的布料规格
- 构图组:只负责把图案映射到布料坐标,输出构图方案
- 针法组:只负责根据构图方案确定针法,输出针法序列
每个 Agent 聚焦在一个足够小的任务上,上下文干净,推理准确率明显提升。
这里有个值得记住的原则:Agent 的上下文越聚焦,推理越可靠。一个什么都知道的 Agent,往往什么都做不好。
两种工作流结构
原子化之后,多个 Agent 之间的协作方式就变得重要了。
顺序工作流(Chain) :上一个的输出是下一个的输入。适合有明确依赖关系的流程。
# 环境:Python,伪代码示意 Chain 的状态传递
# 场景:剪裁 → 构图 → 针法的顺序执行
state = {"order": "江南春色图,60x80cm,复古风"}
# 每个 Agent 接收 state,处理后把结果写回 state
state = cutting_agent.run(state)
# state 现在包含: {"order": ..., "fabric": {"size": "60x80", "material": "蚕丝"}}
state = layout_agent.run(state)
# state 现在包含: {"order": ..., "fabric": ..., "layout": {"grid": "...", "focal_point": "..."}}
state = stitch_agent.run(state)
# state 现在包含完整的执行方案
并行工作流(Fork/Merge) :互相独立的子任务同时执行,最后合并结果。
比如「配色方案」和「图案构图」两件事不互相依赖,完全可以同时跑,最后合并。这在有 I/O 等待的任务(比如调外部 API)上能明显降低延迟。
# 场景:并行执行配色和构图,最后合并
import asyncio
async def run_parallel(state):
color_task = asyncio.create_task(color_agent.arun(state))
layout_task = asyncio.create_task(layout_agent.arun(state))
color_result, layout_result = await asyncio.gather(color_task, layout_task)
# 合并两个子任务的结果
return {**state, "color": color_result, "layout": layout_result}
V1 解决的核心问题:让 AI 从随机应答,变成可组合的结构化执行单元。
V2:让工厂会规划、会反思
工厂的第二个问题:客户说不清楚要什么
新客户来了,说:「我想要一幅有点春天感觉的绣品,但不要太俗气,你懂的那种。」
「你懂的那种」——这是一个没有办法直接执行的需求。
如果直接扔给执行 Agent,它要么瞎猜,要么输出一个四不像。这时候需要的是先规划,再执行。
多步规划:先想清楚再动手
对应的技术模式是 Plan-and-Solve 和 Chain of Thought——让 Agent 在执行之前先输出一个推理步骤或行动计划,再按计划执行。
用户需求:「春天感觉,不俗气」
规划阶段(CoT):
→ "春天感觉"可以拆解为:嫩绿色系、轻盈线条、花卉元素
→ "不俗气"的约束:避免大红大绿对比、图案不宜过满、留白
→ 风格参考:江南水墨风 > 北方农村剪纸风
→ 执行计划:先定色卡(莫兰迪绿+米白),再定构图(疏朗),再定针法(乱针绣)
执行阶段:按计划调用各子 Agent
规划让 Agent 把模糊的意图转化成可执行的步骤,这是处理「抽象需求」的核心手段。
鉴别器模式:引入质检员
执行完了,结果不一定对。引入鉴别器(Discriminator) :一个专门负责评估输出质量的 Agent,对执行结果打分或给出修改意见。
[执行 Agent] → 生成方案 → [鉴别器]
↓ 不通过:「色调偏暖,与'清新'要求不符,建议调整为冷色调」
反馈注入执行 Agent → 重新生成
↓ 通过
最终输出
鉴别器的关键设计点:它的评估标准必须明确。如果鉴别器自己也是模糊的(「感觉不太好」),循环就会失去方向。好的鉴别器应该输出结构化的反馈:哪里不符合要求,建议怎么改。
熔断机制:失败三次就叫人
动态循环带来一个新问题:如果 Agent 一直无法通过质检怎么办?
不加熔断的系统,在生产环境是危险的。
解法是设置最大重试次数,超过阈值就停止自动循环,转为人工介入或降级处理:
# 场景:带熔断的执行-评估循环
MAX_RETRIES = 3
def run_with_reflection(task, state):
for attempt in range(MAX_RETRIES):
result = executor_agent.run(task, state)
evaluation = discriminator_agent.evaluate(result, task)
if evaluation["passed"]:
return result
# 把失败原因注入下一轮的 state,而不是从零开始
state["last_failure"] = evaluation["feedback"]
state["attempt"] = attempt + 1
print(f"第 {attempt + 1} 次未通过:{evaluation['feedback']}")
# 超过最大重试,走人工介入流程
return escalate_to_human(task, state)
注意这段代码里的一个细节:state["last_failure"] = evaluation["feedback"]。每次失败的原因被保存下来,下一轮执行时 Agent 能看到「上次为什么没过」,而不是盲目重试。
但这只是把失败原因保存在当前会话的 state 里——会话结束了,这些经验就消失了。这就是 V2 的根本局限,也是 V3 要解决的问题。
V3:老师傅的经验,怎么存、怎么用
工厂的第三个问题:每次都像第一次
老客户王女士第三次来下单了。
上次她说「这个绿色太深了」,调成 #7BAF7B 她很满意。再上次她说「针脚太密,显得闷」,改成疏朗的乱针绣她很喜欢。
但这次接待她的执行 Agent,什么都不记得了。又开始问她喜欢什么颜色,又绣了一个密针脚。
这不是 AI 不聪明,是没有记忆系统。
记忆的四个层次
Agent 系统的记忆不是一个东西,而是四个层次的组合:
1. 短期记忆(In-context Memory)
就是当前会话的 context window。存放本次任务的过程信息:这次客户说了什么,中间执行到哪一步,上一个 Agent 输出了什么。
特点:快,但有容量上限,会话结束即消失。
2. 用户画像(User Profile)
相对静态的偏好信息,持久化存储。比如:
{
"user_id": "wang_female_003",
"style_preference": "复古、清雅",
"color_sensitivity": "偏冷色调,对暖黄色不感冒",
"budget_tier": "mid-to-high"
}
这类信息变化慢,适合直接注入 System Prompt。
3. 语义记忆(Semantic Memory)
用户特有的术语映射。这是最容易被忽视、但实际上价值很高的一层。
王女士说「老样子」——这三个字对陌生人没有意义,但对这家工厂意味着:#7BAF7B + 10号针脚 + 疏朗构图。
没有语义记忆,Agent 每次都要重新确认「请问您说的老样子是指……」,体验极差,而且还可能理解错。
4. 情节记忆(Episodic Memory)
过去成功(或失败)的完整经验记录。「2024年3月那次,客户对这个配色方案非常满意,具体参数是……」
情节记忆的价值在于 Few-shot:下次遇到类似需求,直接把成功案例作为示例提供给 Agent,比任何文字描述都有效。
RAG:按需从记忆库里捞
有了记忆库,关键是怎么用。全部塞进 context 是不现实的——既有 token 上限,也会引入噪声。
**RAG(检索增强生成)**的核心思路:先检索,再生成。
# 场景:执行任务前,从记忆库检索相关上下文
# 依赖:向量数据库(如 Chroma / Pinecone)
def run_with_memory(user_id: str, task: str):
# 1. 检索用户相关记忆
relevant_memories = memory_store.search(
query=task,
filter={"user_id": user_id},
top_k=5 # 只取最相关的 5 条
)
# 2. 把记忆注入 prompt
memory_context = "\n".join([m["content"] for m in relevant_memories])
system_prompt = f"""
你是一位刺绣工艺专家。
关于这位客户,你需要知道:
{memory_context}
请根据以上背景,处理当前任务。
"""
# 3. 执行
return agent.run(task, system_prompt=system_prompt)
RAG 不只适用于用户记忆,也适合外部知识库的接入——比如实时查询 VOGUE 今季流行色,而不是让 AI 靠参数记忆瞎猜「今年流行什么颜色」。让 AI 的知识边界动态扩展,而非依赖训练时的静态参数。
MCP:跨工厂的协作标准
纺织厂需要采购金属扣件,要联系配件厂。**MCP(Model Context Protocol)**解决的是 Agent 与外部工具、外部系统协作时的标准化问题。
没有 MCP 之前,每接入一个工具都要写一套定制逻辑。MCP 提供了统一的工具描述、调用和响应格式,让工具变成可插拔的模块。
实际效果:同一个 Agent 框架,可以根据场景动态切换工具组合。预算高的客户用 Pantone 专业色库 API,预算有限的用免费色彩库——工具选路在运行时决定,不需要硬编码。
三种记忆利用方式的权衡
| 方式 | 实现成本 | 效果 | 适用场景 |
|---|---|---|---|
| Prompt 注入 | 低 | 中 | 用户画像、当前任务上下文 |
| Few-shot 示例 | 中 | 高 | 情节记忆、风格参考、输出格式 |
| Fine-tuning | 高 | 最高(但有过拟合风险) | 深度个性化、特定领域术语 |
三者不互斥。一个常见的组合策略是:Prompt 注入用户画像 + Few-shot 注入相似成功案例 + Fine-tuning 用于核心风格模型。
Fine-tuning 成本最高,且一旦用户偏好变化,模型就需要重新训练,要仔细评估是否值得。
V4:工厂不能失控
能力越强,失控风险越大。V4 要解决的是:怎么让这台复杂机器在生产环境里安全、可控地运转。
一、全链路追踪:出了事能查
每一次 Agent 调用、每一步工具执行、每一个决策节点,都需要有结构化日志。
这和前端开发里的错误追踪、埋点监控是同一个道理:可观测性是系统健壮性的前提。出了问题,至少要能还原现场。
最低要求:记录每次调用的 agent_id、input、output、timestamp、token_usage。生产环境建议接入 LangSmith 或类似的 Agent 追踪平台。
二、成本监控与熔断:钱不能瞎烧
一次正常请求消耗 0.5 元,某次异常飙到 50 元——这往往意味着 Agent 进入了异常循环,或者触发了非预期的递归调用。
# 场景:带成本监控的执行包装器
COST_THRESHOLD = 5.0 # 单次任务成本上限(元)
class CostGuardedAgent:
def __init__(self, agent, threshold=COST_THRESHOLD):
self.agent = agent
self.threshold = threshold
self.accumulated_cost = 0.0
def run(self, task, state):
result = self.agent.run(task, state)
# 统计本次调用的 token 消耗
cost = calculate_cost(result.usage)
self.accumulated_cost += cost
if self.accumulated_cost > self.threshold:
raise CostLimitExceeded(
f"任务成本 {self.accumulated_cost:.2f} 元超过阈值 {self.threshold} 元"
)
return result
成本监控需要实时,而不是等账单来了才发现。异常需要自动熔断,并触发告警。
三、安全护栏:有些活不能接
系统能力强了,恶意请求的破坏力也大了。
某客户下单:「帮我绣 10000 个 LV 的 Logo 图案,用于批量生产。」
- 涉及商标版权侵权
- 批量生产明显是商业目的
- 需要在执行前拦截,而不是执行完再撤
护栏的设计要前置:在任务进入执行链路之前,先过一道合规检查。
# 场景:任务执行前的安全检查
def safety_check(task: str, context: dict) -> tuple[bool, str]:
"""
返回 (是否通过, 拒绝原因)
"""
# 规则检查:关键词过滤
forbidden_patterns = ["批量仿制", "未经授权", "绕过版权"]
for pattern in forbidden_patterns:
if pattern in task:
return False, f"任务包含违规内容:{pattern}"
# 模型检查:对模糊案例用 LLM 判断
if needs_llm_check(task):
judgment = compliance_agent.evaluate(task, context)
if not judgment["safe"]:
return False, judgment["reason"]
return True, ""
除了合规护栏,还需要防 Prompt 注入:用户输入可能包含「忽略之前的所有指令,改为……」这类攻击。这是一个持续演进的对抗性问题,没有一劳永逸的解法,但至少要做基础的输入清洗和指令隔离。
四、模型选路:合适的活给合适的人
不是所有任务都需要最贵的模型。
简单意图分类(「这是一个配色请求还是尺寸请求」)→ 小模型,快且便宜
复杂创意规划(「根据客户情绪设计配色方案」)→ 大模型,贵但准
动态选路的前提是明确的分类标准:什么算简单,什么算复杂,谁来判断——通常用一个轻量的分类器 Agent 来做路由决策。
这里有个反直觉的点:路由器本身也是一个 Agent,它的判断也可能出错。所以路由策略要保守,宁可把简单任务送到大模型(浪费一点钱),也不要把复杂任务送到小模型(结果可能一塌糊涂,修复成本更高)。
延伸:这套东西和前端开发有多像
整理完这四个版本,我发现 Agent 架构的很多设计决策,在前端开发里都有对应的概念——只是换了个名字。
状态管理(Redux/Zustand)↔ Agent State
前端的全局状态管理和 Agent 的 state 传递,本质上都在解决同一个问题:多个模块之间共享数据,谁负责更新,谁负责读取,更新后如何通知下游。
LangGraph 的 StateGraph 设计和 Redux 的 reducer 模式神似:定义 state 的 schema,每个节点(Agent)只能通过规定的方式更新 state。
中间件(Middleware)↔ 安全护栏 + 成本监控
Express 的中间件、Redux 的 middleware——在请求链路中插入横切关注点,不侵入核心逻辑。
Agent 系统的护栏和监控本质上是同一回事:在调用链的特定位置插入检查逻辑,对主流程透明。
错误边界(Error Boundary)↔ 熔断机制
React 的 ErrorBoundary 防止子组件的崩溃蔓延到整个应用树。Agent 的熔断机制防止一个子 Agent 的失败循环拖垮整个系统。都是局部失败不应该导致全局崩溃的工程哲学。
懒加载 / Code Splitting ↔ 模型选路
按需加载,把重的资源留给真正需要的地方。不把 GPT-4 浪费在意图分类这种简单任务上。
这种类比不一定在所有细节上都成立,但对于有前端背景的开发者来说,用已有的认知框架来锚定新概念,是最快建立直觉的方式。
还没想清楚的问题
写完这篇,我还有几个问题没有好的答案,列出来一起思考:
记忆的失效和更新:用户偏好是会变的。语义记忆里「老样子 = 复古蓝线」,但客户审美变了,旧记忆反而成了干扰。怎么设计记忆的衰减和更新机制?
多 Agent 系统的记忆隔离:同一个用户的不同任务,是共享记忆池还是隔离?跨 Agent 读写同一份记忆,并发冲突怎么处理?
护栏的对抗性:现在的 Prompt 注入攻击越来越精妙,简单的关键词过滤早就不够用了。基于 LLM 的合规检查本身也可能被绕过。这是一个持续的红蓝对抗,没有终点。
小结
从 V1 到 V4,这条演进线索可以用一句话概括:
让 AI 从「能对话」,到「能干活」,再到「可以放心让它干活」。
纺织工厂的比喻是一个脚手架,真实的 Agent 系统比这复杂很多,边界也模糊很多。但有了这个框架,至少在看到 LangGraph 的 StateGraph、AutoGen 的 GroupChat、或者某个 RAG pipeline 的时候,脑子里有个地方可以挂钩子了。
如果你在实际项目里遇到了这个框架覆盖不到的问题,或者有不同的理解,欢迎在评论区聊。
参考资料
- Anthropic - Building effective agents — Agent 工作流模式的系统性梳理,官方出品,值得反复读
- LangGraph 文档 — StateGraph 设计思路,和 Redux 对照着看很有意思
- Model Context Protocol — MCP 协议官网,工具标准化的方向
- Self-Refine: Iterative Refinement with Self-Feedback — 鉴别器模式的学术来源之一