第 6 章

Cursor Composer 实战——多文件编辑、大型功能开发的完整工作流

第6章:Cursor Composer 实战——多文件编辑、大型功能开发的完整工作流

Composer 是 Cursor 和其他 AI 编辑器最大的区别:你描述一个功能,它同时修改 5-10 个文件,展示完整的 diff,你审查后一键应用。这不是补全,是协作开发。本章讲 Composer 的工作原理、三个必须掌握的技巧,以及一个从零添加 Stripe 支付的完整实战案例。

Chat vs Composer:什么时候用哪个

维度 Cursor Chat Cursor Composer
主要用途 理解、讨论、获取建议 直接生成和修改代码
代码修改 需要手动复制粘贴 自动 diff,一键应用
文件范围 单文件讨论为主 跨多文件协调修改
适合任务 问"为什么"、学习原理 做"是什么"、实现功能
上下文控制 @ 引用精确控制 自动分析项目结构

决策规则:需要修改代码时,用 Composer;只需要理解代码时,用 Chat。

Composer 的内部工作流程

当你在 Composer 里提交一个 Prompt,背后发生了这些步骤:

  1. 项目分析:Cursor 扫描项目结构,建立文件依赖图
  2. 语义搜索:在向量索引里找到与你描述相关的文件
  3. 上下文组装:把相关文件内容、.cursorrules 规则、你的 Prompt 组合成一个超长 context
  4. 生成计划:AI 先规划要修改哪些文件、添加什么内容
  5. 生成代码:按计划逐文件生成修改内容
  6. 展示 Diff:用类似 git diff 的界面展示所有改动,你可以逐文件审查

关键的是步骤 6:你在应用之前能看到所有改动。这是 Composer 和"直接帮我写"最重要的区别——AI 是建议者,你是决策者。

三个必须掌握的 Composer 技巧

技巧一:用 Checkpoint 分阶段提交

不要用一个 Prompt 让 Composer 实现整个功能。按逻辑阶段拆分:

# 第一轮 Prompt(数据层)
在 Prisma schema 里添加 Payment 模型,字段包括:
- id: UUID 主键
- userId: 外键关联 User
- amount: Integer(用整数存分,不用浮点数存元)
- currency: String(默认 "USD")
- status: Enum(pending / completed / failed)
- stripePaymentIntentId: String(可为空)
- createdAt: DateTime

生成对应的 migration 文件,不要修改其他任何文件。

第一轮应用完,测试数据库 migration 是否成功,再开第二轮:

# 第二轮 Prompt(服务层)
基于刚才创建的 Payment 模型,创建 PaymentService:
- createPaymentIntent(userId, amount, currency): 调用 Stripe API 创建支付意图
- confirmPayment(paymentIntentId): 在 Webhook 里确认支付成功,更新数据库状态
- getUserPayments(userId): 查询用户的支付历史

使用 @src/lib/stripe.ts 里已有的 Stripe 客户端实例,不要重新初始化。

分阶段的好处:每一步都能测试和验证,哪一步出问题很容易定位,不会出现"改了50个文件但不知道哪里改坏了"。

技巧二:用 Agent 模式处理不确定的大型任务

点击 Composer 里的 "Agent" 按钮,Cursor 会进入自主执行模式:读取文件、运行命令、自己决定下一步。适合"帮我完成这个大型重构"这类任务。

Agent 模式的典型 Prompt:

分析整个项目的错误处理方式,然后统一改成这个标准:
1. 所有 API 错误返回 { success: false, error: { code, message } } 格式
2. 服务层抛出自定义 AppError 类(已在 src/errors.ts 定义)
3. 路由层统一 catch 并格式化返回

先列出计划再执行,每改完一个模块就说明做了什么。

Agent 模式注意: 它会真正执行命令,包括可能的文件删除。开始前确保 git 状态干净,方便出问题时回滚。

技巧三:审查 Diff 的正确方式

Composer 展示 diff 时,不要直接点"Accept All"。正确的审查流程:

  1. 先看文件列表:有没有不该被修改的文件被改了?
  2. 重点看新增的外部调用:新引入了哪些库、哪些 API?是否符合项目规范?
  3. 检查边界情况:错误处理是否完整?空值、零值、超长输入怎么处理?
  4. 验证约束条件:你在 Prompt 里要求的约束(不改接口、保持测试通过),AI 是否都遵守了?

实战案例:添加 Stripe 支付(两轮 Composer)

目标:给现有的 Next.js + Prisma 项目添加 Stripe 一次性支付功能。

第一轮:数据模型和服务层

给项目添加 Stripe 支付功能,第一阶段:基础设施

1. 在 prisma/schema.prisma 里添加 Payment 模型:
   - id, userId(FK), amount(Int,分), currency(String), 
     status(Enum:pending/completed/failed), 
     stripePaymentIntentId(String?), createdAt

2. 创建 src/lib/stripe.ts:初始化 Stripe 客户端(使用 STRIPE_SECRET_KEY 环境变量)

3. 创建 src/services/PaymentService.ts:
   - createPaymentIntent(userId: string, amount: number): Promise<{clientSecret: string, paymentId: string}>
   - confirmPayment(stripePaymentIntentId: string): Promise<void>

只做这三件事,不要碰路由和前端。

第二轮:API 路由和 Webhook

基于上一步的 PaymentService,完成支付功能的第二阶段:

1. POST /api/payments/create-intent:
   - 验证用户登录(用 src/lib/auth.ts 里的 getCurrentUser)
   - 调用 PaymentService.createPaymentIntent
   - 返回 clientSecret 给前端

2. POST /api/webhooks/stripe:
   - 验证 Stripe Webhook 签名(用 stripe.webhooks.constructEvent)
   - 处理 payment_intent.succeeded 事件,调用 PaymentService.confirmPayment
   - 注意:这个路由必须用 req.text() 不能用 req.json()(Stripe 签名需要原始 body)
   
不要创建前端组件,只做后端 API。

两轮完成后,支付后端功能就完整了,整个过程清晰可控。

5 个常见失败模式

失败模式 症状 解决方法
Prompt 太模糊 生成了一堆看起来合理但不符合项目风格的代码 加具体约束:使用哪个库、遵循哪个已有文件的风格
一次要求太多 改了几十个文件,不知道哪里改坏了 拆成小阶段,每次只做一件事
没有 .cursorrules AI 不知道项目约定,每次生成风格不一致 先写 .cursorrules,把技术栈和规范写进去
不审查直接 Accept 发现问题时已经难以追溯是哪轮改坏的 每次 Accept 前认真看 diff
Agent 模式失控 Agent 修改了不该修改的文件,删除了重要内容 开始前 git commit,出问题用 git checkout 回滚

本章要点

  1. Composer 适合"做功能",Chat 适合"理解代码"——搞清楚边界,工具才能发挥价值
  2. 分阶段 Checkpoint 是关键:一个大功能拆成 3-5 个 Prompt,每轮验证再进行下一轮,远比一次提交靠谱
  3. Agent 模式是双刃剑:强大但有风险,使用前确保 git 状态干净,使用中实时监控它在做什么
  4. Diff 审查不是形式:重点看新增的外部调用、边界情况处理、约束条件是否遵守
  5. .cursorrules 是 Composer 的前置投资:没有 .cursorrules,Composer 每次生成的代码风格会漂移
本章评分
4.7  / 5  (51 评分)

💬 留言讨论