Dex Horthy 的 AI That Works 已经更新到第 72 期,这一期的主题是“面向可扩展软件的 Code Mode”。先说我的判断:Code Mode 不是一个“帮你写更多代码”的功能开关,它代表的是 AI 编程工具从“回答代码问题”进入“直接管理代码仓库变化”的工作方式。如果你维护的软件不是一次性脚本,而是会持续迭代、会加模块、会被别人接着维护的产品,那这个主题就非常值得研究。
我在这里不会把第 72 期的原文内容一段段转述出来。博客的价值不在复述,而在于把你听到的概念拆成能自己实验的步骤:Code Mode 到底是什么,跑之前要准备什么,单任务怎么验证,批量修改怎么控制,出了问题按什么顺序排查。
1. Code Mode 解决的不是“写代码”,而是“持续修改代码库”
1.1 普通问答模式缺少的是什么
先解释一下这里说的 Code Mode 取什么含义。现在很多 AI 编程助手都有模式区分:一种是问答式,你问它“这段代码哪里有问题”,它给你解释或者给出一段示例;另一种是传统补全式,你在编辑器里写注释,它补函数体。
Code Mode 通常指向另一种能力:它把整个代码仓库当作工作现场,可以检索文件、读取相关模块、直接编辑代码、运行命令、执行测试,然后根据报错继续调整。不同产品里这个功能的名字可能不一样,有的叫 Agent,有的叫 Build Mode,有的直接叫 Code Mode。名字会变,本质接近。
问答模式和 Code Mode 最大的差异不是“回答质量”,而是“有没有改变文件状态”。问答模式再怎么生成代码,最终动作发生在你的复制粘贴和手动提交里;Code Mode 会真的去改文件、建目录、移动代码、运行测试。也就是说,你需要为自己的代码仓库状态变化负责。
1.2 “可扩展软件”为什么是一个特殊场景
普通脚本写出来跑一遍,正确就行。可扩展软件不是这样。
“可扩展”说的是软件长得大以后还能被维护:模块边界清晰,接口稳定,数据流可追踪,依赖方向不会混乱,新人接手不需要靠猜。这些性质很难用单次测试结果衡量。Code Mode 改代码时,并不会天然把“可扩展性”当作最高优先级。它更倾向于先把眼前任务跑通。
所以“面向可扩展软件”这个限定语,正确的理解大概是这样:不是意味着 Code Mode 已经成熟到能自动架构大型系统,而是提醒使用者,当你想让 AI 在一次多轮修改里处理多个文件、跨模块的需求时,必须用更工程化的方式去约束它。否则它改得越快,制造的问题可能越隐蔽。
我对 Code Mode 的使用原则比较保守:小任务可以放手让它自己试,涉及公共接口、数据模型、跨模块重构时,一定要每一步都看住。
注意:不要因为代码模式能一口气改十个文件,就把复杂的架构决策也一起交给它。它在逻辑正确性上可以帮你,在组织边界和长期成本判断上仍然需要人把关。
2. 在跑 Code Mode 之前,先把这些环境确认好
2.1 仓库本身要允许“快速试错”
很多 Code Mode 失败的问题不在模型,而在项目环境不支持它快速试错。
我建议至少确认这几件事:
- 当前代码能不能在一个干净分支上随意改动,并方便回滚。
- 构建、编译、测试命令能不能在本地快速执行。
- 改动涉及的核心模块是否已经有基础测试覆盖。
- 代码仓库是否已经建立索引,或者工具是否允许你限制只扫描某几个目录。
为什么要这么确认?因为 Code Mode 的工作方式是“改代码、跑测试、看报错、再改”。如果一次完整验证需要三分钟,它迭代十次的成本就是三十分钟;如果测试需要人工介入,它根本无法自动闭环。常见的跨平台大仓库里,光是一个模块编译就要几分钟,这种环境就不适合让 AI 做大量自主尝试。
正确做法是把改动边界收窄。Code Mode 一次只负责一个模块或一条链路,避免在一个巨大 monorepo 里无限制检索。低配置机器也一样能跑,但你要把范围缩小,而不是让它在整个仓库里乱找文件。
2.2 权限、路径、依赖与索引,比“聪明提示词”更容易出问题
有一次我遇到 Code Mode 说“完成”,但实际上一个文件都没改。排查了很久,原因是目标目录权限不对,工具只能读不能写。这类问题非常常见。
正式开工前,按照这个顺序检查一圈:
- 仓库路径里不要出现特殊字符或过长路径。Windows 和 Linux 对路径分隔符、大小写、文件权限的处理不一样,如果团队里有人用 Mac、有人用 Windows,还要额外注意换行符和可执行权限。
- 需要运行的命令能直接在当前环境执行。Python 虚拟环境有没有激活,Node 依赖有没有安装,Go 模块缓存是否正常。
- 代码索引是否覆盖目标文件。有的工具对大仓库需要先构建索引,如果索引只建到一半,Code Mode 会找不到某些符号,然后给你生成一个“看起来合理但并没有复用现有函数”的新版本。
- 依赖版本是否和项目锁文件一致。AI 生成的代码可能在你的机器上没问题,但它假设的依赖版本和项目的实际版本不一致,就会出现接口不存在或者行为不同。
这些不是 Code Mode 自己能判断的。它看到的是文字,你掌握的是真实运行环境。你要做的不是给它一个无比惊艳的提示词,而是把环境调成可预测状态。
3. 把可扩展需求拆给 Code Mode 的通用流程
3.1 用“任务描述”而不是口头聊天
我不太建议你用“帮我优化一下这个模块”这种话去驱动 Code Mode。这句话的信息量太低,模型不知道“优化”指性能、可读性还是接口拆分,也不知道边界在哪里。
我一般会写一份任务描述,包含目标、范围、约束、验收标准四块。结构类似这样:
目标: 在支付结果处理模块中,增加一个可配置的重试策略。 当前入口:src/payment/handler.process_result 范围: 只修改 src/payment 目录下的代码。 不允许改动数据库表结构和对外 API 签名。 约束: 重试间隔必须可配置,不能写死常量。 日志中要记录每次重试的原因。 验收标准: 1. 单元测试覆盖“第一次失败后成功”和“持续失败达到上限”两种情况。 2. 配置项不设置时默认重试 3 次。 3. 现有测试全部通过。 请先输出修改计划,不要直接改代码。任务不能太大。一个任务尽量只解决一个横切关注点。Code Mode 擅长的是把一个局部变化做完整,而不是替你完成整个系统的重构规划。
写完任务描述后,不要马上点“执行”。先让它输出方案。这一步会浪费一点时间,但能避免它拿着错误的架构假设直接动手。
3.2 先“Plan Only”,再“Do It”
实际使用 Code Mode 时,我会把过程拆成两个阶段。
第一阶段只让它读代码、分析目标、给出修改方案。方案里要能回答几个问题:涉及哪些文件、每个文件大致怎么改、会新增什么配置项、会不会影响其他调用方、需要补哪些测试。
第二阶段才是执行。而且执行后不要急着让它继续写下一个功能,先做代码评审。
这个流程背后的原因是成本不对称。一个坏方案被拒绝了,损失只是一个想法;如果模型直接带着坏方案改完十个文件,你要花数倍时间去回滚和解释。
看 diff 的时候,重点不是看代码能不能运行,而是看它是否遵守了你设定的范围。我经常发现的问题包括:说好只改一个模块,它顺手改了公共目录;说好不改数据库结构,它在迁移文件里加了字段。这些问题单看测试不一定暴露,但会让你的可扩展性设想一点点失效。
4. 能不能算“可扩展”,不能只看测试通过
4.1 单条任务的验收标准
Code Mode 跑完一项任务,最简单的判断当然是“有没有报错、测试是否通过”。但如果课题是“面向可扩展软件”,这个标准远远不够。
测试通过说明它在当前环境、当前输入下表现正确,不能说明新代码会不会阻碍后续三个功能的扩展。例如为了快速满足需求,模型可能直接复制了一段类似逻辑,而没有抽成公共函数;也可能为了通过类型检查,给对象加了一个很宽泛的 any;还可能把一个本来只由 A 模块调用的入口,暴露给 B、C、D 到处引用。
对可扩展软件来说,这些问题的恶劣程度往往比“某个边界条件没处理”更高。因为它们是结构性的,越晚发现越难改。
4.2 从五个维度看新增代码
这里整理了一个我评审时常用的检查维度。它不是工具自带的标准,但比较接近做架构评审的人会关心的问题。
| 检查维度 | 看什么 | 可接受信号 |
|---|---|---|
| 模块边界 | 是否绕过了已有的分层,是否引入了反向依赖 | 新代码只依赖下层模块,不窃听兄弟模块内部 |
| 接口稳定 | 是否改动了对外签名,是否破坏既有调用方 | 新增独立函数或接口,而不是偷偷改掉公共契约 |
| 数据流 | 参数是显式传递,还是散落在全局状态里 | 输入输出路径清晰,副作用容易追踪 |
| 性能假设 | 循环内有没有数据库查询,缓存是否无界 | 复杂操作用批量或异步,资源消耗有上限 |
| 可观测性 | 关键分支有没有日志、错误类型和上下文 | 失败时能从日志判断是配置、网络还是业务问题 |
你可以根据自己项目的类型调整维度。如果是数据团队,可能要看 SQL 是否会全表扫;如果是前端项目,可能要看组件状态是否提升合理;如果是基础服务,就要重点看并发安全和资源释放。
重要的是验收动作要包含“结构评审”,而不仅仅是“跑通”。
注意:Code Mode 给的总结里经常说自己“为了可扩展性做了抽象”,这不一定是真的。你要翻开 diff 看抽象是否过度,是否用额外的一层间接性换来了不必要的复杂性。
5. 需要批量改多个模块时,怎么防止 Agent 失控
5.1 一次只拆一个可独立验证的边界
当需求涉及多个模块,不要把所有改动塞进同一个任务描述里。表面上看“让 AI 一次做完”效率更高,实际上会有三个问题:
- 上下文长度有限,改动范围越大,它对每个文件的关注度越低。
- 如果中间某个模块测试失败,它会带着错误状态继续处理另一个模块,错误会传染。
- 产生的 diff 巨大,人工评审很难发现哪里改错了,可扩展性也就无从谈起。
我倾向于把一个批量需求按模块拆成多个阶段,每个阶段对应一次可验证的变更。例如先改数据访问层,不急着改上层接口;等数据层的测试和代码评审通过后,再让 Code Mode 改业务逻辑层。
这样做成本看起来高一些,但它能保证任何一步出问题时,影响范围是可控制的。增量交付本来就是可扩展软件开发的常态。
5.2 批量任务里要有失败重试和日志留痕
Code Mode 在做批量任务时,不能只设置一句“把所有文件都处理一遍”。你需要考虑几件事是普通脚本和自动任务都会遇到的:失败重试、输出命名、日志位置、恢复点。
如果你是让 Code Mode 连续处理多个业务接口,最好为每个接口创建独立的分支或独立的提交,而不是让所有改动都堆在一个工作目录里。这样当第三个接口改坏时,你不需要撤销前两个接口的成果。
如果任务之间有关联,例如都需要先拉取某个配置,那就把“公共准备工作”单独作为一个任务先跑完。Code Mode 自己也会尝试推理,但公共步骤重复执行容易产生冲突。
另外一个容易忽略的点是输出和日志。很多 Code Mode 工具允许你查看执行记录,你要把执行记录保存下来,而不仅仅依赖模型最后那句“完成”。当批量任务跑到一半失败时,日志能告诉你它停在哪里、执行了什么命令、报错内容是什么。这比从头开始一个新会话要可靠得多。
6. Code Mode 报错、跑偏、没改文件时,按这个顺序排查
6.1 先看现象和输入,不要急着调提示词
我见过很多人,第一次碰到 Code Mode 表现不佳,第一反应是“我的提示词不够好”,然后开始加各种复杂的措辞。但很多时候问题根本不在提示词,而在环境或者输入约束。
排查我建议按这个顺序:
- 查看实际现象:是报错、卡住、没改文件,还是改了文件但行为不符合预期。
- 查看它实际改动了哪些文件。有的工具会列出所有编辑过的文件,直接看这个列表,比看它的文字总结靠谱得多。
- 回头检查任务描述里说的范围、路径、名称是否和代码仓库里的真实情况一致。如果模块已经被重命名,而你还写着旧路径,Code Mode 可能花了半天找不存在的东西。
- 再检查仓库索引和权限。工具能不能正常搜索到这个文件?对它来说,这个目录是否只读?
路径和权限问题是“没改文件”这个现象的高频原因。不要以为模型没有理解你的需求,它可能理解了,但写不进去。
6.2 看日志、看资源、看版本,再改参数
如果是代码能改、但测试一直失败,要去看真实的报错信息。
具体操作是先本地手动执行它失败的那条命令。不要只看 Code Mode 转述的“失败”,要自己复现一次。这样能确认是代码本身问题,还是执行环境问题。例如依赖没有安装、环境变量缺失、数据库没启动,这些都会让它反复重试却没有结果。
如果工具运行很慢或者不断卡住,检查机器资源。内存不足时,代码索引和上下文加载会非常慢;磁盘满了,日志写入会失败;并发开得太大,某些本地模式会直接超时。不要一上来就调高并发,先把单个任务跑稳。
还要留意版本问题。AI 编程工具经常更新,不同版本的模型对工具调用的支持不一样。如果某个环境之前能跑,今天不行,先确认工具版本、插件版本、依赖版本是否有变化。
6.3 始终准备一个最小可复现样例
当问题很难定位时,我会把任务缩小到最小可复现样例:只用一个文件、一个入口、一个明确输出,看 Code Mode 能不能完成。
如果最小样例能过,说明整体流程没问题,问题出在大任务拆分不够清晰,或者仓库里某些历史代码干扰了它的判断。如果最小样例也过不了,那大概率是环境、依赖或工具配置出了问题。
这一步看起来很多余,却是最快的定位方式。因为 Code Mode 的失败链路通常很长,报错可能来自它执行的第五步,而不是你最初让它改的那个函数。
7. 什么情况我建议你别急着上 Code Mode
7.1 小任务和学习场景,用简单问答更划算
如果你的需求只是“这个排序算法怎么写”“这个报错是什么意思”,不需要让 Code Mode 获得修改权限。这类任务用普通问答模式更轻,不会污染仓库,不会留下大 diff,也更安全。
学习代码时也建议用问答模式。让 AI 直接改代码,你会错过“为什么这样改”的思考过程。学习的目标是建立自己的判断力,不是让 AI 替你做决定。
7.2 约束不完整的老项目,先补测试和边界再上 Agent
老项目通常是最容易被 Code Mode 改乱的地方。没有测试、文档缺失、模块之间互相偷调用、公共函数里塞着一百个分支。在这种项目里,Code Mode 很难判断哪些依赖是必须保留的,哪些是历史包袱。
如果你还是想用,第一步不是写任务描述,而是先把要改动的那条链路补上少量测试。测试不一定要多,只要能把核心行为锁住。有了测试之后,Code Mode 出问题时会更容易暴露,至少你不会在毫不知情的情况下破坏原有功能。
7.3 不能让 AI 自我判定架构合理性
Code Mode 是一个执行意志很强的工具,但它不具备你对产品未来的理解。它不知道你下个月要加什么功能,不知道团队里谁负责维护这个模块,也不知道公司里哪些约定是“看起来不优雅但绝对不能改”。
因此架构层面的判断必须留在人这边。AI 可以分析依赖图、给出重构建议、实现你确认好的方案,但“什么情况下值得引入抽象、在哪里划模块边界、要不要迁移数据模型”这类问题,本质上依赖业务判断。
你可以把 Code Mode 看作一个很强的实习生:理解力不错,执行速度快,但你对它做的事仍然有最终审查责任。真正落地的时候,最该盯住的不是它列出的能力清单,而是输入范围、资源占用、失败重试和代码评审这几个环节。把这些控制好了,“面向可扩展软件”的 Code Mode 才有意义。