← 返回博客
·AI工具

Cursor 用了 8 个月,这些坑我不想再踩第二次

真实使用 Cursor 8 个月的经验总结,包括代码重构、测试生成、常见坑点和最佳实践

#Cursor#AI编程助手#代码重构#实战经验

# 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.pycontent.pyinteraction.pynotification.pybase.py。拆分逻辑合理,但第一次给出的代码有循环导入问题。

    这里有个坑:**Cursor 在处理多文件重构时,经常会忽略 Python 的导入顺序问题**。它给的代码里,base.py 定义了 Basesession,但 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,然后说:

    给这个函数写完整的单元测试,覆盖:

  • 正常图片上传
  • 非图片文件拒绝
  • 图片尺寸过大时自动缩放
  • S3 上传失败时的异常处理
  • 缩略图生成失败时不阻塞主流程
  • 用 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 在代码补全场景下其实更快,虽然质量可能略逊一点。

    最佳实践总结

  • **用 Ctrl+K 做代码编辑,用 Ctrl+L 做问答,用 Cmd+I 做多文件重构**。三个模式的适用场景不一样,别搞混。
  • 2. **提示词要具体,但不要过度约束**。比如"给这个函数写测试"不如"给这个函数写测试,覆盖边界情况和异常处理,用 pytest 和 mock",但"给这个函数写测试,覆盖边界情况和异常处理,用 pytest 和 mock,测试函数命名用 test_<function>_<scenario> 格式,每个测试要有 docstring"就过度约束了。

    3. **定期清理对话上下文**。尤其是 Agent 模式,上下文满了之后质量下降明显。

    4. **把 Cursor 当初级工程师用,不要当架构师用**。它能帮你实现已经设计好的功能,但不擅长做技术选型和架构设计。

    5. **.cursorrules 文件要写清楚项目规范**。比如我们项目的:

    # .cursorrules

  • 使用 Python 3.11+ 语法
  • 类型注解必须写
  • 使用 sqlalchemy 2.0 风格(不要用 Query 对象)
  • 测试用 pytest,mock 用 unittest.mock
  • 不要在生产代码里使用 print,用 structlog
  • 错误处理用自定义异常类,不要直接 raise Exception
  • 这些规则能显著提升 Cursor 生成代码的质量。

    最后

    Cursor 是个好工具,但它还是个工具。真正决定代码质量的,还是你对业务逻辑的理解、对代码架构的把控、以及对生成结果的审查能力。

    那些"AI 会让程序员失业"的论调,看看就好。真正在用 AI 工具写代码的人都知道,这东西现在还差得远。但它确实能让你写得更快、测试覆盖更全、重构更有信心。

    关键是:**别懒,该看的代码还是要看的**。