Agent 设计模式

Workflow vs Agent:先搞清楚你要什么

一个反直觉的观点:最成功的 AI 实现,往往不是最复杂的那个。在动手搭 Agent 框架之前,先搞清楚你真正需要什么。

核心洞察
"The most successful implementations weren't using complex frameworks or specialized libraries. Instead, they were building with simple, composable patterns." (最成功的实现并没有使用复杂的框架或专门的库,而是采用了简单、可组合的模式。)

这句话值得每个 AI 产品经理背下来。行业里充斥着各种 Agent 框架(LangChain、AutoGen、CrewAI...),但生产环境反复验证的规律是:真正跑得好的系统,用的是最朴素的组合模式

两个核心概念
Workflow
LLM 和工具通过预定义的代码路径编排。开发者在写代码时就决定了执行顺序:先做 A,再做 B,最后做 C。
关键词:确定性、可预测、开发者控制流程
Agent
LLM 动态决定自己的执行流程和工具使用。模型在每一步自主判断下一步做什么、要不要调用工具、什么时候结束。
关键词:自主性、动态决策、模型控制流程
流程对比
Workflow:代码决定流程
输入
步骤 A
步骤 B
输出
Agent:模型决定流程
输入
LLM 决策
工具 / 思考 / 再决策
输出
差异对比
维度 Workflow Agent
控制权 开发者(代码路径固定) 模型(每步动态决定)
可预测性 高 -- 输入确定则输出路径确定 低 -- 同样输入可能走不同路径
适用场景 任务拆解明确、步骤固定 任务开放、需要灵活决策
成本 可控(调用次数固定) 不确定(循环次数未知)
调试难度 低(路径确定,容易复现) 高(行为不确定,难以复现)
典型例子 文案生成管道、数据清洗流水线 Cursor、Claude Code、Devin
什么时候不要用 Agent
大多数情况下,你不需要 Agent
实践证明:对于大多数应用场景,优化单次 LLM 调用配合检索增强(RAG)就够了。只有当简单方案明确无法满足需求时,才应考虑引入 Workflow 或 Agent 的复杂度。

常见的过度设计:用一个 Agent 框架来做本质上一个 Prompt 加一次搜索就能解决的问题。框架引入的延迟、成本、不确定性远大于它带来的收益。
核心原则:复杂度阶梯
先找最简方案,复杂度只在明确提升效果时才加
  • 1 先试单次 LLM 调用:优化 Prompt、加 Few-shot、调 Temperature
  • 2 不够?加检索增强(RAG):让 LLM 能访问外部知识
  • 3 还不够?用Workflow:把任务拆成多步,用代码控制流程
  • 4 真的需要灵活决策?才上Agent:让模型自主规划执行
不是所有问题都需要 Agent,很多时候 Workflow 就够了,甚至一个精调的 Prompt 就够了。复杂度是成本,不是功能。只在明确带来收益时才增加复杂度。
Agent 设计模式

五种 Workflow 模式

业界已验证有效的五种 Workflow 编排模式。它们由简到繁,每种解决特定类型的问题。不追求最复杂的,追求最合适的。

Pattern 1
1
Prompt Chaining
提示链
把一个大任务拆解为多个顺序步骤,上一步的输出直接作为下一步的输入。每一步都是一次独立的 LLM 调用,专注做好一件事。步骤之间可以插入质量门(programmatic gate),只有通过检查才进入下一步。
输入
LLM Step 1
Gate
LLM Step 2
输出
适用场景
任务能自然拆解为多个固定步骤;需要在中间环节做质量检查;用准确度换取延迟。
真实例子:生成营销文案(Step 1)-> 翻译为目标语言(Step 2)-> 格式化为特定平台样式(Step 3)。中间 Gate:检查 Step 1 输出是否包含品牌关键信息。
Pattern 2
2
Routing
路由
分类输入,然后将其导向不同的专门处理分支。每个分支可以有独立的 Prompt、模型甚至工具配置。核心价值:关注点分离,让每个分支只处理一种类型的输入。
输入
分类器
处理分支 A
处理分支 B
处理分支 C
适用场景
输入类型多样,不同类型需要完全不同的处理逻辑;需要成本优化(简单问题用便宜模型,复杂问题用强模型)。
真实例子:客服系统:简单 FAQ 用 Haiku(快且便宜),退款相关用 Sonnet + 订单工具,技术故障用 Sonnet + 日志查询。一个分类器决定走哪条路,实现成本与效果的最优平衡。
Pattern 3
3
Parallelization
并行化
让多个 LLM 调用同时执行,再聚合结果。有两种子模式:
Sectioning(拆分并行):把一个任务拆为独立子任务,并行处理后合并。
Voting(多次投票):同一个任务用相同 Prompt 跑多次,取多数/最佳结果。
输入
LLM A
LLM B
LLM C
聚合
输出
适用场景
子任务之间没有依赖关系;需要提升速度(并行比串行快);需要提升置信度(多次投票降低随机性)。
真实例子 - Sectioning:代码审查中,一个 LLM 检查安全漏洞,一个检查性能问题,一个检查代码风格,最后汇总所有发现。
真实例子 - Voting:内容审核中,同一段文本让 3 个 LLM 分别判断是否违规,取多数意见作为最终结果。
Pattern 4
4
Orchestrator-Workers
编排者-工人
一个中心 LLM(编排者)动态拆解任务并分配给多个工人 LLM。与 Parallelization 的区别:子任务由编排者在运行时动态决定,代码里没有预先定义。这是最接近 Agent 的 Workflow 模式。
输入
编排者 LLM
Worker 1
Worker 2
Worker N...
合并
适用场景
子任务不能提前预知(需要根据输入动态决定);涉及对多个文件/资源的并行操作。
真实例子:代码修改需求「给项目加国际化支持」。编排者分析代码库后动态决定:Worker 1 改 Button 组件、Worker 2 改 Header 组件、Worker 3 创建语言文件。不同需求产生不同数量和类型的 Worker。
Pattern 5
5
Evaluator-Optimizer
评估-优化
一个 LLM 负责生成,另一个 LLM 负责评判,二者形成迭代循环:生成者根据评判者的反馈不断改进输出,直到评判者认为满意或达到迭代上限。
输入
生成者 LLM
评判者 LLM
输出
虚线框 = 循环迭代直到满足标准
适用场景
有明确的质量评估标准;迭代改进能显著提升输出质量;单次生成很难达到要求。
真实例子:文学翻译中,生成者做初步翻译,评判者检查信达雅和风格一致性并给出具体修改建议,生成者根据建议改进。循环 2-3 次后输出终稿。每次迭代的翻译质量都在提升。
动手试试:模拟调度器
点击上方按钮查看不同模式的数据流转动画
总结
五种模式一览
模式 核心思想 典型场景 复杂度
Prompt Chaining 顺序串联,逐步处理 文案生成管道
Routing 分类导向,专门处理 智能客服分流
Parallelization 并行处理,聚合结果 多维度代码审查
Orchestrator-Workers 动态拆分,分布执行 跨文件代码修改 中高
Evaluator-Optimizer 生成评判,迭代改进 高质量翻译
"Start with simple prompts, optimize them with comprehensive evaluation, and add multi-step agentic systems only when simpler solutions fall short." (从简单的提示开始,使用全面的评估优化它们,仅在简单解决方案不够用时才添加多步骤智能系统。)
不要追求最复杂的模式,要追求最合适的。从最简单的 Prompt Chaining 开始,只在确认简单方案不够用时才升级到更复杂的模式。每增加一层复杂度,都要问自己:这个复杂度带来的收益,值得额外的延迟、成本和调试难度吗?
Agent 设计模式

从 Prompt 工程到上下文工程

当我们从单轮对话走向多步 Agent,仅仅优化 Prompt 已经远远不够。真正的挑战是:如何策展每一轮推理时送给模型的全部 Token。

概念演进
过去
Prompt Engineering
优化提示词的写法:措辞、结构、Few-shot 示例
现在
Context Engineering
策展每一轮推理时送给模型的全部 Token:System Prompt、工具定义、MCP 描述、对话历史、外部检索数据...

Prompt 工程关注的是怎么写指令,而上下文工程关注的是一个更大的问题:模型的输入窗口里放什么、怎么放、放多少。当你的系统有 System Prompt、工具描述、历史消息、RAG 检索结果、用户偏好…这些加起来可能占满大半个上下文窗口。如何管理这些 Token,就是上下文工程。

上下文窗口里有什么
System Prompt — 角色定义、规则、约束
Tool Definitions — 工具名称、参数、描述
Conversation History — 多轮对话历史
Retrieved Data — RAG 检索结果、文件内容
User State — 用户偏好、会话状态、环境信息
所有这些加在一起 = 模型每次推理时看到的全部信息
为什么上下文工程重要
Context Rot
上下文越长,模型对信息的检索准确率越低。关键信息被淹没在海量 Token 中。
注意力预算有限
每个 Token 都在消耗模型的注意力预算。无关 Token 占位 = 有用信息被稀释。
n-squared 复杂度
n 个 Token 产生 n x n 个注意力关系。上下文翻倍,计算量四倍增长。
动手试试:Context Rot 模拟器
1K Token
1K Token -- 一段对话
注意力集中,检索准确
检索准确率
95%
0%50%100%
注意力密度
高注意力 低注意力
理解注意力的代价
Transformer 的自注意力机制中,每个 Token 都要和其他所有 Token 计算关联度:
Attention Complexity = O(n^2)
这意味着:把上下文从 50K 扩展到 100K Token,注意力计算量会变为原来的 4 倍,远超翻倍。上下文不是免费的:每多塞一个无关 Token,都在浪费其他 Token 能获得的注意力。
高效上下文的三个原则
System Prompt 的合适高度
太模糊(「你是一个有用的助手」)= 模型缺乏方向感,输出泛泛而谈。
太具体(列举 50 种边界情况)= 模型被过度约束,无法灵活处理新情况。
最佳实践:给出明确的角色定位和核心原则(5-10 条),然后信任模型在此框架下自主判断。像好的管理者一样,给方向,不给每一步的指令。
太低
太模糊
「你是助手」
刚好
合适高度
角色+原则+边界
太高
太具体
50条规则+100个case
System Prompt 的高度要找到中间的甜蜜点
工具集要精简
生产实践验证:如果人类都分不清该用哪个工具,AI 也分不清。

给 Agent 10 个功能相似但描述模糊的工具,不如给 5 个职责清晰、命名精准的工具。每个工具的 description 要像好的 API 文档一样,让调用者(模型)一看就知道什么时候用、怎么用。
Few-shot 精选典型,不要堆砌
Few-shot 示例是上下文中 ROI 最高的部分,但前提是选对了。

正确做法:精选 2-3 个最能代表目标行为的典型例子,覆盖最常见的输入模式。
错误做法:堆砌 10+ 个边界 case 的例子,不仅浪费 Token,还让模型过度关注异常情况而忽略主线。
上下文是稀缺资源。你的目标是找到最小的高信号 Token 集合。每一个 Token 都必须为模型的推理做出贡献,能放多少就放多少的思路行不通。像编辑精修文章一样精修你的上下文:每个多余的词都是噪音。
Agent 设计模式

上下文的三板斧

当任务跨越多个上下文窗口,每个新窗口都会失忆。生产环境中已验证三种策略来应对这个根本挑战,让 Agent 能在长任务中保持连贯和高效。

根本挑战
长任务的失忆问题
一个复杂的编程任务可能需要 Agent 执行数十步操作,产生数万 Token 的对话历史。当上下文窗口快满时,系统面临两难选择:

Option A:开启新窗口,但新窗口什么都不记得,Agent 会重复已做过的工作。
Option B:继续在旧窗口工作,但随着 Token 增多,模型的注意力被稀释,表现下降。

这不是理论问题。Claude Code、Cursor、Devin 这些产品每天都在解决这个问题。
策略一
1
Compaction
上下文压缩
当对话快要触达上下文窗口上限时,用一次 LLM 调用对已有对话做摘要:保留关键信息,丢弃冗余细节,然后在压缩后的上下文上继续工作。
  • 关键决策:选择什么保留、什么丢弃。这是一个信息论问题:并非所有 Token 都等价,有些信息丢了就无法恢复。
  • 低风险操作:清理旧的 tool call 结果(比如文件列表、搜索输出),这些通常不影响后续推理。
  • 高风险操作:丢弃架构决策的推理过程、未解决的 bug 描述,这些如果丢了,Agent 会重蹈覆辙。
  • Claude Code 的实践:保留架构决策和未解决的 bug 信息,丢弃冗余的文件内容输出和已完成任务的中间步骤。
实践 Tip
压缩时让 LLM 生成的摘要应该是结构化的,自由文本很难快速定位信息。例如:「已完成:[列表] | 未完成:[列表] | 关键决策:[列表] | 已知问题:[列表]」,这样后续推理可以快速找到需要的信息。
策略二
2
Structured Note-taking
结构化笔记
Agent 在执行过程中主动将关键信息写到外部文件,而不仅仅依赖对话历史。当上下文重置(新窗口)后,从笔记文件读回这些信息来恢复记忆。
  • 核心思想:把短期记忆(上下文窗口)外化为长期记忆(文件系统),实现跨窗口的信息延续。
  • Claude Code 的实践:维护 TODO list 文件,每完成一步就更新,这样即使上下文被压缩或重置,打开 TODO 就知道进度。
  • Claude 打宝可梦的案例:Agent 维护一个游戏笔记文件,记录地图位置、已获道具、下一步计划。每次新对话开始时先读这个笔记,实现记忆传递。
  • 关键设计:笔记格式要固定且结构化,不能是自由散文,否则读回来时还要额外 Token 来理解笔记内容。
对比 Compaction
Compaction 是压缩旧信息继续用,Note-taking 是把信息存到外面以后取用。前者适合连续工作场景,后者适合可能被中断或需要跨 session 延续的场景。两者可以组合使用。
策略三
3
Sub-agent Architecture
子 Agent 架构
主 Agent 把需要深入探索的子任务委派给子 Agent。子 Agent 在自己独立的上下文窗口中工作(可能消耗数万 Token),最终只返回一个精炼的摘要(1000-2000 Token)给主 Agent。
  • 核心价值:关注点分离 + 上下文隔离。子 Agent 的工作草稿不会污染主 Agent 的上下文。
  • Token 经济:一个子 Agent 可能在内部消耗 30,000 Token 来读代码、分析依赖、做推理,但只向上报告 1,500 Token 的结论。主 Agent 的上下文保持精简。
  • 并行优势:多个子 Agent 可以同时工作,各自探索不同方向,最后由主 Agent 整合。这比单一 Agent 串行探索快得多。
  • 真实应用:Cursor 的 background agent、Claude Code 的 Task tool,都是子 Agent 架构的体现。
类比
想象一个 CEO(主 Agent)让 3 个部门经理(子 Agent)分别调研竞品、分析市场、评估技术。每个经理可能花了一周(大量 Token),但汇报给 CEO 的只是一页 PPT(精炼摘要)。CEO 的认知带宽始终保持在战略层面。
JIT Context vs 预加载
预加载(Preloading)
在对话开始时就把信息塞进上下文
  • CLAUDE.md / Rules 文件直接载入
  • 用户偏好、项目配置
  • 高频使用的上下文信息
  • 优点:即时可用,无需额外调用
  • 缺点:每次都占 Token,不管用不用得到
JIT(Just-In-Time 按需获取)
只在需要时才检索信息到上下文
  • 用 glob/grep 按需搜索文件
  • 用 RAG 检索相关文档
  • 调用 API 获取实时数据
  • 优点:上下文保持精简,只含当前需要的
  • 缺点:多一次工具调用的延迟
最佳实践:混合策略
高频信息预加载(项目约定、核心规则、用户偏好)+ 长尾信息按需获取(具体文件内容、API 文档、历史记录)。

类比浏览器缓存策略:热数据放内存缓存(预加载),冷数据放磁盘或网络获取(JIT)。目标是让上下文的命中率最大化:大多数推理所需的信息已经在窗口里,偶尔需要的才动态获取。
三种策略对比
策略 核心思想 适用场景 代表产品
Compaction 压缩旧上下文,保留关键信息继续 连续长对话,不会被中断 Claude Code auto-compact
Note-taking 主动写笔记到外部,跨窗口读回 可能中断、需跨 session 延续 Claude Code TODO、Cursor Rules
Sub-agent 子 Agent 深入探索,只回传摘要 需要深度探索但不想污染主上下文 Cursor Task、Claude Code spawn
长任务的本质挑战是有限的注意力窗口 vs 无限增长的信息量。压缩、笔记、子 Agent 三板斧,分别解决三个问题:在窗口内保持精简、跨窗口传递记忆、隔离深度探索的噪声。三者组合使用,才能让 Agent 在复杂长任务中保持高效。
1 / 4