一、Cursor 的三大核心交互模式
Cursor 有三种和 AI 交互的方式,分别对应三种不同的使用场景:
| 模式 | 快捷键(Mac) | 快捷键(Win) | 适合做什么 |
|---|---|---|---|
| Chat | Cmd+L |
Ctrl+L |
问问题、理解代码、跨文件分析 |
| Edit | Cmd+K |
Ctrl+K |
就地修改某段代码 |
| Agent | Cmd+I |
Ctrl+I |
自动完成多步骤任务、创建多个文件 |
三个模式不是替代关系,是互补的,实际开发中会混合使用。
二、Chat 模式详解
什么时候用 Chat
- 看不懂一段代码,想让 AI 解释
- 想知道某个问题有没有更好的写法
- 需要 AI 结合多个文件来分析或回答
- 讨论技术方案,还没到写代码那一步
打开方式
按 Cmd+L,右侧出现 Chat 侧边栏。
三种上下文引用方式
① 引用文件:**@文件名**
在 Chat 输入框里输入 @,会弹出文件选择器,选中文件后,AI 会读取该文件内容作为上下文。
@user.service.ts 这个文件的 findAll 方法有没有性能问题?
② 引用目录:**@目录名**
引用整个目录,AI 会读取目录下所有文件。适合分析一个完整模块。
@src/modules/user 这个模块的整体代码结构有什么可以改进的地方?
③ 引用选中代码
在编辑器里选中一段代码,按 Cmd+L,选中的代码会自动附加到 Chat 里。
(选中 findOne 方法后按 Cmd+L)
这个方法用 == 做比较,有什么问题?
AI 回答的语言
AI 会跟随你提问的语言。用中文问就用中文答,用英文问就用英文答。
Chat 的上下文限制
一个 Chat 会话有 Token 上限。对话轮次多了之后,早期的上下文会被截断。遇到这种情况,点 Chat 顶部的「+」新建一个 Chat,从头给 AI 必要的上下文。
三、Edit 模式详解
什么时候用 Edit
- 想修改某个方法,加功能、改逻辑、修 Bug
- 想对某段代码做风格改进(加类型、加注释、改命名)
- 改动范围明确,就是这一段代码
打开方式
光标放在要修改的代码附近,按 Cmd+K,弹出行内输入框。
Edit 的 Diff 工作流
- 按
Cmd+K打开输入框 - 输入修改意图,按 Enter
- AI 生成 Diff(绿色 = 新增,红色 = 删除)
- 按
Tab接受修改,或按Esc拒绝
关键原则:Edit 是非破坏性的。AI 的修改只是建议,你看完 Diff 再决定要不要接受,按 Esc 代码完全回到原样。
控制 Edit 的修改范围
- 只改光标所在行附近:直接按
Cmd+K - 改整个文件:先
Cmd+A全选,再按Cmd+K - 改选中的几行:先鼠标选中,再按
Cmd+K
建议:每次 Edit 范围不要太大,改一个方法、一个函数,改完确认没问题再改下一处。范围越小,Diff 越容易审查。
Edit Prompt 的写法技巧
模糊 Prompt(效果差)
改一下这个方法
精确 Prompt(效果好)
给这个方法加上参数校验:price 不能为负数,如果为负抛出 BadRequestException;
同时把 data: any 改成 CreateProductDto 类型
精确 Prompt 的要素:
- 说清楚改什么(加参数校验)
- 说清楚约束(price 不能为负)
- 说清楚用什么实现(BadRequestException)
- 说清楚类型(CreateProductDto)
四、Agent 模式详解
什么时候用 Agent
- 从零搭建一个新模块(需要创建多个文件)
- 执行一个有多个步骤的任务
- 需要 AI 自己分析、决策、执行,不需要每步都确认
打开方式
按 Cmd+I 打开 Composer,或者在 Chat 里切换到 Agent 模式(输入框下方有切换按钮)。
Agent 的执行过程
Agent 接到任务后会自动:
- 分析项目结构,理解现有代码
- 制定执行计划
- 依次创建/修改文件
- 执行必要的命令(如
npm install) - 汇报完成结果
整个过程在左侧文件变动区域和终端里可以实时看到,不是黑盒。
Agent 中途干预
Agent 执行过程中可以随时追加要求:
等一下,Category 还需要一个 parentId 字段,支持多级分类
Agent 会把新要求纳入当前任务继续执行。
Agent 任务 Prompt 的写法
Agent 的 Prompt 比 Chat 和 Edit 需要更详细,因为它要自主做多个决策:
不够详细的 Prompt
创建一个分类模块
详细的 Prompt
在当前 NestJS 项目里创建 CategoryModule,要求:
1. 使用 Prisma ORM
2. Category 字段:id, name, description, parentId(支持多级分类), createdAt
3. 完整的 CRUD 接口
4. Controller 加 Swagger 注解(@ApiTags、@ApiOperation)
5. 在 app.module.ts 里注册这个模块
6. 不需要生成测试文件
越具体的 Prompt,Agent 需要做的"自我决策"越少,结果越符合预期。
Agent 完成后必须审查
Agent 生成完代码后,不能直接用,要逐文件检查:
- 字段是否和需求一致
- 关键逻辑是否正确(软删除、权限校验、事务等)
- 有没有引入不需要的依赖或文件
app.module.ts里有没有正确注册
五、三大模式的选择逻辑
你想做的事情是什么?
│
├── 理解代码 / 问问题 / 讨论方案
│ └── 用 Chat(Cmd+L)
│
├── 修改一段已有的代码
│ └── 用 Edit(Cmd+K)
│
└── 完成一个完整任务(创建模块 / 多步操作)
└── 用 Agent(Cmd+I)
实际工作里的典型组合:
- 先用 Chat 理解现有代码结构
- 再用 Agent 生成新模块
- 审查完之后用 Edit 修正个别问题
六、其他常用快捷键
| 功能 | Mac | Windows |
|---|---|---|
| 接受 AI 建议 | Tab |
Tab |
| 拒绝 AI 建议 | Esc |
Esc |
| 新建 Chat | Chat 顶部「+」 | 同左 |
| 打开命令面板 | Cmd+Shift+P |
Ctrl+Shift+P |
| 打开文件 | Cmd+P |
Ctrl+P |
| 切换终端 | Cmd+J |
Ctrl+J |
七、演示操作步骤
准备工作
Step 1:初始化演示项目
npx @nestjs/cli new cursor-demo
cd cursor-demo
npm install
npm run start:dev # 确认项目能正常启动
Step 2:用 Cursor 打开项目
cursor cursor-demo
Step 3:Settings 里确认配置
Cmd+,打开 Settings- Editor: Font Size →
16 - AI 模型 → 右下角切换为
claude-sonnet-4
Step 4:在 src/ 下新建演示文件 product/product.service.ts,写入以下内容(故意写有问题,用于 Edit 模式演示):
import { Injectable } from '@nestjs/common'
@Injectable()
export class ProductService {
private products = []
create(data) {
const product = { id: Date.now(), ...data }
this.products.push(product)
return product
}
findAll() {
return this.products
}
findOne(id) {
return this.products.find((p) => p.id == id)
}
update(id, data) {
const index = this.products.findIndex((p) => p.id == id)
if (index > -1) {
this.products[index] = { ...this.products[index], ...data }
}
return this.products[index]
}
remove(id) {
this.products = this.products.filter((p) => p.id != id)
}
}
同时新建 product/product.entity.ts:
import {
Entity,
Column,
PrimaryGeneratedColumn,
CreateDateColumn,
} from 'typeorm'
@Entity()
export class Product {
@PrimaryGeneratedColumn()
id: number
@Column()
name: string
@Column('decimal', { precision: 10, scale: 2 })
price: number
@Column({ default: 0 })
stock: number
@CreateDateColumn()
createdAt: Date
}
Chat 模式演示
Step 1:打开 product.entity.ts,按 Cmd+L 打开 Chat
Step 2:输入以下内容,发送:
@product.entity.ts 解释这个文件里每个装饰器的作用
观察 AI 基于文件内容给出的解释。
Step 3:演示跨文件引用,在 Chat 里输入:
@product.entity.ts @product.service.ts
对比这两个文件,service 层有哪些地方和 entity 不一致?
观察 AI 跨两个文件的分析结果。
Step 4:演示选中代码引用。在编辑器里选中 product.service.ts 的 findOne 方法,按 Cmd+L,在 Chat 里输入:
这个方法用了 ==,有什么潜在问题?
Edit 模式演示
Step 1:打开 product.service.ts,光标放在 create 方法里,按 Cmd+K
Step 2:在弹出的输入框里输入:
给这个方法加上 TypeScript 类型,data 参数改为 CreateProductDto 类型,
price 不能为负数,如果 price < 0 抛出 BadRequestException
Step 3:等待 AI 生成 Diff,检查 Diff 内容:
- 是否加了
CreateProductDto类型 - 是否有
if (price < 0) throw new BadRequestException(...) - 是否引入了
BadRequestException
Step 4:按 Tab 接受修改
Step 5:演示拒绝流程。选中 findOne 方法,按 Cmd+K,输入:
用严格等号 === 替换 ==,参数 id 改为 number 类型,找不到时抛出 NotFoundException
生成 Diff 后,先按 Esc 拒绝,展示代码回到原样。再重新 Cmd+K 接受一次,展示完整的接受流程。
Agent 模式演示
Step 1:按 Cmd+I 打开 Agent(Composer)
Step 2:输入以下任务:
在当前 cursor-demo 项目里,新增一个 CategoryModule(商品分类模块):
1. 使用 TypeORM
2. Category 字段:id, name, description, createdAt
3. 完整的 CRUD 接口
4. Controller 加 Swagger 注解(@ApiTags、@ApiOperation)
5. 在 app.module.ts 里注册这个模块
6. 不需要生成测试文件
Step 3:观察 Agent 执行过程中左侧文件树的变化,记录它创建了哪些文件。
Step 4:Agent 完成后,逐文件审查:
需要检查的文件:
├── src/category/category.entity.ts → 字段是否正确
├── src/category/category.service.ts → CRUD 逻辑是否完整
├── src/category/category.controller.ts → Swagger 注解是否有
├── src/category/category.module.ts → 模块定义是否正确
└── src/app.module.ts → CategoryModule 是否已注册
Step 5:运行项目验证:
npm run start:dev
如果报错,把错误信息贴到 Chat 里,输入:
运行报了这个错误:[粘贴错误信息],帮我修复
Step 6:验证成功后,在浏览器打开 http://localhost:3000/api,确认 Swagger 文档里出现了 Category 相关的接口。
Spec Coding 实战补充:03 Cursor 快速上手
来源:
Spec Coding实战/03 Cursor 快速上手.md,已合并到本章节。
1. Cursor 是什么
Cursor 是一个基于 VS Code 深度改造的代码编辑器,内置了 AI 能力。和在 VS Code 里装 Copilot 插件不同——Cursor 把 AI 从"辅助工具"变成了"核心能力",整个编辑器的交互逻辑都围绕 AI 设计。
底层模型可以选 Claude(Anthropic)、GPT-4o(OpenAI)或 Cursor 自研模型。对于 NestJS 后端开发,Claude 3.5 Sonnet / Claude 3.7 Sonnet 是目前最好的选择——对 TypeScript、装饰器语法、依赖注入的理解最准确。
和 Copilot 的核心区别
| 能力 | GitHub Copilot | Cursor |
|---|---|---|
| 行内补全 | ✅ | ✅ |
| 对话式生成 | 有限 | ✅ 核心功能 |
| 感知整个项目 | ❌ | ✅ @Codebase |
| 读取本地文件 | ❌ | ✅ @文件/@文件夹 |
| 多文件同时修改 | ❌ | ✅ Composer/Agent |
| 自定义规则 | ❌ | ✅ .cursorrules |
2. 安装与基础配置
安装
下载对应系统的安装包,安装后直接导入你的 VS Code 配置(主题、快捷键、插件)——迁移成本几乎为零。
首次配置
选择模型
进入 Cursor Settings → Models,推荐配置:
主力模型:claude-3-5-sonnet(或 claude-3-7-sonnet)
快速模型(补全):cursor-small 或 gpt-4o-mini
设置 API Key(可选)
Cursor 有自己的订阅套餐(Pro $20/月),包含一定量的 Claude / GPT 调用额度。如果你有自己的 Anthropic API Key,也可以在设置里填入,走自己的额度。
关闭不需要的功能
Cursor Settings → Features:
- Auto Import:开
- Auto Scroll:看个人习惯
- Show Suggested Files:开(Agent 模式很有用)
3. 三大核心功能
3.1 Chat(对话)
快捷键:Cmd/Ctrl + L
打开右侧 Chat 面板,这是你和 AI 最主要的对话窗口。
Chat 的几个关键特性
上下文引用:输入 @ 可以引用文件、文件夹、代码符号、文档等。
@src/modules/user/user.service.ts 这个 service 的 findAll 方法
为什么在数据量大时会慢?帮我优化一下
@spec/user.md 按照这份规格,帮我生成 UserModule 的完整实现
包括 Controller、Service、DTO 和 Module 文件
Apply 按钮:AI 给出代码建议后,点 Apply,Cursor 会自动把代码变更应用到对应文件,不需要你手动复制粘贴。
多轮对话:Chat 保留对话历史,同一个任务可以持续追问。
我:帮我实现 UserService.create 方法,按照 @spec/user.md
AI:[给出实现]
我:密码加密的 rounds 改成从配置文件读取,不要硬编码
AI:[修改对应部分]
我:加一个单元测试
AI:[生成测试]
3.2 Edit / Inline Edit(内联编辑)
快捷键:Cmd/Ctrl + K
在编辑器里直接选中一段代码,按 Cmd+K,弹出输入框,AI 直接在原位修改代码。
适合的场景
- 重构一个函数
- 修改一段逻辑
- 给现有代码加错误处理
- 把 callback 改成 async/await
示例操作
选中以下代码,按 Cmd+K,输入"加入事务处理,如果发邮件失败不影响用户创建":
// 选中这段
async create(dto: CreateUserDto) {
const hash = await bcrypt.hash(dto.password, 10)
const user = await this.prisma.user.create({ data: { ...dto, password: hash } })
await this.mailService.sendWelcome(user.email)
return user
}
AI 会直接在编辑器里改,改完后高亮显示 diff,你接受或拒绝。
3.3 Composer / Agent(多文件任务)
快捷键:Cmd/Ctrl + Shift + I(Composer)
这是 Cursor 最强的功能,也是真正意义上的"AI Agent"。
Composer 和 Chat 的区别
- Chat:对话 + 辅助修改,主要你来驱动
- Composer(Agent 模式):你给任务,AI 自主规划、读文件、写文件、执行命令
开启 Agent 模式
在 Composer 面板右上角,把模式切换到 Agent。
一个典型的 Agent 任务
按照 @spec/user.md 的规格,在 src/modules/ 下创建完整的 user 模块。
需要包含:
- user.module.ts
- user.controller.ts
- user.service.ts
- dto/create-user.dto.ts
- dto/update-user.dto.ts
- dto/query-user.dto.ts
使用 Prisma 操作数据库,遵循 .cursorrules 的代码风格要求。
Agent 会:
- 读取你引用的文件和规则
- 分析项目结构
- 依次创建多个文件
- 每个文件的内容互相保持一致(模块名、类名、导入路径等)
你在旁边看它操作,有问题随时打断。
4. 常用快捷键
| 操作 | Mac | Windows/Linux |
|---|---|---|
| 打开 Chat | Cmd + L |
Ctrl + L |
| 内联编辑 | Cmd + K |
Ctrl + K |
| 打开 Composer | Cmd + I |
Ctrl + I |
| 接受 AI 建议 | Tab |
Tab |
| 拒绝 AI 建议 | Esc |
Esc |
| 接受文件变更 | Cmd + Y |
Ctrl + Y |
| 拒绝文件变更 | Cmd + N |
Ctrl + N |
| 在 Chat 中引用当前文件 | @然后选 Current File |
同左 |
| 跳转到符号 | Cmd + T |
Ctrl + T |
5. 几个容易忽视的使用技巧
技巧一:告诉 AI 不要解释,直接给代码
默认情况下,AI 生成代码前会写一段解释。对于有经验的开发者,这段解释是浪费时间。
在 .cursorrules 里加:
When generating code, skip explanations unless explicitly asked.
Output code directly without preamble.
或者在每次对话开头加:
直接给代码,不需要解释
技巧二:让 AI 先列计划,再执行
对于复杂任务,先让 AI 描述它打算怎么做:
按照 @spec/user.md 实现用户模块。
先告诉我你打算创建哪些文件、每个文件的职责是什么,
我确认后再开始写代码。
这样你可以在它动手之前纠正方向,比写完再改省力得多。
技巧三:用 @Docs 引用官方文档
Cursor 支持把外部文档添加进来,输入 @Docs 选择已添加的文档。
推荐添加:
- NestJS 文档:https://docs.nestjs.com
- Prisma 文档:https://www.prisma.io/docs
- class-validator 文档
这样 AI 生成 NestJS 代码时,可以参考最新的 API,减少用法过时的问题。
技巧四:Chat 里引用报错信息
直接把终端里的报错贴进 Chat,AI 能很快定位问题:
运行时报这个错:
[Nest] ERROR [ExceptionHandler] Cannot read properties of undefined (reading 'findMany')
at UserService.findAll (user.service.ts:23)
我的 UserService 用了 @InjectPrismaClient(),
看一下 @src/modules/user/user.service.ts 哪里有问题
技巧五:善用 "Restore Checkpoint"
Cursor 在每次 AI 修改之前会自动保存检查点。如果 AI 改乱了,在 Chat 面板点 Restore Checkpoint 可以一键回到修改前的状态,不需要手动 git checkout。
6. 一次完整的 NestJS 接口开发流程(Cursor 实战)
以下是用 Cursor 从零实现一个用户列表接口的完整过程:
第一步:打开 Composer,描述任务
在 src/modules/user/ 下实现用户列表接口:
GET /api/v1/users
参数:page, pageSize, search(模糊匹配 name 和 email)
返回:{ code: 0, message: 'ok', data: { list, total, page, pageSize } }
使用已有的 PrismaService,遵循 @.cursorrules 的代码风格。
参考 @src/modules/product/product.service.ts 的分页写法。
第二步:检查 Agent 生成的文件列表,确认思路对了再执行
第三步:生成完毕后,运行项目
npm run start:dev
第四步:如果有错误,把报错贴回 Chat
启动报错了:
[错误信息]
帮我看看哪里有问题
第五步:用 Insomnia / Postman 测接口,没问题后写测试
帮我给刚才的 UserService.findAll 写单元测试,
覆盖:有 search 参数时、page 超出范围时、无数据时三个场景
整个过程大概 15-20 分钟,手写的话至少要 1 小时。
7. 小结
Cursor 的三个核心功能:
- Chat:引用文件、对话式开发、追问式迭代
- Inline Edit:快速改单段代码,diff 预览
- Agent:给任务、让 AI 规划执行、多文件同时处理
上手门槛不高,但用好它需要一点思维转变:从"AI 帮我补代码"变成"我给 AI 清晰的任务,AI 帮我执行"。
任务描述越清晰,生成质量越高。这就是为什么 spec.md 和 .cursorrules 是 Cursor 工作流的前置条件。