返回笔记首页

第 03 集:Cursor 快速上手

主题配置

一、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 会读取该文件内容作为上下文。

plain
@user.service.ts 这个文件的 findAll 方法有没有性能问题?

② 引用目录:**@目录名**

引用整个目录,AI 会读取目录下所有文件。适合分析一个完整模块。

plain
@src/modules/user 这个模块的整体代码结构有什么可以改进的地方?

③ 引用选中代码

在编辑器里选中一段代码,按 Cmd+L,选中的代码会自动附加到 Chat 里。

plain
(选中 findOne 方法后按 Cmd+L)
这个方法用 == 做比较,有什么问题?

AI 回答的语言

AI 会跟随你提问的语言。用中文问就用中文答,用英文问就用英文答。

Chat 的上下文限制

一个 Chat 会话有 Token 上限。对话轮次多了之后,早期的上下文会被截断。遇到这种情况,点 Chat 顶部的「+」新建一个 Chat,从头给 AI 必要的上下文。


三、Edit 模式详解

什么时候用 Edit

  • 想修改某个方法,加功能、改逻辑、修 Bug
  • 想对某段代码做风格改进(加类型、加注释、改命名)
  • 改动范围明确,就是这一段代码

打开方式

光标放在要修改的代码附近,按 Cmd+K,弹出行内输入框。

Edit 的 Diff 工作流

  1. Cmd+K 打开输入框
  2. 输入修改意图,按 Enter
  3. AI 生成 Diff(绿色 = 新增,红色 = 删除)
  4. Tab 接受修改,或按 Esc 拒绝

关键原则:Edit 是非破坏性的。AI 的修改只是建议,你看完 Diff 再决定要不要接受,按 Esc 代码完全回到原样。

控制 Edit 的修改范围

  • 只改光标所在行附近:直接按 Cmd+K
  • 改整个文件:先 Cmd+A 全选,再按 Cmd+K
  • 改选中的几行:先鼠标选中,再按 Cmd+K

建议:每次 Edit 范围不要太大,改一个方法、一个函数,改完确认没问题再改下一处。范围越小,Diff 越容易审查。

Edit Prompt 的写法技巧

模糊 Prompt(效果差)

plain
改一下这个方法
精确 Prompt(效果好)
plain
给这个方法加上参数校验:price 不能为负数,如果为负抛出 BadRequestException;
同时把 data: any 改成 CreateProductDto 类型

精确 Prompt 的要素:

  • 说清楚改什么(加参数校验)
  • 说清楚约束(price 不能为负)
  • 说清楚用什么实现(BadRequestException)
  • 说清楚类型(CreateProductDto)

四、Agent 模式详解

什么时候用 Agent

  • 从零搭建一个新模块(需要创建多个文件)
  • 执行一个有多个步骤的任务
  • 需要 AI 自己分析、决策、执行,不需要每步都确认

打开方式

Cmd+I 打开 Composer,或者在 Chat 里切换到 Agent 模式(输入框下方有切换按钮)。

Agent 的执行过程

Agent 接到任务后会自动:

  1. 分析项目结构,理解现有代码
  2. 制定执行计划
  3. 依次创建/修改文件
  4. 执行必要的命令(如 npm install
  5. 汇报完成结果

整个过程在左侧文件变动区域和终端里可以实时看到,不是黑盒。

Agent 中途干预

Agent 执行过程中可以随时追加要求:

plain
等一下,Category 还需要一个 parentId 字段,支持多级分类

Agent 会把新要求纳入当前任务继续执行。

Agent 任务 Prompt 的写法

Agent 的 Prompt 比 Chat 和 Edit 需要更详细,因为它要自主做多个决策:

不够详细的 Prompt

plain
创建一个分类模块
详细的 Prompt
plain
在当前 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 里有没有正确注册

五、三大模式的选择逻辑

plain
你想做的事情是什么?
│
├── 理解代码 / 问问题 / 讨论方案
│   └── 用 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:初始化演示项目

bash
npx @nestjs/cli new cursor-demo
cd cursor-demo
npm install
npm run start:dev   # 确认项目能正常启动

Step 2:用 Cursor 打开项目

bash
cursor cursor-demo

Step 3:Settings 里确认配置

  • Cmd+, 打开 Settings
  • Editor: Font Size → 16
  • AI 模型 → 右下角切换为 claude-sonnet-4

Step 4:在 src/ 下新建演示文件 product/product.service.ts,写入以下内容(故意写有问题,用于 Edit 模式演示):

typescript
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

typescript
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:输入以下内容,发送:

plain
@product.entity.ts 解释这个文件里每个装饰器的作用

观察 AI 基于文件内容给出的解释。

Step 3:演示跨文件引用,在 Chat 里输入:

plain
@product.entity.ts @product.service.ts
对比这两个文件,service 层有哪些地方和 entity 不一致?

观察 AI 跨两个文件的分析结果。

Step 4:演示选中代码引用。在编辑器里选中 product.service.tsfindOne 方法,按 Cmd+L,在 Chat 里输入:

plain
这个方法用了 ==,有什么潜在问题?

Edit 模式演示

Step 1:打开 product.service.ts,光标放在 create 方法里,按 Cmd+K

Step 2:在弹出的输入框里输入:

plain
给这个方法加上 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,输入:

plain
用严格等号 === 替换 ==,参数 id 改为 number 类型,找不到时抛出 NotFoundException

生成 Diff 后,先按 Esc 拒绝,展示代码回到原样。再重新 Cmd+K 接受一次,展示完整的接受流程。


Agent 模式演示

Step 1:按 Cmd+I 打开 Agent(Composer)

Step 2:输入以下任务:

plain
在当前 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 完成后,逐文件审查:

plain
需要检查的文件:
├── 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:运行项目验证:

bash
npm run start:dev

如果报错,把错误信息贴到 Chat 里,输入:

plain
运行报了这个错误:[粘贴错误信息],帮我修复

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. 安装与基础配置

安装

官网:https://cursor.sh

下载对应系统的安装包,安装后直接导入你的 VS Code 配置(主题、快捷键、插件)——迁移成本几乎为零。

首次配置

选择模型

进入 Cursor Settings → Models,推荐配置:

plain
主力模型:claude-3-5-sonnet(或 claude-3-7-sonnet)
快速模型(补全):cursor-small 或 gpt-4o-mini
设置 API Key(可选)

Cursor 有自己的订阅套餐(Pro $20/月),包含一定量的 Claude / GPT 调用额度。如果你有自己的 Anthropic API Key,也可以在设置里填入,走自己的额度。

关闭不需要的功能
plain
Cursor Settings → Features:
- Auto Import:开
- Auto Scroll:看个人习惯
- Show Suggested Files:开(Agent 模式很有用)

3. 三大核心功能

3.1 Chat(对话)

快捷键:Cmd/Ctrl + L

打开右侧 Chat 面板,这是你和 AI 最主要的对话窗口。

Chat 的几个关键特性

上下文引用:输入 @ 可以引用文件、文件夹、代码符号、文档等。

plain
@src/modules/user/user.service.ts 这个 service 的 findAll 方法
为什么在数据量大时会慢?帮我优化一下
plain
@spec/user.md 按照这份规格,帮我生成 UserModule 的完整实现
包括 Controller、Service、DTO 和 Module 文件

Apply 按钮:AI 给出代码建议后,点 Apply,Cursor 会自动把代码变更应用到对应文件,不需要你手动复制粘贴。

多轮对话:Chat 保留对话历史,同一个任务可以持续追问。

plain
我:帮我实现 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,输入"加入事务处理,如果发邮件失败不影响用户创建":

typescript
// 选中这段
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 任务
plain
按照 @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 会:

  1. 读取你引用的文件和规则
  2. 分析项目结构
  3. 依次创建多个文件
  4. 每个文件的内容互相保持一致(模块名、类名、导入路径等)

你在旁边看它操作,有问题随时打断。


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 里加:

plain
When generating code, skip explanations unless explicitly asked.
Output code directly without preamble.

或者在每次对话开头加:

plain
直接给代码,不需要解释

技巧二:让 AI 先列计划,再执行

对于复杂任务,先让 AI 描述它打算怎么做:

plain
按照 @spec/user.md 实现用户模块。
先告诉我你打算创建哪些文件、每个文件的职责是什么,
我确认后再开始写代码。

这样你可以在它动手之前纠正方向,比写完再改省力得多。

技巧三:用 @Docs 引用官方文档

Cursor 支持把外部文档添加进来,输入 @Docs 选择已添加的文档。

推荐添加:

这样 AI 生成 NestJS 代码时,可以参考最新的 API,减少用法过时的问题。

技巧四:Chat 里引用报错信息

直接把终端里的报错贴进 Chat,AI 能很快定位问题:

plain
运行时报这个错:
[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,描述任务

plain
在 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 生成的文件列表,确认思路对了再执行
第三步:生成完毕后,运行项目
bash
npm run start:dev
第四步:如果有错误,把报错贴回 Chat
plain
启动报错了:
[错误信息]

帮我看看哪里有问题
第五步:用 Insomnia / Postman 测接口,没问题后写测试
plain
帮我给刚才的 UserService.findAll 写单元测试,
覆盖:有 search 参数时、page 超出范围时、无数据时三个场景

整个过程大概 15-20 分钟,手写的话至少要 1 小时。


7. 小结

Cursor 的三个核心功能:

  • Chat:引用文件、对话式开发、追问式迭代
  • Inline Edit:快速改单段代码,diff 预览
  • Agent:给任务、让 AI 规划执行、多文件同时处理

上手门槛不高,但用好它需要一点思维转变:从"AI 帮我补代码"变成"我给 AI 清晰的任务,AI 帮我执行"。

任务描述越清晰,生成质量越高。这就是为什么 spec.md 和 .cursorrules 是 Cursor 工作流的前置条件。