Agent Skills 实战第五课:代码能跑还不够,用双轴 Review 查清“写得对”和“做得对”

第四课结束时,ticket 已经完成,Red -> Green 记录齐全,类型检查和完整测试套件也全部通过。

是不是可以合并了?

还不能只看绿灯。测试通过只能说明被测试的行为成立,不能自动证明代码符合仓库标准,也不能证明原始 spec 中的所有承诺都已经交付。

一份代码可能命名漂亮、结构整洁,却把"停止续订"做成了"立即终止";也可能完全实现用户故事,却绕过项目约定的模块边界,留下很高的维护成本。

第五课要完成最后一道工程检查:使用 /code-review 对同一份 diff 进行 Standards + Spec 双轴评审,分别回答"代码是不是按项目方式写的"和"代码是不是做了规格要求的事"。

为什么不能只给一个"通过或不通过"

传统 review 很容易把所有发现混进同一张列表:变量名不清楚、漏了一个用户故事、重复代码、错误处理不完整、顺手加了一个 spec 没要求的扩展点。

这些问题的性质完全不同。

text 复制代码
Standards:Is it built right?  代码是否符合仓库标准和可维护性要求
Spec:      Is it the right thing? 是否完整、准确地实现了原始规格

如果合并成一个总分,几个轻微命名问题可能冲淡一个严重需求遗漏;功能全部实现,也可能让团队忽略代码已经违背架构约定。

所以 /code-review 会让两个独立 sub-agent 并行工作,各自只看一条轴,最后把结果并排展示。它不会把两边的问题重新排序,也不会挑一个"全场最严重问题"。

第一步:先钉死 fixed point

评审不是"看看最近改了什么",而是比较 HEAD 与一个明确的已知正确点。

fixed point 可以是:

  • main 或其他目标分支;
  • 一个 commit SHA;
  • 一个 release tag;
  • HEAD~5 这类明确提交位置。

调用时需要告诉 /code-review 从哪里开始比较,例如:

text 复制代码
/code-review main

或者:

text 复制代码
/code-review v2.4.0

skill 会先确认这个引用确实存在,然后固定使用三点 diff:

bash 复制代码
git diff <fixed-point>...HEAD

三个点意味着从 fixed point 与当前分支的 merge-base 开始比较,只看当前分支真正引入的改动。同时还会记录提交列表:

bash 复制代码
git log <fixed-point>..HEAD --oneline

如果 fixed point 无法解析,或者 diff 为空,评审应该立即停止。不要让两个评审 Agent 在一个错误范围上产出看似专业的意见。

课堂中常见的错误是:有人以 main 为基点,有人看本地未提交文件,有人直接打开整个 PR。范围不同,讨论自然无法对齐。

第二步:找到原始 spec

Spec 轴必须知道这次改动承诺过什么。/code-review 会按下面顺序寻找来源:

  1. 从 commit message 中查找 issue 引用,例如 #318Closes #318 或 GitLab 引用;
  2. 使用调用 /code-review 时提供的 spec 路径;
  3. docs/specs/.scratch/ 中查找与当前分支匹配的规格;
  4. 仍然找不到时,向用户询问 spec 在哪里。

通过 issue 引用查找时,它会按照第一课的 docs/agents/issue-tracker.md 读取 tracker,而不是自行猜测 GitHub、GitLab 或本地 Markdown。

如果团队明确回答"这次没有 spec",Spec 轴会跳过并报告 no spec available。它不能根据代码反推一个需求,再用自己猜出来的需求评审自己。

这也暴露了一个流程信号:经常找不到 spec,说明第三课的产物和第四课的 commit 没有建立可追溯关系。

第三步:找到仓库自己的代码标准

Standards 轴会读取项目里真正约束代码写法的文件,例如:

  • CODING_STANDARDS.md
  • CONTRIBUTING.md
  • 仓库根目录或相关模块里的工程说明;
  • 当前改动范围适用的明确架构规则。

能被 formatter、lint、type checker 自动检查的事情,不应该重复浪费 review 注意力。review 更适合判断工具难以替代的问题:命名是否表达意图、模块职责是否合理、抽象是否过早、变化是否散落。

仓库文档是最高优先级。如果项目明确认可某种写法,内置的通用经验不能把它判成违规。

没有完整标准文档,也不是"随便看一眼"

即使仓库没有 CODING_STANDARDS.md,Standards 轴仍会携带一组 Fowler code smell 基线。它们不是硬规则,而是需要工程判断的提醒。

Smell 在 diff 中通常表现为
Mysterious Name 名字无法说明变量、函数或类型的真实含义
Duplicated Code 多个 hunk 重复相同逻辑结构
Feature Envy 一个方法频繁读取另一个对象的数据
Data Clumps 同一组参数或字段总是一起出现
Primitive Obsession 用 string、number 代替稳定的领域概念
Repeated Switches 多处重复按同一种类型进行条件分支
Shotgun Surgery 一个逻辑变化迫使许多文件到处修改
Divergent Change 一个模块因为多个无关原因被同时修改
Speculative Generality 为 spec 没有提出的未来需求增加抽象和扩展点
Message Chains 调用方依赖过长的对象导航链
Middle Man 新增的类或函数主要只是把调用转发出去
Refused Bequest 子类或实现者拒绝了大部分继承契约

这里有两个必须守住的边界:

第一,仓库标准覆盖 smell 基线。项目有意采用某种结构时,不要拿通用模式压过本地决定。

第二,smell 永远是 judgement call。报告应该写"可能存在 Speculative Generality",并引用具体 hunk 和影响,而不是写成"违反第九条,必须修改"。

Standards 轴到底检查什么

Standards sub-agent 会拿到完整 diff、提交列表、标准文件和全部 smell 基线。它需要分别报告:

  • 违反已记录仓库标准的地方,并引用标准文件和具体规则;
  • diff 中可能出现的 smell,说明属于哪一种并引用代码片段;
  • 哪些是硬性标准违反,哪些只是需要团队权衡的判断。

以停止续订为例,可能出现这样的发现:

text 复制代码
Hard violation:Billing 模块标准要求公开 service 返回 Result,
但新接口直接抛出通用 Error。引用 CONTRIBUTING.md 的错误处理规则。

Judgement call:新增 CancellationStrategyFactory,
目前只支持一个策略,可能属于 Speculative Generality。

第一条有项目文档依据,可以明确判定。第二条需要结合后续方向和维护成本讨论,不能机械要求删除。

Spec 轴到底检查什么

Spec sub-agent 不评价变量名,也不判断代码够不够优雅。它只对照原始规格检查三类问题:

  1. spec 要求但 diff 没有实现,或者只实现了一部分;
  2. diff 新增了 spec 没要求的行为,形成 scope creep;
  3. 看起来实现了要求,但行为方式明显错误。

每条 finding 都要引用 spec 中对应的原句,避免"我觉得需求应该这样"的主观评审。

例如 spec 写着:

text 复制代码
重复提交停止续订请求必须保持幂等,不产生额外状态事件。

如果代码每次调用都会追加一条 RenewalStopped,Spec 轴应该报告"要求实现但行为错误",并引用上面这条规格。

又比如 diff 增加了"立即终止并按比例退款",而 Out of Scope 明确写着第一版不处理退款,这就是 scope creep。即使代码写得很好,也应该从当前 ticket 移除或另开规格。

为什么两个 sub-agent 要并行、隔离上下文

如果同一个评审 Agent 先看到 spec 严重遗漏,再去看代码标准,它很容易把注意力全部放在需求问题上;反过来也一样。

/code-review 把两个轴放进独立上下文:

text 复制代码
同一份 diff
   ├── Standards Agent:只看项目标准与 code smells
   └── Spec Agent:只看原始承诺与实现行为

这样可以减少相互污染,也保证两份报告各自有完整注意力。最终聚合阶段只做轻微整理,不把两边 finding 合成一张重新排序的列表。

最终报告应该长什么样

一份合格输出至少有两个独立章节:

markdown 复制代码
## Standards

- [Hard violation] ...
- [Judgement call: Speculative Generality] ...

## Spec

- [Missing] ...
- [Scope creep] ...
- [Incorrect behaviour] ...

结尾只总结每条轴各有多少发现,以及各自最严重的问题:

text 复制代码
Standards:2 项,最严重的是错误处理违反模块标准。
Spec:1 项,最严重的是重复请求没有保持幂等。

不要再给一个"综合评分 76 分",也不要说"总体最大问题是......"。两个轴故意分开,就是为了避免其中一边遮住另一边。

同一段代码可能在两条轴上同时出现

这不是重复报告,而是两个不同理由。

例如 Agent 为未来可能出现的退款、冻结、暂停订阅设计了一个复杂 CancellationStrategy 体系。

Standards 轴可能把它标为 Speculative Generality:当前只有一个真实策略,抽象带来了额外维护成本。

Spec 轴可能把它标为 scope creep:本次规格只要求停止续订,退款和暂停明确不在范围内。

一个是设计风险,一个是交付范围偏移。修复动作可能相同,但判断依据不同,必须分别保留。

Review 发现以后,先分类再行动

团队拿到报告后,不要让 Agent 立刻一股脑修复。先给每条 finding 指定处理方式:

  • Fix now:当前 ticket 必须修复的硬性标准或规格问题;
  • Clarify spec:规格本身存在歧义,需要回到需求负责人确认;
  • Follow-up ticket:真实存在但不属于当前范围的改进;
  • Accept:团队接受的权衡,并在必要时记录原因;
  • False positive:引用证据关闭误报。

Spec finding 通常优先阻止交付,因为它意味着承诺没有完成或做错。Standards finding 是否阻止合并,要看它是仓库硬规则还是 judgement call。仍然不要把两边合成一个统一严重度排行榜。

用第四课的 diff 做一次完整演练

假设第四课分支是 feature/stop-renewal,目标分支是 main,commit message 引用了 #318

课堂操作可以这样开始:

text 复制代码
/code-review main

Agent 应该依次完成:

text 复制代码
1. 确认 main 可以解析
2. 确认 git diff main...HEAD 非空
3. 记录 main..HEAD 的 commit 列表
4. 从 commit message 找到 #318
5. 根据 issue-tracker.md 获取 spec
6. 查找仓库标准文件
7. 并行运行 Standards 和 Spec 评审
8. 分轴汇总 findings

任何一步缺失,都可能让评审失去依据。例如没有 fixed point,diff 范围不可信;没有 spec,不能声称需求全部实现;没有引用标准,Standards 容易退化成个人代码偏好。

团队使用约定应该写什么

培训最后不要只总结"这几个命令很好用"。要把团队自己的触发条件写具体。

可以从下面这份模板开始:

markdown 复制代码
## Agent Skills 团队约定

### 必须先 /grill-with-docs 的场景

- 出现未定义或多义的业务术语;
- 改动涉及状态机、权限或多个领域上下文;
- 存在难回滚且有真实取舍的架构决定。

### 必须先 /to-spec 的场景

- 用户可见行为发生变化;
- 改动跨越多个模块或需要明确 out of scope;
- 需要提前确认 testing seam。

### 必须拆 /to-tickets 的场景

- 工作无法在一个 fresh context 中完成;
- 存在可以并行的纵向交付路径;
- 工单之间存在必须显式记录的 blocking edges。

### 测试约定

- 测试 seam 在写测试前确认;
- 测试公开行为,不测试私有方法和内部调用次数;
- 每个行为必须先出现有效 Red;
- expected 来自 spec、固定示例或其他独立真值。

### Review 约定

- 默认 fixed point 是目标分支 merge-base;
- Standards 与 Spec 分开报告,不给综合评分;
- 无 spec 时必须明确跳过 Spec 轴;
- code smell 是 judgement call,仓库文档优先。

这份约定应该进入 AGENTS.mdCLAUDE.md 或团队已有的工程手册,并在项目工作方式变化时更新。

常见误区

没有指定 fixed point 就开始 review。 先停下来明确比较点。范围不可信,finding 也不可信。

使用两点 diff。 skill 要求 git diff <fixed-point>...HEAD,通过 merge-base 隔离当前分支引入的变化。

找不到 spec,就按代码猜需求。 Spec 轴应该跳过并明确说明,没有资格虚构验收标准。

Standards 只有个人偏好。 每条硬性问题引用仓库标准;通用 smell 必须标记为 judgement call。

formatter 能发现的问题又报告一遍。 跳过工具已经强制执行的事项,把注意力留给语义和设计。

把两个轴合成一个严重度列表。 保持分开。代码标准和规格符合度的修复路径不同。

一看到 finding 就全部自动修改。 先分类,确认哪些属于当前 ticket,哪些需要补规格或另开 follow-up。

只做一次 review。 Fix now 完成后,使用同一 fixed point 再跑一次,防止修复引入新的需求偏移。

第五课真正完成的是一条可重复的工程闭环

到这里,五节课串成了一条完整链路:

text 复制代码
setup
  -> grill-with-docs
    -> to-spec
      -> to-tickets
        -> implement + tdd
          -> code-review

第一课让 Agent 知道项目规则,第二课不让猜测进入需求,第三课把共识切成可交付工作,第四课让每一步实现都有失败和通过的证据,第五课再把代码标准与规格符合度分开验收。

真正的收益不是团队多记住五个斜杠命令,而是建立了一套 AI 也必须遵守的工程反馈系统。Agent 可以写得很快,但它不能跳过上下文、决定、测试和评审,也不能用"代码能跑"代替"工作已经正确交付"。

相关推荐
李剑一1 小时前
Kimi暂时关上新用户订阅渠道你以为是缺钱吗?其实可能更缺卡!
aigc·openai·ai编程
sg_knight2 小时前
Claude Cowork 文件夹权限与连接器配置指南
ai编程·claude·code·ai工具·claude-code
恋猫de小郭2 小时前
给 AI 的 Agent 实现指南,可控 Agent 的关键
前端·人工智能·ai编程
怕浪猫2 小时前
第9章 工程化落地:评估、优化与部署
aigc·agent·ai编程
AI大模型-小华2 小时前
Codex 任务中断的真实成本:ChatGPT Plus 与 Pro 应该如何选择?
人工智能·chatgpt·ai编程·codex·chatgpt plus·chatgpt pro
AINative软件工程2 小时前
LLM 应用的分层可观测性工程实践:从 Span 到 Prompt Diff,三层 Trace 让 AI 系统真正可调试
后端·ai编程
Ai拆代码的曹操3 小时前
bootstrap源码解析:环境检测、运行时初始化与启动链路
架构·ai编程·opencode·源码拆解
chaors14 小时前
DeepResearchSystem 0x02:Graph 构建
langchain·openai·ai编程
东小西15 小时前
第11篇:《上生产前夜的恐惧:Prompt注入、敏感词、Token成本,我一个一个填坑》
openai·ai编程