Skip to Content
其他AI 辅助开发工作流教程

AI 辅助开发工作流教程

📅 最后更新:2026年3月27日

本文档教你如何使用 AI 辅助开发工具,从需求到上线全流程覆盖。适合有基础编程能力但刚接触 AI 辅助开发的开发者。

核心目标:让 AI 成为你的得力助手,从”会用”到”用好”。


📖 目录


第一部分:快速入门

Tip

如果你是第一次使用 AI 辅助开发,请按以下顺序阅读:

第 1 步 → 阅读本章「核心概念」(约 5 分钟) 第 2 步 → 尝试完成「第一个任务」(约 15 分钟) 第 3 步 → 根据需要阅读工具章节 第 4 步 → 选择适合的工作流程

1. 你的第一个 AI 协作任务(5 分钟)

让我们从一个最简单的任务开始,体验 AI 辅助开发的完整流程。

1.1 启动 OpenCode

# 在项目目录下启动 cd your-project opencode # 或直接启动(会自动检测当前目录) opencode

预期输出

OpenCode v1.x.x Working directory: /path/to/your-project Model: claude-3-5-sonnet Ready for input...

1.2 完成第一个任务

任务:让 AI 帮你解释项目的技术栈。

# 直接输入自然语言 "请解释一下这个项目的技术栈"

AI 会做什么

  1. 读取 package.json 分析依赖
  2. 检查配置文件(tsconfig.jsonnext.config.js 等)
  3. 扫描源代码结构
  4. 生成技术栈报告

预期结果

这个项目使用以下技术栈: 框架:Next.js 15 (App Router) 语言:TypeScript 5.x 样式:Tailwind CSS v4 构建工具:Turbopack ... 主要依赖: - react: 19.x - next: 15.x - typescript: 5.x ...

1.3 完成第二个任务(代码修改)

任务:修改一个按钮的文案。

"请把登录页面的按钮文案从'确定'改成'立即登录'"

AI 会做什么

  1. 搜索包含”确定”按钮的文件
  2. 定位登录页面
  3. 修改文案
  4. 展示修改内容,等待你确认

预期结果

找到文件:app/login/page.tsx 修改内容: - <button>确定</button> + <button>立即登录</button> 是否确认修改?(y/n)

1.4 验证修改

# 类型检查 pnpm typecheck # 构建验证 pnpm build # 手动验证 # 在浏览器中打开登录页面,确认文案已更新
Caution

永远不要跳过验证!

AI 生成的代码可能有错误,必须验证后才能确认完成。

1.5 新手常见错误

错误原因解决方法
不知道说什么担心说错想说什么就说什么,AI 会追问澄清
描述太模糊AI 不知道要做什么用示例补充,如”类似微信的登录页”
直接接受 AI 的修改没看就确认养成先审查再确认的习惯
不验证就认为完成代码可能有问题每次都要运行 pnpm build 验证

2. 核心概念速览

2.1 什么是 TDD?

TDD(Test-Driven Development) = 测试驱动开发

简单说就是:先写测试,再写代码

传统开发:写代码 → 写测试 → 发现 bug → 修 bug (像做完题再对答案,发现错了再改) TDD 开发:写测试 → 测试失败 → 写代码 → 测试通过 → 完成 (像先知道答案,做题时就知道对不对)

为什么 TDD 更好?

  • 测试失败 = 你知道要实现什么(答案告诉你还差什么)
  • 测试通过 = 你知道功能完成了(答案告诉你做对了)
  • 代码永远有测试保护(下次改代码不会改坏)

一个简单例子

// 步骤 1:写失败的测试 test('登录成功后应该跳转到首页', async () => { await login('user@example.com', 'password'); expect(window.location.pathname).toBe('/dashboard'); }); // 步骤 2:运行测试,确认失败 // Error: Expected '/dashboard' but got '/login' // 步骤 3:写最小代码通过测试 async function login(email: string, password: string) { // 最小实现 window.location.pathname = '/dashboard'; } // 步骤 4:运行测试,确认通过 // ✓ 登录成功后应该跳转到首页 // 步骤 5:重构优化(测试必须保持通过)

2.2 什么是 MCP?

MCP(Model Context Protocol) = AI 工具协议

简单说就是:让 AI 能够操作浏览器、调试器等工具的标准接口

没有 MCP 时: 你:帮我测试登录功能 AI:好的,你手动打开浏览器,输入用户名密码,点击登录按钮... 有 MCP 后: 你:帮我测试登录功能 AI:好的,我已经打开浏览器,输入了测试账号,点击了登录,验证通过。

你什么时候需要 MCP?

你的需求需要哪个 MCP 工具必要性
让 AI 帮我点按钮、填表单Playwright MCP开发 Web 应用时很有用
让 AI 帮我分析页面性能Chrome DevTools MCP优化性能时需要
让 AI 测试已登录的功能Real Browser MCP测试后台功能时需要
只是想让 AI 写代码不需要 MCP直接让 AI 写就行

2.3 什么是人/AI 协同?

核心原则:人做决策,AI 做执行

为什么需要协同?AI 不是什么都能做吗?

不是的。AI 有三大局限:

  1. 不懂业务价值:AI 不知道”登录失败 3 次锁定账户”是否符合你的业务需求
  2. 不懂风险判断:AI 不知道这段代码如果出错会造成多大损失
  3. 代码可能有问题:45% 的 AI 代码有安全漏洞

所以分工是这样的

你负责(决策)AI 负责(执行)
决定”做什么”执行”怎么做”
定义验收标准生成测试用例
审查代码安全性写代码、修 bug
最终验收确认生成文档、报告

一个例子

你:我要一个登录功能,支持手机号登录,失败 3 次锁定 AI:好的,我来写代码 AI:代码写好了,请审查 你:审查通过,运行测试 AI:测试通过了 你:我在浏览器里试试...可以!确认完成
Warning

永远不要让 AI 决策关键事项!

AI 不理解业务价值、法律风险、公司政策。安全相关的代码必须人工审查。

2.4 什么是 OpenSpec?

OpenSpec = 规格驱动开发工具

简单说就是:先写清楚要做什么,再让 AI 实现

传统方式: 你:做一个登录功能 AI:[直接写代码] 你:不对,我要的是手机号登录 AI:[改代码] 你:还要失败 3 次锁定 AI:[再改代码] ...(反复返工) OpenSpec 方式: 你:做一个登录功能 AI:[生成规格文档] - 支持手机号登录 - 失败 3 次锁定 - 锁定后 15 分钟解锁 你:确认规格 AI:[按规格实现] 你:验收通过

OpenSpec 四阶段


3. 适用场景判断

Warning

**不是所有项目都需要完整流程。**使用前先判断:

3.1 快速判断表

问:你的项目是否需要完整流程? ├─ 纯静态文档站点(无业务逻辑) │ └─ ❌ 不适用 → 使用简化版流程 ├─ 原型验证阶段 │ └─ ❌ 不适用 → 快速迭代优先,事后再补充测试 ├─ 核心业务逻辑开发 │ └─ ✅ 适用 → 重点使用 TDD 章节 ├─ 高风险模块(支付、认证等) │ └─ ✅ 适用 → 必须使用完整流程 └─ 复杂应用、团队协作项目 └─ ✅ 适用 → 完整流程

3.2 任务复杂度判断

任务类型特征推荐工作流时间投入
简单单文件、明确目标、不涉及架构One-Shot 模式~1 分钟
中等多文件、需理解上下文、有验收标准Plan Mode~2-3 分钟
复杂核心功能、业务逻辑、需高质量保证TDD + AI~5-10 分钟
超复杂大型功能、团队协作、长期维护Spec-Driven~10-30 分钟

3.3 何时不适用本文档

场景原因替代方案
纯静态文档站点无业务逻辑,无测试需求简化版流程
原型验证阶段快速迭代优先Vibe Coding + 事后重构
一次性脚本无长期维护需求One-Shot 模式
配置文件修改简单直接One-Shot 模式

第二部分:工具生态全景

本章介绍 AI 辅助开发的完整工具生态,帮助你理解每个工具的作用和使用场景。


4. OpenCode 入门

4.1 什么是 OpenCode?

OpenCode 是一个 AI 辅助开发的命令行工具,提供:

  • 自然语言交互
  • 代码生成与修改
  • 多代理编排
  • 技能系统
  • MCP 工具集成

4.2 安装与配置

安装

# 使用 npm 安装 npm install -g @anthropic/opencode # 或使用 pnpm pnpm add -g @anthropic/opencode # 验证安装 opencode --version

配置文件

OpenCode 使用 opencode.json 配置文件:

// .ai/.config/opencode/opencode.json { "model": "claude-3-5-sonnet", "maxTokens": 8192, "temperature": 0.7, "mcp": { // MCP 工具配置 }, "skills": [ // 技能配置 ] }

API 订阅推荐

根据官方推荐,以下订阅可良好运行:

订阅价格推荐指数
ChatGPT Subscription $20/月⭐⭐⭐⭐⭐
GLM Coding Plan $10/月⭐⭐⭐⭐

4.3 核心命令速查

命令用途示例
opencode启动交互模式opencode
opencode "prompt"单次执行opencode "解释这个函数"
opencode --help查看帮助opencode --help
/clear清理会话/clear
/exit退出/exit

4.4 代理系统概览

OpenCode 内置多个专业代理,自动路由到最优模型:

核心代理

代理用途何时使用
sisyphus主指挥官默认入口,编排所有代理
explore代码搜索查找代码模式、理解结构
librarian文档查阅外部库文档、API 参考
oracle架构咨询复杂问题、架构决策
prometheus规划师面试式战略规划

其他代理

代理用途
atlas通用代理
metis需求分析
momus计划评审
hephaestus深度工作者

4.5 Category 委派系统

当 Sisyphus 委派子任务时,选择 category,系统自动路由到最优模型:

Category适用场景示例
visual-engineeringUI、样式、动画、布局重新设计侧边栏
ultrabrain复杂逻辑、架构决策、算法实现缓存淘汰算法
deep自主研究 + 端到端实现完整功能开发
artistry非常规问题、创意方法创新解决方案
quick单文件修改、简单配置修复 typo
writing文档、技术写作编写 API 文档

4.6 代理调用语法

// 方式 1: 使用 category(推荐用于任务委派) task( category="quick", // 必需:任务类别 load_skills=[], // 必需:技能数组 description="Fix type error", // 必需:短描述 prompt="Fix the TypeScript error in src/utils.ts line 42...", // 必需:完整提示词 run_in_background=false // 必需:false=任务委派,true=并行探索 ) // 方式 2: 使用 subagent_type(直接调用专门代理) task( subagent_type="explore", // 指定代理类型 load_skills=[], description="Find auth patterns", prompt="搜索认证实现模式...", run_in_background=true // 并行探索时用 true ) // 方式 3: 继续之前的 session task( session_id="ses_abc123", // 上次返回的 session_id load_skills=[], description="Continue auth task", prompt="继续上一个任务...", run_in_background=false )

参数说明

参数必需说明
categorysubagent_type二选一category 自动路由模型,subagent_type 直接指定代理
load_skills技能名称数组,空数组 [] 表示不加载
description短描述(3-5词)
prompt完整详细提示词
run_in_backgroundfalse=任务委派,true=并行探索
session_id继续之前的 session 时提供

5. OpenSpec 工作流

5.1 什么是 OpenSpec?

OpenSpec 是一个规格驱动开发工具,帮助你:

  • 明确需求边界
  • 生成可追溯的规格文档
  • 分解任务
  • 归档资产

5.2 四阶段流程

5.3 Propose(创建规格)

命令/opsx-propose/openspec-propose

适用场景:明确需求,需要生成规格文档。

操作步骤

# 方式 1: 指定变更名称 /opsx-propose add-user-login # 方式 2: 直接描述需求,AI 自动生成名称 "我要添加一个用户登录模块,支持手机号和邮箱登录"

输出物

openspec/changes/add-user-login/ ├── proposal.md # 提案(做什么、为什么) ├── design.md # 设计(怎么做) └── tasks.md # 任务清单

proposal.md 示例

# 用户登录模块 ## 概述 添加用户登录功能,支持手机号和邮箱登录。 ## 验收标准 - [ ] 手机号登录成功 - [ ] 邮箱登录成功 - [ ] 失败 3 次锁定账户 15 分钟 - [ ] 锁定后提示用户 ## 禁止事项 - 不修改现有注册逻辑 - 不添加第三方登录 ## 非目标 - 不包含密码重置功能 - 不包含多因素认证

人确认要点

  • 验收标准是否完整
  • 禁止事项是否明确
  • 任务拆分是否合理

5.4 Explore(需求探索)

命令/opsx-explore/openspec-explore

适用场景:模糊想法,需要深入探索需求边界。

操作步骤

# 进入探索模式 /opsx-explore # 对话式探索 "我需要一个用户登录模块" "支持手机号和邮箱登录" "失败 3 次锁定账户" # AI 会追问: # - 手机号格式是哪国? # - 锁定后如何解锁? # - 是否需要验证码?

探索模式特点

  • 不写代码,只思考
  • 追问澄清需求
  • 发现潜在风险
  • 生成需求文档

何时退出探索模式

  • 需求边界清晰
  • 验收标准明确
  • 准备开始实现

5.5 Apply(执行实现)

命令/opsx-apply/openspec-apply-change

适用场景:规格确认后,执行实现。

操作步骤

# 标准执行 /opsx-apply add-user-login # 全功率执行(复杂任务) ultrawork # 或 /ulw-loop

执行模式对比

模式适用场景特点
标准执行单一任务、简单需求按任务顺序执行
全功率执行复杂需求、多任务并行并行启动多个子代理

全功率执行流程

5.6 Archive(归档保存)

命令/opsx-archive/openspec-archive-change

适用场景:实现完成,归档所有资产。

操作步骤

/opsx-archive add-user-login # 输出: # 归档到 openspec/changes/archive/2026-03-27-add-user-login/

归档内容

openspec/changes/archive/2026-03-27-add-user-login/ ├── proposal.md ├── design.md ├── tasks.md ├── code/ # 代码快照 └── tests/ # 测试快照

5.7 命令别名速查

完整命令简写
/openspec-propose/opsx-propose
/openspec-explore/opsx-explore
/openspec-apply-change/opsx-apply
/openspec-archive-change/opsx-archive

6. Superpowers 核心技能

6.1 什么是 Superpowers?

Superpowers 是一套经过验证的 AI 辅助开发技能,帮助你:

  • 系统化地完成任务
  • 避免常见陷阱
  • 提高代码质量

6.2 核心技能概览

6.3 brainstorming(创意探索)

触发条件:创建功能、构建组件、添加功能、修改行为之前。

核心原则:先探索意图和需求,再实现。

使用方式

# 方式 1: 自动触发(推荐) # AI 会根据任务自动判断是否需要 brainstorming # 方式 2: 手动调用 skill(name="brainstorming")

工作流程

实际示例

用户: 我要做一个用户登录模块 AI (brainstorming 模式): 让我先理解你的需求... 1. 登录方式: - 手机号登录? - 邮箱登录? - 第三方登录(微信、GitHub)? 2. 安全要求: - 失败几次锁定? - 锁定多久? - 如何解锁? 3. 用户体验: - 记住登录状态? - 自动填充上次账号? 请告诉我你的具体需求...

何时跳过 brainstorming

  • 简单 bug 修复
  • 明确的小改动
  • 紧急修复

6.4 test-driven-development(TDD)

触发条件:实现功能或修复 bug 之前。

核心原则:先写测试,再写代码。

使用方式

skill(name="test-driven-development")

RED-GREEN-REFACTOR 循环

阶段 1: RED(写失败测试)

// tests/auth/login.spec.ts import { test, expect } from '@playwright/test'; test('用户应该能够成功登录', async ({ page }) => { // Given: 用户在登录页 await page.goto('/login'); // When: 填写正确的凭据并提交 await page.getByLabel('邮箱').fill('test@example.com'); await page.getByLabel('密码').fill('password123'); await page.getByRole('button', { name: '登录' }).click(); // Then: 应该跳转到仪表板 await expect(page).toHaveURL('/dashboard'); });

验证测试失败

npx playwright test tests/auth/login.spec.ts # 期望输出:Error: page.waitForURL: Timeout # (说明测试正确地失败了,因为功能还没实现)
Warning

常见错误:测试失败是因为语法错误,而不是功能缺失。

一定要确认失败原因是”功能不存在”,而不是”代码写错了”。

阶段 2: GREEN(最小实现)

// app/login/page.tsx 'use client'; import { useRouter } from 'next/navigation'; import { FormEvent } from 'react'; export default function LoginPage() { const router = useRouter(); const handleSubmit = async (e: FormEvent) => { e.preventDefault(); // 最小实现:直接跳转(后续再实现真正的认证逻辑) router.push('/dashboard'); }; return ( <form onSubmit={handleSubmit}> <input aria-label="邮箱" type="email" name="email" /> <input aria-label="密码" type="password" name="password" /> <button type="submit">登录</button> </form> ); }

验证测试通过

npx playwright test tests/auth/login.spec.ts # 期望:1 passed

阶段 3: REFACTOR(重构优化)

// 重构内容: // 1. 提取表单组件 // 2. 添加表单验证 // 3. 实现真正的认证逻辑 // 4. 添加错误处理 // 每次重构后都要运行测试,确保不破坏功能 npx playwright test tests/auth/login.spec.ts # 期望:1 passed

何时使用 TDD

✅ 推荐使用: - 核心业务逻辑 - 支付、认证等高风险模块 - 复杂算法实现 - 需要长期维护的代码 ❌ 可跳过: - UI/UX 密集型代码 - 快速原型验证 - 一次性脚本 - 配置文件修改

6.5 systematic-debugging(系统化调试)

触发条件:遇到 bug、测试失败、意外行为时。

核心原则:先定位问题,再修复。

使用方式

skill(name="systematic-debugging")

调试流程

实际示例

用户: 登录失败 3 次没有锁定账户 AI (systematic-debugging 模式): 让我系统化地调试这个问题... 步骤 1: 复现问题 - 输入错误密码 3 - 观察账户状态 - 结果:账户未被锁定 步骤 2: 检查相关代码 - 查找登录逻辑:src/auth/login.ts - 查找锁定逻辑:src/auth/lockout.ts 步骤 3: 定位问题 - 发现:lockout.ts 中的计数器没有正确递增 - 原因:使用了错误的变量名 步骤 4: 验证假设 - 修复变量名 - 运行测试 步骤 5: 确认修复 - 测试通过 - 手动验证:账户正确锁定

6.6 verification-before-completion(完成验证)

触发条件:声称工作完成、修复完成、测试通过之前。

核心原则:无证据不完成。

使用方式

skill(name="verification-before-completion")

强制规则

⚠️ 无验证证据 = 未完成 必须验证: 1. 类型检查:pnpm typecheck 2. 构建验证:pnpm build 3. 代码检查:pnpm lint 4. 测试通过:pnpm test 5. 功能手动验证(最重要)

验证清单

- [ ] 代码通过 lint 检查 - [ ] TypeScript 编译无错误 - [ ] 构建成功 - [ ] 测试全部通过 - [ ] 功能手动验证过 - [ ] 边界情况考虑过 - [ ] 安全风险审查过

实际示例

AI: 登录功能已完成 你: 请运行验证 AI: 运行 pnpm typecheck... 通过 运行 pnpm build... 通过 运行 pnpm lint... 通过 运行 pnpm test... 8 passed 验证结果: - 类型检查:通过 - 构建:成功 - Lint:无错误 - 测试:8 passed 请手动验证: 1. 在浏览器中测试登录功能 2. 测试失败 3 次锁定 3. 测试锁定后解锁 你: 手动验证通过,确认完成

6.7 其他重要技能

writing-plans(编写计划)

触发条件:有规格或需求,需要多步骤任务,在写代码之前。

使用方式

skill(name="writing-plans")

输出:详细的实现计划,包含步骤、验证点、风险。

executing-plans(执行计划)

触发条件:有书面实现计划,需要在独立会话中执行。

使用方式

skill(name="executing-plans")

特点:按计划执行,有检查点,可恢复。

requesting-code-review(请求审查)

触发条件:完成任务、实现主要功能、合并前。

使用方式

skill(name="requesting-code-review")

receiving-code-review(接收审查)

触发条件:收到代码审查反馈,实施建议之前。

使用方式

skill(name="receiving-code-review")

7. MCP 工具集成

Warning

**MCP 工具需要手动安装和配置。**以下工具默认未启用。

重要:请全局安装 MCP 工具(npm install -g),避免使用 npx 方式启动。npx 每次运行都可能会临时下载包,受 npm 自动清理机制或缓存有效期机制影响,导致启动延迟和网络依赖。

7.1 MCP 工具概览

工具核心能力适用场景是否默认启用
Playwright MCP浏览器自动化、代码生成新功能开发、E2E 测试❌ 需手动启用
Chrome DevTools MCP性能分析、网络调试性能优化、问题诊断❌ 需手动启用
Real Browser MCP真实浏览器、已登录会话已登录场景、真实环境验证❌ 需手动启用

7.2 安装步骤

# 1. 全局安装 MCP 工具 npm install -g @playwright/mcp@latest npm install -g chrome-devtools-mcp npm install -g real-browser-mcp # 2. 修改配置文件 # 编辑 .ai/.config/opencode/opencode.json # 在 "mcp" 对象中添加配置(见下文)

7.3 Playwright MCP 配置

// opencode.json { "mcp": { "playwright-mcp": { "command": ["playwright-mcp", "--cdp-endpoint", "http://localhost:9222"], "enabled": false, "type": "local" } } }

使用示例

# 启动开发服务器 pnpm dev # 启用 Playwright MCP(修改配置:enabled: true) # 自然语言指令 "打开 http://localhost:3000/login,填写测试账号并提交" "验证登录成功后跳转到 /dashboard"

Playwright AI Agents

Playwright v1.56+ 提供三个内置 AI Agent:

Agent用途命令
@planner生成测试计划@planner 为登录流程生成测试计划
@generator生成测试代码@generator 将测试计划转换为测试
@healer修复失败测试@healer 修复失败的测试

7.4 Chrome DevTools MCP 配置

// opencode.json { "mcp": { "chrome-devtools-mcp": { "command": ["chrome-devtools-mcp", "-u", "http://localhost:9222"], "enabled": false, "type": "local" } } }

启动方式

# 启动 Chrome 并开启调试端口 google-chrome --remote-debugging-port=9222 # 或使用快捷脚本 pnpm chrome:debug

使用示例

# 性能分析 "在 localhost:3000/products 运行性能追踪" "报告 LCP、CLS、INP 指标并提供改进建议" # 网络调试 "检查 localhost:3000/api/users 的网络请求" "分析请求耗时和响应数据" # 控制台调试 "捕获 localhost:3000 的控制台错误" "分析错误堆栈并提供修复建议"

7.5 Real Browser MCP 配置

// opencode.json { "mcp": { "real-browser-mcp": { "command": ["real-browser-mcp"], "enabled": false, "type": "local", "environment": { "PORT": "7225" } } } }

使用场景

  • 已登录的 Web 应用测试
  • 需要真实浏览器环境的操作
  • 避免反爬检测

启动方式

# 默认:headless 模式,端口 9851 scripts/real_browser.sh # 可见窗口模式 scripts/real_browser.sh --headed # 自定义端口 scripts/real_browser.sh 9888 # 保留登录状态(更快启动) scripts/real_browser.sh --keep-profile

登录状态说明

站点类型示例登录状态
普通站点X, Reddit, GitHub, 知乎✅ 保留
高安全站点Google, Claude, ChatGPT⚠️ 可能登出

7.6 工具选择决策树

问:需要什么类型的浏览器自动化? ├─ 开发新功能 / E2E 测试 │ └─ 使用 Playwright MCP ├─ 性能分析 / 问题诊断 │ └─ 使用 Chrome DevTools MCP ├─ 已登录场景 / 真实环境 │ └─ 使用 Real Browser MCP └─ 复杂场景(组合使用) └─ Playwright MCP (开发) + Chrome DevTools MCP (调试)

7.7 组合使用方案

方案 A: 开发到验证全流程

# 阶段 1: 开发(Playwright MCP) @planner 为用户注册流程生成测试计划 @generator 将测试计划转换为测试代码 # 阶段 2: 实现 # AI 生成代码,人审查并调整 # 阶段 3: 验证(Playwright MCP) npx playwright test # 阶段 4: 性能检查(Chrome DevTools MCP) "在注册页面运行性能追踪" "确保 LCP < 2.5s" # 阶段 5: 真实环境验证(Real Browser MCP) "使用已登录账号验证注册流程"

方案 B: Bug 修复流程

# 阶段 1: 复现(Chrome DevTools MCP) "捕获 localhost:3000/dashboard 的控制台错误" "分析错误堆栈" # 阶段 2: 定位 # 人根据错误信息定位代码位置 # 阶段 3: TDD 修复 # 写失败的测试复现 bug # 修复代码 # 确认测试通过 # 阶段 4: 验证(Playwright MCP) npx playwright test

第三部分:项目特定技能

本章介绍项目中的特定技能,帮助你更高效地完成各类任务。


8. 浏览器与调试技能

8.1 real-browser(登录状态测试)

描述:启动带有登录状态的真实 Chrome,暴露 CDP 端口。

触发条件

  • 测试需要登录的功能
  • 需要真实浏览器环境
  • 避免反爬检测

使用方式

# 加载技能 skill(name="real-browser") # 同时需要加载 agent-browser 技能 skill(name="agent-browser")

工作流程

启动命令

# 默认:headless 模式,端口 9851 scripts/real_browser.sh # 可见窗口模式 scripts/real_browser.sh --headed # 自定义端口 scripts/real_browser.sh 9888 # 保留登录状态 scripts/real_browser.sh --keep-profile

实际示例

# 1. 启动浏览器 scripts/real_browser.sh # 2. 使用 agent-browser 操作 agent-browser --cdp 9851 open https://x.com agent-browser --cdp 9851 wait --load networkidle agent-browser --cdp 9851 snapshot -i # 3. 点击元素 agent-browser --cdp 9851 click @e3 # 4. 填写表单 agent-browser --cdp 9851 fill @e5 "hello@world.com"

环境变量

变量用途示例
REAL_BROWSER_BIN覆盖 Chrome 路径REAL_BROWSER_BIN=/usr/bin/brave-browser
REAL_BROWSER_EXTRA_ARGS额外参数REAL_BROWSER_EXTRA_ARGS="--no-sandbox"
REAL_BROWSER_LOG_LEVEL日志级别REAL_BROWSER_LOG_LEVEL=debug

注意事项

  1. --cdp <port> 必须在每个 agent-browser 命令中
  2. open 后必须 wait --load networkidle
  3. 交互前必须 snapshot -i 获取最新引用
  4. 不要混用 chrome-devtoolsagent-browser

8.2 chrome-devtools(性能分析)

描述:使用 Chrome DevTools 进行调试、性能分析、浏览器自动化。

触发条件

  • 调试 Web 页面
  • 分析性能
  • 检查网络请求

使用方式

skill(name="chrome-devtools")

核心概念

  • 浏览器生命周期:首次调用工具时自动启动
  • 页面选择:使用 list_pagesselect_page 切换
  • 元素交互:使用 take_snapshot 获取元素 uid

工作流程

实际示例

# 1. 导航到页面 "打开 https://example.com" # 2. 等待内容加载 "等待页面加载完成" # 3. 获取页面快照 "获取页面结构" # 4. 性能分析 "运行性能追踪" "报告 LCP、CLS、INP 指标" # 5. 网络调试 "检查网络请求" "分析请求耗时"

工具选择

场景推荐工具
自动化/交互take_snapshot(文本化,更快)
视觉检查take_screenshot(需要看视觉状态)
获取额外数据evaluate_script(执行 JS)

故障排除

如果 chrome-devtools-mcp 不足,引导用户使用 Chrome DevTools UI:

8.3 web-design-reviewer(设计审查)

描述:视觉检查网站设计,识别并修复设计问题。

触发条件

  • “review website design”
  • “check the UI”
  • “fix the layout”
  • “find design problems”

使用方式

skill(name="web-design-reviewer")

适用范围

  • 静态站点(HTML/CSS/JS)
  • SPA 框架(React/Vue/Angular/Svelte)
  • 全栈框架(Next.js/Nuxt/SvelteKit)
  • CMS 平台(WordPress/Drupal)

工作流程

检查项目

布局问题

问题描述严重性
元素溢出内容溢出父元素或视口
元素重叠非预期的元素重叠
对齐问题Grid 或 Flex 对齐问题
间距不一致Padding/Margin 不一致

响应式问题

问题描述严重性
非移动友好小屏幕布局崩溃
断点问题屏幕尺寸变化时过渡不自然
触摸目标移动端按钮太小

可访问性问题

问题描述严重性
对比度不足文本与背景对比度低
无焦点状态键盘导航时无法确定状态
缺少 alt 文本图片无替代文本

视口测试

名称宽度代表设备
Mobile375pxiPhone SE/12 mini
Tablet768pxiPad
Desktop1280px标准 PC
Wide1920px大显示器

实际示例

# 1. 提供 URL 用户: 请审查 http://localhost:3000 的设计 AI: 开始设计审查... ## 信息收集 - 框架:Next.js 15 - 样式:Tailwind CSS - 检查范围:首页 ## 视觉检查 正在检查桌面视图 (1280px)... 正在检查移动视图 (375px)... ## 发现问题 ### [P1] 按钮溢出 - 页面:首页 - 元素:.cta-button - 问题:按钮在小屏幕上溢出容器 - 修复文件:app/page.tsx ### [P2] 对比度不足 - 页面:首页 - 元素:.description - 问题:文本对比度 3.2:1,低于 WCAG AA 标准 4.5:1 - 修复文件:app/globals.css ## 修复中... 按钮溢出已修复 对比度已修复 ## 重新验证 桌面视图正常 移动视图正常 ## 完成报告 - 检测问题:2 - 修复问题:2 - 未修复:0

最佳实践

  • ✅ 修复前保存截图
  • ✅ 一次修复一个问题并验证
  • ✅ 遵循项目现有代码风格
  • ❌ 不要一次修复多个问题
  • ❌ 不要忽略设计系统或品牌指南

9. 代码质量技能

9.1 code-simplifier(代码简化)

描述:简化和优化代码,提高清晰度、一致性和可维护性,同时保留所有功能。

触发条件

  • 代码写完后
  • 代码审查时
  • 重构时

使用方式

skill(name="code-simplifier")

核心原则

  1. 保留功能:永远不改变代码做什么,只改变怎么做
  2. 应用项目标准:遵循 CLAUDE.md 中的编码标准
  3. 增强清晰度:减少不必要的复杂度和嵌套
  4. 保持平衡:避免过度简化

简化内容

简化类型说明
减少嵌套消除不必要的 if-else 嵌套
消除冗余移除重复代码和抽象
改进命名使用清晰的变量和函数名
合并逻辑整合相关逻辑
移除无用注释删除描述明显代码的注释

实际示例

简化前

// 检查用户是否可以访问 function checkAccess(user: User, resource: Resource): boolean { let canAccess = false; if (user !== null) { if (user.isActive === true) { if (resource.isPublic === true) { canAccess = true; } else { if (user.role === 'admin') { canAccess = true; } else { if (user.permissions.includes(resource.requiredPermission)) { canAccess = true; } else { canAccess = false; } } } } else { canAccess = false; } } else { canAccess = false; } return canAccess; }

简化后

function checkAccess(user: User | null, resource: Resource): boolean { if (!user?.isActive) return false; if (resource.isPublic) return true; if (user.role === 'admin') return true; return user.permissions.includes(resource.requiredPermission); }

注意事项

  • ❌ 避免嵌套三元运算符,使用 switch 或 if/else
  • ❌ 不要为了”更少行数”牺牲可读性
  • ✅ 选择清晰而非简洁
  • ✅ 显式代码通常比过度紧凑的代码更好

9.2 review-and-refactor(审查重构)

描述:根据项目编码规范审查和重构代码。

触发条件

  • 代码审查
  • 重构需求
  • 代码质量检查

使用方式

skill(name="review-and-refactor")

工作流程

  1. 读取 .github/instructions/*.md.github/copilot-instructions.md 中的编码规范
  2. 审查所有代码
  3. 根据规范进行重构
  4. 确保测试仍然通过

审查要点

检查项说明
代码风格是否符合项目规范
命名规范变量、函数、组件命名是否清晰
代码结构是否有重复、冗余代码
最佳实践是否遵循项目最佳实践
测试覆盖测试是否仍然通过

实际示例

用户: 请审查并重构 src/auth/ 目录下的代码 AI: 正在审查代码... ## 审查结果 ### 发现问题 1. **命名不规范** - 文件:src/auth/login.ts - 问题:函数名 `doLogin` 不符合 camelCase 规范 - 建议:改为 `login` 2. **重复代码** - 文件:src/auth/login.ts, src/auth/register.ts - 问题:验证逻辑重复 - 建议:提取到共享函数 3. **缺少类型注解** - 文件:src/auth/utils.ts - 问题:函数缺少返回类型 - 建议:添加显式类型注解 ## 重构中... 重命名 doLogin login 提取共享验证函数到 src/auth/validation.ts 添加类型注解 ## 验证 运行 pnpm test... 通过 运行 pnpm typecheck... 通过 重构完成!

10. 前端开发技能

10.1 frontend-design(前端设计)

描述:创建高质量、生产级的前端界面。

触发条件

  • 构建 Web 组件
  • 创建页面
  • 设计 UI
  • 样式美化

使用方式

skill(name="frontend-design")

设计原则

  • 高设计质量
  • 避免”AI 美学”(通用、无特色的设计)
  • 创意、精致的代码和 UI 设计

实际示例

用户: 创建一个登录页面 AI (frontend-design 模式): 我将创建一个现代、精致的登录页面... [生成代码] - 独特的视觉风格 - 精心设计的交互 - 响应式布局 - 可访问性支持

10.2 shadcn-ui(组件库)

描述:提供 shadcn/ui 组件库模式,包括安装、配置和实现。

触发条件

  • 设置 shadcn/ui
  • 安装组件
  • 构建表单(React Hook Form + Zod)
  • 自定义主题

使用方式

skill(name="shadcn-ui")

核心功能

功能说明
安装配置初始化 shadcn/ui
组件安装添加 Button、Dialog、Dropdown 等
表单构建React Hook Form + Zod 验证
主题定制Tailwind CSS 自定义

实际示例

# 初始化 npx shadcn@latest init # 安装组件 npx shadcn@latest add button npx shadcn@latest add dialog npx shadcn@latest add form # 使用组件 import { Button } from "@/components/ui/button" import { Dialog, DialogContent, DialogTrigger } from "@/components/ui/dialog"

10.3 tailwind-design-system(设计系统)

描述:使用 Tailwind CSS v4 构建可扩展的设计系统。

触发条件

  • 创建组件库
  • 实现设计系统
  • 标准化 UI 模式

使用方式

skill(name="tailwind-design-system")

核心概念

  • 设计令牌(Design Tokens)
  • 组件库
  • 响应式模式

实际示例

/* globals.css */ @theme { --color-primary: oklch(0.6 0.2 250); --color-secondary: oklch(0.7 0.15 180); --font-sans: "Inter", system-ui, sans-serif; --spacing-section: 4rem; --radius-card: 1rem; }

10.4 ahooks(React Hooks)

描述:全面的 ahooks React Hooks 库专家,覆盖 76+ 个 Hooks。

触发条件

  • 使用 ahooks 库
  • 需要 React Hooks 工具
  • 学习最佳实践

使用方式

skill(name="ahooks")

核心 Hooks 分类

分类示例 Hooks
StateuseRequest, useToggle, useBoolean
EffectuseDebounce, useThrottle, useUpdateEffect
DOMuseSize, useScroll, useMouse
AdvanceduseCreation, usePersistFn

实际示例

import { useRequest, useDebounce } from 'ahooks'; function SearchComponent() { const [keyword, setKeyword] = useState(''); const debouncedKeyword = useDebounce(keyword, { wait: 500 }); const { data, loading } = useRequest( () => fetchSearchResults(debouncedKeyword), { refreshDeps: [debouncedKeyword] } ); return ( <div> <input onChange={(e) => setKeyword(e.target.value)} /> {loading ? 'Loading...' : <Results data={data} />} </div> ); }

第四部分:工作流程实战

本章提供完整的工作流程示例,让你可以直接复制运行。


11. 简单任务:One-Shot 模式

11.1 适用场景

特征

  • 单文件或少数文件
  • 明确的输入输出
  • 不涉及架构决策
  • 能在 1-2 句话内描述清楚

示例

  • 修改按钮文案
  • 添加一个工具函数
  • 修复一个简单 bug
  • 更新配置文件

11.2 操作步骤

步骤 1:描述需求

# 直接描述,一句话搞定 "把 handleLogin 函数中的 try-catch 改为返回 Result 类型" "在 utils.ts 中添加一个 formatDate 函数,支持相对时间" "修复 src/api/users.ts 中的 TypeScript 错误"

步骤 2:AI 执行

AI 会:

  1. 定位相关文件
  2. 理解现有代码
  3. 生成修改
  4. 展示修改内容

步骤 3:审查结果

# 检查 AI 的修改 # - 逻辑是否正确 # - 是否符合项目风格 # - 是否有潜在问题

步骤 4:验证

# 类型检查 pnpm typecheck # 手动验证 # 在浏览器中测试功能

11.3 完整示例

任务:添加一个格式化日期的函数

# 步骤 1:描述需求 用户: src/utils/date.ts 中添加一个 formatDate 函数,支持: - 相对时间(如"3 分钟前") - 绝对时间(如"2026-03-27 10:30") - 自动选择(小于 24 小时用相对时间) # 步骤 2:AI 执行 AI: 好的,我来添加这个函数... 创建文件:src/utils/date.ts ```typescript /** * 格式化日期 * @param date - 日期对象或时间戳 * @param mode - 格式化模式:'relative' | 'absolute' | 'auto' */ export function formatDate( date: Date | number, mode: 'relative' | 'absolute' | 'auto' = 'auto' ): string { const timestamp = typeof date === 'number' ? date : date.getTime(); const now = Date.now(); const diff = now - timestamp; if (mode === 'relative' || (mode === 'auto' && diff < 24 * 60 * 60 * 1000)) { return formatRelative(diff); } return formatAbsolute(new Date(timestamp)); } function formatRelative(diff: number): string { const seconds = Math.floor(diff / 1000); const minutes = Math.floor(seconds / 60); const hours = Math.floor(minutes / 60); if (seconds < 60) return '刚刚'; if (minutes < 60) return `${minutes} 分钟前`; if (hours < 24) return `${hours} 小时前`; return `${Math.floor(hours / 24)} 天前`; } function formatAbsolute(date: Date): string { const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); const hour = String(date.getHours()).padStart(2, '0'); const minute = String(date.getMinutes()).padStart(2, '0'); return `${year}-${month}-${day} ${hour}:${minute}`; }

是否确认创建?

步骤 3:审查结果

用户: 确认

步骤 4:验证

AI: 运行 pnpm typecheck… ✓ 通过

请手动验证:

  • formatDate(new Date(), ‘relative’) 返回 “刚刚”
  • formatDate(Date.now() - 60000, ‘auto’) 返回 “1 分钟前”
  • formatDate(new Date(‘2026-01-01’), ‘absolute’) 返回 “2026-01-01 00:00”

用户: 验证通过,完成

--- ## 12. 中等任务:Plan Mode + 验证 ### 12.1 适用场景 **特征**: - 涉及多个文件 - 需要理解现有代码模式 - 有明确的验收标准 - 需要先规划再执行 **示例**: - 添加用户权限系统 - 重构某个模块 - 集成第三方服务 - 添加新功能 ### 12.2 操作步骤 ```mermaid flowchart TB A[描述需求] --> B[AI 分析并制定计划] B --> C[审查计划] C --> D{计划合理?} D -->|否| E[调整需求] E --> B D -->|是| F[分步实现] F --> G[每步验证] G --> H{还有步骤?} H -->|是| F H -->|否| I[最终验证]

步骤 1:描述需求

"我需要添加用户权限系统。先分析现有代码,然后制定实施计划。"

步骤 2:AI 制定计划

AI 会:

  1. 分析现有代码结构
  2. 识别需要修改的文件
  3. 制定实施步骤
  4. 识别潜在风险

步骤 3:审查计划

检查:

  • 步骤是否合理
  • 是否遗漏了什么
  • 风险是否可控

步骤 4:分步实现

每完成一步,验证后再继续下一步。

12.3 计划模板

## 目标 [一句话描述要达成什么] ## 涉及文件 - file1.ts - [修改原因] - file2.ts - [修改原因] ## 实施步骤 1. [第一步] → 验证点:[如何验证] 2. [第二步] → 验证点:[如何验证] 3. [第三步] → 验证点:[如何验证] ## 风险点 - [潜在问题及应对]

12.4 完整示例

任务:添加用户权限系统

# 步骤 1:描述需求 用户: 我需要添加用户权限系统。要求: 1. 支持角色:admin、editor、viewer 2. 支持权限:read、write、delete 3. 角色与权限的映射关系 4. API 中间件中检查权限 # 步骤 2:AI 分析并制定计划 AI: 让我分析现有代码结构... ## 分析结果 - 当前认证:src/auth/middleware.ts - 用户模型:src/models/user.ts - API 路由:src/api/* ## 实施计划 ### 目标 添加基于角色的权限控制系统 ### 涉及文件 - src/models/user.ts - 添加角色字段 - src/auth/permissions.ts - 新建权限定义 - src/auth/middleware.ts - 添加权限检查 - src/api/users/route.ts - 应用权限检查 ### 实施步骤 1. 定义权限和角色 验证:类型检查通过 2. 更新用户模型 验证:数据库迁移成功 3. 创建权限中间件 验证:单元测试通过 4. 应用到 API 路由 验证:集成测试通过 ### 风险点 - 现有用户默认角色:需要设置默认值 - 权限检查遗漏:需要全面审查 API 是否确认此计划? # 步骤 3:审查并确认 用户: 确认,开始执行 # 步骤 4:分步实现 AI: 开始执行步骤 1:定义权限和角色... [创建 src/auth/permissions.ts] ```typescript // 权限定义 export type Permission = 'read' | 'write' | 'delete'; // 角色定义 export type Role = 'admin' | 'editor' | 'viewer'; // 角色权限映射 export const ROLE_PERMISSIONS: Record<Role, Permission[]> = { admin: ['read', 'write', 'delete'], editor: ['read', 'write'], viewer: ['read'], }; // 检查权限 export function hasPermission(role: Role, permission: Permission): boolean { return ROLE_PERMISSIONS[role].includes(permission); }

验证:pnpm typecheck ✓ 通过

继续步骤 2?

用户: 继续

AI: 执行步骤 2:更新用户模型…

[修改 src/models/user.ts]

import { Role } from '../auth/permissions'; interface User { id: string; email: string; name: string; role: Role; // 新增 createdAt: Date; updatedAt: Date; }

验证:pnpm typecheck ✓ 通过

继续步骤 3?

用户: 继续

[… 继续执行 …]

步骤 5:最终验证

AI: 所有步骤完成!

运行 pnpm typecheck… ✓ 通过 运行 pnpm build… ✓ 通过 运行 pnpm test… ✓ 12 passed

请手动验证:

  1. admin 用户可以删除
  2. editor 用户不能删除
  3. viewer 用户只能读取

用户: 验证通过,完成

--- ## 13. 核心功能:TDD + AI ### 13.1 适用场景 **特征**: - 核心业务逻辑 - 支付、认证等高风险模块 - 复杂算法实现 - 需要长期维护的代码 ### 13.2 RED-GREEN-REFACTOR 循环 ```mermaid flowchart TB subgraph RED["RED 阶段"] R1[写失败测试] --> R2[运行测试确认失败] R2 --> R3{失败原因正确?} R3 -->|否| R4[修正测试] R4 --> R2 R3 -->|是| G1 end subgraph GREEN["GREEN 阶段"] G1[写最小实现] --> G2[运行测试确认通过] G2 --> G3{测试通过?} G3 -->|否| G4[修改代码] G4 --> G2 G3 -->|是| F1 end subgraph REFACTOR["REFACTOR 阶段"] F1[重构代码] --> F2[运行测试确认通过] F2 --> F3{测试通过?} F3 -->|否| F4[回滚或修复] F4 --> F2 F3 -->|是| F5{还有功能?} F5 -->|是| R1 F5 -->|否| DONE[完成] end

13.3 完整示例:登录功能

需求:实现用户登录功能,支持:

  • 邮箱密码登录
  • 失败 3 次锁定账户 15 分钟
  • 登录成功返回 token

阶段 1:RED(写失败测试)

// tests/auth/login.spec.ts import { describe, test, expect, beforeEach } from 'vitest'; import { login, LoginError } from '@/auth/login'; describe('login', () => { const validEmail = 'user@example.com'; const validPassword = 'password123'; beforeEach(() => { // 重置测试状态 resetAuthState(); }); test('成功登录返回 token', async () => { const result = await login(validEmail, validPassword); expect(result.success).toBe(true); expect(result.token).toBeDefined(); expect(result.token).toMatch(/^eyJ/); // JWT 格式 }); test('密码错误返回失败', async () => { const result = await login(validEmail, 'wrong-password'); expect(result.success).toBe(false); expect(result.error).toBe(LoginError.INVALID_CREDENTIALS); }); test('失败 3 次锁定账户', async () => { // 失败 3 次 await login(validEmail, 'wrong'); await login(validEmail, 'wrong'); await login(validEmail, 'wrong'); // 第 4 次即使密码正确也应该被锁定 const result = await login(validEmail, validPassword); expect(result.success).toBe(false); expect(result.error).toBe(LoginError.ACCOUNT_LOCKED); }); test('锁定 15 分钟后自动解锁', async () => { // 失败 3 次锁定 await login(validEmail, 'wrong'); await login(validEmail, 'wrong'); await login(validEmail, 'wrong'); // 模拟 15 分钟后 vi.useFakeTimers(); vi.advanceTimersByTime(15 * 60 * 1000); const result = await login(validEmail, validPassword); expect(result.success).toBe(true); vi.useRealTimers(); }); });

运行测试,确认失败

pnpm test tests/auth/login.spec.ts # 期望输出: # ❌ login 成功登录返回 token # Error: Cannot find module '@/auth/login' # ❌ login 密码错误返回失败 # ❌ login 失败 3 次锁定账户 # ❌ login 锁定 15 分钟后自动解锁

阶段 2:GREEN(最小实现)

// src/auth/login.ts import jwt from 'jsonwebtoken'; export enum LoginError { INVALID_CREDENTIALS = 'INVALID_CREDENTIALS', ACCOUNT_LOCKED = 'ACCOUNT_LOCKED', } interface LoginResult { success: boolean; token?: string; error?: LoginError; } // 简单的内存存储(实际项目用数据库) const failedAttempts = new Map<string, number>(); const lockoutUntil = new Map<string, number>(); export async function login( email: string, password: string ): Promise<LoginResult> { // 检查是否被锁定 const lockoutTime = lockoutUntil.get(email); if (lockoutTime && Date.now() < lockoutTime) { return { success: false, error: LoginError.ACCOUNT_LOCKED }; } // 验证凭据(简化版,实际项目要查数据库) const validCredentials = email === 'user@example.com' && password === 'password123'; if (!validCredentials) { // 记录失败次数 const attempts = (failedAttempts.get(email) || 0) + 1; failedAttempts.set(email, attempts); // 3 次失败后锁定 if (attempts >= 3) { lockoutUntil.set(email, Date.now() + 15 * 60 * 1000); } return { success: false, error: LoginError.INVALID_CREDENTIALS }; } // 登录成功,重置失败计数 failedAttempts.delete(email); lockoutUntil.delete(email); // 生成 token const token = jwt.sign({ email }, process.env.JWT_SECRET!, { expiresIn: '1h' }); return { success: true, token }; } // 测试辅助函数 export function resetAuthState() { failedAttempts.clear(); lockoutUntil.clear(); }

运行测试,确认通过

pnpm test tests/auth/login.spec.ts # 期望输出: # ✓ login 成功登录返回 token # ✓ login 密码错误返回失败 # ✓ login 失败 3 次锁定账户 # ✓ login 锁定 15 分钟后自动解锁 # # Test Files 1 passed # Tests 4 passed

阶段 3:REFACTOR(重构优化)

// src/auth/login.ts(重构后) import jwt from 'jsonwebtoken'; export enum LoginError { INVALID_CREDENTIALS = 'INVALID_CREDENTIALS', ACCOUNT_LOCKED = 'ACCOUNT_LOCKED', USER_NOT_FOUND = 'USER_NOT_FOUND', } interface User { id: string; email: string; passwordHash: string; } interface LoginResult { success: boolean; token?: string; error?: LoginError; } interface AuthConfig { maxAttempts: number; lockoutDurationMs: number; tokenExpiry: string; } const DEFAULT_CONFIG: AuthConfig = { maxAttempts: 3, lockoutDurationMs: 15 * 60 * 1000, // 15 分钟 tokenExpiry: '1h', }; export class AuthService { private failedAttempts = new Map<string, number>(); private lockoutUntil = new Map<string, number>(); constructor( private getUser: (email: string) => Promise<User | null>, private config: AuthConfig = DEFAULT_CONFIG ) {} async login(email: string, password: string): Promise<LoginResult> { // 检查锁定状态 if (this.isLocked(email)) { return { success: false, error: LoginError.ACCOUNT_LOCKED }; } // 获取用户 const user = await this.getUser(email); if (!user) { return { success: false, error: LoginError.USER_NOT_FOUND }; } // 验证密码 const validPassword = await this.verifyPassword(password, user.passwordHash); if (!validPassword) { this.recordFailure(email); return { success: false, error: LoginError.INVALID_CREDENTIALS }; } // 登录成功 this.clearFailures(email); const token = this.generateToken(user); return { success: true, token }; } private isLocked(email: string): boolean { const lockoutTime = this.lockoutUntil.get(email); return lockoutTime !== undefined && Date.now() < lockoutTime; } private recordFailure(email: string): void { const attempts = (this.failedAttempts.get(email) || 0) + 1; this.failedAttempts.set(email, attempts); if (attempts >= this.config.maxAttempts) { this.lockoutUntil.set( email, Date.now() + this.config.lockoutDurationMs ); } } private clearFailures(email: string): void { this.failedAttempts.delete(email); this.lockoutUntil.delete(email); } private generateToken(user: User): string { return jwt.sign( { sub: user.id, email: user.email }, process.env.JWT_SECRET!, { expiresIn: this.config.tokenExpiry } ); } private async verifyPassword(password: string, hash: string): Promise<boolean> { // 实际项目使用 bcrypt 或 argon2 const bcrypt = await import('bcrypt'); return bcrypt.compare(password, hash); } // 测试辅助方法 resetState(): void { this.failedAttempts.clear(); this.lockoutUntil.clear(); } }

运行测试,确认重构后仍通过

pnpm test tests/auth/login.spec.ts # 期望输出: # ✓ login 成功登录返回 token # ✓ login 密码错误返回失败 # ✓ login 失败 3 次锁定账户 # ✓ login 锁定 15 分钟后自动解锁 # # Test Files 1 passed # Tests 4 passed

14. 大型项目:Spec-Driven Development

14.1 适用场景

特征

  • 跨多个系统/服务
  • 需要架构决策
  • 长期维护需求
  • 团队协作

14.2 四阶段流程

14.3 完整示例:支付系统

需求:实现完整的支付系统,包含订单、支付、回调。

阶段 1:Specify(规格)

/opsx-propose add-payment-system

proposal.md

# 支付系统 ## 概述 实现完整的支付系统,支持订单创建、支付处理、回调通知。 ## 用户故事 作为用户,我想要在线支付订单,以便完成购买。 ## 验收标准 - [ ] 用户可以创建订单 - [ ] 用户可以选择支付方式(微信、支付宝) - [ ] 支付成功后订单状态更新 - [ ] 支付失败后订单状态更新 - [ ] 支付超时后订单自动取消 - [ ] 支付回调验签正确 ## 约束条件 - 必须使用 HTTPS - 必须验证支付回调签名 - 敏感信息必须加密存储 ## 非目标 - 不包含退款功能(后续迭代) - 不包含分期付款(后续迭代)

design.md

# 支付系统设计 ## 架构 ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ 前端 │────▶│ API │────▶│ 支付网关 │ │ (Next.js) │ │ (Node.js) │ │ (微信/支付宝)│ └─────────────┘ └─────────────┘ └─────────────┘ ┌─────────────┐ │ 数据库 │ │ (PostgreSQL)│ └─────────────┘ ## 数据模型 ### Order(订单) - id: UUID - userId: UUID - amount: Decimal - status: Enum (pending, paid, failed, cancelled) - paymentMethod: Enum (wechat, alipay) - createdAt: DateTime - paidAt: DateTime? ### Payment(支付记录) - id: UUID - orderId: UUID - transactionId: String - status: Enum - rawCallback: JSON - createdAt: DateTime ## API 设计 ### POST /api/orders 创建订单 ### POST /api/orders/:id/pay 发起支付 ### POST /api/payments/callback/wechat 微信支付回调 ### POST /api/payments/callback/alipay 支付宝支付回调 ## 安全考虑 1. 回调验签 2. 幂等性处理 3. 金额校验 4. 超时处理

tasks.md

# 支付系统任务 ## 阶段 1:基础设施 - [ ] 创建数据库迁移 - [ ] 定义数据模型 - [ ] 创建基础 API 路由 ## 阶段 2:订单模块 - [ ] 实现订单创建 API - [ ] 实现订单查询 API - [ ] 编写订单测试 ## 阶段 3:支付模块 - [ ] 集成微信支付 SDK - [ ] 集成支付宝 SDK - [ ] 实现支付发起 API - [ ] 实现支付回调 API - [ ] 编写支付测试 ## 阶段 4:前端 - [ ] 创建订单页面 - [ ] 创建支付页面 - [ ] 创建支付结果页面 ## 阶段 5:集成测试 - [ ] 端到端测试 - [ ] 性能测试 - [ ] 安全测试

阶段 2:Plan(规划)

# 使用 Prometheus 规划师 /start-work # 或直接对话规划 "基于支付系统规格,生成详细的技术实现计划"

阶段 3:Implement(实现)

# 全功率执行 ultrawork # 或标准执行 /opsx-apply add-payment-system

阶段 4:Archive(归档)

/opsx-archive add-payment-system

15. 完整案例:用户登录模块开发

本节提供一个完整的、可执行的案例,展示从需求到上线的全流程。

15.1 需求定义

用户故事

作为用户,我想要通过手机号登录,以便快速访问我的账户。

验收标准

  • 手机号格式验证(中国大陆 11 位,1 开头)
  • 验证码发送(6 位数字,5 分钟有效)
  • 验证码验证
  • 登录成功返回 token
  • 登录失败提示明确

禁止事项

  • 不修改现有邮箱登录逻辑
  • 不添加第三方登录

15.2 规格生成

/opsx-propose add-phone-login

输出

openspec/changes/add-phone-login/ ├── proposal.md ├── design.md └── tasks.md

15.3 测试设计

skill(name="test-driven-development")

测试文件

// tests/auth/phone-login.spec.ts import { describe, test, expect, beforeEach, vi } from 'vitest'; describe('手机号登录', () => { const validPhone = '13800138000'; const validCode = '123456'; beforeEach(() => { vi.clearAllMocks(); }); describe('发送验证码', () => { test('有效手机号发送成功', async () => { const result = await sendVerificationCode(validPhone); expect(result.success).toBe(true); expect(result.message).toBe('验证码已发送'); }); test('无效手机号返回错误', async () => { const result = await sendVerificationCode('12345'); expect(result.success).toBe(false); expect(result.error).toBe('手机号格式错误'); }); test('60 秒内重复发送返回错误', async () => { await sendVerificationCode(validPhone); const result = await sendVerificationCode(validPhone); expect(result.success).toBe(false); expect(result.error).toBe('验证码发送过于频繁'); }); }); describe('验证码登录', () => { test('正确验证码登录成功', async () => { await sendVerificationCode(validPhone); const result = await loginWithPhone(validPhone, validCode); expect(result.success).toBe(true); expect(result.token).toBeDefined(); }); test('错误验证码登录失败', async () => { await sendVerificationCode(validPhone); const result = await loginWithPhone(validPhone, '000000'); expect(result.success).toBe(false); expect(result.error).toBe('验证码错误'); }); test('过期验证码登录失败', async () => { await sendVerificationCode(validPhone); // 模拟 6 分钟后 vi.useFakeTimers(); vi.advanceTimersByTime(6 * 60 * 1000); const result = await loginWithPhone(validPhone, validCode); expect(result.success).toBe(false); expect(result.error).toBe('验证码已过期'); vi.useRealTimers(); }); }); });

15.4 代码实现

// src/auth/phone-login.ts import jwt from 'jsonwebtoken'; interface SendCodeResult { success: boolean; message?: string; error?: string; } interface LoginResult { success: boolean; token?: string; error?: string; } // 验证码存储(实际项目用 Redis) const verificationCodes = new Map<string, { code: string; expiresAt: number }>(); const lastSentAt = new Map<string, number>(); // 手机号验证 function isValidPhone(phone: string): boolean { return /^1[3-9]\d{9}$/.test(phone); } // 发送验证码 export async function sendVerificationCode(phone: string): Promise<SendCodeResult> { // 验证手机号 if (!isValidPhone(phone)) { return { success: false, error: '手机号格式错误' }; } // 检查发送频率 const lastSent = lastSentAt.get(phone); if (lastSent && Date.now() - lastSent < 60 * 1000) { return { success: false, error: '验证码发送过于频繁' }; } // 生成验证码 const code = Math.random().toString().slice(2, 8); const expiresAt = Date.now() + 5 * 60 * 1000; // 5 分钟有效 // 存储 verificationCodes.set(phone, { code, expiresAt }); lastSentAt.set(phone, Date.now()); // 发送(实际项目调用短信服务) console.log(`[SMS] 发送验证码 ${code} 到 ${phone}`); return { success: true, message: '验证码已发送' }; } // 验证码登录 export async function loginWithPhone(phone: string, code: string): Promise<LoginResult> { // 验证手机号 if (!isValidPhone(phone)) { return { success: false, error: '手机号格式错误' }; } // 获取存储的验证码 const stored = verificationCodes.get(phone); if (!stored) { return { success: false, error: '请先获取验证码' }; } // 检查是否过期 if (Date.now() > stored.expiresAt) { verificationCodes.delete(phone); return { success: false, error: '验证码已过期' }; } // 验证码校验 if (stored.code !== code) { return { success: false, error: '验证码错误' }; } // 登录成功,清除验证码 verificationCodes.delete(phone); // 生成 token const token = jwt.sign( { phone }, process.env.JWT_SECRET!, { expiresIn: '7d' } ); return { success: true, token }; }

15.5 API 路由

// app/api/auth/send-code/route.ts import { NextRequest, NextResponse } from 'next/server'; import { sendVerificationCode } from '@/auth/phone-login'; export async function POST(request: NextRequest) { const { phone } = await request.json(); const result = await sendVerificationCode(phone); return NextResponse.json(result); }
// app/api/auth/phone-login/route.ts import { NextRequest, NextResponse } from 'next/server'; import { loginWithPhone } from '@/auth/phone-login'; export async function POST(request: NextRequest) { const { phone, code } = await request.json(); const result = await loginWithPhone(phone, code); return NextResponse.json(result); }

15.6 前端页面

// app/login/page.tsx 'use client'; import { useState } from 'react'; import { useRouter } from 'next/navigation'; export default function PhoneLoginPage() { const router = useRouter(); const [phone, setPhone] = useState(''); const [code, setCode] = useState(''); const [countdown, setCountdown] = useState(0); const [loading, setLoading] = useState(false); const [error, setError] = useState(''); // 发送验证码 const handleSendCode = async () => { if (countdown > 0) return; setLoading(true); setError(''); try { const res = await fetch('/api/auth/send-code', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ phone }), }); const data = await res.json(); if (data.success) { // 开始倒计时 setCountdown(60); const timer = setInterval(() => { setCountdown((prev) => { if (prev <= 1) { clearInterval(timer); return 0; } return prev - 1; }); }, 1000); } else { setError(data.error); } } finally { setLoading(false); } }; // 登录 const handleLogin = async () => { setLoading(true); setError(''); try { const res = await fetch('/api/auth/phone-login', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ phone, code }), }); const data = await res.json(); if (data.success) { // 存储 token localStorage.setItem('token', data.token); router.push('/dashboard'); } else { setError(data.error); } } finally { setLoading(false); } }; return ( <div className="min-h-screen flex items-center justify-center bg-gray-50"> <div className="max-w-md w-full space-y-8 p-8 bg-white rounded-lg shadow"> <h2 className="text-2xl font-bold text-center">手机号登录</h2> {error && ( <div className="p-3 text-red-600 bg-red-50 rounded"> {error} </div> )} <div className="space-y-4"> <div> <label htmlFor="phone" className="block text-sm font-medium"> 手机号 </label> <input id="phone" type="tel" value={phone} onChange={(e) => setPhone(e.target.value)} placeholder="请输入手机号" className="mt-1 block w-full px-3 py-2 border rounded-md" /> </div> <div> <label htmlFor="code" className="block text-sm font-medium"> 验证码 </label> <div className="flex gap-2"> <input id="code" type="text" value={code} onChange={(e) => setCode(e.target.value)} placeholder="请输入验证码" className="flex-1 px-3 py-2 border rounded-md" /> <button onClick={handleSendCode} disabled={countdown > 0 || loading} className="px-4 py-2 bg-blue-600 text-white rounded-md disabled:opacity-50" > {countdown > 0 ? `${countdown}s` : '发送验证码'} </button> </div> </div> <button onClick={handleLogin} disabled={loading} className="w-full py-2 bg-blue-600 text-white rounded-md hover:bg-blue-700 disabled:opacity-50" > {loading ? '登录中...' : '登录'} </button> </div> </div> </div> ); }

15.7 验证确认

# 自动化验证 pnpm typecheck # ✓ 类型检查通过 pnpm build # ✓ 构建成功 pnpm lint # ✓ 代码检查通过 pnpm test # ✓ 8 passed # 手动验证 # 1. 打开 http://localhost:3000/login # 2. 输入手机号 13800138000 # 3. 点击发送验证码 # 4. 查看控制台输出的验证码 # 5. 输入验证码 # 6. 点击登录 # 7. 确认跳转到 /dashboard

15.8 归档保存

/opsx-archive add-phone-login # 输出: # 归档到 openspec/changes/archive/2026-03-27-add-phone-login/

第五部分:常见陷阱与解决方案

本章总结 AI 辅助开发中的常见陷阱,帮助你避免踩坑。


16. 测试陷阱

16.1 测试实现细节

问题:测试 CSS 类或内部状态,UI 改变时测试失败。

错误示例

// ❌ 测试 CSS 类 await expect(page.locator('.error-message')).toHaveClass('visible'); // ❌ 测试内部状态 expect(component.state.isLoading).toBe(true);

正确做法

// ✅ 测试用户看到的内容 await expect(page.getByText('登录失败')).toBeVisible(); // ✅ 测试用户可观察的行为 await expect(page.getByRole('alert')).toHaveText('加载中...');

16.2 硬编码等待

问题:使用固定等待时间,测试变慢且不稳定。

错误示例

// ❌ 硬编码等待 await page.waitForTimeout(3000); await page.click('button'); // ❌ 等待固定时间 await new Promise(resolve => setTimeout(resolve, 2000));

正确做法

// ✅ 使用 Playwright 自动等待 await page.click('button'); // ✅ 等待特定条件 await expect(page.getByText('加载完成')).toBeVisible(); // ✅ 等待网络请求完成 await page.waitForLoadState('networkidle');

16.3 脆弱选择器

问题:使用 CSS 类或 XPath,页面结构变化时测试失败。

选择器优先级

1. BEST - Test ID: page.getByTestId('submit-button') 2. GOOD - Role: page.getByRole('button', { name: '提交' }) 3. OK - Label: page.getByLabel('邮箱') 4. AVOID - CSS: page.locator('.btn-primary.submit') 5. NEVER - XPath: page.locator('//div[@class="btn"]')

错误示例

// ❌ 脆弱的 CSS 选择器 page.locator('.btn-primary.submit') page.locator('div.container > form > button:nth-child(3)') // ❌ XPath page.locator('//button[contains(@class, "submit")]')

正确做法

// ✅ Test ID(最稳定) page.getByTestId('submit-button') // ✅ Role(语义化) page.getByRole('button', { name: '提交' }) // ✅ Label(表单元素) page.getByLabel('邮箱') // ✅ Text(文本内容) page.getByText('登录')

16.4 测试间共享状态

问题:测试之间共享状态,导致测试不稳定。

错误示例

// ❌ 全局状态 let user: User; beforeAll(async () => { user = await createUser(); // 所有测试共享 }); test('test1', () => { // 修改 user }); test('test2', () => { // user 可能已被 test1 修改 });

正确做法

// ✅ 每个测试独立状态 beforeEach(async () => { user = await createUser(); // 每个测试前重新创建 }); // ✅ 使用 fixtures test('test1', async ({ page, user }) => { // user 是每个测试独立的 });

16.5 过度 E2E 测试

问题:所有测试都写 E2E,反馈循环慢。

测试金字塔

/\ / \ E2E 测试(慢,少) /----\ / \ 集成测试(中) /--------\ / \ 单元测试(快,多) /------------\

建议

测试类型比例速度适用场景
单元测试70%纯函数、工具类
集成测试20%API、组件交互
E2E 测试10%关键用户流程

17. 代码陷阱

17.1 过度信任 AI 输出

问题:AI 生成的代码 45% 包含 OWASP 安全漏洞。

数据来源:Veracode 2025 研究报告

常见漏洞

漏洞类型占比示例
XSS86%未转义用户输入
SQL 注入72%字符串拼接 SQL
敏感数据泄露45%日志输出密码

解决方案

// ❌ AI 可能生成的危险代码 app.get('/user/:id', (req, res) => { const query = `SELECT * FROM users WHERE id = ${req.params.id}`; db.query(query); }); // ✅ 安全的代码 app.get('/user/:id', (req, res) => { const query = 'SELECT * FROM users WHERE id = ?'; db.query(query, [req.params.id]); });

审查清单

- [ ] 是否有 SQL 注入风险? - [ ] 是否有 XSS 漏洞? - [ ] 敏感数据是否加密? - [ ] 权限检查是否完整? - [ ] 输入验证是否充分?

17.2 认知债务累积

问题:速度提升导致对代码理解下降。

症状

  • 不知道 AI 生成的代码做了什么
  • 无法解释代码的工作原理
  • 修改时不知道从哪里下手

解决方案

  1. 定期停下来理解代码

    # 每完成一个功能,花 5 分钟理解 "请解释这段代码的工作原理"
  2. 不让 AI 完全替代判断

    # 关键决策自己来做 "这里有两个方案,我选择方案 A,因为..."
  3. 保持核心技能练习

    # 偶尔手动写代码 # 不依赖 AI 完成所有工作

17.3 跳过验证

问题:不验证就认为完成,功能实际不工作。

强制规则

⚠️ 无验证证据 = 未完成 必须验证: 1. 类型检查:pnpm typecheck 2. 构建验证:pnpm build 3. 代码检查:pnpm lint 4. 测试通过:pnpm test 5. 功能手动验证(最重要)

验证清单

- [ ] 代码通过 lint 检查 - [ ] TypeScript 编译无错误 - [ ] 构建成功 - [ ] 测试全部通过 - [ ] 功能手动验证过 - [ ] 边界情况考虑过 - [ ] 安全风险审查过

18. 流程陷阱

18.1 过度工程

问题:简单任务使用复杂流程,浪费时间。

判断标准

任务复杂度判断: 简单任务特征: ✓ 单文件或少数文件 ✓ 明确的输入输出 ✓ 不涉及架构决策 → 使用 One-Shot 模式 中等任务特征: ✓ 涉及多个模块 ✓ 需要理解现有代码模式 ✓ 有明确的验收标准 → 使用 Plan Mode 复杂任务特征: ✓ 跨多个系统/服务 ✓ 需要架构决策 ✓ 长期维护需求 → 使用 Spec-Driven Development

18.2 中断丢失

问题:任务中断后无法恢复,重复工作。

解决方案

# 查看活跃变更 openspec list --json # 查看活跃 session session_list # 继续执行 /opsx-apply <change-name> # 或使用 session_id 继续 task( session_id="ses_abc123", load_skills=[], description="Continue task", prompt="继续之前的任务...", run_in_background=false )

18.3 规格模糊

问题:规格阶段没有充分澄清,后期返工。

解决方案

/opsx-explore 阶段:

  1. 追问边界情况

    "如果用户输入了无效数据会怎样?" "如果网络请求失败会怎样?" "如果并发访问会怎样?"
  2. 明确验收标准

    ## 验收标准 - [ ] 正常场景:用户输入正确数据,功能正常 - [ ] 异常场景:用户输入错误数据,提示明确 - [ ] 边界场景:用户输入边界值,处理正确
  3. 定义禁止事项

    ## 禁止事项 - 不修改现有登录逻辑 - 不添加第三方登录 - 不存储明文密码

19. 工具陷阱

19.1 MCP 配置错误

问题:MCP 工具配置不正确,无法使用。

常见错误

// ❌ 错误:缺少 type 字段 { "mcp": { "playwright-mcp": { "command": ["playwright-mcp"], "enabled": true } } } // ❌ 错误:command 不是数组 { "mcp": { "playwright-mcp": { "command": "playwright-mcp", "enabled": true, "type": "local" } } }

正确配置

// ✅ 正确 { "mcp": { "playwright-mcp": { "command": ["playwright-mcp", "--cdp-endpoint", "http://localhost:9222"], "enabled": true, "type": "local" } } }

19.2 代理调用错误

问题:代理调用语法错误,无法执行。

常见错误

// ❌ 错误:缺少必需参数 task(category="quick") // ❌ 错误:参数名错误 task( type="quick", // 应该是 category skills=[], // 应该是 load_skills desc="Fix bug" // 应该是 description ) // ❌ 错误:run_in_background 不是布尔值 task( category="quick", load_skills=[], description="Fix bug", prompt="...", run_in_background="yes" // 应该是 true/false )

正确调用

// ✅ 正确 task( category="quick", load_skills=[], description="Fix type error", prompt="Fix the TypeScript error in src/utils.ts line 42...", run_in_background=false )

19.3 Session 恢复问题

问题:session_id 无效或过期,无法恢复。

解决方案

# 查看所有 session session_list # 搜索 session 内容 session_search(query="认证实现") # 读取 session 历史 session_read(session_id="ses_abc123")

注意事项

  • session_id 区分大小写
  • session 可能过期(取决于配置)
  • 建议及时保存重要信息

第六部分:FAQ

本章回答 AI 辅助开发中的常见问题。


20. 入门问题

Q1:我是 AI 开发新手,应该从哪里开始?

A:按以下步骤开始:

第 1 步 → 安装 OpenCode opencode --version 第 2 步 → 完成第一个简单任务 "请解释这个项目的技术栈" 第 3 步 → 尝试修改代码 "把按钮文案改成中文" 第 4 步 → 学习验证流程 pnpm typecheck && pnpm build 第 5 步 → 根据需要学习进阶内容

Q2:AI 生成的代码可以直接用吗?

A:**不可以!**必须审查:

检查项说明
逻辑正确性是否真正解决了问题?
边界情况是否处理了异常输入?
安全性是否有注入、泄露风险?
性能是否有不必要的复杂度?
可维护性代码是否容易理解?
Warning

研究表明,AI 生成的代码中 45% 包含 OWASP 安全漏洞

Q3:什么时候需要写测试?

A:判断标准:

改动影响 < 10 行代码 → 可以不写测试 改动影响 10-50 行代码 → 建议写测试 改动影响 > 50 行代码 → 必须写测试 涉及核心业务逻辑 → 必须写测试 涉及支付/认证 → 必须 TDD + 人工审查

Q4:AI 不理解我的需求怎么办?

A:优化你的描述方式:

  1. 使用更具体的语言

    ❌ "登录后进入主页" ✅ "点击登录按钮后跳转到 /dashboard"
  2. 提供示例

    ❌ "做一个登录页面" ✅ "类似微信的登录页面,有手机号输入框和验证码按钮"
  3. 明确边界

    ❌ "密码不能太短" ✅ "密码长度 6-20 位,必须包含数字和字母"
  4. 分步骤描述

    ❌ "做一个完整的用户系统" ✅ "第一步:用户注册;第二步:用户登录;第三步:密码重置"

Q5:如何避免 AI 生成不安全的代码?

A:遵循以下原则:

  1. 安全相关代码必须人工审查
  2. 使用安全检查清单
    - [ ] 是否有 SQL 注入风险? - [ ] 是否有 XSS 漏洞? - [ ] 敏感数据是否加密? - [ ] 权限检查是否完整?
  3. 使用静态分析工具pnpm lint 可以发现部分问题

21. 工具使用问题

Q6:如何选择正确的 MCP 工具?

A:根据场景选择:

开发新功能 / E2E 测试 → Playwright MCP 性能分析 / 问题诊断 → Chrome DevTools MCP 已登录场景 / 真实环境 → Real Browser MCP

Q7:MCP 工具启动失败怎么办?

A:检查以下项:

  1. 是否正确安装

    npm list -g @playwright/mcp@latest
  2. 配置是否正确

    { "mcp": { "playwright-mcp": { "command": ["playwright-mcp"], "enabled": true, "type": "local" } } }
  3. 端口是否被占用

    lsof -i :9222

Q8:如何查看当前有哪些活跃的变更?

A:使用以下命令:

# 查看活跃变更 openspec list --json # 或 /opsx-apply # 不指定名称时会提示选择

Q9:如何继续之前中断的任务?

A:两种方式:

# 方式 1:继续执行变更 /opsx-apply <change-name> # 方式 2:使用 session_id task( session_id="ses_abc123", load_skills=[], description="Continue task", prompt="继续之前的任务...", run_in_background=false )

Q10:如何获取 session_id?

A:每次调用 task() 后,返回结果中会包含 session_id

// task() 返回结果示例 { "session_id": "ses_abc123", "status": "completed", ... }

22. 流程问题

Q11:什么时候使用 TDD?

A

✅ 推荐使用: - 核心业务逻辑 - 支付、认证等高风险模块 - 复杂算法实现 - 需要长期维护的代码 ❌ 可跳过: - UI/UX 密集型代码 - 快速原型验证 - 一次性脚本 - 配置文件修改

Q12:什么时候使用多代理?

A:仅在以下情况:

  • 任务高度开放,路径不可预测
  • 需要不同专业领域的处理
  • 有明确的成功标准和反馈机制

优先尝试的简化方案

  • 单代理 + 多工具
  • Prompt Chaining
  • Plan-and-Execute

Q13:规格文档写错了怎么办?

A:直接编辑 openspec/changes/<name>/ 下的文件,然后继续执行。

Q14:执行过程中发现设计有问题?

A

  1. 暂停执行(直接告诉 AI)
  2. 进入 /opsx-explore 重新讨论
  3. 更新规格文档
  4. 继续 /opsx-apply

Q15:测试一直失败怎么办?

A

  1. 使用 skill(name="systematic-debugging") 进行系统化调试
  2. 检查测试是否正确描述了预期行为
  3. 必要时咨询 oracle 子代理

22. CI/CD 集成方案

22.1 Playwright 测试 CI 配置

GitHub Actions 配置示例

# .github/workflows/playwright.yml name: Playwright Tests on: push: branches: [main, develop] pull_request: branches: [main] jobs: test: timeout-minutes: 60 runs-on: ubuntu-latest strategy: matrix: shard: [1/4, 2/4, 3/4, 4/4] steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' cache: 'npm' - name: Install dependencies run: npm ci - name: Install Playwright Browsers run: npx playwright install --with-deps - name: Run Playwright tests run: npx playwright test --shard=${{ matrix.shard }} - name: Upload test results if: always() uses: actions/upload-artifact@v4 with: name: playwright-report-${{ matrix.shard }} path: playwright-report/ retention-days: 30 merge-reports: needs: test runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/setup-node@v4 with: node-version: '20' - name: Download artifacts uses: actions/download-artifact@v4 with: path: all-blob-reports - name: Merge reports run: npx playwright merge-reports --reporter html ./all-blob-reports - name: Upload merged report uses: actions/upload-artifact@v4 with: name: playwright-report path: playwright-report/ retention-days: 30

22.2 Playwright 配置文件

// playwright.config.ts import { defineConfig } from '@playwright/test'; export default defineConfig({ testDir: './tests/e2e', fullyParallel: true, // CI 环境感知 forbidOnly: !!process.env.CI, retries: process.env.CI ? 2 : 0, workers: process.env.CI ? '50%' : undefined, reporter: process.env.CI ? 'blob' : 'html', use: { trace: 'on-first-retry', screenshot: 'only-on-failure', video: 'retain-on-failure', baseURL: process.env.BASE_URL || 'http://localhost:3000', }, projects: [ { name: 'chromium', use: { browserName: 'chromium' }, }, ], // 本地开发时自动启动服务器 webServer: process.env.CI ? undefined : { command: 'pnpm dev', url: 'http://localhost:3000', reuseExistingServer: true, }, });

22.3 测试目录结构

tests/ ├── e2e/ # E2E 测试(按功能组织) │ ├── auth/ │ │ ├── login.spec.ts │ │ └── signup.spec.ts │ ├── checkout/ │ │ └── checkout.spec.ts │ └── dashboard/ │ └── overview.spec.ts ├── pages/ # Page Object Model │ ├── BasePage.ts │ ├── LoginPage.ts │ └── DashboardPage.ts ├── fixtures/ # 自定义 fixtures │ └── auth.fixture.ts └── utils/ # 共享工具 └── data-factory.ts

22.4 本地验证脚本

// package.json { "scripts": { "test:e2e": "playwright test", "test:e2e:ui": "playwright test --ui", "test:e2e:debug": "playwright test --debug", "test:e2e:report": "playwright show-report" } }

22.5 质量门禁配置

推荐的 CI 质量门禁

# 添加到 CI 工作流 - name: Type check run: pnpm typecheck - name: Lint check run: pnpm lint - name: Build check run: pnpm build - name: Unit tests run: pnpm test - name: E2E tests run: pnpm test:e2e

23. 故障排除

Q16:OpenCode 启动失败

检查项

# 1. 检查安装 opencode --version # 2. 检查 Node.js 版本 node --version # 需要 v18+ # 3. 检查配置文件 cat .ai/.config/opencode/opencode.json # 4. 检查 API Key echo $ANTHROPIC_API_KEY

Q17:构建失败

检查项

# 1. 清理缓存 rm -rf .next node_modules pnpm install # 2. 检查 TypeScript 错误 pnpm typecheck # 3. 检查依赖冲突 pnpm why <package-name>

Q18:测试超时

解决方案

// 增加超时时间 test('my test', async () => { // ... }, { timeout: 30000 }); // 30 秒 // 或全局配置 // playwright.config.ts export default defineConfig({ timeout: 30000, });

Q19:浏览器自动化失败

检查项

# 1. 检查浏览器安装 npx playwright install # 2. 检查 CDP 端口 lsof -i :9222 # 3. 检查 MCP 配置 cat .ai/.config/opencode/opencode.json | grep -A 10 "mcp"

Q20:AI 输出质量下降

原因:长会话导致上下文污染。

解决方案

# 1. 清理会话 /clear # 2. 开始新会话 /exit opencode # 3. 使用 session_id 继续相关工作 task(session_id="ses_abc123", ...)

附录


A. 核心命令速查卡

OpenCode 命令

命令用途
opencode启动交互模式
opencode "prompt"单次执行
/clear清理会话
/exit退出

OpenSpec 命令

命令简写用途
/openspec-propose/opsx-propose创建规格
/openspec-explore/opsx-explore需求探索
/openspec-apply-change/opsx-apply执行实现
/openspec-archive-change/opsx-archive归档保存

Superpowers 技能

技能触发方式作用
brainstormingskill(name="brainstorming")创建功能前的意图探索
test-driven-developmentskill(name="test-driven-development")编码前的测试先行
systematic-debuggingskill(name="systematic-debugging")系统化调试
verification-before-completionskill(name="verification-before-completion")完成前的验证证据

Playwright AI Agents

Agent命令用途
@planner@planner 为登录流程生成测试计划生成测试计划
@generator@generator 将测试计划转换为测试生成测试代码
@healer@healer 修复失败的测试修复失败测试

代理调用

// 使用 category task( category="quick", load_skills=[], description="Fix type error", prompt="Fix the TypeScript error...", run_in_background=false ) // 使用 subagent_type task( subagent_type="explore", load_skills=[], description="Find auth patterns", prompt="搜索认证实现模式...", run_in_background=true ) // 继续之前的 session task( session_id="ses_abc123", load_skills=[], description="Continue task", prompt="继续之前的任务...", run_in_background=false )

B. 验证清单

基础验证

- [ ] 类型检查: pnpm typecheck - [ ] 构建成功: pnpm build - [ ] 代码检查: pnpm lint - [ ] 测试通过: pnpm test

完整验证

- [ ] 代码通过 lint 检查 - [ ] TypeScript 编译无错误 - [ ] 构建成功 - [ ] 测试全部通过 - [ ] 功能手动验证过 - [ ] 边界情况考虑过 - [ ] 安全风险审查过

AI 代码审查

- [ ] 逻辑正确性:是否真正解决了问题? - [ ] 边界情况:是否处理了异常输入? - [ ] 安全性:是否有注入、泄露风险? - [ ] 性能:是否有不必要的复杂度? - [ ] 可维护性:代码是否容易理解?

安全检查

- [ ] 是否有 SQL 注入风险? - [ ] 是否有 XSS 漏洞? - [ ] 敏感数据是否加密? - [ ] 权限检查是否完整? - [ ] 输入验证是否充分?

C. 行业数据参考

AI 编程工具现状(2025-2026)

指标数据来源
AI 工具使用率84%Stack Overflow 2025
高度信任 AI 输出仅 3%Stack Overflow 2025
不信任 AI 准确性46%Stack Overflow 2025
AI 代码漏洞率2.74x 于人工Veracode 2025
含 OWASP 漏洞45%Veracode 2025
XSS 漏洞失败率86%Veracode 2025
Java 安全失败率72%Veracode 2025
连续任务成功率下降80% → 38%USC 研究
实际速度变化可能慢 19%METR RCT

关键结论

  1. AI 是乘数,不是自动提升器:高级工程师获益更多
  2. 信任与实际存在差距:感觉更快 ≠ 实际更快
  3. 安全性需要额外关注:AI 代码漏洞率显著更高
  4. 简单模式通常足够:Anthropic 官方验证

TDD 效果数据

研究发现
Damm (2016)88% 研究显示外部质量提升
IEEE 元分析对质量有小正面影响
工业环境质量提升 40-90%,开发时间增加 15-35%

D. 参考资料

官方文档

技能文档

最佳实践

研究报告


E. 术语表

术语全称解释
TDDTest-Driven Development测试驱动开发,先写测试再写代码
MCPModel Context ProtocolAI 工具协议,让 AI 操作浏览器等工具
CDPChrome DevTools ProtocolChrome 调试协议
E2EEnd-to-End端到端测试
SDDSpec-Driven Development规格驱动开发
OWASPOpen Web Application Security Project开放式 Web 应用安全项目
JWTJSON Web TokenJSON 网络令牌
RSCReact Server ComponentsReact 服务端组件

F. 更新日志

v2.0.0 (2026-03-27)

新增

  • 完整的工具生态介绍(OpenCode、OpenSpec、Superpowers、MCP)
  • 19 个项目技能详细指南
  • 完整可执行的工作流程示例
  • 扩展的 FAQ(20 个问题)
  • 行业数据参考

改进

  • 重新组织文档结构(六大部分)
  • 增加更多代码示例
  • 添加 Mermaid 流程图
  • 补充故障排除指南

基于

  • work-flow-1~5.md
  • 项目技能文档
  • OpenCode/Superpowers/OpenSpec 官方文档

Tip

记住这三句话

  1. 人做决策,AI 做执行 — 你是决策者,AI 是执行者
  2. 无证据不完成 — 没有验证就没有完成
  3. AI 代码必须审查 — 45% 的 AI 代码有安全漏洞

祝你与 AI 协作愉快!

Last updated on