从补全到 Agent:AI 辅助开发的四种形态与能力边界
同一个模型放进不同的壳里,能干的事差一个数量级:行内补全只能改光标附近那几行,终端 Agent(terminal agent)能自己读文件、跑测试、连改八个文件。选错形态的代价不是「效果差一点」,而是你可能要为一批自己没读过的改动签字。这一章把 AI 辅助开发拆成四种形态,给出每种形态的输入、产出、验证方式与能力边界,作为后面 15 章的坐标系。
四种形态:输入、产出与验证成本
| 形态 | 你给什么 | 它产出什么 | 你的验证成本 |
|---|---|---|---|
| 行内补全(completion) | 当前文件与光标前缀 | 几行候选,接受或拒绝 | 极低,但只适合「手已经知道要写什么」 |
| 对话问答(chat) | 贴出的片段 + 问题 | 解释、方案、示例代码 | 中等:要自己把答案接回仓库 |
| 编辑器内 Agent(in-editor agent) | 任务描述 + 读仓库的许可 | 跨文件补丁 + 命令执行记录 | 较高:逐项确认改动与影响面 |
| 终端 Agent(terminal agent) | 任务 + 验收命令 | 多轮「读—改—跑—再改」的结果 | 最高:审查 diff、跑验收、承担后果 |
四种形态不是新旧替代,而是验证成本逐级递增:越靠下产出越多,你需要的验收手段越硬。于是选形态的问题可以改写成一句话——这次改动,我打算用什么方式证明它是对的?
形态一:行内补全——只在你已经知道要写什么时最快
补全能看到的上下文只有光标附近的几十行。它擅长的是「你已经想清了逻辑,只是懒得多敲」:补表驱动测试的第 5 个用例、补一段 switch 的剩余分支、把重复的字段赋值抄完。
// 写出前两个用例,后面的同构用例交给它续写最划算
func TestParseAmount(t *testing.T) {
cases := []struct{ name, in string; want int64; wantErr bool }{
{name: "整数", in: "199", want: 19900},
{name: "两位小数", in: "1.99", want: 199},
// 光标停在下一行,让它按同样结构续写:三位小数、空串、负数、超长
}
// 遍历与断言部分也可以让它补,但每个期待值都要自己核一遍
}
边界很清楚:它看不见调用方、看不见类型定义以外的约定、也不会替你想边界。如果一段代码你只能「凭感觉觉得对」,就不该用补全写,而应该切到对话形态先把规格讲清楚。
形态二:对话问答——用来对齐认知,不是用来交付代码
对话形态最被低估的用法是「先问清再动手」:让它读完代码后复述数据流、列出你没想到的边界、对比两三种方案。产出代码反而是次要的。
先不要写代码。请阅读下面这段 Go 中间件,回答三个问题:
1) 请求从进入到离开经过了哪些函数?按顺序列出函数名与「文件:行号」;
2) 它在什么情况下会吞掉错误而不返回 5xx?指到具体分支;
3) 如果要加「按用户维度限流」,最小改动是什么?列出会碰到的函数,不要写实现。
常见误用是拿它当编译器:贴一段代码问「这样写对吗」,通常只会得到礼貌的附和。问「哪里会错、什么情况下会挂」比问「对吗」有用得多。
形态三:编辑器内 Agent——跨文件,但范围仍然可控
这一档的关键差别是它能读整个仓库、按需改多个文件,且每次改动通常要你确认。它适合「我清楚要改什么,但涉及的文件有七八个」:字段重命名、给调用链加一个参数、照现有模式接一个新接口。
任务:为 internal/order 的 CreateOrder 增加可选参数 idempotencyKey。
要求:
1) 先列出你打算修改的文件与每处改动的位置,等我确认;
2) 只改这一条链路:handler → service → repo,不重构其它逻辑、不调格式;
3) 兼容旧调用:不传该参数时行为与现在完全一致;
4) 改完运行 `go test ./internal/order/... -count=1`,贴出完整输出。
要点是划范围:写清「只改哪条链路」「什么行为必须不变」「用什么命令自证」。这三句写进提示词,比事后读三百行 diff 便宜得多。
形态四:终端 Agent——能跑命令,所以必须先给验收命令
终端 Agent 能自己 grep、读文件、跑测试、看报错并继续改,这是它真正的能力来源,也是它最大的风险来源。用它之前先把两件事准备好:
# 1) 一条能判定「好没好」的验收命令,写进提示词
make check # = lint + go test ./... -count=1 + 类型检查
# 2) 一个干净的起点,避免无关改动混进来
git status --short && git stash list
背景:`make check` 目前在 internal/order 下有 2 个失败用例。
任务:修到 `make check` 全绿。约束:
- 不许跳过或删除任何测试,不许加 t.Skip;
- 每次修改后自己跑 `make check`,说清失败原因再继续;
- 一次只改一个文件,改完报告「改了哪个文件、为什么、结果如何」;
- 如果 5 轮内没修好,停下来说明你的假设与已验证的事实,不要继续盲改。
「先给验收命令」是把 Agent 从「会说话的编辑器」变成「可验证的执行者」的分界线:没有验收命令,它只能用「已完成」向你交代。
能力边界清单(可直接抄进评审清单)
| 它通常能做 | 它通常做不好 | 应对 |
|---|---|---|
| 按既有模式批量改写、补测试骨架、写样板代码 | 判断业务语义对错(金额口径、状态机含义) | 语义由人给规格并验收 |
| 定位报错、二分缩小范围、解释陌生代码 | 需要真实环境反馈的问题(并发复现、线上数据) | 由人提供真实日志与复现步骤 |
| 复用你写进规则文件的约定 | 记住只在对话里说过一次的约定 | 约定必须落进 AGENTS.md(见第 3 章) |
| 生成看起来正确、API 也像真的代码 | 区分「真实存在的库函数」与「听起来合理的编造」 | 编译、类型检查、单测三件套兜底 |
| 一次改十几个文件 | 保证这十几个文件彼此一致 | 缩小范围 + 分步提交(见第 7 章) |
| 按你给的验收命令自证 | 自己发明合适的验收标准 | 验收标准永远由人写 |
一句话概括边界:它擅长「你定义清楚、且能被机器验证」的部分;它不擅长「需要业务判断、且只有人能验证」的部分。
选形态的决策表
| 你的处境 | 选哪种形态 | 理由 |
|---|---|---|
| 思路已清晰,只差敲代码 | 行内补全 | 零沟通成本,不满意的直接不收 |
| 不确定该怎么做、想对比方案 | 对话问答 | 目的是对齐认知,不是产出补丁 |
| 改动能列出文件清单,跨 3~10 个文件 | 编辑器内 Agent | 范围可列举,确认粒度能到文件 |
| 需要跑测试、看报错、反复迭代 | 终端 Agent | 只有它能闭环验证 |
| 改动会碰数据库、部署、依赖升级 | 先别让 Agent 动手 | 风险高、回滚贵,先让它只出方案 |
| 你不清楚这段代码在干什么 | 对话问答 | 先理解,再决定是否交给 Agent |
常见坑
| 坑 | 后果 | 规避 |
|---|---|---|
| 用补全写自己没想清楚的逻辑 | 得到一段看着合理、实则错误的代码 | 切到对话形态,把规格先讲清 |
| 把对话里的代码直接粘进仓库 | 编译不过或语义错位 | 粘完必须自己跑编译与测试 |
| 让 Agent 自由发挥 | 顺手重构,无关改动混进提交 | 提示词写「只改哪条链路 + 不做的事」 |
| 没有验收命令就开跑 | 只能听它说「已完成」 | 先准备 make check 这类一条命令 |
| 同时开多个 Agent 改同一模块 | 改动互相覆盖 | 同一时刻只让一个工具动代码 |
| 规则只写在对话里 | 换个会话全部失效 | 落到仓库里的规则文件 |
小结:四种形态的差别不在模型,而在它能看到多少上下文、能动手到哪一步、你用哪种方式验收;补全用在已经想清楚的地方,对话用在对齐认知,编辑器内 Agent 用在范围可列举的跨文件改动,终端 Agent 用在「有验收命令、能闭环」的任务上;边界清单里最该记住的一条是——能被机器验证的事交给它,需要业务判断的验收留给人。