Cursor 用了 8 个月,这些坑我不想再踩第二次
真实使用 Cursor 8 个月的经验总结,包括代码重构、测试生成、常见坑点和最佳实践
# Cursor 用了 8 个月,这些坑我不想再踩第二次
去年十月份开始用 Cursor,从 1.0 beta 版本一路用到现在的 0.32 正式版(版本号越来越小这个事咱就不吐槽了)。踩过的坑、省下的时间、还有那些让人又爱又恨的瞬间,值得好好复盘一下。
先说结论:值得买,但别迷信
Cursor 确实能提升效率,尤其是写样板代码、单元测试、类型定义这些"知道怎么写但不想手写"的场景。但如果你指望它帮你从 0 到 1 写一个完整功能,大概率会失望。
我现在的用法是:70% 的时间用来做代码重构和补全,20% 用来生成测试,剩下 10% 用来做代码解释和文档生成。那些"用 Cursor 10 分钟搭个 Instagram" 的 demo 视频,看看就算了,真这么干的人现在应该在重构第一个月写的代码。
实战场景一:重构 SQLAlchemy 模型
我们项目有个历史遗留的 SQLAlchemy 模型文件,2000 多行,所有表定义在一个文件里。以前看过几次想重构,每次都因为改动太大、担心引入 bug 而作罢。
用 Cursor 的 Composer(现在的 Agent 模式)处理这个任务,提示词是这样的:
这个文件里的模型定义需要拆分到不同的模块,按照业务域划分。
要求:
2. 关系定义不能断
3. 拆分后需要能正常导入和运行
4. 给我一个完整的迁移方案,包括文件结构、导入顺序、测试用例
Cursor 给出的方案是把模型拆成了 5 个模块:auth.py、content.py、interaction.py、notification.py、base.py。拆分逻辑合理,但第一次给出的代码有循环导入问题。
这里有个坑:**Cursor 在处理多文件重构时,经常会忽略 Python 的导入顺序问题**。它给的代码里,base.py 定义了 Base 和 session,但 auth.py 里用了 Content 模型(定义在 content.py),而 content.py 又需要 User(定义在 auth.py)。
解决办法是使用 __init__.py 做延迟导入:
# models/__init__.py
from .base import Base, engine, session
# 先导入不依赖其他模型的模块
from .auth import User, Role, UserRole
# 再导入有外键依赖的模块
from .content import Post, Page, Media
from .interaction import Comment, Like, Share
from .notification import Notification, NotificationTemplate
# 最后配置关系
def configure_relationships():
from sqlalchemy.orm import configure_mappers
configure_mappers()
这个模式是我在和 Cursor 来回对话了 4 次后才得到的。它一开始坚持要在每个子模块里单独处理关系,导致代码重复且难以维护。
实战场景二:写测试是真的快
这个是 Cursor 最值得吹的地方。给你看个真实案例:
我有个函数用来处理用户上传的头像,需要验证文件类型、缩放尺寸、生成缩略图、上传到 S3。原函数 80 行,手写测试怎么也得 1-2 小时。
用 Cursor 的方式是选中函数,按 Cmd+K,然后说:
给这个函数写完整的单元测试,覆盖:
用 pytest 和 moto mock S3
30 秒后给了我这个:
import pytest
from unittest.mock import patch, MagicMock
from moto import mock_aws
import boto3
from PIL import Image
import io
from app.services.avatar import process_avatar
@pytest.fixture
def s3_bucket():
with mock_aws():
s3 = boto3.client('s3', region_name='us-east-1')
s3.create_bucket(Bucket='test-avatars')
yield s3
@pytest.fixture
def valid_image():
img = Image.new('RGB', (800, 600), color='red')
buf = io.BytesIO()
img.save(buf, format='JPEG')
buf.seek(0)
return buf
@mock_aws
def test_process_valid_image(s3_bucket, valid_image):
result = process_avatar(valid_image, 'user123', 'jpg')
assert result['avatar_url'] is not None
assert result['thumbnail_url'] is not None
@mock_aws
def test_non_image_file_rejected(s3_bucket):
fake_file = io.BytesIO(b'this is not an image')
with pytest.raises(ValueError, match='Invalid image format'):
process_avatar(fake_file, 'user123', 'txt')
@mock_aws
def test_large_image_auto_resize(s3_bucket):
# 创建一个 3000x3000 的图片
img = Image.new('RGB', (3000, 3000), color='blue')
buf = io.BytesIO()
img.save(buf, format='JPEG')
buf.seek(0)
result = process_avatar(buf, 'user123', 'jpg')
# 验证上传的图片尺寸是否正确
s3 = boto3.client('s3', region_name='us-east-1')
key = result['avatar_url'].split('/')[-1]
obj = s3.get_object(Bucket='test-avatars', Key=key)
# ... 验证尺寸逻辑
测试覆盖率从 40% 提到了 85%,而且发现了两个我之前没考虑的边界情况:EXIF 方向信息和 HEIC 格式支持。
那些让人抓狂的时刻
1. 上下文窗口满了之后开始胡说
Cursor 的上下文管理策略是"最近优先",这导致当你对话轮次多了之后,它容易忘记最开始的约束条件。
比如我在做一个功能,前面说了"不要用 Redux,用 Zustand",聊了 10 个回合后它开始给我生成 Redux 的代码。这时候需要手动在设置里清理上下文,或者重新开始对话。
2. 代码补全有时会"过度联想"
有个坑爹的经历:我在写一个函数叫 delete_user,Cursor 补全的时候自动加了一行 send_notification_email()。看起来很贴心,但这个函数是在管理员后台调用的,删除用户不应该发通知(我们有单独的操作日志)。
**教训:Cursor 补全的代码,一定要看一遍再按 Tab**。不要因为它的建议看起来合理就盲目接受。
3. .cursorignore 配置很重要
默认情况下 Cursor 会索引整个项目目录。我们项目有个 fixtures/ 目录,里面是 50MB 的 JSON 测试数据,还有 node_modules、__pycache__ 这些。
没配置 .cursorignore 之前,Cursor 经常从这些文件里"学习",导致补全质量下降,索引速度也慢。
正确的配置:
# .cursorignore
node_modules/
__pycache__/
*.pyc
fixtures/
*.json
dist/
build/
.coverage
htmlcov/
4. Agent 模式会"幻觉"出不存在的 API
这个是最危险的。有一次我让 Cursor Agent 帮我写一个功能,它调用了一个看起来完全合理的函数 stripe.Customer.delete_source(),但实际上 Stripe SDK 的这个方法是 delete_card()。
如果你不仔细看就去跑代码,就会在运行时报错。更糟的是,如果它"幻觉"出来的 API 恰好和真实 API 名字接近,你可能要调试半天。
付费版值不值?
Cursor 的免费版每月 50 次 GPT-4 调用,对于轻度使用够了。但如果你像我一样每天要用它做代码审查、重构建议、测试生成,50 次真的不够。
专业版每月 $20,无限 Claude 3.5 Sonnet 和 GPT-4 调用。算笔账:省下来的时间如果按小时计费,早就把订阅费赚回来了。
但有个坑:**切换到 Claude 3.5 Sonnet 后,代码补全的速度会明显下降**。GPT-4o 在代码补全场景下其实更快,虽然质量可能略逊一点。
最佳实践总结
2. **提示词要具体,但不要过度约束**。比如"给这个函数写测试"不如"给这个函数写测试,覆盖边界情况和异常处理,用 pytest 和 mock",但"给这个函数写测试,覆盖边界情况和异常处理,用 pytest 和 mock,测试函数命名用 test_<function>_<scenario> 格式,每个测试要有 docstring"就过度约束了。
3. **定期清理对话上下文**。尤其是 Agent 模式,上下文满了之后质量下降明显。
4. **把 Cursor 当初级工程师用,不要当架构师用**。它能帮你实现已经设计好的功能,但不擅长做技术选型和架构设计。
5. **.cursorrules 文件要写清楚项目规范**。比如我们项目的:
# .cursorrules
这些规则能显著提升 Cursor 生成代码的质量。
最后
Cursor 是个好工具,但它还是个工具。真正决定代码质量的,还是你对业务逻辑的理解、对代码架构的把控、以及对生成结果的审查能力。
那些"AI 会让程序员失业"的论调,看看就好。真正在用 AI 工具写代码的人都知道,这东西现在还差得远。但它确实能让你写得更快、测试覆盖更全、重构更有信心。
关键是:**别懒,该看的代码还是要看的**。
VkingAI