Cursor Agent 端到端开发实战

Cursor 是大多数开发者接触 AI 编程的第一个工具。前面章节讲了 Rules 和 Prompt 的理论,本章进入实战——用 Cursor 的 Agent 模式完成 AI 视频平台的真实开发任务:从简单的组件生成到跨文件重构,从 Bug 修复到完整功能实现。每个案例都展示完整的操作流程、Prompt 写法、Agent 的执行过程,以及需要人工介入的环节。

1. Cursor Agent 工作模式

1.1 三种交互模式

模式快捷键适合场景自主程度
Tab 补全Tab写代码时的实时补全最低,逐行确认
Cmd+K 内联Cmd+K局部修改一个函数/块中等,选区内替换
AgentCmd+L → Agent多步骤、多文件任务最高,自主规划执行

Agent 模式是 Cursor 最强大的能力——你描述目标,Agent 自主决定读哪些文件、改哪些代码、执行什么命令。

1.2 Agent 的执行流程

用户输入 Prompt
  ↓
Agent 分析任务 → 制定计划
  ↓
循环执行:
  ├── 读取文件(理解现有代码)
  ├── 搜索代码库(找到相关文件)
  ├── 编辑文件(生成 diff)
  ├── 执行命令(运行测试/构建)
  ├── 调用 MCP 工具(查数据库等)
  └── 检查结果 → 决定下一步
  ↓
展示所有修改(diff 视图)
  ↓
用户逐个审查 → Accept / Reject

关键点:Agent 的每次文件修改都以 diff 形式展示,你可以逐个接受或拒绝。这是 Cursor 与 Claude Code 最大的区别——Cursor 始终保持人在回路。

2. 实战:创建 API + 前端功能

2.1 场景:添加视频收藏功能

这是一个典型的全栈任务——需要数据库 schema、API 路由、前端 composable 和 UI 组件。

Prompt

给 AI 视频平台添加视频收藏功能:

数据库:
- 创建 favorites schema(packages/database/schema/favorites.ts)
- 字段:id, userId, videoId, createdAt
- userId + videoId 唯一约束

API(server/api/favorites/):
- toggle.post.ts:切换收藏状态(收藏/取消)
- index.get.ts:获取当前用户的收藏列表(分页)
- check.get.ts:检查某视频是否已收藏

Composable:
- composables/useFavorite.ts:封装收藏逻辑,Optimistic UI

组件:
- components/FavoriteButton.vue:收藏按钮(心形图标,已收藏显示实心)

参考 @server/api/videos/[id]/like.post.ts 的风格
参考 @composables/useLike.ts 的 Optimistic UI 模式

2.2 Agent 的执行过程

Agent 接收到这个 Prompt 后,典型的执行过程:

Step 1:读取参考文件

Agent 读取:
- server/api/videos/[id]/like.post.ts(理解 API 风格)
- composables/useLike.ts(理解 Optimistic UI 模式)
- packages/database/schema/likes.ts(理解 schema 风格)

Step 2:创建 schema

// packages/database/schema/favorites.ts
export const favorites = pgTable('favorites', {
  id: text('id').primaryKey().$defaultFn(() => createId()),
  userId: text('user_id').notNull().references(() => users.id),
  videoId: text('video_id').notNull().references(() => videos.id),
  createdAt: timestamp('created_at').defaultNow().notNull(),
}, (table) => ({
  uniqueUserVideo: unique().on(table.userId, table.videoId),
}))

Step 3:创建 API 路由(3 个文件)

Step 4:创建 composable

Step 5:创建 UI 组件

Step 6:运行 typecheck 验证

整个过程 Agent 自动完成,你在最后审查所有 diff。

2.3 审查要点

Agent 生成的代码通常 80-90% 正确,需要关注:

  • 导入是否正确:Nuxt 自动导入的不应该手动 import
  • SSR 安全性:收藏状态初始值来自 useFetch,不是 localStorage
  • 错误处理:toggle API 是否处理了并发场景
  • 类型完整性:返回类型是否与前端 composable 匹配

3. 实战:Cmd+K 局部修改

3.1 场景:给现有组件添加功能

已有 VideoCard.vue 组件,想添加视频时长显示和悬停预览。

操作流程

  1. 打开 VideoCard.vue
  2. 选中整个 <template>
  3. 按 Cmd+K
  4. 输入:
在缩略图右下角添加视频时长显示(格式 mm:ss),
缩略图 hover 时显示前 3 秒的 GIF 预览(从 video.previewUrl 获取)

3.2 Cmd+K 的优势

Cmd+K 适合精确的局部修改

  • 已经知道要改哪个文件、哪个位置
  • 修改范围明确(一个函数、一段模板)
  • 不需要跨文件操作

相比 Agent,Cmd+K 更快(不需要搜索代码库),更可控(只改选中的部分)。

3.3 进阶技巧

链式 Cmd+K:先改 template,再改 script。

第 1 次 Cmd+K(选中 template):
"添加一个搜索框,绑定 searchQuery ref,支持回车搜索和清空"

第 2 次 Cmd+K(选中 script):
"添加 searchQuery ref,watch 它做 300ms 防抖搜索,
调用 /api/search 接口"

4. 实战:代码重构

4.1 场景:拆分过大的组件

VideoPlayer.vue 已经 500 行了,需要拆分。

Prompt

重构 @components/VideoPlayer.vue:

这个组件太大了(500+ 行),请拆分为:

1. components/VideoPlayer.vue(主组件,负责组合)
2. components/player/VideoControls.vue(播放控制栏)
3. components/player/QualitySelector.vue(画质选择)
4. components/player/DanmakuLayer.client.vue(弹幕层)
5. composables/useVideoPlayer.ts(播放器核心逻辑)
6. composables/useVideoHotkeys.ts(快捷键逻辑)

要求:
- 保持 VideoPlayer.vue 的 props/emits 不变(不影响外部调用)
- 子组件通过 provide/inject 或 props 通信
- 弹幕层标记为 .client.vue(只在客户端渲染)

4.2 Agent 重构的执行

Agent 会:

  1. 先读取 VideoPlayer.vue 完整代码
  2. 分析 代码结构,识别可拆分的逻辑块
  3. 逐个创建 新文件,移动对应代码
  4. 修改 VideoPlayer.vue,引入拆分后的子组件
  5. 运行 typecheck 验证类型一致

4.3 审查重点

重构的审查比新功能更需要仔细:

  • 功能完整:拆分后所有原有功能是否保留
  • 状态通信:父子组件之间的数据流是否正确
  • 事件传播:子组件的事件是否正确向上传递
  • SSR 兼容:弹幕层是否正确使用了 .client.vue

5. 上下文引用技巧

5.1 @ 引用体系

Cursor 的 @ 引用是提升 Prompt 质量的关键武器:

引用方式语法用途
文件@filename.ts让 AI 读取特定文件
文件夹@server/api/让 AI 了解目录结构
代码库@codebase语义搜索整个项目
文档@docs引用 Cursor 索引的文档
Git@git引用 Git 历史
Web@web搜索互联网

5.2 最佳实践

引用参考文件

创建 server/api/comments/index.post.ts
参考 @server/api/videos/[id]/like.post.ts 的认证和校验模式

引用类型定义

@packages/shared/types/video.ts 基于这个类型,
创建一个 VideoCard 组件,展示视频的所有信息

引用代码库搜索

@codebase 项目中所有使用 useFetch 的地方都是怎么处理错误的?
帮我统一错误处理模式

引用 Git 变更

@git 上次提交改了什么?帮我检查是否有 SSR 安全问题

5.3 上下文窗口管理

Cursor 的上下文窗口有限。引用太多文件会稀释注意力。原则:

  • 精确引用:只引用直接相关的 2-3 个文件,不要引用整个目录
  • 先搜后引:不确定哪个文件相关时,先让 Agent 用 @codebase 搜索
  • 新会话:长对话后上下文会被历史消息占满,开新会话更高效

6. Bug 修复实战

6.1 场景:SSR Hydration Mismatch

Bug:视频列表页在 SSR 渲染后,客户端 hydration 报错:
"Hydration text content mismatch"

错误出现在 VideoCard 的时间显示上:
- 服务端渲染 "3 分钟前"
- 客户端 hydration 时变成 "4 分钟前"

相关文件:
@components/VideoCard.vue
@composables/useTimeAgo.ts

请分析原因并修复。

6.2 Agent 的调试过程

1. 读取 VideoCard.vue → 找到时间显示逻辑
2. 读取 useTimeAgo.ts → 发现用了 new Date()
3. 分析:SSR 和 CSR 的时间差导致文本不一致
4. 修复方案:
   - 使用 <ClientOnly> 包裹时间显示
   - 或使用 useNuxtApp().ssrContext 统一时间源

6.3 修复后验证

Agent 修复后,你应该:

  1. 检查 diff:确认修复方案合理
  2. 本地测试:刷新页面确认 hydration 错误消失
  3. 边缘情况:检查 SEO 是否受影响(&lt;ClientOnly&gt; 内的内容不会被搜索引擎抓取)

7. 高效使用 Cursor 的习惯

7.1 模式选择决策树

任务类型判断:
├── 写新代码,知道大概怎么写 → Tab 补全
├── 修改一个函数/块 → Cmd+K
├── 探索性问题,想了解代码 → Chat(Cmd+L)
├── 多文件创建/修改 → Agent
└── 复杂重构/全栈功能 → Agent 或 Claude Code

7.2 会话管理

  • 一任务一会话:不要在一个会话里做多个不相关的事
  • 及时开新会话:超过 10 轮对话,上下文已经很拥挤
  • 保存好的 Prompt:把常用的 Prompt 模板存到项目的 .ai/prompts/ 目录

7.3 审查纪律

Agent 的输出不是最终代码——它是初稿

  • 必审:每个 diff 都要看,理解 Agent 做了什么
  • 必测:Agent 不一定运行了测试,手动验证关键功能
  • 必改:Agent 的变量命名、注释质量可能不理想,顺手调整

7.4 与 Claude Code 的协作

不同任务选不同工具:

日常开发流程:
1. Cursor Agent 快速生成代码骨架
2. Cursor Tab/Cmd+K 做细节调整
3. 遇到复杂问题 → 切换到 Claude Code
4. Claude Code 完成后 → 回到 Cursor 审查和微调

本章小结

  • 三种模式:Tab(逐行)→ Cmd+K(局部)→ Agent(多步多文件),按任务复杂度选择
  • 全栈功能:Agent 可以一次生成 schema + API + composable + 组件,审查 diff 后接受
  • 局部修改:Cmd+K 适合精确的单文件修改,链式 Cmd+K 可以分步改 template 和 script
  • 代码重构:明确拆分目标和约束,Agent 自动移动代码并保持类型一致
  • 上下文引用:@ 文件/代码库/Git/Web 是提升 Prompt 质量的关键,精确引用 > 大量引用
  • 审查纪律:Agent 输出是初稿,必审 diff、必测功能、必改细节