自回归大语言模型在缺乏外部强约束时,天然存在向局部贪婪变异发散的病态冲动。Claude Code 的 Plan 模式通过外挂离散有限状态机(FSM),将动作空间硬性投影至零副作用的只读子集,利用人机交互屏障强制在决策树上切断代价高昂的物理回溯分支。
在传统的软件工程中,经验丰富的工程师往往遵循「设计先行」的直觉:在碰第一行代码前梳理依赖链、推演类型签名、界定修改边界。然而对 LLM 而言,这种直觉并不存在。在基础 RLHF 训练中,模型被严重塑造成「立刻给出行动并解决问题」的顺从者。一旦拿到写权限,它更倾向于在缺乏全局视野的状态下盲目修改文件,从而在复杂的软件拓扑中引发连锁雪崩。
动作近视与马尔可夫决策树的发散灾难 #
在马尔可夫决策过程(MDP)中,Agent 依靠自回归解码连续选择动作。如果将整个软件重构任务抽象为一棵庞大的状态转移树,系统在第 $T$ 步保持全局正确的概率受制于级联误差累积:
$$P(\text{Success}_T) = \prod_{t=1}^T (1 - \epsilon_t)$$即使每一步工具调用的失误率 $\epsilon_t$ 控制在极低的 $5%$,经历 15 步连续的自发修改后,系统处于未偏离目标状态的累积概率仅为:
$$P(\text{Success}_{15}) = (1 - 0.05)^{15} \approx 46.3\%$$在自由的读写执行环境中,大模型极易陷入动作近视(Action Myopia):
- 看到一个函数报错,立即调用
edit粗暴修改入参; - 修改导致调用方的测试崩塌,模型进一步调用
write_file覆盖调用方; - 第三层间接依赖随之报错,模型继续向整个代码库蔓延扩散。
|
|
这种发散在工程现实中的代价被称为物理回溯惩罚(Physical Backtracking Penalty)。一旦模型在错误的分支上涂抹了十几个文件,想要回滚状态就必须依赖复杂的 Git 撤销、临时文件清理以及长篇累牍的纠错 Token。这种回溯不仅消耗显存预算,更会彻底污染模型的短期记忆,正如我们在 上下文压缩的物理代价 中剖析的那样。
Plan 模式的形式化:有限状态机与屏障同步 #
Plan 模式的核心价值,是在应用运行时外嵌了一套硬性双状态有限状态机(FSM):
$$\mathcal{S} \in \{\text{PLAN}, \text{EXECUTE}\}$$
|
|
1. 动作空间的非对称投影 #
设系统的全量可用工具集合为 $\mathcal{A}$,包含读、写、执行等全部系统调用封装。在 PLAN 状态下,运行时的工具分发网关对动作空间实施强制收缩:
在 权限系统与真实安全边界 中提到过,权限拦截必须发生在底层系统调用被触发之前。处于 PLAN 状态时,一旦模型试图派生 write_file 或高危 bash,执行引擎直接阻断并在本地返回错误回执。该阻断由应用层路由器硬性截断触发。
2. 人工屏障同步(Barrier Synchronization) #
从状态 PLAN 向 EXECUTE 的跃迁依赖一道离散的人机交互屏障:
- Agent 必须在只读约束下完成项目探索;
- 汇聚生成一份包含「文件变更清单、潜在破坏性影响、执行步骤顺序」的结构化 Markdown 蓝图;
- 运行主循环被动挂起,等待终端人类按下确认键。
通过这道屏障,决策树上的回溯成本发生了量级转移:在 Plan 模式下发现方向错误,人类只需回复一句「方向不对,不要碰数据库层」,代价仅仅是废弃几百字文本;而在 Execute 模式下发现方向错误,付出的是十几处代码覆盖与脏工作区的治理代价。
Plan 模式的实质,是用极其廉价的文本剪枝,替代代价高昂的物理状态回溯。
静态规划的破灭:遭遇真实编译器的脆弱性 #
然而,将 Plan 模式奉为万灵药是典型的教条主义。预先规划机制在现实软件系统面前有着致命的先天缺陷:软件系统具备强非线性与动态运行时反馈,而静态文本规划天然缺乏编译器感知。
大模型无法在其神经网络中准确模拟完整的编译器语义检查。如果强制要求模型在不动手验证的前提下写出巨细靡遗的执行计划,不仅严重拖慢工程节奏,还会带来严重的认知负担。
边际收益递减与工程反思:BYF 为何在 ADR 0008 中废除 Plan Mode #
在开源 Agent 引擎 BYF 的早期版本中,团队曾经完整复刻了 Claude Code 的 Plan 模式。但在迭代至 ADR 0008 时,工程团队做出了一个看似激进却极其理性的决定:彻底剔除 Plan Mode 机制,将其自核心状态机中剥离。
导致这一架构决断的核心原因在于工程复杂度的沉重负担与严重的边际收益递减:
1. Token 显存的持续失血 #
为了维持 Plan 模式的严密运转,系统付出了昂贵的常驻上下文代价:
EnterPlanMode与ExitPlanMode两个工具的 JSON Schema 描述,每轮迭代均需被序列化进 Prompt,常驻消耗约 1,425 Token;- 周期性的
PlanModeInjector需要向历史消息不断追加「你当前处于规划模式,请勿修改代码」的状态同步片段; - 生成的长篇计划文本通常占据 2k–5k Token,严重挤占后续代码生成的注意力带宽。
2. 代码拓扑与状态污染 #
Plan Mode 并非一个纯粹的局部特性,它像藤蔓一样侵入到底层架构的各个角落:
- CLI/TUI 层需要适配
/plan命令、快捷键监听、专属卡片与状态栏角标; - 核心引擎需要维护双重状态迁移逻辑与复杂的重入死锁防御;
- 涉及 70 多个源码文件的跨模块耦合,显著拉高了系统的测试与维护成本。
3. 交互屏障的“橡皮图章化” #
正如权限确认中的疲劳衰减一样,当模型频繁向开发者输出上百行的抽象规划列表时,绝大多数人类工程师根本没有耐性逐行审查其中的逻辑漏洞。开发者快速扫一眼便敲击回车,形式上的严格屏障最终退化为无意义的操作摩擦。
BYF 最终论证出的工程路径是:代理应当在连续的探索与行动中交错推进,避免被人工预设的二元状态割裂。 用户通过自然语言明确发出「先阅读相关代码并向我说明思路,确认后再动工」的指令,配合细粒度的工具审计机制,足以达到同样的规划效果,而无需为此背负庞大的状态机包袱。
规划模式的适用边界与分工法则 #
否定盲目崇拜不等于否认规划的价值。在实际工程落地中,是否应当使用类似 Plan 模式的强约束机制,取决于任务的不确定性与爆炸半径:
| 任务场景维度 | 推荐协作姿态 | 控制面手段 | 代价与权衡考量 |
|---|---|---|---|
| 局部确定性修复 (修复单一单测、字段增补、函数重命名) |
流畅交错(免规划) | 直接在普通模式下快速修改并执行测试验证 | 避免多余的 Token 消耗与状态切换摩擦 |
| 跨模块架构重构 (状态管理迁移、数据库 ORM 重构) |
强阻断规划(Plan 模式) | 限制文件写权限,强制生成明确模块边界方案 | 优先保障分支剪枝,防止脏工作区扩散 |
| 未知代码库摸底 (新项目排查、开源依赖内部实现勘探) |
探索式只读 | 仅挂载只读工具集,阻断一切非必要修改 | 防止模型在勘探过程中意外引入无效副作用 |
结语:给随机系统套上力学夹板 #
Plan 模式是一套给具备随机性的生成模型套上的力学夹板。
它通过限制自由度,遏制了模型在动作近视驱使下的盲目改动;通过外置的有限状态机与屏障同步,以极低的文本代价替开发者切断了潜在的深渊分支。
但优秀的系统工程师必须看透:夹板能够固定骨骼,却不能代替骨骼本身的强度。静态规划一旦脱离编译器的即时反馈,就会迅速撞上边际效益递减的物理之墙。在软件开发这样高度复杂的动态系统中,懂得在严格约束与自适应验证之间取得平衡,才是构建可靠 AI 生产工具的坚实基础。