这堂课中途跑去看了一眼 DeepSeek Harness。
本来只是一次时事插课,结果它反而把经典 Agent 范式重新照亮了一遍。
我们之前已经分别讨论过 ReAct、Plan-and-Solve 和 Reflection。如果只按定义复习,这一课几乎没有必要再上一次:
ReAct
边思考、边行动、边观察
Plan-and-Solve
先规划,再执行
Reflection
做完以后反思,再改进这些都对。
但真正把三种范式放回工程以后,更有用的问题其实是:
谁在什么时候拥有重新决定下一步的权力?
从这个问题继续往下追,经典范式就不再是三套 Prompt,而开始变成一套 Agent 控制系统。
学习主线仍然参考 Datawhale 的 Hello-Agents。上游当前把 ReAct、Plan-and-Solve、Reflection 放在“智能体经典范式构建”章节中;我们仍然不严格追章节编号,而是把教材主线和正在发生的 Mira 工程问题放在一起学。
ReAct:把局部行动权留在运行时#
ReAct 最重要的不是 Thought / Action / Observation 这三个词。
真正重要的是 Observation 回来以后,Agent 重新拥有一次决策权。
State₀
↓
decide()
↓
Action₁
↓
Observation₁
↓
State₁
↓
decide again()这意味着 Agent 不必在任务开始时预知全部环境。
调试代码、浏览网页、排查未知 Bug、研究一个不确定问题时,这一点尤其重要。新的证据可能让前一步的假设直接失效。
但 ReAct 也有天然弱点:
局部合理,不等于整体合理。
一个 Coding Agent 可以连续做出十几个“这一刻看起来都合理”的动作,最后却离原始 Goal 越来越远。
发现 A 报错
→ 改 A
→ B 报错
→ 改 B
→ 顺手重构 C
→ 测试又坏了
→ 再回头改 A它每一步都在响应 Observation,却可能已经忘记最初为什么开始。
所以 ReAct 擅长的是:
局部实时控制。
它并不天然保证全局目标收敛。
Plan-and-Solve:提前冻结一部分未来决策#
Plan-and-Solve 常被理解成“先列 TODO”。
这太浅了。
Plan 真正做的事情,是在任务开始时先拿走一部分未来的自由度。
比如:
Goal:修复登录问题
Plan:
1. 定位鉴权失败位置
2. 确认 token 生命周期
3. 修改 refresh 逻辑
4. 补回归测试
5. 验证登录 / 续期 / 退出Executor 执行第二步时当然仍然可以思考。
但它不应该随便把任务改写成:
“既然来了,顺便把整个 Auth Architecture 重构掉。”所以 Plan 的价值不只是告诉 Agent “下一步做什么”。
它同样在告诉 Agent:
现在什么事情不应该做。
如果把它写成决策空间:
ReAct
当前状态
→ 很大的 Action Space
Plan-and-Solve
当前状态 + Plan
→ 被约束后的 Action Space这就是为什么复杂工程里 Planning 能抑制 trajectory drift。
Plan-and-Solve 不是替代 ReAct,而是包住 ReAct#
教材里的 Plan-and-Solve 很适合解释思想:先生成计划,再逐步执行。
但真实环境会变化。
比如计划原本是:
1. 修改代码
2. 跑测试
3. 提 PR
4. Review
5. Merge到第二步突然发现:
API contract 已经变化,
原计划依赖的关键假设不再成立。继续严格执行旧 Plan 显然不对。
让 Executor 完全自由发挥,同样会重新回到 ReAct 漂移问题。
更常见的工程结构其实是:
Planner
↓
High-level Plan
↓
Executor
↓
Local ReAct
↓
Evidence
↙ ↘
假设仍成立 假设失效
↓ ↓
继续 Local Replan所以更准确的理解是:
Plan-and-Solve 包住 ReAct,而不是替代 ReAct。
Planner 控制全局的未来决策空间;Executor 在当前步骤内部保留局部适应能力。
一个负责“方向”,一个负责“这一脚应该踩在哪里”。
Retry 还是 Replan,关键看新证据改没改变世界模型#
课堂测试里,Tomz 给了一个很好的判断规则。
问题是:执行失败以后,什么时候应该 local retry,什么时候应该回 Planner 重新规划?
他的回答是:
前者是有确定无关变量影响的证据,后者是证据影响计划决策。
展开一下就是:
网络瞬时抖动
临时 500
锁冲突
偶发超时如果有证据表明这些失败不改变原计划成立的条件,那么 retry 很合理。
而:
API contract 变化
依赖不存在
目标约束改变
原始假设被证伪已经改变了 Planner 当初做决定时依据的世界模型。
这时继续 retry,只是在对已经失效的路线重复用力。
更值得记住的判断不是:
失败严重吗?而是:
这份新 Evidence 有没有改变 Plan 成立的前提?
Reflection:第二次思考不等于第二份证据#
Reflection 最容易被 Prompt Engineering 骗到。
例如模型 A 写了一段数据库迁移代码。
然后还是同一个模型、同一个上下文:
“请仔细反思刚才代码是否安全。”
模型认真看了一遍:
“经过检查,没有问题。”
这当然可能有帮助,但它没有天然获得新的事实来源。
如果第一次错误来自同一个知识盲区,第二次 Reflection 很可能仍然沿着同一个盲区走。
所以:
Self Reflection
≠
Independent Verification更可靠的 Reflection 通常至少改变一个东西:
Evaluator
换模型、换独立 Reviewer
Evidence
跑测试、schema diff、dry-run、静态分析
Criteria
明确安全规则、验收清单、Design System
Context
去掉原推理,只给结果和目标重新审课堂上 Tomz 的回答是:
换模型,换模式,比如 ReAct(证据),换角度(Context)。
方向是对的。
但我们最后把第二点再收紧了一层:
真正提高可靠性的不是“用了 ReAct”这三个字,而是 ReAct 带回了新的 Observation / Evidence。
如果模型只是换了一种 Prompt 继续在同一份信息上打转,它仍然可能只是把同一个错误说得更认真。
一句话:
Reflection 提供第二次思考;Evidence 提供第二个事实来源。
通常后者更值钱。
谁有权宣布任务完成?#
学到这里,三种经典范式都在解决“怎么继续做”。
但真正工程化以后,还有一个更危险的问题:
谁有权说“已经做完了”?
教学版 ReAct 很容易让模型自己输出 Finish。
问答任务里这通常够用。
但把任务换成:
修复 Token Refresh Bug,并保证没有回归。
Agent 修改完代码,看到 npm test 全绿,就说:
Finish后来才发现,测试集中根本没有覆盖“token 过期后自动刷新”这个核心场景。
于是必须把三个状态拆开:
canAnswer
≠
taskComplete
≠
acceptedcanAnswer#
模型已经有足够信息生成回复。
taskComplete#
目标状态已经真实发生,并有足够证据覆盖 Success Criteria。
accepted#
外部验收条件已经满足,例如 Review、门禁、人工验收或其他业务条件。
课堂里 Tomz 第一反应是:
canAnswer = true
taskComplete = false
accepted = true第三个被我们判错。
因为“现有测试全绿”只证明现有门禁绿了。
如果门禁没有覆盖核心验收场景,那么门禁本身就是残缺的。
所以更合理是:
canAnswer = true
taskComplete = false
accepted = false这件事对 Mira 特别熟悉。
过去我们把很多终止判断放进 Planner。
现在更准确的理解是:
Planner 可以 propose finish,但最终状态不应该只靠 Planner 自我宣布。
更成熟的结构是:
Planner / Executor
“I think I'm done.”
↓
propose finish
↓
Harness
检查 Goal / Evidence / Criteria / Policy
↓
commit taskComplete于是经典范式之外,又长出了一层:
Harness 持有终止权和状态写入权。
Planner 负责聪明,Harness 负责不让“聪明”直接改事实#
这堂课最后 Tomz 还有一个容易混淆的点:
他知道 Mira 当前把结束判断放在 Planner,于是自然会说:
“Planner 验收,Planner 提交任务完成信号。”
这在已有实现里很好理解。
但如果把 Planner 看成 Harness 的一个智能控制组件,职责会更清楚:
Planner
判断:
- 目标覆盖了吗?
- 还缺什么?
- 是否值得结束?
Harness
执行:
- 状态是否合法?
- Evidence 是否满足条件?
- Policy 是否允许?
- 是否写入 completed?也就是说:
会判断,不等于拥有最终状态写入权。
这个边界很重要。
否则一个语言模型只需要成功说服自己“我完成了”,系统状态就真的变成完成。
三种经典范式,其实是三种控制机制#
到这里再回头看:
ReAct#
负责局部反馈控制。
Observation 改变
→ 下一步重新决策它拥有的是:
当前行动权。
Plan-and-Solve#
负责前馈式全局约束。
Goal
→ Plan
→ 约束未来行动空间它影响的是:
未来决策权。
Reflection#
负责对结果和目标之间的差距做二次校正。
它拥有的是:
纠错建议权。
再把真实工程补进来:
Harness#
负责运行状态、终止条件和合法状态转移。
它拥有的是:
终止权 / 状态写入权。
Policy#
负责限制哪些动作可以真实发生。
它拥有的是:
行动许可权。
这样以后再看到一个 Agent 框架,我们就不用先问:
它用了什么 Prompt?
它是不是 ReAct?更值得先问的是:
谁决定下一步?
谁约束长期目标?
谁负责纠错?
谁允许动作发生?
谁可以宣布完成?这些问题比框架名字稳定得多。
一次 DSH 插课:Tool Routing 和 Responsibility Routing#
这堂课中间,我们看了 DeepSeek Harness(DSH),顺便讨论了一人公司的“AI 员工”。
原本的直觉是:
员工
= 模型
+ Prompt
+ MCP
+ Tool
+ Skill但 Harness 的插件化和作用域思路让这个公式开始变化。
更像:
Employee Runtime
= Identity
+ Model
+ Context
+ dynamically mounted Capabilities
+ scoped Memory
+ governed Permissions然后我们碰到一个经典范式之外、但和 Planning 很相关的问题。
Engineer 做任务时发现 Android signing 自己不会,而 Release Agent 会。
有两种路线:
A
Engineer 临时获得 signing skill / tool / credential
继续做
B
Engineer 完成自己的部分
→ delegate Release Agent
→ Release Agent signing / publish
→ 返回 Evidence默认我们更偏 B,因为职责和权限边界更干净。
但 Tomz 提醒了一个很现实的反例:
A 也很常见,因为 Engineer 在完成任务中积累了可能影响打包的上下文。比如中途有别的线程混入提交。
这一句非常重要。
切换 Agent 并不是免费的。
它在权衡:
Context Locality
vs
Capability Isolation于是我们又把两个概念拆开:
Tool Routing
当前责任主体不变
→ 我该调用哪个工具?
Responsibility Routing
先判断责任主体
→ 这件事还该不该由我做?
→ 是否应该交给另一个 Agent?当“组织结构”真的进入 Agent Runtime,它控制的就不只是工具列表,而是:
谁负责完成
谁可以决定
谁只能建议
谁可以接管
谁需要交付证据
谁对最终结果负责这已经是 Responsibility / Authority Graph。
我们会在后面的 Agent Framework / Multi-Agent 主线里继续回来收这个问题。
课堂测试:不是背概念,而是判断控制权#
学完以后,我们做了一次 100 分测试。
最终成绩:
86 / 100
没有美化成满分。
因为错的地方刚好比答对的地方更能暴露概念边界。
第 1 题:未知故障应该怎么调查?——15 / 15#
场景:Mira Mobile 偶发远程消息丢失,一开始不知道问题在 Mobile、Desktop Host、网络还是协议层。
四种候选思路分别是:固定完整计划、纯 ReAct、先高层目标再局部 ReAct、先 Reflection 猜根因。
Tomz 选择了混合结构,并解释:
不选 A,因为环境是随着执行步骤变化的。
不选 B,因为这个线索可能是局部的甚至是假的。
不选 D,因为光猜,每次输入的环境参数都一样。
这三个否定比选择 C 本身更重要。
他已经把三类风险分开:
静态 Plan
→ 环境变化以后失效
纯 ReAct
→ 被局部 / 假 Evidence 带跑
无新增 Evidence 的 Reflection
→ 在相同认知条件下重新猜正确结构是:
Global Goal + Success Criteria
↓
定位阶段:ReAct
↓
确认 Root Cause
↓
形成明确修复 Plan
↓
局部失败时允许 Replan第 2 题:测试全绿,为什么仍然不能验收?——10 / 15#
场景:Token Refresh Bug 修改完成,npm test 全绿,但核心“token 过期自动刷新”场景根本没有测试。
Tomz 很快判断:
taskComplete 应该由 Harness 根据目标、证据和验收条件计算。
这部分正确。
但随后给出:
canAnswer = true
taskComplete = false
accepted = true错误就在最后一个 true。
这暴露了一个很常见的误区:
Gate Pass ≠ Acceptance Valid。
如果 Gate 本身漏掉核心 Criteria,它通过并不能证明任务被正确验收。
第 3 题:怎样让 Reflection 真的变可靠?——13 / 15#
Tomz 的答案:
换模型,换模式,比如 ReAct(证据),换角度(Context)。
三条都在正确方向。
我们扣掉的两分只因为要把第二条说得更严格:
ReAct 本身不是可靠性的来源,新增 Evidence 才是。
例如:
数据库 dry-run
schema diff
migration test
静态分析这些甚至完全不需要第二个 LLM。
第 4 题:Retry 还是 Replan?——15 / 15#
场景:执行 Mobile 计划时发现 Desktop API contract 与原假设不同。
Tomz 选择 Replan,并给出整场测试里最干净的一句判断:
前者是有确定无关变量影响的证据,后者是证据影响计划决策。
这句话可以直接留下来。
第 5 题:给 Engineer 扩权,还是找 Release Agent?——17 / 20#
默认选择 Responsibility Routing:交给 Release Agent。
但 Tomz 没有把 B 当成教条。
他指出 Engineer 已经积累的局部 Context 可能难以完整交接,比如:
中途有别的线程混入提交。
这说明实际设计要比较:
handoff cost
vs
temporary capability grant cost扣的三分来自最后一个概念混淆:最开始把 Responsibility Routing 又说回了“根据动态工具”。
真正的区别是:
Tool Routing
选能力
Responsibility Routing
选责任主体第 6 题:设计一个真实 Figma Agent Loop——16 / 20#
任务:把已有 Web 产品两个页面迁移到 Figma,视觉高度一致,并符合已有 Design System。
Tomz 的核心结构是:
Planner 规划
↓
绘制过程中持续拿证据
↓
完成一轮后 Reflection
↓
发现画布、设计系统等关键前提错误则 Replan
↓
人工最终验收方向成立。
最后需要修正的仍然是 Planner 与 Harness 的职责:
Planner
→ 判断目标覆盖
→ propose finish
Harness
→ 检查 Criteria + Evidence + Review 状态
→ commit taskComplete
Human Gate
→ accepted因此这道综合题也回到了整堂课的最后一个边界:
Planner 可以很聪明,但不能因为“觉得自己完成了”,就直接把世界状态写成 completed。
86 分暴露出来的三个剩余盲点#
这次测试没有暴露“不会 ReAct”或者“不懂 Reflection”这种基础问题。
真正剩下的是三个更工程化的边界。
第一:
Planner
≠
Harness前者负责智能判断,后者负责状态治理。
第二:
Tool Routing
≠
Responsibility Routing前者选择能力,后者选择承担责任的主体。
第三:
Gate Pass
≠
Accepted验收规则本身也可能不完整,Evidence 必须真的覆盖目标。
这三处恰好都已经超过“经典 Prompt 范式”本身,开始往 Agent Runtime / Framework 走。
这堂课真正应该留下什么#
如果只留三句话:
ReAct = 边想边做
Plan-and-Solve = 先计划再做
Reflection = 做完反思那这一课很快就会忘。
我们最后留下的是另一组东西:
ReAct
→ 当前行动权
Planning
→ 未来决策权
Reflection
→ 纠错权
Policy
→ 行动许可权
Harness
→ 终止权 / 状态写入权这样以后不管遇到 LangGraph、DeepSeek Harness、Codex、OpenCode,还是 Mira 自己的下一版 Agent Runtime,都可以先跳过产品名问:
谁在做决定?
谁能改变决定?
谁能让动作真实发生?
谁能宣布任务完成?
当这些“权”分清楚,Agent Loop 才真正开始从 Prompt 变成系统。
下一站#
经典范式主线到这里可以正式收掉。
接下来不必为了教材顺序去做低代码平台操作题。
更值得顺着今天已经冒出来的问题,往 Hello-Agents 的 框架开发实践 / 构建自己的 Agent Framework 继续:
一个 Agent Framework 到底应该负责什么?
Planner、Tool、Skill、Memory、Policy、Harness
应该怎样成为可组合的 Runtime?
能力动态装载以后,权限和 Context 怎样跟着走?
组织结构怎样真正进入 Agent Loop?DSH 已经提前把这个问题撩开了一条缝。
下一课,我们就从这条缝往里面看。