1. 为什么我要把 Cursor 当成一个“项目”来用
第一次用 Cursor 的人,十有八九是把它当成“能聊天的 VS Code”。装完插件、打开侧边栏、敲一句“帮我写个登录页”,然后看着它吐出一大段代码,复制粘贴,跑起来,报错,再问,再改。折腾一下午,代码是能跑了,但你自己心里清楚:这玩意儿没帮你省多少事,反而多了一堆看不懂的代码。
我用 Cursor 大概有半年多,前两个月基本就在这个循环里打转。真正让我改变用法的,是一个很朴素的念头:别把它当补全工具,把它当成一个刚入职、能力很强但完全不了解你项目的同事。这个同事记性很好、打字飞快、知识面广,但他不知道你的目录结构、不知道你的命名习惯、不知道你上周为什么把那个函数拆成三个。你要做的不是“让他写代码”,而是“让他先读懂项目,再动手”。
这个视角一换,用法就完全不一样了。PStack 这个系列我一直想写的就是这种“把工具当项目来管理”的思路。这篇就围绕 Cursor 展开,讲清楚我怎么用它、为什么这么用、哪些坑我踩过。适合两类人看:一类是刚上手 Cursor、还在“聊天框里贴代码”阶段的朋友;另一类是用了挺久但总觉得效率没提上去、想系统化整理工作流的人。全文不讲玄学,只讲我实际跑通的流程和参数。
2. 先搞清楚 Cursor 到底强在哪,别用错力气
2.1 它和普通补全工具的本质区别
普通代码补全工具的核心能力是“预测你下一行要写什么”,它的上下文窗口通常只有当前文件甚至当前几行。Cursor 的核心能力是“理解一个代码库的局部,然后按你的意图生成或修改代码”。这个区别听起来很虚,但落到操作上非常具体。
举个我自己的例子。我有个项目里有个utils/format.ts,里面有个formatCurrency函数,处理了三种货币符号和两种小数位规则。普通补全工具在我写formatCurrency(的时候,只能提示参数名。而 Cursor 在我选中一段调用代码、按Cmd+K输入“把这个调用改成支持日元,小数位保留 0 位”之后,它会去读formatCurrency的定义,发现里面有个currencyMap对象,然后自动往里面加日元配置,再改调用处。它做的是跨文件的语义修改,不是文本替换。
这就是为什么我说“别用错力气”。如果你只让它补全单行,那它的价值可能还不如一些轻量插件。它的价值在“理解 + 批量修改 + 跨文件重构”。
2.2 三种交互模式,对应三种完全不同的场景
Cursor 的交互入口主要有三个,我按使用频率排:
| 模式 | 触发方式 | 适合场景 | 我的使用频率 |
|---|---|---|---|
| Tab 补全 | 直接打字时自动出现 | 写重复结构、补全参数、改错别字 | 每天几百次 |
| 行内编辑 | 选中代码后Cmd+K | 局部重构、加注释、改逻辑 | 每天几十次 |
| 侧边栏对话 | Cmd+L或点侧边栏 | 跨文件任务、问架构、生成新模块 | 每天十几次 |
很多人只用了第一个和第三个,忽略了Cmd+K这个中间态。实际上Cmd+K是我用得最顺手的:选中一段代码,输入一句自然语言,它直接在原地改,改完你还能看 diff 决定接不接受。这个“原地改 + diff 确认”的体验,比在侧边栏里来回粘贴强太多。
提示:
Cmd+K的输入框里可以写多行指令,按Shift+Enter换行。我经常写两三行,把约束条件列清楚,比一句话效果好很多。
2.3 上下文窗口不是越大越好,关键在“喂什么”
Cursor 支持把整个文件、整个目录甚至整个项目加进上下文。新手容易犯的错是“全选,加进去,让它自己找”。实测下来,上下文塞太满反而会让它抓不住重点,生成的东西开始“飘”。
我的做法是:只喂和当前任务直接相关的 2 到 4 个文件。比如我要改一个 API 的返回结构,我会加三个文件:路由定义、对应的 service、以及类型定义文件。这三个文件足够它理解数据流,又不会让它分心。如果任务涉及更广,我会先用侧边栏问一句“这个功能涉及哪些文件”,让它列出来,我再手动挑几个加进去。
这个“先问范围,再喂文件”的习惯,是我踩了无数次“它改错文件”的坑之后养成的。
3. 我的 Cursor 工作流:从项目初始化到日常开发
3.1 项目初始化阶段:先写一份“给 AI 看的说明书”
新项目或者刚接手一个老项目,我做的第一件事不是写代码,而是在项目根目录建一个.cursorrules文件。这个文件 Cursor 会自动读取,相当于给它的“项目须知”。
我自己的.cursorrules大概长这样,你可以直接抄结构:
# 项目技术栈 - 前端:React 18 + TypeScript + Vite - 状态管理:Zustand,禁止引入 Redux - 样式:Tailwind CSS,禁止写内联 style - 请求:统一走 src/api/request.ts 封装,禁止直接用 fetch # 代码规范 - 组件文件用 PascalCase,工具函数用 camelCase - 所有导出必须显式写类型,禁止 any - 注释用中文,函数上方写一行说明用途 # 目录约定 - src/components 放通用组件 - src/pages 放页面级组件 - src/hooks 放自定义 hooks - src/utils 放纯函数工具 # 禁止事项 - 不要自动生成测试文件,除非我明确要求 - 不要修改 package.json 里的依赖版本 - 不要动 .env 文件这份文件看起来简单,但它解决了一个大问题:每次对话不用重复交代背景。以前我每开一个新对话都要说“我们用 Zustand 不用 Redux”,现在它自己知道。实测下来,有了这份文件之后,它生成代码的“返工率”至少降了一半。
注意:
.cursorrules不要写太长,控制在 50 行以内。写太多它反而会忽略部分内容。把最关键的约束放前面。
3.2 日常开发:把任务拆成“它能一次做对”的粒度
这是我最想强调的一点。Cursor 不是不能做复杂任务,而是复杂任务需要你拆。我见过有人直接输入“帮我实现一个完整的用户管理模块,包含增删改查和权限控制”,然后抱怨它生成的东西不能用。这不是它的问题,是任务粒度的问题。
我的拆法是这样的。假设要做一个用户列表页,我会拆成四步,每步单独对话:
- 第一步:定义类型。输入“根据这个接口文档,在
src/types/user.ts里定义 User 类型和查询参数类型”。这一步只产出类型文件,简单、可验证。 - 第二步:写 API 层。输入“在
src/api/user.ts里写 getUserList 函数,用 request.ts 封装,参数用上一步的类型”。它读得到上一步的文件,直接复用。 - 第三步:写 hooks。输入“写一个 useUserList hook,调用 getUserList,处理 loading 和 error 状态”。
- 第四步:写页面。输入“用 useUserList 写一个用户列表页,用 Tailwind 做表格,支持分页”。
每一步的产出我都能快速看一眼、跑一下、确认没问题再进下一步。这样即使某一步它做错了,我也只损失几分钟,而不是推翻一整个模块。
这个“四步拆解法”是我用得最顺的节奏。它的本质是让每一步的上下文都足够小、足够明确,这样 Cursor 的准确率会高很多。
3.3 重构场景:用Cmd+K做“外科手术”
重构是我觉得 Cursor 最值的地方。以前改一个函数的签名,要全局搜索、逐个改、还要担心漏掉。现在我的流程是:
- 选中函数定义,
Cmd+K输入“把参数从对象改成三个独立参数,并更新所有调用处”。 - 它会先改定义,然后提示“发现 7 处调用,是否一并修改”。
- 我点确认,它逐个改,每改一处我都能看 diff。
这里有个细节:改之前先提交一次 git。因为 Cursor 的批量修改偶尔会改错地方,尤其是当有同名函数的时候。有 git 兜底,改错了直接git checkout .重来,心里不慌。
还有一个技巧:如果重构涉及的文件超过 5 个,我会先在侧边栏问“这个函数被哪些文件引用了”,让它列清单,然后我手动确认清单对不对,再让它动手。多这一步,能避免它漏改或者改错。
4. 那些让我效率翻倍的进阶用法
4.1 用@精确指定上下文
在侧边栏对话时,输入@会弹出文件、目录、甚至符号的列表。我常用的三种:
@文件路径:精确加某个文件。比如@src/utils/format.ts。@目录路径:加整个目录。比如@src/components,适合“这个目录下所有组件都加一个 props 校验”这种任务。@符号名:加某个函数或类。这个用得少,但在大文件里定位很准。
新手容易忽略@,直接在对话里说“那个 format 文件”。它可能找得到,也可能找错。用@是零成本的精确,没理由不用。
4.2 让它“先解释,再动手”
遇到不熟悉的代码,我会先让它解释,而不是直接改。比如选中一段复杂的正则,Cmd+K输入“逐段解释这个正则的含义,用中文”。它解释完,我理解了,再决定怎么改。
这个习惯帮我避免了很多“它改完我看不懂、出了问题查不出”的情况。尤其是接手老项目的时候,先让它当“翻译”,比直接让它当“手术刀”安全得多。
4.3 用对话历史做“决策记录”
Cursor 的侧边栏对话是可以保存和命名的。我会把一些重要的技术决策对话命名保存,比如“用户模块架构讨论”“支付流程重构方案”。过两周回头看,能快速回忆起当时为什么这么设计。
这个用法有点像“把 Cursor 当会议记录员”。它记录的不是结论,而是推导过程。有时候我忘了某个设计的原因,翻一下当时的对话,比翻 git log 还快。
5. 踩过的坑和排查技巧
5.1 它改错文件了怎么办
这是最常见的坑。表现是:你让它改 A 文件,它把 B 文件也改了,或者改到了错误的函数里。
排查思路分三步:
- 看 diff。Cursor 每次修改都会显示 diff,养成“改完必看 diff”的习惯,能拦住 90% 的错误。
- 检查上下文。如果 diff 里出现了你没加进上下文的文件,说明它“自作主张”了。这时候回退,重新用
@精确指定文件。 - 检查同名符号。如果项目里有两个
handleSubmit,它可能改错。解决方法是选中你要改的那个,用Cmd+K而不是侧边栏,因为Cmd+K的上下文是你选中的代码,更精确。
5.2 生成的代码跑不起来
常见原因和解决方式我整理成表:
| 现象 | 可能原因 | 解决方式 |
|---|---|---|
| 报“找不到模块” | 它用了不存在的依赖 | 检查 package.json,手动装或让它换方案 |
| 类型报错 | 它没读到类型定义文件 | 把类型文件用@加进上下文 |
| 逻辑不对 | 任务描述有歧义 | 把任务拆小,重新描述 |
| 样式不生效 | 它用了内联 style 而项目用 Tailwind | 在.cursorrules里写清楚样式规范 |
5.3 对话越来越“飘”
长对话到后面,它开始忘记前面的约束,生成的东西越来越离谱。这是上下文窗口的固有限制,不是 bug。
我的应对方式是:一个任务一个对话。做完一个任务,开新对话。如果任务确实很长,我会在对话中间手动“复述约束”,比如“注意,我们仍然用 Zustand,不要引入其他状态库”。这句话能把它拉回来。
提示:侧边栏对话右上角有个“新对话”按钮,别舍不得开新对话。一个干净的上下文比一个塞满历史的上下文好用得多。
5.4 关于隐私和代码安全
这一点必须提。Cursor 会把你的代码片段发送到它的服务端处理。如果你的项目涉及敏感信息,要么用它的本地模式(如果版本支持),要么对敏感部分做脱敏。
我自己的做法是:涉及密钥、内部地址、用户数据的代码,不直接贴进对话。需要它帮忙时,我会用占位符替换敏感值,比如把真实地址换成API_BASE_URL,让它基于占位符写逻辑,我再手动替换回去。
6. 我总结的一套“最小可用工作流”
如果你只想记住一件事,那就记住这个流程:
- 项目开始:写
.cursorrules,把技术栈、规范、禁止事项列清楚。 - 每个任务:拆成 3 到 4 步,每步一个对话,每步产出可验证。
- 改代码:优先用
Cmd+K原地改,改完必看 diff。 - 加文件:用
@精确指定,只喂相关的 2 到 4 个文件。 - 长任务:中间手动复述约束,做完开新对话。
- 敏感代码:脱敏后再贴,或者不贴。
这套流程我跑了几个月,最大的感受是:Cursor 的上限不取决于它自己,取决于你怎么用它。你把它当聊天框,它就是个聊天框;你把它当项目成员来管理,它就能真的帮你干活。
最后分享一个小技巧:每周花十分钟回顾一下你这周和 Cursor 的对话,看看哪些任务它一次做对了、哪些反复出错。出错多的任务类型,往往是你描述方式有问题,或者.cursorrules里缺了某条约束。把这个补上,下周的效率又会高一点。这个“复盘”习惯,比任何技巧都管用。