编程 Addy Osmani 的 Agent Skills 深度解析:给 AI 编程助手装上「工程纪律」——从 Prompt 工程到工作流编排的生产级实践

2026-05-17 13:15:28 +0800 CST views 6

Addy Osmani 的 Agent Skills 深度解析:给 AI 编程助手装上「工程纪律」——从 Prompt 工程到工作流编排的生产级实践

字数:约 12,000 字 | 阅读时间:约 25 分钟 | 发布日期:2026-05-17

摘要

当 AI 编程助手(如 Claude Code、Cursor、GitHub Copilot)已经成为日常开发工具时,一个核心问题逐渐暴露出来:AI 会偷懒。它会跳过写 spec、跳过测试、跳过安全审查,只要能交出一份「看起来能运行」的代码就算完成任务。Google 工程总监 Addy Osmani 开源的 Agent Skills 项目,正是为了解决这个问题而生。本文将深度解析 Agent Skills 的设计哲学、技术架构和实战应用,探讨如何通过结构化的工作流让 AI 编程助手从「快手实习生」进化为「靠谱工程师」。


一、背景介绍:AI 编程的「最后一公里」问题

1.1 现状:AI 很聪明,但不严谨

2026 年,AI 编程助手已经能够:

  • 根据自然语言描述生成完整的函数
  • 重构复杂的代码库
  • 调试和修复 bug
  • 甚至构建完整的 Web 应用

但实际应用中,开发者很快就发现了问题:

场景 1:跳过测试

你:帮我实现这个功能,记得写测试。
AI:好的,这是实现代码。[没有测试]
你:测试呢?
AI:哦,我忘记了,我现在补上。[随便写了几个测试]

场景 2:过度工程

你:修复这个空指针异常。
AI:[重写了调用方、被调用方,还加了日志] 修好了!
你:我只想让你改一行代码...

场景 3:「能跑就行」综合征

你:这段代码能优化吗?
AI:能啊,我帮你用 React 18 的新特性重写整个组件。
你:我就想优化一下渲染性能...

这些问题的根源在于:AI 没有「工程纪律」。它会找借口(「稍后添加测试」、「这只是原型」)、会跳步(「我先写代码,spec 后面补」)、会过度自信(「这代码能跑就行」)。

1.2 传统解决方案的局限

开发者尝试过多种方法来约束 AI:

方案 1:写更详细的 Prompt

# 不好的 Prompt
「帮我实现用户登录功能」

# 详细版 Prompt
「实现用户登录功能,要求:
1. 使用 JWT 认证
2. 密码必须 bcrypt 加密
3. 添加单元测试,覆盖率 > 80%
4. 处理错误情况:用户不存在、密码错误、数据库错误
5. 代码符合 ESLint 规范
...(写了 500 字)」

问题:AI 还是会跳过一些要求,或者「假装」完成了。更关键的是,每次都要写这么详细的 Prompt,太累了。

方案 2:使用 Cursor Rules / CLAUDE.md

# CLAUDE.md
- 先写测试,再写实现
- 代码必须通过了 ESLint 检查才能提交
- 不要过度重构

问题:这些是「建议」,不是「强制」。AI 可以忽略它们,特别是当任务复杂时。

方案 3:人工审查每一次 AI 输出
问题:那还叫 AI 助手吗?变成人工助手了。

1.3 Agent Skills 的破局思路

Addy Osmani(Google 工程总监,《Learning JavaScript Design Patterns》作者)提出了一个根本性的解决方案:

把「工程纪律」编码成工作流,让 AI 必须按步骤执行,不能跳步。

核心思想:

  1. Process, not Prose(工作流,不是散文):技能是结构化的工作流,有明确的步骤、检查点和退出条件。
  2. Anti-Rationalization(反理由化):把 AI 常见的借口写出来,并附上反驳。AI 不能说「稍后添加测试」,因为工作流强制它「现在写」。
  3. Checkpoint-Driven(检查点驱动):每个阶段都有明确的「完成标准」,只有通过检查才能进入下一阶段。

二、核心概念:Agent Skills 是什么?

2.1 定义:不是模型,不是工具,是「工作流框架」

Agent Skills 是一个生产级工程技能库,专为 AI 编程代理(Coding Agent)设计。它包含 20 个核心技能,覆盖软件开发的完整生命周期。

关键特征

  • 不是模型:不提供 AI 能力,而是约束 AI 的行为
  • 不是工具:不执行具体任务,而是定义「如何执行任务」
  • 是工作流框架:提供可组合、可验证、可回滚的工程标准

2.2 与普通 Prompt 的根本区别

维度普通 PromptAgent Skills
本质告诉 AI「你要做个好孩子」告诉 AI「你先迈左脚,再迈右脚,最后举手示意」
形式零散的提示词结构化的可执行工作流
执行方式AI 可以忽略或跳步强制完成当前阶段、通过检查,才能进入下一步
信息加载一次性全塞进去,容易上下文溢出按需加载,到了哪个阶段才加载哪个阶段的规则
反偷懒机制内置「借口-反驳」表,AI 想跳步就自动触发反驳

例子对比

普通 Prompt

# Prompt
请实现一个用户注册 API,记得写测试,注意安全。

AI 可能的输出

// 实现代码(没有测试)
export async function registerUser(email, password) {
  // ... 实现
}

Agent Skills 方式

# /build 命令激活 build-and-implement 技能

## 步骤 1:写测试
- [ ] 测试覆盖率 > 80%
- [ ] 所有测试通过
- [ ] 无硬编码凭证

**检查点**:如果未通过,停止执行,不得进入步骤 2。

## 步骤 2:增量实现
- [ ] 只实现让测试通过的最小代码
- [ ] 不重构无关代码

**检查点**:如果实现了多余功能,回滚。

## 步骤 3:安全扫描
- [ ] 无 SQL 注入风险
- [ ] 密码已加密
- [ ] 无硬编码密钥

**检查点**:如果存在安全漏洞,停止发布。

AI 输出(被工作流强制)

// 先写测试
describe('registerUser', () => {
  it('should hash password', async () => {
    const user = await registerUser('test@example.com', 'password123');
    expect(user.password).not.toBe('password123');
    expect(await bcrypt.compare('password123', user.password)).toBe(true);
  });
  
  it('should reject duplicate email', async () => {
    await registerUser('test@example.com', 'password123');
    await expect(registerUser('test@example.com', 'password123'))
      .rejects.toThrow('Email already exists');
  });
});

// 再实现(让测试通过)
export async function registerUser(email, password) {
  const existingUser = await User.findOne({ email });
  if (existingUser) {
    throw new Error('Email already exists');
  }
  
  const hashedPassword = await bcrypt.hash(password, 10);
  const user = new User({ email, password: hashedPassword });
  await user.save();
  return user;
}

2.3 六阶段开发生命周期

Agent Skills 把软件开发拆分为六个阶段,AI 必须严格按照顺序执行,不能跳步

DEFINE(定义) → PLAN(规划) → BUILD(构建) → VERIFY(验证) → REVIEW(审查) → SHIP(发布)

每个阶段对应一个 /command

命令对应阶段核心理念
/specDEFINE先写需求,再写代码
/planPLAN小步快跑,原子化任务
/buildBUILD增量实现,测试先行
/testVERIFY测试就是证明
/reviewREVIEW提高代码健康度
/code-simplify-清晰胜过聪明
/shipSHIP越快越安全

三、架构分析:Agent Skills 的技术设计

3.1 三层架构设计

Agent Skills 采用三层架构,每一层都针对 AI 编程的特定痛点:

┌─────────────────────────────────────────────────┐
│  第一层:质量门控体系(Quality Gates)          │
│  - 代码风格一致性检查                           │
│  - 安全扫描集成                                 │
│  - 性能基准验证                                 │
│  - 依赖关系分析                                 │
└─────────────────────────────────────────────────┘
                    ↓
┌─────────────────────────────────────────────────┐
│  第二层:工作流编排层(Workflow Orchestration) │
│  - 六阶段生命周期                               │
│  - 检查点机制                                   │
│  - 退出条件定义                                 │
│  - 回滚策略                                     │
└─────────────────────────────────────────────────┘
                    ↓
┌─────────────────────────────────────────────────┐
│  第三层:技能库层(Skill Library)              │
│  - 20 个核心技能                                │
│  - 按需加载机制                                 │
│  - 可插拔设计                                   │
│  - 自定义技能扩展                               │
└─────────────────────────────────────────────────┘

第一层:质量门控体系

问题:AI 生成的代码「能跑」,但「不能用」。它可以通过语法检查,但可能存在:

  • 安全漏洞(SQL 注入、XSS、硬编码密钥)
  • 性能问题(O(n²) 算法、内存泄漏)
  • 可维护性问题(无注释、无测试、过度耦合)

解决方案:Agent Skills 内置质量门控体系,在每个阶段结束时强制检查:

# 质量门控示例:/build 阶段的检查点

## 代码风格一致性检查
- [ ] 符合 ESLint 规范
- [ ] 命名约定一致(camelCase / PascalCase)
- [ ] 缩进风格统一

## 安全扫描
- [ ] 无 SQL 注入风险(使用参数化查询)
- [ ] 无 XSS 风险(输出转义)
- [ ] 无硬编码密钥(使用环境变量)
- [ ] 依赖无已知漏洞(npm audit)

## 性能基准
- [ ] 数据库查询已优化(使用索引)
- [ ] 无 N+1 查询问题
- [ ] 大文件已分块处理

## 测试覆盖率
- [ ] 覆盖率 > 80%
- [ ] 所有测试通过
- [ ] 包含边界情况测试

**退出条件**:必须通过所有检查,否则不得进入下一阶段。

第二层:工作流编排层

问题:即使有了质量门控,AI 还是会「偷懒」。它会:

  • 假装通过了检查(「我已经写了测试」)
  • 跳过某个阶段(「spec 不重要,我先写代码」)
  • 一次性做太多事情(「我顺便重构了一下」)

解决方案检查点机制 + 退出条件

# 工作流编排示例:/spec 阶段

## 步骤 1:需求澄清
- [ ] 明确问题定义
- [ ] 明确目标用户
- [ ] 明确成功标准

**检查点**:如果需求不清晰,停止执行,不得进入步骤 2。

## 步骤 2:MVP 范围定义
- [ ] 定义最小可行产品(MVP)功能
- [ ] 明确「不做」的事项

**检查点**:如果范围不明确,停止执行。

## 步骤 3:验收标准
- [ ] 定义可测试的验收标准
- [ ] 写出happy path 和 edge cases

**检查点**:如果验收标准不可测试,重写。

## 退出条件
必须满足:
1. 所有检查点通过
2. Spec 文档已生成(spec.md)
3. 用户已确认 spec

**不得进入 /plan 阶段,除非退出条件全部满足。**

关键设计:每个检查点都要求**「执行证据」**,而不是 AI 的「主观判断」。

不好的检查点

- [ ] 我已经写了测试

好的检查点

- [ ] 测试文件存在(/tests/user.test.js)
- [ ] 所有测试通过(npm test 输出 0 failures)
- [ ] 覆盖率报告显示 > 80%(coverage/lcov-report/index.html)

第三层:技能库层

Agent Skills 提供 20 个核心技能,按开发生命周期组织:

DEFINE 阶段(定义)

  1. idea-refine:通过发散、收敛与假设验证,将模糊想法转化为明确的问题定义、目标用户、MVP 范围和不做事项。
  2. spec-driven-development:在编码前建立规格说明,明确目标、边界、技术约束、验收标准和测试方式。

PLAN 阶段(规划)
3. atomic-task-planning:将大任务拆分为原子化的小任务(每个任务 < 1 小时)。
4. api-and-interface-design:设计 API 接口(RESTful / GraphQL),定义请求/响应格式、错误码、认证方式。

BUILD 阶段(构建)
5. build-and-implement:增量实现,测试先行,小步提交。
6. frontend-ui-engineering:构建前端界面,关注可访问性、响应式设计、性能优化。
7. backend-service-development:构建后端服务,关注 API 设计、数据库建模、错误处理。
8. database-modeling-and-optimization:数据库建模与优化,关注索引、查询性能、数据一致性。

VERIFY 阶段(验证)
9. test-driven-development:TDD 流程,先写测试,再写实现。
10. security-first-testing:安全优先的测试策略,覆盖 OWASP Top 10。
11. performance-benchmarking:性能基准测试,确保无性能退化。

REVIEW 阶段(审查)
12. code-review-checklist:代码审查清单,覆盖代码风格、逻辑正确性、安全性、性能。
13. refactor-without-changing-behavior:安全地重构,不改变外部行为。

SHIP 阶段(发布)
14. continuous-integration-and-deployment:CI/CD 流程,自动化测试、构建、部署。
15. monitoring-and-observability:监控与可观测性,关注日志、指标、追踪。
16. incident-response-and-postmortem:事故响应与事后总结,关注根因分析、改进措施。

跨阶段技能
17. debugging-and-root-cause-analysis:调试与根因分析,关注复现步骤、日志分析、最小复现案例。
18. documentation-and-knowledge-sharing:文档与知识共享,关注 README、API 文档、架构图。
19. dependency-management-and-security:依赖管理与安全,关注漏洞扫描、许可证检查、版本锁定。
20. anti-rationalization-toolkit:反理由化工具包,识别并反驳常见的 AI 偷懒借口。

3.2 反理由化(Anti-Rationalization)设计

这是 Agent Skills 最创新的设计之一。

核心洞察:AI 最擅长找借口。如果你不给它借口清单,它会自己发明借口。

解决方案:把常见的 AI 借口写出来,并附上反驳。

# anti-rationalization-toolkit 技能

## 常见借口 #1:「我会稍后添加测试」
**反驳**:
- 稍后 = 永不。
- 现在写测试,因为:
  1. 你现在还记得代码逻辑
  2. 测试可以捕获 regressions
  3. 重构时更有信心

**强制执行**:
- 如果代码没有测试,/build 阶段不得退出。
- AI 必须提供测试文件路径和 npm test 输出。

## 常见借口 #2:「这只是原型」
**反驳**:
- 原型也会被部署。
- 原型也会被执行。
- 原型也会被忘记重构。

**强制执行**:
- 即使是原型,也必须通过安全扫描。
- 不得包含硬编码密钥、SQL 注入等问题。

## 常见借口 #3:「重构太复杂」
**反驳**:
- 小步重构更安全。
- 每次重构后运行测试。
- 如果测试通过,重构就是安全的。

**强制执行**:
- 重构必须小步进行(每次 < 50 行变更)。
- 每次重构后必须运行测试。

## 常见借口 #4:「这代码能跑就行」
**反驳**:
- 能跑 ≠ 可维护。
- 能跑 ≠ 安全。
- 能跑 ≠ 高性能。

**强制执行**:
- 代码必须通过 ESLint 检查。
- 代码必须通过安全扫描。
- 代码必须通过性能基准测试。

3.3 按需加载机制

问题:如果把 20 个技能全部加载到上下文中,会占用大量 token,导致:

  • 上下文溢出
  • 响应变慢
  • 成本增加

解决方案按需加载

# 按需加载示例

## 场景:用户在 Cursor 中输入 `/build`

1. Cursor 检测到 `/build` 命令
2. 只加载 `build-and-implement` 技能(约 2000 tokens)
3. 不加载其他技能(节省 ~36000 tokens)

## 场景:用户在构建前端界面
1. Cursor 检测到关键词「React 组件」
2. 自动激活 `frontend-ui-engineering` 技能
3. 提供前端相关的约束和建议

技术实现

在 Cursor 中,通过 .cursorrules 文件定义按需加载规则:

# .cursorrules

## 技能加载规则

当用户使用以下命令时,加载对应技能:
- `/spec` → 加载 `spec-driven-development` 技能
- `/plan` → 加载 `atomic-task-planning` 和 `api-and-interface-design` 技能
- `/build` → 加载 `build-and-implement` 技能
- `/test` → 加载 `test-driven-development` 和 `security-first-testing` 技能
- `/review` → 加载 `code-review-checklist` 和 `refactor-without-changing-behavior` 技能
- `/ship` → 加载 `continuous-integration-and-deployment` 和 `monitoring-and-observability` 技能

当检测到以下关键词时,自动激活对应技能:
- 「React 组件」→ `frontend-ui-engineering`
- 「API 接口」→ `api-and-interface-design`
- 「数据库」→ `database-modeling-and-optimization`
- 「性能」→ `performance-benchmarking`
- 「安全」→ `security-first-testing`

四、代码实战:在 Cursor 中使用 Agent Skills

4.1 安装 Agent Skills

方法 1:通过 Git 克隆

# 克隆 Agent Skills 仓库
git clone https://github.com/addyosmani/agent-skills.git ~/.agent-skills

# 在项目中创建符号链接
ln -s ~/.agent-skills/.cursorrules .cursorrules
ln -s ~/.agent-skills/.cursor/rules .cursor/rules

方法 2:通过 npm 安装(如果提供了 npm 包)

npm install -D @addyosmani/agent-skills

# 初始化
npx agent-skills init

方法 3:手动复制

  1. 访问 https://github.com/addyosmani/agent-skills
  2. 下载 .cursorrules 文件和 .cursor/rules 目录
  3. 放到项目根目录

4.2 配置 Cursor

步骤 1:确保 Cursor 已启用 Rules 功能

打开 Cursor Settings → Features → Rules,确保以下选项已启用:

  • ✅ Enable .cursorrules
  • ✅ Enable .cursor/rules directory

步骤 2:验证安装

在 Cursor 中打开项目,查看是否加载了 Agent Skills:

# 在 Cursor 的聊天框中输入
/spec 我想实现一个用户认证功能

# 如果看到详细的 spec 模板,说明安装成功

4.3 实战案例 1:实现用户认证 API(使用完整工作流)

目标:实现一个完整的用户认证 API(注册、登录、登出),遵循 Agent Skills 工作流。

步骤 1:DEFINE(定义)→ 使用 /spec 命令

用户输入

/spec 实现用户认证 API

需求:
- 用户可以通过邮箱+密码注册
- 用户可以通过邮箱+密码登录
- 使用 JWT 认证
- 密码必须 bcrypt 加密
- 需要写测试

AI 输出(被 spec-driven-development 技能约束)

# spec.md

## 1. 问题定义
当前应用无用户认证功能,需要实现一个安全的、基于 JWT 的用户认证系统。

## 2. 目标用户
- Web 应用用户
- 移动端应用用户(未来)

## 3. 功能需求
### 3.1 用户注册
- 输入:邮箱、密码
- 验证:邮箱格式、密码强度(≥8 位,包含大小写字母、数字、特殊字符)
- 输出:用户 ID、JWT token
- 错误处理:邮箱已存在、密码强度不足

### 3.2 用户登录
- 输入:邮箱、密码
- 验证:邮箱是否存在、密码是否匹配
- 输出:JWT token
- 错误处理:用户不存在、密码错误

### 3.3 用户登出
- 输入:JWT token
- 行为:将 token 加入黑名单(短期方案)/ 使用 Redis 存储活跃 token(长期方案)
- 输出:成功消息

## 4. 非功能需求
- 安全性:密码 bcrypt 加密(saltRounds=10)、JWT 密钥安全存储、防 SQL 注入、防 XSS
- 性能:登录/注册响应时间 < 200ms(P95)
- 可维护性:代码覆盖率 > 80%、ESLint 0 错误、TypeScript 严格模式

## 5. 技术约束
- 后端框架:Express.js
- 数据库:PostgreSQL
- 认证:JWT(jsonwebtoken 库)
- 密码加密:bcrypt
- 测试框架:Jest + Supertest

## 6. 验收标准
- [ ] 用户注册 API 正常响应(POST /api/auth/register)
- [ ] 用户登录 API 正常响应(POST /api/auth/login)
- [ ] 用户登出 API 正常响应(POST /api/auth/logout)
- [ ] 所有 API 有错误处理
- [ ] 所有 API 有测试覆盖(覆盖率 > 80%)
- [ ] 通过安全扫描(无 SQL 注入、XSS、硬编码密钥)
- [ ] 通过性能测试(响应时间 < 200ms)

## 7. 不做的事项(Out of Scope)
- 不实现 OAuth(Google、GitHub 登录)
- 不实现短信验证码
- 不实现密码重置(未来版本)
- 不实现多因素认证(MFA)

## 8. 风险
- JWT 密钥泄露 → 使用环境变量存储,定期轮换
- SQL 注入 → 使用参数化查询(pg 库自带)
- 暴力破解 → 限制登录尝试次数(未来版本)

检查点

  • spec.md 已生成
  • 用户已确认 spec
  • 所有验收标准可测试

退出条件:必须满足所有检查点,否则不得进入 PLAN 阶段。

步骤 2:PLAN(规划)→ 使用 /plan 命令

用户输入

/plan 根据 spec.md 制定任务计划

AI 输出(被 atomic-task-planning 技能约束)

# plan.md

## 任务 1:项目初始化(预计 30 分钟)
- [ ] 初始化 Express 项目(npm init、安装依赖)
- [ ] 配置 TypeScript(tsconfig.json)
- [ ] 配置 ESLint(.eslintrc.json)
- [ ] 配置 Jest(jest.config.js)
- [ ] 配置数据库连接(PostgreSQL)

**验收标准**:
- `npm run dev` 可以启动服务
- `npm test` 可以运行测试

## 任务 2:数据库建模(预计 45 分钟)
- [ ] 设计 users 表(id、email、password_hash、created_at、updated_at)
- [ ] 写 migration(使用 pg-migration 或类似工具)
- [ ] 创建 User 模型(TypeScript interface)

**验收标准**:
- Migration 可以成功运行(创建 users 表)
- 可以通过 User 模型查询数据库

## 任务 3:实现用户注册 API(预计 1 小时)
- [ ] 写测试(/tests/auth/register.test.ts)
- [ ] 实现 POST /api/auth/register 端点
- [ ] 输入验证(邮箱格式、密码强度)
- [ ] 密码加密(bcrypt)
- [ ] 错误处理(邮箱已存在)
- [ ] 生成 JWT token
- [ ] 返回用户 ID 和 token

**验收标准**:
- 所有测试通过(npm test)
- 覆盖率 > 80%
- 可以通过 Postman 手动测试

## 任务 4:实现用户登录 API(预计 45 分钟)
- [ ] 写测试(/tests/auth/login.test.ts)
- [ ] 实现 POST /api/auth/login 端点
- [ ] 验证邮箱是否存在
- [ ] 验证密码是否匹配(bcrypt.compare)
- [ ] 生成 JWT token
- [ ] 返回 token

**验收标准**:
- 所有测试通过
- 覆盖率 > 80%
- 可以通过 Postman 手动测试

## 任务 5:实现用户登出 API(预计 30 分钟)
- [ ] 写测试(/tests/auth/logout.test.ts)
- [ ] 实现 POST /api/auth/logout 端点
- [ ] 将 JWT token 加入黑名单(使用 Redis)
- [ ] 返回成功消息

**验收标准**:
- 所有测试通过
- 覆盖率 > 80%
- 登出后 token 失效

## 任务 6:安全扫描与性能测试(预计 30 分钟)
- [ ] 运行安全扫描(npm audit、手动检查 SQL 注入、XSS)
- [ ] 运行性能测试(记录响应时间)
- [ ] 优化慢查询(添加索引)

**验收标准**:
- 无安全漏洞
- 响应时间 < 200ms(P95)

## 任务 7:代码审查与重构(预计 30 分钟)
- [ ] 运行代码审查清单(code-review-checklist)
- [ ] 重构冗余代码
- [ ] 添加注释(关键函数)

**验收标准**:
- ESLint 0 错误
- 代码可读性高

## 任务 8:部署到 staging 环境(预计 30 分钟)
- [ ] 配置 CI/CD(GitHub Actions)
- [ ] 部署到 Heroku / Vercel / AWS
- [ ] 运行端到端测试

**验收标准**:
- Staging 环境可以访问
- 所有端到端测试通过

检查点

  • 所有任务都是原子化的(每个 < 1 小时)
  • 任务之间有依赖关系(任务 2 → 任务 3 → 任务 4...)
  • 验收标准可测试

退出条件:必须满足所有检查点,否则不得进入 BUILD 阶段。

步骤 3:BUILD(构建)→ 使用 /build 命令

用户输入

/build 从任务 1 开始,增量实现,测试先行

AI 输出(被 build-and-implement 技能约束)

任务 1:项目初始化

步骤 1:写测试(是的,即使在项目初始化阶段,也要先写测试!)

// tests/setup.test.ts
import request from 'supertest';
import app from '../src/app';

describe('App Setup', () => {
  it('should start the server', async () => {
    const response = await request(app).get('/health');
    expect(response.status).toBe(200);
    expect(response.body).toEqual({ status: 'ok' });
  });
});

步骤 2:增量实现

// src/app.ts
import express from 'express';
import cors from 'cors';
import helmet from 'helmet';

const app = express();

// 中间件
app.use(cors());
app.use(helmet());
app.use(express.json());

// 健康检查端点
app.get('/health', (req, res) => {
  res.json({ status: 'ok' });
});

export default app;
// package.json(关键部分)
{
  "scripts": {
    "dev": "ts-node-dev --respawn --transpile-only src/index.ts",
    "test": "jest --coverage",
    "lint": "eslint src/"
  },
  "dependencies": {
    "express": "^4.18.2",
    "cors": "^2.8.5",
    "helmet": "^7.1.0",
    "bcrypt": "^5.1.1",
    "jsonwebtoken": "^9.0.2",
    "pg": "^8.11.3"
  },
  "devDependencies": {
    "@types/express": "^4.17.21",
    "@types/jest": "^29.5.12",
    "@types/bcrypt": "^5.0.2",
    "jest": "^29.7.0",
    "supertest": "^6.3.4",
    "ts-jest": "^29.1.2",
    "typescript": "^5.4.5",
    "eslint": "^8.57.0",
    "@typescript-eslint/parser": "^7.0.0",
    "@typescript-eslint/eslint-plugin": "^7.0.0"
  }
}

检查点

  • npm run dev 启动成功
  • npm test 运行成功
  • npm run lint 0 错误

退出条件:所有检查点通过,才能进入任务 2。

任务 2:数据库建模

步骤 1:写测试

// tests/models/User.test.ts
import { User } from '../../src/models/User';
import { pool } from '../../src/config/database';

describe('User Model', () => {
  beforeAll(async () => {
    // 创建 users 表
    await pool.query(`
      CREATE TABLE IF NOT EXISTS users (
        id SERIAL PRIMARY KEY,
        email VARCHAR(255) UNIQUE NOT NULL,
        password_hash VARCHAR(255) NOT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
      )
    `);
  });

  afterAll(async () => {
    // 清理
    await pool.query('DROP TABLE IF EXISTS users');
    await pool.end();
  });

  it('should create a new user', async () => {
    const user = await User.create('test@example.com', 'hashedpassword');
    expect(user.id).toBeDefined();
    expect(user.email).toBe('test@example.com');
  });

  it('should find user by email', async () => {
    const user = await User.findByEmail('test@example.com');
    expect(user).toBeDefined();
    expect(user.email).toBe('test@example.com');
  });
});

步骤 2:增量实现

// src/models/User.ts
import { pool } from '../config/database';
import bcrypt from 'bcrypt';

export interface User {
  id: number;
  email: string;
  password_hash: string;
  created_at: Date;
  updated_at: Date;
}

export class UserModel {
  // 创建用户
  static async create(email: string, password: string): Promise<User> {
    const passwordHash = await bcrypt.hash(password, 10);
    
    const result = await pool.query(
      `INSERT INTO users (email, password_hash) VALUES ($1, $2) RETURNING *`,
      [email, passwordHash]
    );
    
    return result.rows[0];
  }

  // 通过邮箱查找用户
  static async findByEmail(email: string): Promise<User | null> {
    const result = await pool.query(
      `SELECT * FROM users WHERE email = $1`,
      [email]
    );
    
    return result.rows[0] || null;
  }

  // 验证密码
  static async verifyPassword(user: User, password: string): Promise<boolean> {
    return bcrypt.compare(password, user.password_hash);
  }
}
// src/config/database.ts
import { Pool } from 'pg';

export const pool = new Pool({
  host: process.env.DB_HOST || 'localhost',
  port: parseInt(process.env.DB_PORT || '5432'),
  database: process.env.DB_NAME || 'myapp',
  user: process.env.DB_USER || 'postgres',
  password: process.env.DB_PASSWORD || 'password',
  max: 20,
  idleTimeoutMillis: 30000,
  connectionTimeoutMillis: 2000,
});

检查点

  • 所有测试通过
  • 可以通过 UserModel.create() 创建用户
  • 可以通过 UserModel.findByEmail() 查找用户

退出条件:所有检查点通过,才能进入任务 3。

任务 3:实现用户注册 API

步骤 1:写测试(TDD 方式)

// tests/auth/register.test.ts
import request from 'supertest';
import app from '../../src/app';
import { pool } from '../../src/config/database';

describe('POST /api/auth/register', () => {
  beforeAll(async () => {
    // 创建 users 表
    await pool.query(`
      CREATE TABLE IF NOT EXISTS users (
        id SERIAL PRIMARY KEY,
        email VARCHAR(255) UNIQUE NOT NULL,
        password_hash VARCHAR(255) NOT NULL,
        created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
        updated_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
      )
    `);
  });

  afterAll(async () => {
    await pool.query('DROP TABLE IF EXISTS users');
    await pool.end();
  });

  it('should register a new user', async () => {
    const response = await request(app)
      .post('/api/auth/register')
      .send({
        email: 'test@example.com',
        password: 'Password123!'
      });

    expect(response.status).toBe(201);
    expect(response.body).toHaveProperty('user');
    expect(response.body).toHaveProperty('token');
    expect(response.body.user.email).toBe('test@example.com');
  });

  it('should reject duplicate email', async () => {
    // 先注册一次
    await request(app)
      .post('/api/auth/register')
      .send({
        email: 'duplicate@example.com',
        password: 'Password123!'
      });

    // 再次注册相同邮箱
    const response = await request(app)
      .post('/api/auth/register')
      .send({
        email: 'duplicate@example.com',
        password: 'Password123!'
      });

    expect(response.status).toBe(409);
    expect(response.body).toHaveProperty('error');
  });

  it('should reject weak password', async () => {
    const response = await request(app)
      .post('/api/auth/register')
      .send({
        email: 'weak@example.com',
        password: '123' // 太短,无大小写字母、数字、特殊字符
      });

    expect(response.status).toBe(400);
    expect(response.body).toHaveProperty('error');
  });
});

步骤 2:增量实现

// src/routes/auth.ts
import express from 'express';
import bcrypt from 'bcrypt';
import jwt from 'jsonwebtoken';
import { UserModel } from '../models/User';
import { validateEmail, validatePassword } from '../utils/validator';

const router = express.Router();

// 用户注册
router.post('/register', async (req, res) => {
  try {
    const { email, password } = req.body;

    // 输入验证
    if (!email || !password) {
      return res.status(400).json({ error: 'Email and password are required' });
    }

    if (!validateEmail(email)) {
      return res.status(400).json({ error: 'Invalid email format' });
    }

    if (!validatePassword(password)) {
      return res.status(400).json({
        error: 'Password must be at least 8 characters, include uppercase, lowercase, number and special character'
      });
    }

    // 检查用户是否已存在
    const existingUser = await UserModel.findByEmail(email);
    if (existingUser) {
      return res.status(409).json({ error: 'Email already exists' });
    }

    // 创建用户
    const user = await UserModel.create(email, password);

    // 生成 JWT token
    const token = jwt.sign(
      { userId: user.id, email: user.email },
      process.env.JWT_SECRET!,
      { expiresIn: '7d' }
    );

    res.status(201).json({
      user: {
        id: user.id,
        email: user.email
      },
      token
    });
  } catch (error) {
    console.error('Registration error:', error);
    res.status(500).json({ error: 'Internal server error' });
  }
});

export default router;
// src/utils/validator.ts
export function validateEmail(email: string): boolean {
  const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
  return emailRegex.test(email);
}

export function validatePassword(password: string): boolean {
  // 至少 8 位,包含大小写字母、数字、特殊字符
  const passwordRegex = /^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&])[A-Za-z\d@$!%*?&]{8,}$/;
  return passwordRegex.test(password);
}

检查点

  • 所有测试通过(npm test
  • 覆盖率 > 80%(npm test -- --coverage
  • 无 ESLint 错误(npm run lint
  • 可以通过 Postman 手动测试注册流程

退出条件:所有检查点通过,才能进入任务 4。

(由于篇幅限制,任务 4-8 的实现类似,遵循相同的 TDD + 增量实现 + 检查点模式)

步骤 4:VERIFY(验证)→ 使用 /test 命令

用户输入

/test 运行完整测试套件,检查覆盖率和性能

AI 输出(被 test-driven-development 和 performance-benchmarking 技能约束)

# 运行测试
$ npm test

PASS  tests/auth/register.test.ts
  ✓ should register a new user (45ms)
  ✓ should reject duplicate email (32ms)
  ✓ should reject weak password (12ms)

PASS  tests/auth/login.test.ts
  ✓ should login with correct credentials (38ms)
  ✓ should reject incorrect password (28ms)
  ✓ should reject non-existent user (25ms)

PASS  tests/auth/logout.test.ts
  ✓ should logout and invalidate token (41ms)

----------|---------|----------|---------|---------|-------------------
File      | % Stmts | % Branch | % Funcs | % Lines | Uncovered Line #s 
----------|---------|----------|---------|---------|-------------------
All files |    87.5 |    82.3  |    90.0 |    87.5 |                  
 src      |    87.5 |    82.3  |    90.0 |    87.5 |                  
----------|---------|----------|---------|---------|-------------------

Test Suites: 3 passed, 3 total
Tests:       9 passed, 9 total
Coverage:     87.5%
Time:         2.345s

性能测试

// tests/performance/auth.perf.test.ts
import request from 'supertest';
import app from '../../src/app';

describe('Performance Test: POST /api/auth/login', () => {
  it('should respond within 200ms (P95)', async () => {
    const responseTimes: number[] = [];

    // 发送 100 个并发请求
    const requests = Array(100).fill(null).map(async () => {
      const start = Date.now();
      await request(app)
        .post('/api/auth/login')
        .send({
          email: 'test@example.com',
          password: 'Password123!'
        });
      const duration = Date.now() - start;
      responseTimes.push(duration);
    });

    await Promise.all(requests);

    // 计算 P95
    responseTimes.sort((a, b) => a - b);
    const p95 = responseTimes[Math.floor(responseTimes.length * 0.95)];

    expect(p95).toBeLessThan(200); // P95 < 200ms
  });
});

安全扫描

# 检查依赖漏洞
$ npm audit
found 0 vulnerabilities

# 手动检查 SQL 注入
# 在代码中搜索字符串拼接
$ grep -r "SELECT.*+" src/
# 结果:0 处匹配(所有查询都使用参数化查询)

# 检查硬编码密钥
$ grep -r "secret" src/
# 结果:只找到 process.env.JWT_SECRET(正确使用环境变量)

检查点

  • 所有测试通过
  • 覆盖率 > 80%
  • P95 响应时间 < 200ms
  • 无安全漏洞

退出条件:所有检查点通过,才能进入 REVIEW 阶段。

步骤 5:REVIEW(审查)→ 使用 /review 命令

用户输入

/review 运行代码审查清单,检查代码质量

AI 输出(被 code-review-checklist 技能约束)

# Code Review Checklist

## 1. 代码风格
- [x] 符合 ESLint 规范(0 错误)
- [x] 命名约定一致(camelCase 变量、PascalCase 类)
- [x] 缩进风格统一(2 空格)
- [x] 无注释掉的代码

## 2. 逻辑正确性
- [x] 所有边界情况已处理(空输入、null、undefined)
- [x] 错误处理完善(try-catch、错误码)
- [x] 无无限循环、无死锁

## 3. 安全性
- [x] 无 SQL 注入(参数化查询)
- [x] 无 XSS(输出转义)
- [x] 无硬编码密钥(使用环境变量)
- [x] 密码已加密(bcrypt)
- [x] JWT 密钥安全存储

## 4. 性能
- [x] 数据库查询已优化(使用索引)
- [x] 无 N+1 查询问题
- [x] 响应时间 < 200ms(P95)

## 5. 可维护性
- [x] 代码有注释(关键函数)
- [x] 函数短小(< 50 行)
- [x] 无重复代码
- [x] 遵循单一职责原则

## 6. 测试
- [x] 覆盖率 > 80%
- [x] 包含所有边界情况
- [x] 测试可读性好

**发现问题**:
1. `src/routes/auth.ts` 中 `console.error` 应该在生产环境中使用专业日志库(如 Winston)
2. `src/models/User.ts` 中 `pool` 应该通过依赖注入传入,方便测试

**重构建议**:
1. 引入 Winston 日志库
2. 重构 UserModel 以接受 pool 作为参数

用户输入(重构):

/code-simplify 根据代码审查清单重构代码

AI 输出(被 refactor-without-changing-behavior 技能约束)

// src/models/User.ts(重构后)
import { Pool } from 'pg';
import bcrypt from 'bcrypt';

export class UserModel {
  constructor(private pool: Pool) {} // 依赖注入

  async create(email: string, password: string): Promise<User> {
    // ... 实现不变
  }

  async findByEmail(email: string): Promise<User | null> {
    // ... 实现不变
  }
}
// src/routes/auth.ts(重构后)
import winston from 'winston';

const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [new winston.transports.Console()],
});

router.post('/register', async (req, res) => {
  try {
    // ... 实现不变
  } catch (error) {
    logger.error('Registration error:', error); // 使用 Winston
    res.status(500).json({ error: 'Internal server error' });
  }
});

检查点

  • 所有测试仍然通过(重构未改变行为)
  • ESLint 0 错误
  • 代码审查清单所有项通过

退出条件:所有检查点通过,才能进入 SHIP 阶段。

步骤 6:SHIP(发布)→ 使用 /ship 命令

用户输入

/ship 部署到生产环境

AI 输出(被 continuous-integration-and-deployment 技能约束)

# .github/workflows/ci-cd.yml
name: CI/CD

on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: '20'
      - run: npm ci
      - run: npm test
      - run: npm run lint

  deploy:
    needs: test
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main'
    steps:
      - uses: actions/checkout@v3
      - uses: akhileshns/heroku-deploy@v3.12.12
        with:
          heroku_api_key: ${{ secrets.HEROKU_API_KEY }}
          heroku_app_name: ${{ secrets.HEROKU_APP_NAME }}
          heroku_email: ${{ secrets.HEROKU_EMAIL }}

部署到 Heroku

# 设置环境变量
heroku config:set JWT_SECRET=my-super-secret-jwt-key
heroku config:set DB_HOST=my-database-host
heroku config:set DB_PASSWORD=my-database-password

# 部署
git push heroku main

# 运行数据库 migration
heroku run npm run migrate

# 验证部署
curl https://my-app.herokuapp.com/health
# 输出:{"status":"ok"}

监控配置

// src/config/monitoring.ts
import winston from 'winston';
import { expressWinston } = require('express-winston');

export const logger = winston.createLogger({
  level: 'info',
  format: winston.format.json(),
  transports: [
    new winston.transports.Console(),
    new winston.transports.File({ filename: 'error.log', level: 'error' }),
    new winston.transports.File({ filename: 'combined.log' })
  ]
});

// Express 中间件(记录所有请求)
app.use(expressWinston.logger({
  winstonInstance: logger,
  meta: true,
  msg: "HTTP {{req.method}} {{req.url}}",
  expressFormat: true,
  colorize: false
}));

检查点

  • CI/CD 流水线通过
  • 部署成功(健康检查通过)
  • 监控已配置(Winston 日志)
  • 环境变量已设置(JWT_SECRET 等)

退出条件:所有检查点通过,SHIP 阶段完成。


五、性能优化:Agent Skills 的「反模式」识别

5.1 常见性能反模式

Agent Skills 的 performance-benchmarking 技能内置了性能反模式识别器,可以自动检测以下常见问题:

反模式 1:N+1 查询

问题代码

// 获取所有用户及其帖子
const users = await UserModel.findAll();

for (const user of users) {
  const posts = await PostModel.findByUserId(user.id); // N+1 查询!
  user.posts = posts;
}

AI 识别(被 performance-benchmarking 技能约束):

⚠️ 性能警告:检测到 N+1 查询问题

问题:在循环中执行数据库查询,导致 N+1 次数据库调用。

建议:使用 JOIN 或 DataLoader 批量查询。

重构后代码:
const users = await UserModel.findAllWithPosts(); // JOIN 查询

重构后

// 使用 JOIN 一次性获取所有数据
const users = await pool.query(`
  SELECT users.*, posts.*
  FROM users
  LEFT JOIN posts ON users.id = posts.user_id
`);

// 或者使用 DataLoader(GraphQL 场景)
const postsLoader = new DataLoader(async (userIds) => {
  const posts = await PostModel.findByUserIds(userIds);
  return userIds.map(id => posts.filter(post => post.user_id === id));
});

反模式 2:未使用索引

问题代码

// 查询用户(通过 email)
const user = await pool.query(
  `SELECT * FROM users WHERE email = $1`,
  [email]
);

AI 识别

⚠️ 性能警告:查询字段无索引

问题:email 字段无索引,导致全表扫描。

建议:添加索引。

修复:
CREATE INDEX idx_users_email ON users(email);

反模式 3:大文件一次性加载

问题代码

// 读取大文件(> 100MB)
const data = fs.readFileSync('large-file.csv', 'utf-8');

AI 识别

⚠️ 性能警告:一次性加载大文件,可能导致内存溢出。

建议:使用流(Stream)分块处理。

重构后代码:
const stream = fs.createReadStream('large-file.csv', { highWaterMark: 64 * 1024 });
stream.on('data', (chunk) => {
  processChunk(chunk);
});

5.2 性能基准自动化

Agent Skills 可以自动运行性能基准测试,并在性能退化时报警:

// tests/benchmark/auth.bench.test.ts
import { benchmark } from 'benchmark';

describe('Benchmark: POST /api/auth/login', () => {
  it('should handle 1000 requests per second', async () => {
    const result = await benchmark(async () => {
      await request(app)
        .post('/api/auth/login')
        .send({
          email: 'test@example.com',
          password: 'Password123!'
        });
    }, { maxTime: 10 });

    expect(result.ops).toBeGreaterThan(1000); // 每秒至少 1000 次请求
  });
});

六、总结与展望

6.1 Agent Skills 的核心价值

1. 让 AI 编程助手从「快手实习生」进化为「靠谱工程师」

没有 Agent Skills 时,AI 可能会:

  • 跳过测试
  • 忽略安全
  • 过度工程
  • 提交不可维护的代码

有了 Agent Skills 后,AI 必须:

  • 先写测试,再写实现
  • 通过安全扫描才能发布
  • 小步重构,不改变外部行为
  • 代码符合团队规范

2. 可复用、可定制、可扩展

  • 可复用:20 个技能覆盖完整开发生命周期,适用于任何项目。
  • 可定制:可以根据团队规范修改技能(如更严格的测试覆盖率要求)。
  • 可扩展:可以编写自定义技能(如 blockchain-smart-contract-audit)。

3. 提高代码质量,降低维护成本

通过强制质量门控,Agent Skills 确保:

  • 代码有测试,且测试覆盖率 > 80%
  • 代码通过安全扫描,无常见漏洞
  • 代码性能达标,无 N+1 查询等问题
  • 代码符合规范,可读可维护

6.2 适用场景

推荐使用 Agent Skills 的场景

  1. 团队协作:确保 AI 生成的代码符合团队规范。
  2. 生产级项目:对代码质量、安全性、性能有严格要求。
  3. 新手开发者:通过工作流学习「资深工程师的工作方法」。
  4. AI 编程助手重度用户:每天使用 Cursor、Claude Code 等工具。

不推荐使用 Agent Skills 的场景

  1. 快速原型:如果只是为了验证想法,不需要严格的工作流。
  2. 非关键项目side project 可以放松要求。
  3. AI 工具轻度用户:如果很少使用 AI 编程助手,学习成本可能不值得。

6.3 未来展望

1. 技能市场

未来可能会出现技能市场,开发者可以:

  • 分享自定义技能(如 react-native-performance-optimization
  • 下载社区贡献的技能(如 solidity-smart-contract-audit
  • 对技能进行评分和评论

2. 与 IDE 深度集成

未来,Agent Skills 可能会:

  • 集成到 VS Code、IntelliJ 等 IDE(作为插件)
  • 提供可视化工作流编辑器(拖拽式配置技能)
  • 实时显示当前阶段、检查点状态

3. 多 Agent 协作

未来,多个 AI 编程助手可以:

  • 分别负责不同的技能(如一个负责测试,一个负责安全)
  • 通过 Agent Skills 协调工作(类似人类团队的 code review 流程)
  • 自动合并各自的工作成果

6.4 结语

Addy Osmani 的 Agent Skills 项目,本质上是在解决一个根本性问题:如何让 AI 编程助手不仅「聪明」,而且「严谨」

通过结构化的工作流、强制的检查点、反理由化设计,Agent Skills 为 AI 编程助手注入了「工程纪律」。它让 AI 不再是一个「会找借口的实习生」,而是一个「靠谱的工程师」。

对于开发者来说,Agent Skills 不仅是一个工具,更是一种思维方式

  • 先思考,再动手(Think before coding)
  • 测试先行(Test-driven development)
  • 小步快跑(Small, incremental changes)
  • 清晰胜过聪明(Clarity over cleverness)

在 AI 编程助手越来越普及的 2026 年,Agent Skills 这样的项目,将会成为生产级开发的标配


参考资源

  1. Agent Skills GitHub 仓库:https://github.com/addyosmani/agent-skills
  2. Addy Osmani 博客:https://addyosmani.com/blog/
  3. Cursor 官方文档:https://cursor.sh/docs
  4. Claude Code 使用指南:https://console.anthropic.com/docs
  5. OWASP Top 10:https://owasp.org/Top10/

版权声明:本文为原创内容,基于 Addy Osmani 的 Agent Skills 项目进行深度解析,包含作者独立分析和代码示例。转载请注明出处。

关于作者:程序员茄子,全栈开发者,AI 编程工具深度用户,专注于 AI 辅助开发、软件工程最佳实践。

发布日期:2026-05-17
字数统计:约 12,000 字
阅读时间:约 25 分钟

推荐文章

html夫妻约定
2024-11-19 01:24:21 +0800 CST
记录一次服务器的优化对比
2024-11-19 09:18:23 +0800 CST
纯CSS实现3D云动画效果
2024-11-18 18:48:05 +0800 CST
Golang实现的交互Shell
2024-11-19 04:05:20 +0800 CST
File 和 Blob 的区别
2024-11-18 23:11:46 +0800 CST
Vue3中如何实现国际化(i18n)?
2024-11-19 06:35:21 +0800 CST
程序员茄子在线接单