现在用 Coding Agent 做一个 Demo 已经很容易了。
一句 Prompt,页面出来了。
再说一句,后端也有了。
继续聊,数据库、登录、部署都能往上加。
真正难的是第 20 次对话以后。
需求开始变化,文档越来越多,Agent 开始读到旧方案,一个任务顺手改了另一个模块,你甚至要翻聊天记录确认:
“这个功能到底做完没有?”
我自己踩过这些坑以后,才意识到:
大型项目不是一个更大的 Prompt。
它更像一个状态机(State Machine)。
大白话就是:
项目现在在哪一步,下一步能做什么,做完要满足什么条件,都应该是确定的。
Coding Agent 只负责把项目从一个正确状态,推到下一个正确状态。
这基本就是我现在做大型项目的方式。
先设计,再编码
专业一点叫 Requirements + Architecture。
大白话就是:
先想清楚做什么、怎么做,再碰代码。
我现在开一个大项目,第一步通常不是打开 Coding Agent 开始写。
我会先把这些事情整理出来:
谁用?
解决什么问题?
V1 到底做什么?
哪些东西这版坚决不做?
前后端怎么分?
数据库怎么设计?
API 谁说了算?
部署怎么做?
甚至会直接告诉 Agent:
当前阶段禁止写代码。
因为我以前干过相反的事。
一个想法刚出来,看起来很明确,就先写。
写到后面才发现模块边界要改、接口要改、数据库也要改。
Agent 写代码很快。
所以它也可以非常快地帮你制造返工。
真正的第一步不是生成代码,而是先生成约束。
不要相信第一版架构
这一步叫 Architecture Review。
大白话就是:
方案写完,先找人专门挑毛病。
我现在一般会让两个独立 Agent 看同一份方案。
一个正常审:
模块怎么拆、技术栈合不合理、以后好不好维护。
另一个做 Red Team。
大白话就是:
假装自己专门来搞死这个方案。
它重点找权限、并发、安全、失败场景和过度设计。
而且第二个 Agent 不先看第一个的答案。
因为我要的是两个独立判断,不是两个 AI 互相点头。
最后真正重要的决定,我会写成 ADR(Architecture Decision Record)。
大白话:
这件事已经讨论完了,以后先按这个决定做。
我之前就专门冻结过一个决定:
AI 能不能直接碰数据库?
最后答案是不允许,只能经过规定的业务入口。
一旦这个决定定下来,后面的 Agent 就不能因为:
“直接操作数据库更简单。”
又重新设计一遍系统。
Agent 可以写架构里的代码,但不能每次进来都重新发明架构。
Review 的目的也不是收集更多建议,而是把讨论过的东西变成后续执行时真正有效的边界。
把大项目切成 Agent 能吃下的大小
这叫 Task Decomposition。
大白话就是:
不要让 Agent 一口吃掉整个项目。
我现在不会再给:
帮我把这个系统做完。
这种任务。
而是:
Project → Phase → Feature → Task
一个功能还可以继续拆成:
后端。
前端。
客户端。
联调。
一次只做其中一个。
而且一个真正能交给 Agent 的 Task,至少要说清楚五件事:
GOAL —— 这次到底要完成什么。
IN_SCOPE —— 这次允许改什么。
OUT_OF_SCOPE —— 哪些东西看到了也别动。
ACCEPTANCE —— 满足什么条件才算完成。
STATUS —— 现在处于什么状态。
我以前做到过一个阶段,甚至开始问:
A3 到底完成了吗?
A4 是 READY,还是已经开始了?
这其实已经说明项目失控了。
如果一个项目的当前状态只能靠人的聊天记忆维持,它迟早会乱。
所以我现在会给每个 Task 一个明确状态:
READY
IN_PROGRESS
REVIEW
DONE
上一件事情没有真的 DONE,下一件事情不会因为 Agent “有空”就自己开始。
任务拆分不是为了让 Agent 少写一点,而是为了让每一次修改都有边界、有验收、有状态。
Context 不是越多越好
这一步叫 Context Management。
大白话就是:
它今天干什么,就只告诉它今天需要知道什么。
我以前也犯过一个很自然的错误:
项目资料有 5000 行?
全给 Agent。
感觉它知道得越多,应该越聪明。
后来发现完全不是。
项目做久以后,一定会同时存在:
旧 Research。
旧方案。
新 ADR。
历史 Task。
聊天记录。
最新代码。
一个 Agent 找到了新方案。
另一个 Agent 搜到了三周前的旧设计。
两边都有“证据”。
所以我现在做一个 Task,一般只给它:
AGENTS.md
PROJECT_CONTEXT.md
相关 ADR
当前 Task
相关 Contract
当前代码
其他东西,需要的时候再找。
更多 Context 不等于更多理解。
在大型项目里,正确的 Context 往往比完整的 Context 更重要。
还有一个变化也很重要:
聊天可以是工作区,但不能是项目真值。
关键状态、边界和决定必须回到仓库里。
聊天记录可以丢,项目状态不能跟着丢。
给 Agent 学会“停”的能力
我把这一层叫 Gate。
大白话就是:
有些条件不满足,就别往下干。
这可能是我踩坑以后变化最大的一点。
以前我总想:
怎么让 Agent 更自主?
怎么让它遇到问题自己解决?
后来有一次,我要求它修改一个仓库。
结果实际工作环境进入了另一个仓库。
如果没有规则,一个很积极的 Agent 完全可能开始“想办法完成任务”。
自己模拟一个接口。
在错误仓库里创建对应文件。
甚至给你解释为什么这样设计也合理。
所以现在修改代码以前,我会先检查:
Repo。
Root。
Branch。
HEAD。
Worktree。
Git Status。
目标不匹配:
STOP。
同样,一个 Task 里我也会明确写:
IN_SCOPE
这次做什么。
OUT_OF_SCOPE
这次不做什么。
Agent 发现旁边还有三个问题?
很好。
记下来。
别顺手修。
我现在越来越觉得:
对大型项目来说,“知道什么时候不能做”本身就是 Agent 能力的一部分。
自主性不是无限行动。
真正可靠的自主性,是在明确边界里自己推进,碰到 Gate 就停。
最后,只相信证据
这叫 Verification。
大白话就是:
“我做完了”没有意义,“我跑过了”才有意义。
Coding Agent 很容易告诉你:
已完成。
测试应该可以通过。
理论上没有问题。
这些话现在对我基本没有价值。
我要看的是:
跑了什么命令?
测试是真的执行了吗?
Build 过了吗?
CI 过了吗?
哪些东西没测试?
我自己遇到过几次,看起来像代码坏了。
最后继续查,发现是 Docker、网络或者运行环境出了问题。
如果一看到报错就让 Agent 改代码,很可能本来代码没坏,最后真被它改坏了。
所以我现在还会先分:
Code Failure —— 代码真的有问题。
Environment Failure —— 环境有问题。
没有真实执行过的东西,就写:
NOT VERIFIED
就这么简单。
Done 是一个声明,Evidence 才是完成的证明。
写代码的人和挑毛病的人分开
专业一点叫 Implementation / Review Separation。
大白话就是:
写代码的人和挑代码毛病的人分开。
我的流程现在通常是:
实现 Agent → 独立 Review → 原 Agent 修复 → 验证 → Merge
以前我也试过几个 Agent 轮流改。
A 写。
B 看完顺手重构。
C 又觉得可以优化。
代码确实被三个模型“审核”过。
但最后已经没人知道是谁把什么改成这样的。
所以现在 Reviewer 默认只找问题。
它告诉我:
哪里错了。
证据是什么。
为什么。
建议怎么修。
然后交还给实现者。
这样做的好处不是“多一个 AI”。
而是职责变清楚了:
实现者对修改负责。
Reviewer 对发现问题负责。
Verification 对最终证据负责。
把流程写进仓库,而不是写进脑子
如果上面的东西最后只存在聊天里,它还是很容易丢。
所以我现在会尽量把这套流程落进仓库本身。
AGENTS.md:Agent 的行为规则和边界。
PROJECT_CONTEXT.md:当前项目真正需要知道的上下文。
docs/adr/:已经讨论并冻结的重要架构决定。
Task 文档:当前任务的范围、状态和验收条件。
PR / CI / Test Log:这次修改到底做了什么,以及有没有真的通过验证。
这些文件不是为了把项目文档写得更漂亮。
它们真正解决的是一个问题:
下一个 Agent 进入项目以后,不需要相信上一个 Agent 的记忆。
它只需要读取当前真值,然后继续做正确的下一步。
如果要把整套东西压缩成一句话:
不要让 Coding Agent 做一个大型项目。要把大型项目设计成一连串它可以可靠完成的小状态转换。
需求确定。
架构确定。
Review 通过。
Task READY。
开始实现。
实现完成。
独立审查。
真实验证。
Merge。
再进入下一步。
以前我研究的是:
怎么让 Coding Agent 一次做更多。
现在我更关心:
怎么让它每一次都只做正确的下一步。
我觉得这才是用 Coding Agent 做大型项目,真正开始变得可靠的地方。