理解像 Cursor、Windsurf 和 Copilot 这样的 AI 编码工具是如何在后台工作的,可以大大提升你的工作效率,使这些工具能够更一致地工作------尤其是在大型复杂的代码库中。当人们在尝试让 AI IDEs 有效工作时遇到困难时,他们往往像对待传统工具一样使用它们,忽视了了解它们固有限制和如何克服这些限制的重要性。一旦你掌握了它们的内部工作原理和限制,这就会成为"作弊代码",显著改善你的工作流程。截至撰写本文时,Cursor 大约编写了我 70%的代码 1。
在本文中,我想深入了解这些 IDE 实际上是如何工作的,Cursor 系统提示,以及如何优化你的代码编写和 Cursor 规则。
从LLM到编程代理
大型语言模型
LLMs 通过一次又一次地预测下一个单词来有效工作,正是从这个简单的概念出发,我们能够构建复杂的应用程序。
从基本编码到代理,有三个阶段: 蓝色 是我们使用的前缀(即提示), 橙色是模型自动生成的内容。对于代理,我们多次运行该模型,直到它生成用户可面对的响应。每次运行时,客户端代码(而不是代理)计算工具结果并将其返回给代理。
提示早期解码器(例如 GPT-2)涉及创建一个前缀字符串,当完成时,可以得到所需的结果。你不会说"写一首关于鲸鱼的诗",而是说"主题:鲸鱼\n 诗歌:"或者甚至"主题:树木\n 诗歌:......实际的树诗......\n 主题:鲸鱼\n 诗歌:"。对于代码,这看起来像是"PR 标题:重构 Foo 方法\n 描述:......\n 完整差异:",你构建了一个前缀,当完成时可以实现你想要的功能。"提示工程"是创造性地构建理想的前缀,以诱使模型自动完成答案。
然后引入了指令调优 (例如,ChatGPT),使得LLMs 显著更加易于使用。你现在可以输入"写一个 PR 重构 Foo",它会返回代码。幕后,这几乎完全是上述自动补全过程的同义词,但前缀变成了" 写一个 PR 重构 Foo",其中的LLM 现在在进行对话。即使在今天,你也会看到一些奇怪的情况,其中这个事实会泄露出来,LLM 会通过继续自动补全超过""标记来自问自答。
当模型足够大的时候,我们进一步添加了"工具调用"功能。不只是填充助手文本,在前缀中我们可以提示"如果需要读取文件,请输入 read_file(path: str)
而不是直接响应"。LLM在收到编程任务时,将完成"read_file('index.py')",我们(客户端)再提示"... index.py 的完整内容 ..."并要求它继续完成文本。虽然这只是自动补全,LLM现在可以与外部世界和系统进行交互。
代理编程
类似 Cursor 的 IDE 是这个简单概念的复杂封装。
要构建一个 AI IDE,你需要:
-
添加聊天界面并选择一个好的LLM(例如 Sonnet 3.7)
-
为编码代理实施工具
- 读取文件(full_path: str)
write_file(full_path: str, content: str)
- 运行命令(command: str)
-
优化内部提示:"你是一个专家程序员","不要假设,使用工具"等。
而且基本上就是这样。最难的部分是设计出真正有效且一致的提示和工具。如果你真的按照我描述的方式构建它,它会勉强工作,但经常会遇到语法错误、幻觉,并且非常不一致。
优化自主编程
制作一个好的 AI IDE 的关键在于弄清楚它擅长什么,并围绕其限制精心设计提示和工具。这通常意味着通过使用较小的模型来处理子任务,来简化主要的LLM代理所完成的任务(参见我另一篇文章《构建多代理系统》)。构建多代理系统)。
这是当你使用 AI IDE 时幕后发生的情况的图表。我们简化了主要代理的工具,并将"认知负担"转移到其他LLMs上。IDE 将你的@-标签注入上下文,调用多个工具来收集更多上下文,用特殊的差异语法编辑文件,然后返回给用户一个总结响应。
优化与用户提示技巧
-
通常用户已经知道正确的文件或上下文,因此我们在 Chat UI 中添加了"@file"语法,并在调用LLM时传递所有附加文件的完整内容,使用""块。这相当于用户直接复制粘贴整个文件或文件夹。
- 提示 : 在这些 IDE 中积极使用@folder/@file(更明确的上下文有助于更快更准确的响应)。
-
代码搜索可能很复杂,特别是对于像"我们在哪里实现认证代码"这样的语义查询。与其让代理擅长编写搜索正则表达式,我们会在编码LLM时将整个代码库索引到一个向量存储中。查询时使用另一个LLM重新排名和过滤文件以提高相关性。这确保了主要代理能够得到关于认证代码的'完美'结果。
- 提示 : 代码注释和文档字符串指导嵌入式模型,使它们比仅仅为人类同伴服务时更为重要。在文件顶部,应有一段话说明文件的内容,它所实现的语义功能,以及何时需要更新。
-
写出完美的每行代码是困难且昂贵的,因此优化 write_file(...)工具是这些 IDE 的核心。通常,LLM生成一个"语义差异",只提供更改的内容,并附带指导如何插入更改的代码注释。另一种更便宜、更快的代码应用LLM以这个语义差异作为提示,编写实际的文件内容并修复任何小的语法问题。新文件随后通过一个检查器,工具结果包含实际的差异和检查结果,这些结果可以用于自我纠正已损坏的文件更改。我喜欢将此视为与一个懒惰的资深工程师合作,他只写足够的代码片段,让实习生进行实际更改。
- 提示 : 你不能提示应用模型。像"停止删除随机代码"、"停止添加或删除随机注释"这样的建议是徒劳的,因为这些内容是应用模型工作方式的结果。相反,给主要代理更多的控制权,"在编辑文件指令中提供整个文件"。
- 提示 : 编辑非常大的文件时,应用模型会很慢且容易出错,将文件分割成小于 500 行代码。
- 提示 : 代码审查反馈信号非常高,你应该投资一个高质量的代码审查器,它能提供高质量的建议。使用编译和类型化的语言可以在编译时提供更丰富的反馈,这很有帮助。2。
- 提示 : 使用唯一的文件名(而不是代码库中有多个不同的 page.js 文件,更喜欢 foo-page.js、bar-page.js 等),在文档中使用完整的文件路径,并将热点代码组织到同一个文件或文件夹中,以减少编辑工具的歧义。
-
使用擅长编写这种代理风格代码的模型(而不是仅仅编写通用代码)。这就是为什么 Anthropic 模型在像 Cursor 这样的 IDE 中表现如此出色的原因,它们不仅能编写高质量的代码,还能将编程任务分解为这些类型的工具调用。
- 提示 : 使用的模型不仅仅是"擅长编程"的,而是特别针对代理型 IDE 优化的。目前(据我所知)唯一测试这方面表现良好的排行榜是 WebDev 竞技场3。
一个(非常昂贵的)技巧是我自己的 AI IDE 中使用的方法之一,以使其在自我纠正方面更好。我给它添加了一个"apply_and_check_tool"。这个工具会运行更昂贵的代码审查,并启动一个无头浏览器来获取控制台日志和应用程序用户流程的截图,以便为代理提供反馈。在这种情况下,MCP(模型上下文协议) 将真正发光,因为它可以为代理提供更多的自主权和上下文。
Thanks for reading Shrivu's Substack! Subscribe for free to receive new posts and support my work.
Subscribe
Cursor 逐行系统提示分析
使用一个 MCP 基础的提示注入,我提取了 Cursor 代理模式在 2025 年 3 月使用的最新提示。作为一个在LLMs上大量构建的人,我对 Cursor 的'提示工程师'们有着极大的敬意(依我之见),他们编写的提示比我在其他 AI IDE 中看到的要好得多。这也是他们成为领先编程工具之一的重要原因之一。深入研究这样的提示也有助于提高你自己的提示和代理架构能力------大多数 GPT 封装都是"开放提示"的。
Cursor 代理系统的片段提示。点击查看完整的提示和工具定义。
- "","<tool_calling>"等 ------使用混合的 markdown 和 XML 节标签可以提高提示的可读性,对人类和LLM来说都是如此。4
- "由 Claude 3.5 松赞驱动" --- 很多时候LLMs并不能准确告诉你它们运行的是哪个模型。明确指出这一点可以减少用户因计费模型与 Cursor 显示的模型不符而产生的抱怨。5
- "世界上最优秀的 IDE" --- 这是一种简洁的方式,告诉LLM不要在出现问题时推荐替代产品,这对于品牌代理来说非常重要。6
- "我们可能会自动附加一些信息......遵循用户的指示......通过<user_query> 标签。" --- 与直接将用户提示传递给LLM不同,Cursor 还会将它们放入一个特殊的标签中。这使得 Cursor 可以在 消息中传递额外的用户相关信息,而不会使LLM或用户感到困惑。
- "不要道歉" --- 他们显然因为 Sonnet 的倾向而添加了这一点。
- "NEVER 在说话时提及工具名称" --- Cursor 加了粗体,但仍然经常看到"使用 edit_tool"这样的表述。这是最近 Sonnet 模型的一个令人烦恼的问题。
- "在调用每个工具之前,先解释一下" --- 在 LLM 流式传输工具调用时,这可能会导致 UX 有些奇怪,因为聊天看起来会卡顿几秒钟。这有助于让用户感到有信心,知道某些事情正在发生。
- "部分满足用户的查询,但你不确定时,再收集更多信息" --- LLM 代理有早期停止过于自信的趋势。在做出回应之前,给他们一个深入挖掘的借口是有帮助的。
- "NEVER 向用户输出代码" --- 默认情况下,LLMs 希望在内联 markdown 代码块中生成代码,因此需要额外的引导,使其仅使用工具来生成代码,这些代码然后通过 UI 间接显示给用户。
- "如果你从头开始构建一个 web 应用,给它一个漂亮且现代的 UI"------这里有一些演示黑客技巧,可以生成非常炫目的单指令应用。
- "你必须阅读你正在编辑的内容的 7 部分或章节" ------通常编码代理真的想写代码,但不想收集上下文,所以你会看到很多明确的指示来避免这种情况。
- "不要超过三次循环来修复代码检查器错误"------旨在防止 Cursor 陷入编辑循环。这有所帮助,但任何经常使用 Cursor 的人都知道,这仍然很容易陷入这种情况。
- "要解决根本原因而不是症状。"------作为LLM对齐不良的一个例子,他们通常会默认删除错误消息代码,而不是解决问题。
- "不要硬编码 API 密钥"------这是许多安全最佳实践之一,至少可以防止一些明显的安全问题。
- 工具 "codebase_search","read_file","grep_search","file_search","web_search"------鉴于LLM在编码前收集正确上下文的重要性,它们提供了多种不同形状的搜索工具,以提供所需的一切,使其轻松确定需要进行哪些更改。
- 在一些工具中 "一句话解释......为什么需要运行此命令......"------大多数工具包含这个非功能性参数,迫使LLM考虑将传递哪些参数。这是一种提高工具调用质量的常见技术。
- 工具 "reapply"------它 "调用更智能的模型来应用上次编辑" ------允许主要代理动态升级应用模型,以解决更昂贵的自我问题。
- 工具 "edit_file" 状态为 "代表所有未更改的代码使用您正在编辑的语言的注释" ------这就是所有那些随机注释的来源,这对于应用模型正常工作是必要的。
- 你还会注意到整个系统提示和工具描述都是静态的(即没有个性化的用户或代码库文本),这样 Cursor 可以充分利用提示缓存,从而降低费用和首次生成令牌的延迟。这对于每次工具使用都会进行 LLM 调用的代理来说至关重要。
如何有效使用 Cursor 规则
现在最大的问题是"正确"的方式是什么来编写 Cursor 规则,虽然我的总体答案是"按照对你最有效的方式",但我基于提示经验以及对 Cursor 内部机制的了解,有很多观点。
Here's how 你的 Cursor 项目规则看起来LLM。它看到一个名字和描述的列表,基于这些信息它可以调用一个工具函数 fetch_rules(...) 并读取它们的内容 。
重要的是要理解,这些规则不是附加到系统提示中的,而是作为命名的指令集来引用。你应该将规则视为百科全书文章而不是命令 。
- 不要 在规则中提供身份,比如"你是一名资深前端工程师,擅长 typescript"之类的,你可能在 cursor.directory 中看到这样的内容。这会让代理在已经提供了身份的情况下感到困惑。
- 不要 (或避免)尝试覆盖系统提示指令或使用"不要添加注释","在编码前问我问题","不要删除我没有要求你删除的代码"之类的提示来尝试应用模型。这些直接冲突,破坏了工具的使用,并使代理感到困惑。
- 不要 (或者避免)告诉它不要做什么。 最好遵循积极的指令"对于 , "而不是仅仅列出限制条件。 你可以在 Cursor 自己的提示中看到这一点。
- 花时间编写高度显眼的规则名称和描述。关键在于,代理在对你的代码库知之甚少的情况下,能够直观地知道何时适用规则并使用其 fetch_rules(...)工具。有时你应该有不同名称和描述的重复规则以提高检索率,就像你正在构建一个手工制作的逆向索引文档一样。尽量保持描述简洁,不要过于冗长。
- 写你的规则就像百科全书的页面一样,为你的模块或常见的代码更改提供指导。就像维基百科一样,使用 mdc 链接语法将关键术语链接到代码文件,这将极大地帮助代理确定所需的正确上下文。有时这也意味着避免提供详细的步骤说明(专注于"是什么"而不是"怎么做"),除非绝对必要,以避免使代理过度适应特定类型的更改。
- 使用 Cursor 本身来起草你的规则。LLMs在撰写内容方面非常出色,可以为其他LLMs撰写。如果你不确定如何格式化文档或编码上下文,可以"@文件夹/生成一个 markdown 文件,描述关键文件路径和通常预期更改的定义"。
- Do 考虑不要有太多的规则作为反模式。这似乎有些反直觉,但规则对于使 AI IDE 在大型代码库中工作至关重要,同时也表明代码库不是 AI 友好的。我在 AI 驱动的软件工程中写得更详细了,但理想的未来代码库应该是直观的,使得编码代理只需要内置工具就能每次都完美地工作。
看看我生成的一些示例。
结论
令人难以置信的是,一个基于几乎开源代理提示和公开可访问的模型 API 的 VSCode 分支,估值接近 100 亿美元------带有"包装倍数"为 68。有趣的是,Cursor 是否会开发自己的代理模型(感觉不太可能)或者 Anthropic 是否会以 Claude Code + 下一代 Sonnet 的身份成为竞争对手。
无论最终情况如何,了解如何塑造代码库、文档和规则仍将是一项有用的技能。希望这次深入探讨能给你一个更具体而非凭感觉的理解,了解事情是如何运作的以及如何优化以适应 AI。我经常这么说,我会再说一遍,如果你觉得 Cursor 不起作用,那是因为你没有正确使用它。
Thanks for reading Shrivu's Substack! Subscribe for free to receive new posts and support my work.
Subscribe
这是一个基于感觉的统计数据,但我觉得这并不远。一旦你掌握了 Cursor 的规则,大量的 PR 实际上只需要一个提示就能完成。我原本以为这要到 2027 年才能实现,但随着 Anthropic、Cursor 和我自己在提示技巧上的同时提升,事情的进展比我预想的要快。
我对 CodeRabbit 的代码检查功能印象深刻,计划使用 MCP 将其反馈到 Cursor 中。如果 Cursor 的默认代码检查器更好,其他条件不变的话,使用起来会感觉像是在使用 Sonnet 3.8。
(大多数)LLMs的美妙之处在于,虽然这是一个网页开发基准,但在我的经验中,性能与各种编程和框架的性能高度相关。
没有找到相关的科学研究,但根据我的经验,这种方法效果很好,我甚至不会惊讶于 Anthropic 模型是否明确训练了伪 XML 语法。
这确实有一些 意外的副作用,其中编码模型会将代码库中引用的模型名称更改为与自身相同的名称。
这里有一个有趣的法律灰色地带。实际上,根据 FTC 法案,兰哈姆法案,Cursor 将无法在其网站上发布此内容,但目前他们可以在提示中使用它,并让LLM代为说出。
FYI Cursor 团队,我发现了拼写错误(:
这是我自创的一个术语,指的是 GPT 封装的价值与其提供者模型之间的比率。在这种情况下,Anthropic : Cursor = 600 亿 : 100 亿 = 6。凭我的直觉,"6"不是一个合理的比率。以一个不成熟的投资者的身份来看,我认为 Anthropic 应该接近 1000 亿,而 Cursor 可以高达 100 亿(封装倍数为 100)。很难想象他们中任何一方都有长期的竞争壁垒,而且 Anthropic 似乎很容易构建自己的下一代 AI IDE 竞争对手。