Nick Tune 谈 Agentic 代码工作流实践

内容管家 编程开发评论0字数 3848阅读12分49秒阅读模式
Nick Tune 谈 Agentic 代码工作流实践

Nick Tune:AI 工程化编码实践

在 AI 编程工具层出不穷的当下,工程师们逐渐摸索出自己的工作方式:有人直接通过网页调用 LLM,有人依赖 GitHub Copilot 或 Claude Code。然而真正决定最终代码质量的,并非工具本身,而是工作流程的设计。本文整理自 Nick Tune 在播客与公开分享中的实践精华,涵盖他如何将开发流程建模为状态机、如何用确定性规则守护架构、如何借助 TDD 与分层审核&查验实现高效自主开发。

Nick 是谁

Nick Tune 是一名高级软件工程师(Senior Staff Software Engineer),目前在 PayFit(欧洲薪资与 HR 服务商)任职。他著有《Architecture Modernization》(Manning 出版社),专注于遗留系统迁移、领域驱动设计(DDD)和持续交付领域,现居英国伦敦。

Nick 的 AI 工具使用心法

核心原则:全面尝试 + 严格计时

Nick 的策略是在所有场景中尝试 AI,再通过计时追踪实际收益。具体做法如下:

  • 每接触一项新任务,先问"AI 能帮我做什么?"
  • 给实验设定明确的时间上限(如 1 小时),防止沉没成本
  • 记录每次尝试的产出,积累自己的"AI 效率账本"

Nick 坦承,并非所有实验都能成功——有时结局是浪费时间与挫败感。但他认为,最优结果往往需要前期投入,关键在于控制风险、持续迭代。

实战案例:客户工单处理工具

Nick 分享了一个典型案例:他负责处理客户支持工单时,意识到需要一个统一的工具来管理工单并为 AI 代理提供记忆,从而并行处理 10 个工单。

起初他顾虑旺季积压风险,但最终还是用 1 小时完成了初步构建。结果令人意外:

  • 2–2.5 天后达到盈亏平衡点(工单处理量已超过手动完成的数量)
  • 到周末结束时,效率提升约 20–40%
  • 更复杂的是:某工单涉及 3 个代码库的数据关联分析,Claude 自主追踪到了问题根因

Nick 总结:"就是那 1 小时的计时实验带来了后续的持续回报。"

主流 AI 编码工具现状

目前工程师群体中流行的方案主要包括:

  • 纯 LLM(网页端):门槛最低,适合快速探索
  • GitHub Copilot:深度集成 IDE,适合日常辅助
  • Claude Code:命令行优先,适合自主执行完整任务

Nick 的判断是:工具差异并非决定性因素,工作流程的设计才是核心。他自己的实践完全围绕这一理念展开。

状态机设计:Submitting 阶段的行为约束

在 Nick 的 AI 编程工作流中,"Submitting"是一个独立状态,专门处理 Pull Request 提交流程。该状态具有以下关键约束:

状态前缀与指令注入

每次 agent 发送消息时,系统会自动添加 🚀SUBMITTING 前缀,确保开发者始终了解当前工作流阶段。相关指令定义在 states/submitting-pr.md 文件中,仅在两种场景下触发注入:

  • agent 转换到该状态时
  • agent 出错需要重新提醒时

合法的状态转换

从 Submitting 状态只能转换到 AWAITINGBLOCKED,试图转向其他状态将被阻止,错误消息中会重新注入 submitting-pr.md 的内容。

可执行的操作

  • 允许调用record-pr 工作流操作(更新工作流状态)
  • 允许使用git pushgh pr(全局禁止的命令在此阶段例外放行)
  • 禁止操作:写入文件、调用其他工作流方法

PR 编号的强制要求

状态转换时,若 ctx.state.prNumber 未被设置,转换将直接失败。这是 Submitting 阶段的核心前置条件——必须创建 PR 并记录 PR 编号,否则后续所有工作流步骤都无法执行,整个流程将中断。

规划先行:不同项目的规划策略

Nick 根据项目类型采用差异化规划方法,而非一刀切的流程。

开源项目的 PRD 专家 Agent

对于开源项目,Nick 使用专门的 PRD 专家 Agent,帮助团队讨论项目需求、定义架构,并产出结构化的 PRD 文档。PRD 模板结构如下:

# PRD: [功能名称] 状态: Draft | Planning | Awaiting Architecture Review | Approved ## 1. Problem [问题描述、目标用户、重要性] ## 2. Design Principles [优化目标、权衡取舍、原因] ## 3. What We're Building [详细需求] ## 4. What We're NOT Building [明确的范围边界] ## 5. Success Criteria [成功衡量标准] ## 6. Open Questions [待解决的疑问,仅 Draft 阶段] ## 7. Milestones [主要里程碑,仅 Planning 阶段] ### M1: [ 名称 ] #### Deliverables - D1.1: [交付物名称] - 关键场景(正向流程 + 已知边界情况) - 验收标准 - 验证方式 ### M2: [ 名称 ]... ## 8. Parallelization [可并行推进的工作流] ## 9. Architecture [架构评审阶段补充]

tracks: - id: A name: [ 轨道名称 ] deliverables: - M1 - D2.1 - id: B name: [ 轨道名称 ] deliverables: - D1.2 - M3

PRD 完成后,Nick 通过命令在 GitHub 创建任务(作为 Issue)。选择 GitHub 的原因很实际:提交 PR 时会自动关联 Issue,代码审核&查验者(人工或 AI)可以基于完整上下文进行审核&查验。

Nick 强调,PRD 讨论阶段投入大量时间,PRD 专家 Agent 的定位是"教练"——提出好问题、挑战既有假设,而非机械执行流程。

遗留系统迁移的团队 Agent

对于遗留系统迁移项目,Nick 组建 Agent 团队并行工作:

  • 扫描代码库、映射当前状态
  • 识别迁移选项
  • 产出草稿级 ADR(架构决策记录)供人工审核

具体任务如:

  • "识别代码库中所有 API 端点,进行完整的端到端分析(为优化上下文窗口,每个 API 端点使用独立 subagent)"
  • "对比遗留系统与目标系统中现有 API 端点的差异,判断最佳匹配方案或是否需要新建端点"

这类任务的指令需要高度结构化和精确,Nick 倾向于将自身思维过程固化到文档中,而非给 AI 过多自主空间。

代码实现:自主开发工作流

核心流程

Nick 的默认实现方式是一条自主开发工作流:启动 Claude 后,它将完成整个功能实现,目标是产出通过全部检查、经 CodeReview Agent 和 CodeRabbit 审核&查验的 Pull Request。

工作流定义在 docs/workflow.md 中,主要面向 agent 读取,包含状态描述和对应命令。值得注意的是,Nick 混合使用斜杠命令和实际代码,追求最大程度的确定性。

TDD 与防护栏

Claude 遵循 Nick 的 TDD 工作流进行需求实现。项目中设置了多重检查机制:

  • pre-commit hooks:禁止提交无法编译或 lint 不通过的代码
  • 禁用 --no-verify:Claude 无法绕过这些安全约束

真实代码优于 Markdown 文档

Nick 的一个核心原则是:任何需要确定性执行的流程,必须用真实代码实现,而非依赖 agent 读取 Markdown 文件中的指令。

例如,Nick 编写了创建 GitHub PR、等待检查通过、获取 PR 反馈的自动化脚本。相比写在 prompt 或文档中的流程说明,真实代码具有:

  • 确定性:每次执行结果一致
  • 可测试性:可以通过单元测试验证行为

Nick 在实践中吃过太多亏——反复要求 agent 遵循流程却总是失败。转向代码化工作流后,可靠性大幅提升。下面的单元测试展示了如何验证工作流步骤的严格顺序:

describe('executeCompleteTask', () => {
 it('passes workflow steps in correct order', () => {
 executeCompleteTask()
 const steps: unknown[] = mockRunWorkflow.mock.calls[0][0]
 const stepNames = steps.map((s) => {
 const step = s && typeof s === 'object' && 'name' in s ? s : null
 return step?.name
 })
 expect(stepNames).toStrictEqual([
 'verify-build',
 'code-review',
 'submit-pr',
 'fetch-pr-feedback',
 ])
 })
 // ...
})

持续改进:Lint 规则与架构约束

持续改进是 AI 编程的关键。每次 Agent 生成糟糕的代码,都需要一种机制来确保它今后不再犯同样的错误。最有效的做法是使用确定性工具来强制执行规范。

代码质量规则集

Nick 维护了一套丰富的 Lint 规则,覆盖以下维度:

  • 文件大小规则:防止单个文件过度膨胀
  • 函数复杂度规则:避免过于复杂的逻辑
  • 命名规则:统一代码风格
  • 注释规则:确保关键逻辑有适当说明
  • 禁止语法规则:例如在 TypeScript 中禁止使用 aslet,强制写出类型安全且不可变的代码

这些规则通过 ESLint 配置实现,详见 GitHub 仓库

架构分层约束

除了代码风格,Nick 还使用 dependency-cruiser 来强制执行架构规则。典型约束包括:domain 层文件不得依赖 infra 层文件。其 DDD/CQRS 架构定义在 GitHub 仓库 中,目录结构如下:

features/
 ├── platform/
 ├── shell/
 │ ├── checkout/
 │ │ └── domain/
 │ └── cli.ts
 ├── entrypoint/
 │ └── tax-calc/
 │ └── commands/
 └── infra/
 ├── queries/
 ├── external-clients/
 ├── domain/
 ├── http/
 └── infra/
 ├── cli/
 │ ├── mappers/
 ├── persistence/
 └── persistence/
 ├── config/
 └── logging/
 └── refunds/
 ├── entrypoint/
 │ ├── commands/
 │ ├── queries/
 │ └── domain/

功能模块隔离规则

规则 SoC-006 明确了入口层的职责边界:入口层是外部世界与命令/查询之间的薄翻译层,执行"解析外部输入 → 调用命令/查询 → 映射结果到外部响应"这一流程,除此之外不承担其他逻辑。

Pre-commit 钩子和 PR 检查会通过 dependency-cruiser 规则自动拒绝违反架构约束的代码提交。例如,以下规则确保各功能模块(垂直切片)之间相互独立,不得跨模块导入:

{
 name: "no-cross-feature-imports",
 severity: "error",
 comment: "Features must not import from other features",
 from: { path: "features/([^/]+)/.+" },
 to: { path: "features/([^/]+)/.+" , pathNot: "features/$1/.+" }
}

Nick 指出,Claude Code 在代码放置决策上常常遇到困难,因此严格规则和清晰指引是核心保障

代码审核&查验

CodeRabbit:AI 驱动的 PR 审核&查验

Nick 在所有项目(个人项目和工作项目)中都使用 CodeRabbit 进行代码审核&查验。其优势不仅在于识别不良代码和安全漏洞,还能配置为读取团队的编码规范和 ADR(架构决策记录)并检测违规。CodeRabbit 还支持学习机制,可以告诉它"下次记住审核&查验这个"或"不要建议那个"。

Nick 也会在创建分支前通过 CLI 运行 CodeRabbit 进行预检。

本地专用审核&查验 Agent

除 CodeRabbit 外,Nick 还配置了多类本地审核&查验 Agent:

  • Code Review Agent:代码质量审核&查验
  • Architect Review Agent:架构合规性审核&查验
  • Test Review Agent:测试覆盖度审核&查验
  • QA Check Agent:验证功能是否真正实现了需求
  • Bug Check Agent:潜在缺陷检测

工作流强制执行

在部分项目中,Nick 实施了严格的工作流即代码规范:在 PR 创建前,必须完成上述所有审核&查验。具体通过一个 Git 钩子实现——禁止直接执行 git push,而必须使用 /complete-task 命令,该命令会运行完整的验证流水线(Lint → 测试 → 代码审核&查验 → PR 提交)。

{
 pattern: /bgits+pushb/,
 reason: 'Blocked: Direct git push bypasses required workflow. Use /complete-task command instead, which runs the complete verification pipeline.'
}

工作流脚本会强制要求本地代码审核&查验通过后才能提交 PR:

runWorkflow<CompleteTaskContext>(
 [verifyBuild, codeReview, submitPR, fetchPRFeedback],
 buildCompleteTaskContext,
 (result: WorkflowResult, ctx: CompleteTaskContext) => formatCompleteTaskResult(result, ctx)
)

审核&查验要精确,不要模糊

Nick 总结出一条关键经验:审核&查验描述要精确。不要笼统地说"根据这些原则审核&查验代码",而应明确要求"针对每个修改的文件,逐条对照各审核&查验原则(Nick 为每条原则分配了 CR-001 这样的编号)并写出审计表"。这种精确性避免了 Agent 为了速度而牺牲正确性的倾向。

当然,Nick 本人也会亲自审核&查验代码。对于他来说,未经自己审阅的代码绝不部署到生产环境。核心观点是:PR 收到反馈本身就是流程失败的信号,说明 AI 第一次没有做对。因此,反馈中包含的经验应固化到 Agent 的工具链中,使其在未来自动应用。

测试策略

Nick 在职业生涯中一直推行 TDD,也会引导 Agent 遵循类似流程。核心原则是:

  • 先写测试:测试驱动实现
  • 用最简单的方案实现:避免过度设计
  • 结构化的前置条件定义:状态转换有清晰的边界

TDD 实战技巧与测试规范

RED 阶段:只实现错误信息要求的内容

在 TDD 的 RED 阶段,核心原则是只实现错误信息明确要求的内容,不要猜测或提前添加额外逻辑。

具体检查步骤如下:

  • 错误要求什么:错误信息字面上要求什么?
  • 硬编码是否可行:yes/no
  • 如果可以:使用什么硬编码值?
  • 如果不行:为什么必须用真实逻辑?

执行时需严格遵循以下流程:

  1. 仅实现错误信息要求的内容(尽可能硬编码)
  2. 不提前解决未来可能的错误
  3. 执行测试,确认 PASS(绿色条)
  4. 执行编译检查,确认 SUCCESS
  5. 执行 lint 检查,确认 PASS
  6. 将所有成功输出展示给用户

过渡到 GREEN 阶段的前提:测试必须 PASS、代码必须编译通过、lint 必须无错误,三者缺一不可。

测试代码的严格规范

Nick 为测试代码设置了极高的门槛:

  • 覆盖率 100%:CI 构建会在覆盖率不足时失败
  • 每个测试最多 4 条断言:避免过度测试
  • 禁止条件断言:确保测试行为可预测
  • 单文件最多 400 行:强制将测试拆分为描述性片段,并使用 it 等模式组织

此外,Nick 还部署了一个专注于测试的 code-review agent,实时审核&查验测试质量。

自定义 CLI 工具:快速启动专属角色

Nick 开发了自己的 CLI 启动工具,用于快速启动 Claude Code 会话。

该工具通过 claude --system-prompt 加载特定角色的系统提示,例如执行 claude prd opus 会启动 PRD 专家角色。好处包括:

  • 提示嵌入系统提示:提高 AI 遵从度
  • 按角色按需加载:PRD 角色仅加载 PRD 相关规则,无需加载测试规则等无关内容
  • 效率更高:无需在会话启动后读取额外文件

建议:动手构建自己的工具

AI 时代最大的红利是工具构建门槛极低。Nick 的建议是:

  1. 思考当前工作中最耗时的环节
  2. 问自己:什么 CLI 命令、界面或知识管理工具能提升效率?
  3. 如何自动化那些繁琐的步骤,让自己专注于核心价值?
  4. 然后让 AI 代理帮你设计并实现这个工具

Nick 自己就构建了一整套项目管理工具,用于规划和交付遗留系统现代化项目——相当于在等待 AI 处理任务时,自己在另一个终端顺手完成了整个功能。

延伸阅读

 
内容管家

发表评论