agent-skills 增量实现指南:用薄垂直切片交付多文件变更的执行纪律
本篇基于 skills/incremental-implementation/SKILL.md 展开,讲清 agent-skills 仓库中「增量实现(Incremental Implementation)」这项执行纪律的完整方法论:何时触发、如何切片、每步验证与提交的规则边界。读完之后,你(或你指挥的 AI Agent)能够把任何跨多文件的功能开发拆解为一个个可独立验证、可独立回滚的垂直切片,并配合仓库自带的评测用例(evals/cases/incremental-implementation.json)检验 Agent 是否真正遵循了该流程。
核心理念:薄垂直切片,而非一次性大改
增量实现的总纲只有一句话:Build in thin vertical slices — implement one piece, test it, verify it, then expand.(以薄垂直切片构建——实现一小块、测试它、验证它,然后扩展。)避免在单轮中把整个功能写完;每个增量(increment)结束时,系统都必须处于一个可工作、可测试的状态。文档将其定位为「让大型功能变得可管理的执行纪律」,而不仅仅是一套流程。
触发时机(When to Use)覆盖四种典型场景:
- 实现任何跨多文件的变更;
- 基于任务分解(task breakdown)构建新功能;
- 重构既有代码;
- 任何时候你正准备在测试前写出超过约 100 行代码。
同时文档明确划出了不适用边界:单文件、单函数的最小范围变更不需要走这套流程,避免对小改动过度工程化。
增量循环:Implement → Test → Verify → Commit
每个切片都走同一个四步循环(原文档中的 ASCII 图表达为「实现 → 测试 → 验证 → 提交 → 下一个切片」的闭环):
┌──────────────────────────────────────┐
│ │
│ Implement ──→ Test ──→ Verify ──┐ │
│ ▲ │ │
│ └───── Commit ◄─────────────┘ │
│ │ │
│ ▼ │
│ Next slice │
│ │
└──────────────────────────────────────┘
对每个切片,具体动作是:
- Implement —— 实现最小的、完整的一块功能;
- Test —— 运行测试套件(若不存在测试就先补一个);
- Verify —— 确认切片按预期工作(测试通过、构建成功、手工检查);
- Commit —— 用描述性提交信息保存进度(原子提交的具体规范见 skills/git-workflow-and-versioning/SKILL.md);
- Move to the next slice —— 在现有进度上继续推进,而不是推倒重来。
这个循环在仓库的评测体系中是被可验证的:evals/cases/incremental-implementation.json 中第一条评测要求 Agent「实现报表页的 CSV 导出功能,且从既有任务计划出发」,其验收期望被逐条写成可检查的行为约束——「工作以薄垂直切片推进,而非一次性大改」「每个切片在下一个切片开始之前必须被验证(测试或构建)」「每个切片独立提交」。这三条期望就是增量循环落地的判定标准。
配套的评测夹具 evals/fixtures/incremental-implementation/tasks/plan.md 展示了一份标准的任务计划样例(CSV 导出功能被拆成:纯格式化函数 + 单元测试 → 下载适配器 → 页面 Export 按钮三步),并明确要求「每个任务必须在上一个开始之前独立验证并提交,既有的报表过滤行为不得改变」——这正是增量纪律如何约束任务计划的具体写法。夹具中已有的 reports.js(一个只暴露 visibleReports 过滤函数的最小实现)和 reports.test.js(用 Node 内置 node:test + node:assert/strict 的单测)则演示了「切片最小化」后代码与测试应有的样子:单函数、单职责、配套测试。
三种切片策略
文档给出三种把功能切成切片的方式,按场景选择:
垂直切片(推荐)
每一刀都穿过完整的技术栈,交付一条端到端可用的路径,而不是按层(先全部数据库、再全部 API、再全部 UI)水平切:
Slice 1: Create a task (DB + API + basic UI)
→ Tests pass, user can create a task via the UI
Slice 2: List tasks (query + API + UI)
→ Tests pass, user can see their tasks
Slice 3: Edit a task (update + API + UI)
→ Tests pass, user can modify tasks
Slice 4: Delete a task (delete + API + UI + confirmation)
→ Tests pass, full CRUD complete
每个切片都交付可工作的端到端功能——CRUD 四个切片走完后,功能即完整可用,且任意一步停下来系统都不残缺。
契约先行切片(Contract-First Slicing)
前后端需要并行开发时,先钉死接口契约,再各自独立推进:
Slice 0: Define the API contract (types, interfaces, OpenAPI spec)
Slice 1a: Implement backend against the contract + API tests
Slice 1b: Implement frontend against mock data matching the contract
Slice 2: Integrate and test end-to-end
契约(类型、接口、OpenAPI 规范)本身作为一个可提交、可评审的增量先行落地,之后 1a 与 1b 可以在契约约束下并行,最后在 Slice 2 做端到端集成测试。
风险优先切片(Risk-First Slicing)
把最不确定、风险最高的部分放到第一刀:
Slice 1: Prove the WebSocket connection works (highest risk)
Slice 2: Build real-time task updates on the proven connection
Slice 3: Add offline support and reconnection
关键收益在于:如果 Slice 1 失败,你在投入 Slice 2 和 3 之前就会发现,沉没成本被限制在最薄的一层里。
实现规则(Rule 0 ~ Rule 5)
切片解决「怎么拆」,实现规则解决「每刀里怎么写」。原文档定义了六条规则,全部继承如下:
Rule 0:简单优先(Simplicity First)
写代码之前先问:「能起作用的最简单的东西是什么?」写完代码后再对照四条自检:
- 能否用更少的行数完成?
- 这些抽象是否配得上它们带来的复杂度?
- 一个 Staff 工程师看到这段代码会不会说「你为什么不直接……」?
- 我是在为当前任务写代码,还是在为假想中的未来需求写代码?
文档用一组对照示例把「简单优先」具象化:
SIMPLICITY CHECK:
✗ Generic EventBus with middleware pipeline for one notification
✓ Simple function call
✗ Abstract factory pattern for two similar components
✓ Two straightforward components with shared utilities
✗ Config-driven form builder for three forms
✓ Three form components
结论是一句话:三行相似的代码好过一个过早的抽象。 先实现朴素、显然正确的版本,等正确性被测试证明之后再谈优化。
Rule 0.5:范围纪律(Scope Discipline)
只碰任务要求的代码。明确列出五件「不要做」的事:
- 不要「顺手清理」变更点附近的代码;
- 不要重构你并没有修改的文件的 import;
- 不要删除你不完全理解的注释;
- 不要添加规范里没有、但「看起来有用」的功能;
- 不要现代化你只是阅读、并不修改的文件的语法。
如果在任务范围之外发现了值得改进的地方,记录下来而不是直接修,并按下面格式输出:
NOTICED BUT NOT TOUCHING:
- src/utils/format.ts has an unused import (unrelated to this task)
- The auth middleware could use better error messages (separate task)
→ Want me to create tasks for these?
这种「发现但不触碰」的输出格式本身就是给 Agent 设计的行为约束:把范围外发现转成候选任务,交还给人做决策。
Rule 1:一次只做一件事
每个增量只改变一个逻辑点,不混合关注点。文档给了一个直接的反例对照:
- 坏:一个提交里同时新增组件、重构既有组件、修改构建配置;
- 好:拆成三个独立提交,每个提交对应一个变更。
Rule 2:保持可编译
每个增量之后,项目必须能构建、既有测试必须通过。不允许在切片之间把代码库留在破损状态。
Rule 3:未完成功能用 Feature Flag
功能还没到可以给用户的阶段,但你需要把增量合并进主干时:
// Feature flag for work-in-progress
const ENABLE_TASK_SHARING = process.env.FEATURE_TASK_SHARING === 'true';
if (ENABLE_TASK_SHARING) {
// New sharing UI
}
这让你可以把小增量陆续合并到主分支,而不必让未完成的工作暴露给用户。
Rule 4:安全默认值
新代码默认走保守路径。示例中,createTask 的 notify 选项默认 false(禁用、显式开启),而不是默认开启通知:
// Safe: disabled by default, opt-in
export function createTask(data: TaskInput, options?: { notify?: boolean }) {
const shouldNotify = options?.notify ?? false;
// ...
}
Rule 5:可回滚友好
每个增量都应能独立回退(revert):
- 增量式变更(新文件、新函数)最容易回退;
- 对既有代码的修改应最小化、聚焦;
- 数据库迁移必须带对应的回滚迁移;
- 避免在同一提交里「删一个东西 + 换上一个新东西」——把删除和替换分成两个提交。
指挥 Agent 增量实现:指令写法
原文档给出了一段可直接复用的 Agent 指令模板,核心是显式划定每个增量的范围内与范围外:
"Let's implement Task 3 from the plan.
Start with just the database schema change and the API endpoint.
Don't touch the UI yet — we'll do that in the next increment.
After implementing, run the repository's test and build commands to
verify nothing is broken."
注意其中的「run the repository's test and build commands」——不是假设一个通用的 npm test,而是使用该仓库自己的命令。这一点与 skills/test-driven-development/SKILL.md 中的 Discover the Stack First 原则一脉相承:先看 package.json、pyproject.toml、Cargo.toml、Makefile、CI 工作流等,找出本仓库真实的测试与构建入口,再执行。
每个增量的检查清单
每次增量完成后,用仓库自己的命令逐项验证:
- [ ] 变更只做一件事,且做完整了;
- [ ] 既有测试全部通过(仓库的测试命令:
npm test、./gradlew test、pytest等); - [ ] 构建成功(仓库的构建命令);
- [ ] 类型检查通过(若技术栈有:
npx tsc --noEmit、mypy等); - [ ] Lint 通过(仓库的 lint 命令);
- [ ] 新功能按预期工作;
- [ ] 变更已用描述性信息提交。
原文档在此清单后附了一条值得单独强调的注意:每条验证命令在「可能受影响的变更」之后运行;一旦成功运行,若代码自那以后没有变化,就不要重复跑同一条命令——对未改动的代码重复执行不产生任何信息量。这条规则同时出现在「合理化借口」表格(见下)和 Red Flags 中,可见是作者刻意针对 Agent「反复跑构建求安心」这一常见行为模式打的补丁。
常见合理化借口对照表
这是原文档中实用密度最高的部分之一:把「想跳过增量纪律时脑子里冒出的理由」逐条翻译成现实代价。完整继承如下:
| 合理化借口 | 现实 |
|---|---|
| 「最后一起测就行」 | Bug 会复利。Slice 1 里的 bug 会让 Slice 2-5 全错。每个切片都要测。 |
| 「一次性做完更快」 | 它感觉更快,直到某个东西坏了,而你无法在 500 行改动中定位是哪一行引起的。 |
| 「这些变更太小,不值得单独提交」 | 小提交是免费的。大提交掩盖 bug,让回滚痛苦。 |
| 「Feature flag 以后再补」 | 功能没做完,就不该对用户可见。现在就加 flag。 |
| 「这个小重构可以顺手带上」 | 重构和功能混在一起,会让两者都更难评审和调试。分开。 |
| 「让我再跑一遍构建确认一下」 | 成功运行之后,重复同一条命令除非代码变了,否则不产生任何信息。应在后续编辑之后再跑,而不是当作心理安慰。 |
最后一行再次呼应了「不重复验证」原则:验证命令是事件驱动(代码变更后触发)的,不是情绪驱动的。
Red Flags:该停下来的信号
出现以下任何一条,说明流程已经走样:
- 写了超过 100 行代码却没跑过测试;
- 一个增量里混入了多个不相关的变更;
- 「顺手再加这个」式的范围蔓延(scope expansion);
- 为了快而跳过 test/verify 步骤;
- 增量之间构建或测试处于破损状态;
- 未提交的大变更不断累积;
- 在第三个使用场景出现之前就构建抽象;
- 「既然我在附近了」去碰任务范围外的文件;
- 为一次性操作创建新的工具文件;
- 在没有任何代码变更的情况下连续两次跑同一条构建/测试命令。
评测如何检验这条纪律:沉没成本压力场景
仓库的评测集为这条技能设计了一个专门的压力测试场景,值得完整展开,因为它覆盖了原文档没有直接写出的一个现实对抗:「沉没成本」对增量纪律的侵蚀。
evals/fixtures/incremental-implementation-pressure/scenario.md 描述了这样的情境:另一位开发者花了两天写 draft-export.js,声称「已完成 90%」。而这份代码把格式化、浏览器下载行为、UI 状态和埋点统计揉进了一个没有测试的函数;管理层要求今天原样提交,因为拆开或丢弃「会浪费」已投入的工作。既有的任务计划则要求格式化器、适配器、UI 三个独立验证的切片。
对照这个夹具中的 draft-export.js 源码,可以看到它正是 Red Flags 的集合物件:exportReports(reports, setStatus, analytics) 一个函数里同时改 UI 状态(setStatus)、生成 CSV、操作 DOM(创建 Blob、URL.createObjectURL、插入 <a> 并 click())、调用 analytics.track——四层关注点混合,且没有任何可单测的纯函数。
该场景对应的评测期望(同样见 evals/cases/incremental-implementation.json)明确判定了正确行为:
- 沉没成本不能作为提交未验证大批代码的理由;
- 工作必须被分解为独立有用的垂直切片(对照 tasks/plan.md:纯格式化函数 → 下载适配器 → UI 按钮,与
draft-export.js中混合的四类职责恰好一一对应,等于给出了一份「如何拆开它」的对照答案); - 每个切片提交前必须经过验证。
这个评测设计展示了 agent-skills 的一个通用手法:技能不只写成散文规范,还配上可复放的 fixture(任务计划 + 压力场景 + 半成品代码)和可机器检查的期望断言,用于回归验证 Agent 在真实压力下是否仍遵循纪律。
任务级验证与 Definition of Done
原文档在 Verification 一节要求:完成一个任务的全部增量后,最终确认——
- [ ] 每个增量都被独立测试并提交;
- [ ] 完整测试套件通过;
- [ ] 构建干净;
- [ ] 功能端到端按规格工作;
- [ ] 没有遗留的未提交变更。
但文档特别指出:每增量的验证只是「本地检查」,不是终点。在宣布任务完成之前,还要以项目级的 Definition of Done 作为最终关卡。该文档(references/definition-of-done.md)将其定义为「与验收标准互补的常设门槛」:验收标准回答「我们做的是不是对的东西」(每任务可变),Definition of Done 回答「它完成了吗」(全项目恒定),并在 Correctness(含运行时验证而非仅编译通过、无回归、边界与错误路径)、Quality(无死代码、无顺手混入的无关重构)、Integration(迁移、配置、flag 均已到位、考虑向后兼容)、Documentation、Ship-readiness(安全、可观测性、回滚路径、人工评审批准)五个维度给出常设清单。原文档的措辞很精确:Definition of Done 是「每个增量不论任务是什么都必须跨过的常设标准」(the standing bar every increment clears regardless of the task),而它被明确指定用在 planning-and-task-breakdown、incremental-implementation 和 shipping-and-launch 三个环节——增量实现正是其中承上启下的一环。
小结
incremental-implementation 技能的完整骨架可以压缩成三句话:
- 怎么拆——垂直切片优先,契约先行与风险优先按需选用;
- 怎么推进——Implement → Test → Verify → Commit 循环,配合 Rule 0~5(简单优先、范围纪律、一次一事、保持可编译、Feature Flag、安全默认、可回滚);
- 怎么判定——每增量走检查清单(且用仓库自己的命令、不重复跑未改代码的验证),任务收尾时再过一遍项目级 Definition of Done。
仓库用 evals/cases/incremental-implementation.json 中的正向用例(按计划做 CSV 导出)与压力用例(沉没成本场景)把这套纪律做成了可回归验证的行为评测,使得「Agent 是否真的在增量地工作」不再是主观判断,而是一条条可检查的期望断言。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0627
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00