DAY 05 / PHASE 1 · ENGINEERING

Agent Design Patterns

Workflow vs Agent · ReAct / Plan / Reflexion · Multi-agent 反模式 · 失败模式手册

2026-05-23 · BigCat

能用 workflow 解决的事,别用 agent;能用 single agent 的事,别用 multi-agent。

前置概念 → ai-ml-daily Day 5: Agent 架构(ReAct, Plan-and-Execute, Reflexion)

// WHY THIS MATTERS

过去一年「agent」被滥用到几乎失去意义——任何带 LLM 调用的脚本都自称 agent,任何 demo 都堆 3 个角色互相 debate。但当你真的把这些跑进生产,会发现一条残酷的曲线:agent 化程度越高,可靠性越低、延迟越大、token 成本越爆。Anthropic 在 Building Effective Agents 里给出了那条被反复引用的结论——「Find the simplest solution possible, and only increase complexity when needed」。这一期不讲哪个框架更好(LangGraph / CrewAI / AutoGen 谁更香这种事毫无意义),讲真正决定可靠性的四件事:什么时候 该用 agent、ReAct/Plan/Reflexion 三种主流 loop 的真实差异、为什么 multi-agent 几乎都是反模式、以及让 agent 项目挂掉的五种典型失败模式与诊断方法。

// 01

Workflow vs Agent:先问该不该用 agent

论断:90% 自称 agent 的项目其实是 workflow;workflow 用 agent 跑只会更慢更贵更不可靠。

背景与原理

Anthropic Building Effective Agents 给出了一个被严重低估的二分法:

区别不在「用没用 tool」,而在控制流由谁决定。一个跑 5 步 prompt chain 的 RAG 是 workflow,不是 agent;一个能自己决定要不要再查一次资料、要不要换工具的才是 agent。

为什么这件事重要?因为 agent 的可靠性大致等于「每一步成功率」的 N 次方。每步 95% 成功的 agent,跑 10 步只剩 60%;跑 20 步只剩 36%。workflow 把不必要的「自决」固化成代码,等于把指数衰减压成线性。同样的任务,能写成 workflow 就不要写成 agent——这不是性能洁癖,是 reliability 的物理事实。

什么时候 用 agent?Anthropic 的判断标准只有一条:任务的步骤数和路径不可预先枚举。比如「修这个 bug」——你不知道要读几个文件、改几处;「研究这个开源项目」——你不知道要 fetch 多少链接。其余 90% 的场景(提取信息 + 改写 + 校验 + 存库;分类 + 路由;翻译 + 润色 + 翻回去对照)都是 workflow。

Workflow(路径写死,LLM 做节点判断) input ──▶ [classify] ──┬──▶ [extract] ──▶ [validate] ──▶ output └──▶ [summarize] ──▶ [validate] ──▶ output ✓ 步数确定 ✓ 可单元测试 ✓ p99 延迟可控 ✓ 成本可预测 Agent(路径动态,LLM 自决下一步) input ──▶ ┌─ LLM ─┐ ──tool_use──▶ [tool] ──tool_result──┐ │ │ ◀──────────────────────────────────┘ └─ stop?─┘ ──end_turn──▶ output ✓ 路径不可枚举 ✗ 步数不定 ✗ 难单测 ✗ p99 延迟不可控

实战示例

「给一份会议录音生成结构化纪要 + 待办 + 关键决策」——是 workflow,不是 agent:

# —— 这是 workflow(5 行业务代码 + 3 次 LLM 调用) ——
transcript = whisper.transcribe(audio_path)
summary    = llm(SUMMARY_PROMPT,  transcript)
todos      = llm(TODO_PROMPT,     transcript)
decisions  = llm(DECISION_PROMPT, transcript)
return {"summary":summary, "todos":todos, "decisions":decisions}

# 步数固定 = 3, 不需要 agent loop / tool selection / state machine
# p99 延迟 = 3 × LLM 调用上界, 可缓存可批量可并行

「修这个 issue:用户报告 dashboard 在 Safari 上偶发 white screen」——是 agent:

# —— 这是 agent(路径不可枚举) ——
# 可能的步骤:
#   读 issue → grep dashboard 入口 → 读 entry → 看 git log →
#   找 Safari 相关 polyfill → 跑测试 → 改 → 再跑 → 写 PR
# 但「可能」二字意味着具体走哪条路要看每步看到什么
agent(task=issue_body, tools=[read,grep,bash,edit,write,fetch])

一个简单决策口诀:能在白板上把所有可能路径画出来,就是 workflow;画不出来,才是 agent

失败模式:(1)把固定流程写成 agent,让模型每一步「自决」该 extract 还是 summarize——成功率从 99% 掉到 80%,因为引入了不必要的 selection 风险。(2)用 agent 实现路由——「问候问题/技术问题/账户问题分流」用 classifier workflow 就够,包成 agent 加 tool 是 over-engineering。(3)混合:路径明明确定但用 agent 跑「显得 AI 一点」——延迟 / 成本 / 不可观测性三杀。
进阶资源 · Anthropic Building Effective Agents, anthropic.com/engineering/building-effective-agents · Lilian Weng LLM Powered Autonomous Agents, lilianweng.github.io/.../agent · Simon Willison What are agents?, simonwillison.net/.../agents
// 02

ReAct vs Plan-and-Execute vs Reflexion:三种 loop 的真实分工

论断:默认用 ReAct;任务跨越 ≥ 8 步且高代价才上 Plan;只有可验证型任务才用 Reflexion。

背景与原理

三种最常见的 agent loop,被 LangChain / LlamaIndex 文档讲得像三种「框架选择」,其实是三种不同复杂度场景的不同收益曲线。理解它们什么时候 work、什么时候不 work,比记住它们的名字重要 100 倍。

ReAct(Yao et al. 2022, arXiv:2210.03629)——Thought / Action / Observation 三段交替,每一步看完结果再决定下一步。优点:简单、低延迟、容错好(错了下一步可纠)。Claude Code、Cursor 的 agent loop 本质都是 ReAct 的变体。这是默认应该选的 pattern

Plan-and-Execute(Wang et al. 2023, arXiv:2305.04091)——先用一次 LLM 调用生成完整计划(List[step]),再逐步执行。优点:步骤之间可并行、计划阶段可被人 review、token 利用率高。缺点:计划基于不完整信息,执行中遇到意外只能强行走完或全盘 replan。适用:步骤多(≥ 8)、每步代价高(涉及钱 / 时间)、且初始信息足够支持靠谱 plan 的场景。

Reflexion(Shinn et al. 2023, arXiv:2303.11366)——做完后让 LLM 反思「这次哪里没做好」,把反思写进 memory,下一轮带着反思重新做。它在论文里在 HumanEval / AlfWorld 上有明显提升,但前提是任务结果可验证(代码能跑测试、游戏有 score)。在「写文章」「客服对话」这类没 ground truth 的任务上,反思容易变成自我感觉良好的 noise——模型反思出来的「下次该这样」很可能是错的。

ReAct(默认) ┌─ Thought ─▶ Action ─▶ Observation ─┐ └─────────────────◀──────────────────┘ 每步看到结果再决定 ✓ 容错 ✓ 低延迟 ✗ 难并行 Plan-and-Execute(步多 + 高代价) ┌─ Plan ─▶ [s1,s2,s3,...,s10] │ │ │ │ │ │ ▼ ▼ ▼ … ▼ (可并行) └────────── Execute ────── output ✓ 计划可 review ✗ 不能动态调整 Reflexion(可验证任务) ┌─ Trajectory ─▶ Verifier ─▶ pass? ──end │ │ fail │ ▼ └────── Reflect ──▶ Memory ────┘ ✓ HumanEval/AlfWorld 类有提升 ✗ 无 verifier 时多半无用

实战示例

# —— ReAct 骨架(你自己 harness 的 hot path) ——
while True:
    r = llm(system=SYS, tools=TOOLS, messages=msgs)
    msgs.append({"role":"assistant","content":r.content})
    if r.stop_reason == "end_turn": break
    results = [run_tool(b) for b in r.content if b.type=="tool_use"]
    msgs.append({"role":"user","content":results})

# —— Plan-and-Execute 骨架 ——
plan = llm(PLAN_PROMPT, task)                # List[Step], step 间标 deps
for wave in topo_sort(plan):              # 按依赖分波
    await asyncio.gather(*[execute(s) for s in wave])
if not satisfied(plan.goal):
    plan = llm(REPLAN_PROMPT, task, history)  # 整体 replan, 不是局部修

# —— Reflexion 骨架(只在 verifier 存在时用) ——
for attempt in range(MAX_ATTEMPTS):
    traj   = react_agent(task, memory=reflections)
    result = verifier(traj)                  # 例:跑测试 / 校验 schema
    if result.passed: return traj
    reflections.append(llm(REFLECT_PROMPT, traj, result.errors))

选型决策树:

  1. 任务路径不可枚举 → 用 agent;否则用 workflow(见 §1)。
  2. 任务平均步数 ≤ 7 步、每步成本低 → ReAct
  3. 步数多(10+)、每步代价高(发邮件 / 调付费 API / 改生产)、初始信息够规划 → Plan-and-Execute
  4. 有自动可验证 oracle(测试 / schema / score) → 在 ReAct 外层套 Reflexion
  5. 没有 oracle 但你想加「反思」?停。先想办法造 oracle,或加 LLM-as-judge(见 Day 6)。
失败模式:(1)默认上 Plan-and-Execute 觉得「更高级」——计划基于错信息,执行时全 plan 报废,比 ReAct 更慢更贵。(2)给所有任务都加 Reflexion——没 verifier 时反思 = 自说自话;论文里那些数字都是有 oracle 的实验。(3)混合三种 pattern——「让 agent 先 plan,每步用 ReAct,最后 reflect」听起来酷,工程上 debug 噩梦。先纯一种跑稳,再考虑混合。
进阶资源 · ReAct paper, arXiv:2210.03629 · Reflexion paper, arXiv:2303.11366 · Plan-and-Solve paper, arXiv:2305.04091 · Lilian Weng LLM Powered Autonomous Agents(含 ReAct/Reflexion 对比), lilianweng.github.io
// 03

Multi-agent 几乎都是反模式:什么时候是例外

论断:默认 single agent + 好 prompt + 好 tools;只有「context 隔离收益 > orchestration 成本」时 multi-agent 才赢。

背景与原理

2023-2024 年 AutoGen / CrewAI / MetaGPT 把 multi-agent 炒成「未来」,2025 年的工程现实是:大多数 multi-agent 系统的产出,不如同一个模型 + 一个写得好的 system prompt + 一组好工具。原因相当物理:

那 multi-agent 什么时候真的值?Anthropic 给出的具体场景特征:

  1. 任务天然并行——可拆成独立子任务,子任务之间几乎无依赖。比如「搜 5 个不同主题然后汇总」。
  2. 每个子 agent 都要消耗大量 context——分到不同 agent 是为了不让一个 agent 的 context window 被挤爆,每个 agent 看自己的小窗口。
  3. orchestrator-worker 而非 peer debate——一个明确的 lead agent 拆任务、分发、汇总;worker 不互相说话。peer debate(多个 agent 互相辩论)在真实任务里几乎没赢过。

这也是为什么 Claude Code 的 Task tool 就是 orchestrator-worker:主 agent 调 Task 启动子 agent 做独立调研,子 agent 完成后返回一段总结。是让子 agent 互相对话。

✓ Orchestrator-Worker(推荐) ✗ Peer Debate(多半反模式) ┌─ Lead Agent ─┐ ┌──▶ Agent A ◀──┐ │ plan │ │ │ │ ┌────┼────┬────┐ │ │ ▼ │ ▼ ▼ ▼ ▼ │ ▼ Agent B ▼ WkA WkB WkC WkD │ Agent C ──▶ ◀── Agent D │ │ │ │ │ ↑ ↓ │ └────┴────┴────┴────┘ └───────┴───────┘ 并行执行 → 汇总 所有人都和所有人说话 context 隔离, 无 peer chat token N², 错误叠加, 谁先 stop?

实战示例

「调研 5 家竞品 + 写一份对比报告」——这是 multi-agent 真正赢的场景:

# —— Orchestrator-Worker:lead 拆任务, workers 并行调研, lead 汇总 ——
async def research_orchestrator(query):
    plan = lead_agent(f"Break this research into 3-6 independent subtopics: {query}")
    # plan = ["company A pricing", "company B product", ...]

    subreports = await asyncio.gather(*[
        worker_agent(topic, tools=[web_search, fetch], max_iters=15)
        for topic in plan
    ])  # 每个 worker 自己一个 context window, 不互相通信

    return lead_agent(f"Synthesize into a report: {subreports}")

# 收益: 每个 worker 自己处理 50k token 的 web 内容
#       单 agent 串行做要 ~250k context, 不仅慢, 还 lost-in-the-middle
#       分给 5 个 worker 后, lead 只看 5 段总结 ~5k token, 高质量汇总

「写一个函数」——这是 multi-agent 不该出现的场景:

# BAD: "coder + reviewer + tester" 三 agent debate
#   - 3× token, 3× latency, 错误叠加
#   - reviewer 看不到 coder 没说出的上下文
#   - tester 跑测试这步本来就不是 LLM, 是 tool

# GOOD: 1 个 agent + 测试 tool + 好 system prompt
agent(task, tools=[read, edit, run_tests],
      system="Write code, run tests, fix until green.")
#   1× token, 用 verifier (tests) 替代 reviewer/tester agent

判断 multi-agent 该不该上的口诀:「能不能让 worker 之间不说话」?能 → orchestrator-worker 可上;不能(worker 必须 debate / 协作 / 互相依赖)→ 改回 single agent 或拆 workflow。

失败模式:(1)「Manager / Engineer / Critic / PM」四角色——agent 互相 review,token 爆炸,没人真正 stop。(2)peer debate 用来「提升准确率」——研究表明对客观任务(数学 / 代码)提升微弱,主观任务(写作)甚至更糟。(3)忘了 verifier 比另一个 agent 强 10 倍——能跑测试就别让另一个 agent 「review code」;能 schema validation 就别让另一个 agent 「check output」。
进阶资源 · Anthropic How we built our multi-agent research system, anthropic.com/.../built-multi-agent-research-system · Cognition AI Don't Build Multi-Agents, cognition.ai/blog/dont-build-multi-agents · 论文 Should We Be Going MAD? on multi-agent debate limits, arXiv:2402.18272
// 04

Agent 失败模式手册:5 种死法 + 诊断方法

论断:每个上过生产的 agent 都死过这 5 种死法之一;先认识它们,再设防。

背景与原理

当你跑过几个真实 agent 项目,会发现失败长得很像——它们反复以以下 5 种「死法」出现。把它们做成内部 incident 分类,能让你的迭代速度翻倍。

  1. 无限循环(Loop Lock):agent 卡在 read → think → read same file → think 的循环;或反复调同一个失败 tool 期待不同结果。根因:模型对当前结果没新理解,但 stop 条件没触发。
  2. 过度规划(Over-planning):花几轮在 plan、写 todo、推理「我接下来应该」,token 耗了一半还没真正做事。根因:system prompt 鼓励了 verbosity,或任务太抽象触发了模型的「show your work」习惯。
  3. Tool Thrashing:在多个相似工具之间反复横跳,或拿到 tool error 后不修参数只换工具。根因:tool description 重叠(见 W04 §2),或 error message 不可读(见 W04 §combo)。
  4. Context Bloat:context 一路膨胀到 80%+ 窗口,模型开始遗忘任务起点(lost-in-the-middle,见 W02)、误用早期数据、产出越来越偏。根因:每轮 tool_result 都全文塞回,没有 compaction。
  5. Silent Stop / 提前 end_turn:任务没完成 agent 就说「Done!」。根因:完成判定模糊,模型把「我做了点东西」当「目标达成」。

这 5 种失败几乎都不会在 dev 时被发现——开发者跑 3 个 happy path 就部署,生产里第一周就全部撞见。诊断不靠看 log,靠 trace:每个 turn 记 (tool_name, args_hash, result_hash, token_delta, elapsed),用脚本扫异常 pattern。

实战示例

给你的 agent harness 加一个 30 行的 failure detector:

from hashlib import md5

def hash_call(name, args):
    return md5(f"{name}|{sorted(args.items())}".encode()).hexdigest()[:8]

class AgentMonitor:
    def __init__(self):
        self.history = []  # list of (turn, name, args_hash, result_hash)
        self.token_path = []

    def record(self, turn, name, args, result, tokens):
        ah, rh = hash_call(name, args), md5(str(result).encode()).hexdigest()[:8]
        self.history.append((turn, name, ah, rh))
        self.token_path.append(tokens)

    def check(self):
        h = self.history
        # 1. Loop lock: 同 (name, args_hash) 连续 ≥ 3 次, 且 result_hash 几乎不变
        if len(h) >= 3 and len(set((x[1],x[2]) for x in h[-3:])) == 1:
            return "LOOP_LOCK"
        # 2. Tool thrashing: 最近 5 轮调了 4+ 个不同 tool
        if len(h) >= 5 and len(set(x[1] for x in h[-5:])) >= 4:
            return "TOOL_THRASHING"
        # 3. Context bloat: token 占用单调上升且 > 80% 窗口
        if self.token_path and self.token_path[-1] > 0.8 * MAX_CTX:
            return "CONTEXT_BLOAT"
        return None

# 在 harness 主循环里调用
if (state := monitor.check()):
    if   state == "LOOP_LOCK":       inject_msg("You're repeating. Try a different approach or ask the user.")
    elif state == "TOOL_THRASHING":  inject_msg("Stop trying tools. State your hypothesis first.")
    elif state == "CONTEXT_BLOAT":   compact_history(msgs)

对应防御策略:

失败模式(元):(1)只看 happy path 上线——dev 跑通 ≠ 生产可用;agent 必须用 trace 抽样和 failure replay 工具迭代。(2)出问题就换模型——很多人把 ReAct 卡死归咎于「Claude 不够聪明」,其实是 harness 没设 max_iters / verifier / compaction。模型解决不了系统问题。(3)用更复杂的 framework 解决简单 bug——LangGraph 替换 LangChain 不会修好你的 loop lock,加 30 行 monitor 才会。
进阶资源 · Anthropic Effective context engineering for AI agents, anthropic.com/.../effective-context-engineering · Anthropic Building Effective Agents — failure modes 段, anthropic.com/.../building-effective-agents · Hamel Husain Your AI Product Needs Evals, hamel.dev/blog/posts/evals

// 综合实战 · 给一个新 agent 项目的 7 步决策清单

把这 4 节浓缩成一份「开 agent 项目前先过」的 checklist。下次有人喊「我想做个 AI agent」时拿这张表问回去:

  1. 能不能写成 workflow? 如果路径可枚举,不要做 agent。代码 + 几个 LLM 调用解决(见 §1)。
  2. 步数和代价多少? 平均 ≤ 7 步、低代价 → ReAct;> 10 步且高代价 → Plan-and-Execute(见 §2)。
  3. 有没有 verifier? 有(测试 / schema / score)→ 可考虑外套 Reflexion;没有 → 不要碰 Reflexion,先想办法造 verifier。
  4. 真的需要 multi-agent 吗? 默认 single agent + 好 tools。只有「任务天然并行 + 子任务 context 大 + orchestrator-worker 拓扑」才上 multi-agent(见 §3)。
  5. Tool registry ≤ 10? 见 W04 §2,超过 15 个 tool 已经在退化区。
  6. Harness 防 5 种死法了吗? max_iters、loop detector、context compactor、tool error 上限、verifier-based stop 各加一条(见 §4)。
  7. 有 eval 吗? 不是 happy path demo,是 20+ 真实场景的 regression suite(Day 6 主题)。没 eval 的 agent = 玄学项目。

能在这 7 步里诚实回答「不需要 agent / single agent 够 / 不需要 multi-agent」是顶级工程素养。Anthropic / Cognition / Cursor 工程团队的共识,归结起来就是一句话——complexity is a tax, pay only when it's worth it

// ENGLISH GLOSSARY

Workflow
预定义代码路径编排 LLM 调用与 tool,路径由代码决定。
Agent
由 LLM 动态决定下一步、循环到自认完成的 system。
ReAct
Reasoning + Acting,Thought / Action / Observation 交替的最常见 agent loop。
Plan-and-Execute
先一次性生成完整计划再分步执行的 pattern,适合多步高代价任务。
Reflexion
做完后自我反思并写入 memory,下一轮带反思重做;需要 verifier。
Orchestrator-Worker
一个 lead agent 拆任务分发给若干 worker 子 agent 并行执行后汇总。
Peer Debate
多个 agent 互相辩论,多数真实场景为反模式。
Loop Lock
agent 卡在重复同一调用却期待不同结果的死循环。
Tool Thrashing
在相似工具之间反复横跳无法收敛。
Context Bloat
对话历史持续膨胀至挤压窗口、产出退化。
Verifier
自动判断 agent 输出是否达标的程序,如单元测试 / schema validation。
Trace
每个 turn 的结构化日志,用于事后分析失败模式。

// 深入思考

ReAct 是默认选择,但 ReAct 核心是 Reason-Act-Observe 循环。这和 Chain-of-Thought 有什么本质区别?
CoT 是单次推理(生成完整思考链再输出答案),ReAct 是交错(思考 → 动手 → 看结果 → 再思考)。本质区别:CoT 假设答案能纯推理出,ReAct 假设需要外部反馈。所以 ReAct 必须配 tool(无 tool 退化成 CoT)。Yao 2022:ReAct 在 knowledge-grounded 任务(HotpotQA)比 CoT 高 30%,纯推理(GSM8K)差不多。
Plan-and-Execute 看起来比 ReAct 系统,为什么默认不用它?
三个原因:1) Plan 阶段的成本:一次推理生成 10 步 plan,执行到第 3 步发现 plan 错了要全 replan,浪费 token;2) 静态 plan 适应不了动态环境(如 web 内容变);3) 实测 Plan-and-Execute 在短任务(≤5 步)输给 ReAct 5-10pp。只在长任务(10+ 步)且环境稳定(如代码生成)时才赢。
Multi-agent debate 论文很多,production 几乎没人用。除了 orchestration 复杂,还有什么本质问题?
1) 成本 N×(agent 数)的 inference cost;2) Agent 互相 reinforce 错误(echo chamber),尤其用同一基座模型;3) 真正提升的指标少(Anthropic 实验:debate 在 reasoning task 提升 2-5%,成本翻 4 倍)。例外是 context isolation 收益大的:长文档分析(每 agent 看一段,最后 aggregate),multi-agent > single 显著。
Reflexion 让 agent 自我改进——但它需要 verifier。什么任务有好 verifier,什么任务没有?
有 verifier:代码(运行测试)、数学(验算)、SQL(执行结果)、search(结果数 ≥ threshold)。没 verifier:写作(质量主观)、对话(无 ground truth)、设计(多答案)。无 verifier 时强行用 Reflexion 会让 agent 在自己产生的「幻觉评分」里循环退化。能写 verifier 就用 Reflexion,不能就别用。
Agent 失败模式中最常见的是什么?怎么提前 detect?
最常见:「tool selection 死循环」——模型反复调同一 tool,因为不知道为何失败。Detection:1) 维护 last_N_tools deque (N=3),若 [A,A,A] 就强制中断;2) 每次 tool result 后检查 progress signal(output 是否变化、是否接近目标),无 progress 就 escalate。第二常见:context overflow——历史太长,最早指令被挤掉。

// 延伸阅读