赛博纺织工厂:一个比喻,讲透 AI Agent 工作流的四次进化

0 阅读15分钟

最近在梳理 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-SolveChain 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_idinputoutputtimestamptoken_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 的时候,脑子里有个地方可以挂钩子了。

如果你在实际项目里遇到了这个框架覆盖不到的问题,或者有不同的理解,欢迎在评论区聊。


参考资料