30 秒看懂
2022 年 6 月,Aman Sanger 打赌,语言模型会在 2024 年中之前拿到国际数学奥林匹克(IMO)金牌。Sualeh Asif 本人也是竞赛数学选手,却认为 Aman 疯了;后来 DeepMind 的系统只差一分。这条陡峭的能力曲线,正是 Cursor 成立的前提:如果模型能力持续跃升,整个编程环境就得重建,而做什么,仍然要由人来决定。
- 1Arvid 的产品原则几乎就是一句口号:快就是好玩。感觉慢的实验会被扔掉,哪怕它在技术上很巧妙。
- 2Aman 的看法是,在 AI 编程这一行,领先几个月,产品就能实用得多;一年后的 Cursor,应当让现在的版本显得落伍。
- 3Cursor Tab 要做的是预测下一步动作。预测的不只是下一个字符,还有下一处改动、下一个跳转位置,甚至下一个文件或终端命令,让每一个零熵的击键都被 Tab 略过。
- 4SWE-Bench 这类公开的智能体(Agent)基准受到了严重污染。在没有代码仓库上下文的情况下做 SWE-Bench 题目,模型可能会凭空编出正确的文件路径和函数名。
- 5Cursor 团队不认为智能体会接管编程。编程的大部分价值在于迭代,而且你往往要先看到第一版,才知道自己到底想要什么。
- 6Michael 赌的是这样一种未来:程序员仍握着方向盘,保有速度、自主权与掌控力,而不是把机器人当成一支工程团队来喊话。
按章节阅读整理后的全文
代码编辑器是强化版的文字处理器,而且必须好玩
Lex Fridman 开场就向 Cursor 的四位创始人提出了一个故意开门见山的问题:代码编辑器到底是干什么用的?这四位分别是 Michael Truell、Aman Sanger、Sualeh Asif 和 Arvid Lunnemark。Michael 的回答很务实。长期以来,编辑器都是人们用文本编辑一门形式化语言来造软件的地方;对不写代码的人来说,它就是一个强化版的文字处理器。代码有结构,这让工具能做到文字处理软件做不到的事:用语法高亮让你一眼扫完,像网页超链接一样点进定义处,还能做基础的错误检查。
他并不想把这个定义固定住。他说,未来十年里,代码编辑器究竟是什么,会发生很大的变化,因为造软件这件事本身,可能会呈现出不一样的样子。这款产品要做的,是在造软件这件事本身发生变化的时候,依然是软件被制作出来的地方,而非守住今天这个文本框。
Arvid 补充了一条团队拿来当“一票否决”的标准:代码编辑器应该好玩。他们做出来、试过、然后扔掉的很多东西,都没有通过这一关。在他们那里,“好玩”和速度紧紧绑在一起。“快就是好玩。”他说,团队把这句话当成了可以印在 T 恤上的口号。Michael 指出,人们最初之所以会被计算机吸引,靠的就是疯狂的迭代速度:你和机器面对面,不用等什么委员会,很快就能做出一件很酷的东西。
他们从 Vim 转到 Copilot,又分叉了 VS Code,好让天花板能继续往上抬
四个创始人最早都是纯粹的 Vim 用户,只用 Vim 加终端,连 Neovim 都不碰。转折点是 2021 年的 GitHub Copilot。Aman 想试试它,而当时唯一能用上它的编辑器是 VS Code,结果体验好到他再也没有回去。Fridman 把好的补全比作亲密朋友替你把话接下去:接得准的时候,那种被人真正读懂的感觉会让人上瘾;接不准,你就删掉重打。Arvid 指出一个容易被忽略的地方:接错的代价很小。你再敲一个字符,建议就会重新生成。Sualeh 说得更远:Copilot 是语言模型第一个真正意义上的消费级产品,是第一款把语言模型从论文和演示里带出来的杀手级应用。
Michael 说,Cursor 的起点要追溯到 2020 年 OpenAI 那几篇 scaling law 论文:哪怕没有新点子,只要增加算力和数据,效果就能稳定地变好。他们对知识工作的理论设想,在两个时刻变得具体起来:一是玩 Copilot 的内测版,二是 2022 年底拿到 GPT-4 的早期使用权。能力的跃升让他们之前做的那些小工具显得太小了,比如给金融从业者用的 Jupyter 小工具,还有一些静态分析的尝试。如果把逻辑推到底,那么所有编程都将经过这些模型,这需要一个全新的环境,而非在旧环境上再加一个插件。
Sualeh 讲了一个在团队内部至今还被当作“性格测试”的故事。2022 年 6 月,Aman 和 Sualeh 的室友 Shengtong(一位 IMO 金牌得主)打赌:到 2024 年 6 月或 7 月,模型能不能拿到 IMO 金牌。Arvid 和 Sualeh 都参加过竞赛,Sualeh 的反应是 Aman 疯了。他现在承认自己当时错得很离谱。DeepMind 后来的系统离金牌线只差一分。Aman 的热情还配了一套行头:一件印着 scaling law 图表的 T 恤。他也给这个赌注加了限定。数学,尤其是形式化定理证明,是一个有干净验证器的领域,所以不需要 AGI(通用人工智能)也能做出超人水平的数学。
对他们来说,分叉 VS Code 并不需要多少论证。插件式的做法掌控不了编辑器的足够多部分,而他们预计,新能力会改写软件的开发方式。Aman 认为,AI 编程和以往的技术浪潮不一样:每次模型跃升都会打开一批新功能,所以早几个月起步,产品就明显更有用。他的意思是,一年后的 Cursor 要让今天的版本显得过时。他说,微软做过很了不起的事,但它未必适合持续进行那种能抬高天花板的研究和实验。Sualeh 的理由更个人化:他们为自己而做,眼看模型一天天变强,Copilot 却几乎没有动静,他忍不住问:“那些 alpha 功能都去哪儿了?”Arvid 提到,他们的组织优势在于,做界面的人和训练模型的人相距大约 18 英尺(约 5.5 米),而且常常是同一个人。
Tab 是对下一步动作的预测:跳过每一次不携带新信息的击键
Michael 把现在的 Cursor 归结为两件事。一件是像一个反应很快的同事那样在你肩后看着,并抢在你前面:它补全的不止光标后面的字符,还会预测下一整处改动、下一次改动的差异,甚至是你接下来要跳转到的位置。另一件正好反过来:你带着指令走在 AI 前面,从意图一步步走到代码。两件事都要顺手、聪明、快。Sualeh 说,他们想要的是一个能编辑代码的模型,而不只是填空的模型,他们试了很多次,才得到一个真正擅长这件事的模型。
“跳到下一处改动”这个想法,来自接受一处修改之后的一种感觉:下一个该去的地方往往一目了然,就在下面 18 行。Vim 用户可以敲 18jj,为什么还要人自己去数?于是你按一下 Tab,它就跳过去,显示下一处改动,你再按一次 Tab。团队内部还有一场比赛:看能让人按下多少次 Tab。这背后的抽象概念就是零熵编辑(zero-entropy editing)。意图一旦确定,剩下的字符就不再携带新的信息,你只是在告诉电脑你本来就想表达的东西。模型应该读懂你的心思,把这些比特统统用 Tab 略过去。
Aman 从建模的角度给出直觉。代码的每字节比特损失(bits per byte)比自然语言更低,也就是说,代码里很多 token 本来就可以预测。而如果预测的对象是人在现有代码上的下一步编辑,可预测性还会更高。Cursor Tab 的目标,是在编辑器里消除低熵的动作,让你直接跳到时间线的前面。近期的计划相当雄心勃勃:先是跨行生成和编辑,然后是文件内跳转、跨文件跳转,再是建议一条终端命令,甚至把你带到某个定义处,让你有足够的信息去验证下一条补全。Michael 说,编程是一门奇怪的手艺,因为接下来的五分钟,有时候从你刚做过的事情就能推断出来。
让这一切感觉瞬间完成的,是系统工程。这类任务非常吃预填充(prefill),生成的 token 很少,所以他们训练的是小型的混合专家(MoE)模型,而非每敲一个键都调用前沿大模型。提示词必须对缓存友好,否则每个按键都要把整个上下文重算一遍,会把 GPU 压垮。他们还做了投机编辑(speculative edits),这是投机解码(speculative decoding)的近亲:不用一个很小的草稿模型,而是把屏幕上已经存在的代码当作草稿。把原始代码块原样喂回模型,它大多数时候会同意这些行保持不变,于是这些行可以并行处理;直到某一行模型开始不同意,它才生成新的 token,然后再重新投机。Sualeh 还提到一个交互上的额外好处:改写是流式输出的,你可以边看边审,不用等加载动画转完。
模型的改动越来越大,目前尚未解决的产品问题,是帮人类去验证这些改动
Fridman 对 Cursor 红绿对比的 diff 界面很感兴趣:建议直接出现在编辑区,Apply 在聊天框里,你可以接受或拒绝。Sualeh 说,他们大概会做四五种 diff,因为自动补全(视线固定在一个位置)和审阅跨文件的大改动,根本不是同一个问题。现在的侧边框,是几次失败尝试之后留下来的幸存者。早期版本用的是类似 Google Docs 的删除线加上新代码并排显示,分心得厉害。后来的一版要求你按住 Option 键:一个蓝色高亮提示这里有 AI 的建议,按住就能看到,松开就回到原来的代码。Fridman 的质疑一句话就说完了整个交互问题:“你得先知道要按住 Option 键才行。”
Arvid 点出了更深层的问题,也就是验证问题。小改动用 diff 没问题;改动一大或者涉及多个文件,逐行审阅就会变得不现实。一个思路是把高信息量的代码块和低熵的重复内容区分开,前者高亮,后者变灰。另一个思路是让模型先看一眼 diff,判断哪里可能有 bug,然后在你真正该读的地方画一道红色波浪线。他说,现在的 diff 算法只是普通的算法:人的智慧花在了设计这些算法上,但运行的时候,它们并不关心这次改动意味着什么。你需要的是一个模型,带着人去读那些必须读的部分,而且只读那些。
Sualeh 把这个时间线又往前推了一步:模型会提出越来越大的改动,这意味着人要做的验证工作越来越多,而他不想把全部时间都花在看代码上。GitHub 式的 PR 审阅是显而易见的模板,但也是个糟糕的模板。Aman 说,代码审阅“挺烂的”:你即使读懂了陌生的代码,还是会漏掉 bug;而它最初是为两个人类之间的协作设计的。当作者是语言模型时,你就可以不必顾及作者的感受,围绕审阅者整个重新设计体验。顺序也很重要:PR 通常是从上往下读,但逻辑上的阅读顺序并不一样,模型应该带你走一遍。Arvid 不认为所有编程都会变成自然语言。结对编程的时候,最快的办法有时是抢过键盘演示一下;有时是直接拖动界面。自然语言会有它的位置,但它不会成为大多数人在大多数时间里的编程方式。
前沿模型负责勾草图,专门模型负责落地,没有哪个模型能全面占优
Fridman 说,这个编辑器底下跑着大量的机器学习。Aman 描述了一套组合方案:推理密集型的工作交给前沿模型,那些大模型仍然做不好的事情,就交给自研模型。Cursor Tab 就是一个例子:在它自己的评测上,专门的模型能击败前沿模型。另一个例子是不太起眼的 Apply。前沿模型擅长勾勒改动的草图,却不擅长输出精确的 diff:在大文件里,它们会犯“数行号”这种蠢错误。于是 Cursor 的做法是让大模型画出一个粗略的代码块,再训练一个模型把这份草图落到文件里。Sualeh 说了一个出人意料的结论:和很多人想象的不一样,把建议和原文合并,并非一个确定性算法能解决的问题。有人试过用浅拷贝和匹配的办法硬做,至少 40% 的时候会出错,产品体验直接被毁掉。Apply 还有第二重好处:贵的模型只需要输出很小的草图,便宜的模型负责实现。Aman 认为这种模式会越来越深入,比如让 o1 这一类的模型写出高层计划,再由下级模型递归地去落实。
被问到写代码到底是 GPT 还是 Claude 更强,Aman 拒绝给出一个冠军。在速度、改代码的能力、长上下文处理和编码能力这几个维度上,没有哪个模型能全面占优。综合下来最好的,也是社区的共识,是 Sonnet。o1 在面试题和 LeetCode 式的题目上推理能力很强,但对人粗糙的意图,它似乎不如 Sonnet 理解得好。Aman 对一些前沿模型还有一层含蓄的批评,问题出在分布上:它们在基准测试和接近基准的任务上表现很好,但稍微离开那个范围,能力就会明显下滑。而 Sonnet 是那种你只是随口让它处理一段代码,能力也不会打折扣的模型。
Sualeh 说,基准和真实编程之间的差距,在于规格说明。真实的工作往往是半截英语:“照我之前那样做”,“加这个,再加那个,顺便把那个界面改一下”。面试题依赖完整的规格;人却很少给出完整的规格。Michael 补充了公开基准的乱象。SWE-Bench 是一个流行的智能体评测,它在基础模型的训练数据里被严重污染。如果你让模型做 SWE-Bench 的题目,却不给代码仓库,它会凭空编出正确的路径和函数名。Aman 指出,各家实验室不会为了让排行榜更干净,就把 sympy 和其他热门 Python 仓库从训练数据里删掉。于是团队只好换个办法去逼近真实情况:找人跟模型互动,给出定性反馈。Arvid 把这叫作“vibe”。Fridman 承认,他自己也会在 Reddit 和 X 上这么做,还时不时会冒出“Claude 变笨了”的感觉。Aman 转述了一种猜测:AWS 的芯片和经过量化的 Bedrock 版本,数值表现可能跟 Anthropic 自己的 GPU 不一样。Sualeh 的意思不是要搞阴谋论。芯片很复杂,浮点运算量巨大,而 bug 有多难避免,怎么强调都不过分。
他们用 JSX 写提示词,也希望智能体处理那些两句话就能说清的 bug
Arvid 的内部提示词系统叫 Preempt。它出现的时候,GPT-4 级别的模型只有 8000 token 的窗口,而编辑器能拿到的候选上下文又太多:文档、附件和对话历史都挤在一起。即使到了现在,塞满窗口依然费钱、变慢,有些模型也会因此糊涂。他从网页设计那里借来一个比喻:纸质杂志早就知道每篇文章落在哪一页,网页的输入却是动态的,版面还得成立。于是 Cursor 改用 JSX 来写提示词。它有若干组件,其中的 File 组件接收光标位置,离光标最近的行权重最高,越往外越低;Preempt 渲染器会在光标附近尽量多放行,直到放不下为止。检索得分也能用同样方式给代码块排定优先级。现在这套抽象更关心的,已经不只是把内容压进 8k,而是把原始输入和渲染分离,改了渲染器之后,可以拿旧提示词在一整套评测集上重放。
那用户也该用 JSX 写提问吗?Arvid 的答案是不用。目标是让你按最自然的方式去表达,Cursor 的工作是把相关的信息找出来,让你的意思能被理解。Fridman 想起 Perplexity 的 Aravind 说过,应该让用户尽量偷懒,但他接着反驳:对程序员,其实是可以多要求一些的。这里有个张力,在偷懒和激发人多想一想之间。Aman 给出了两种处理意图不足的办法:一是让模型直接追问,二是如果搜索空间不大,就生成五六个结果让你选。一个最近还在实验中的功能,会在你打字的时候推测你的不确定之处,并建议你附加哪些文件。比如你在改一个 API,系统可能会根据同一个文件里的提交历史判断,客户端和服务端都应该放进上下文里,而这一切都发生在你按下回车之前。
说到智能体(Agent),Arvid 既兴奋又冷静。Demo 看起来离 AGI 很近;但对很多真实任务来说,智能体还没有那么有用,不过正在接近。他举的例子非常具体:Cursor 的聊天输入框里,Command+C、Command+V 有时候会失灵。这个 bug 用两句话就能说清楚。他很想要一个智能体:自己找到相关文件,复现问题,修好,再验证一遍,等到第二天你回来看结果就行。但他不认同智能体会接管所有编程的看法。编程的很大一部分价值在于迭代:你没法事先把东西说清楚,因为在看到第一版之前,你并不知道自己想要什么。这类工作你需要的是即时反馈。他还喜欢一种后台智能体的形态:你在做一个 PR 的前端时,智能体在后台先起草后端的代码。那些繁琐的环境配置工作,也属于让编程变得更好玩的范围,尽管今天他们还没有在积极做一个完整的部署智能体。
速度是一整套缓存技巧的叠加,影子工作区(Shadow Workspace)让模型拿到 lint 反馈
Fridman 注意到,在 Cursor 里唯一让他觉得慢的功能是 Apply,而慢的也就一两秒钟,这恰好说明其他部分有多快。他还注意到,Arvid 的表情显示,他对这一点也很痛苦。Aman 讲的第一个技巧是缓存预热(cache warming):你在打字的时候,系统可以猜到你接下来会需要哪些上下文,提前把当前文件预先填进 KV 缓存(KV cache),这样你按下回车时,首个 token 出现的时间(TTFT)就会明显缩短。他还解释了为什么需要这个缓存。注意力机制要为之前的每一个 token 保存 key 和 value;如果不存下来,每生成一个新 token,就得把整个提示词重新算一遍。把 KV 留在 GPU 上,生成下一个 token 就只需要对最后一个 token 做一次前向计算,再对已缓存的状态做注意力。这是 Transformer 中唯一的串行依赖,而缓存基本上把这部分的代价付掉了。
Tab 还有一个更高层的技巧:假设用户已经接受了当前建议,提前发起下一个请求,这样等他真的按下 Tab 时,后面的建议已经准备好了。这是投机和缓存的结合,即使模型本身并没有变快,用起来也感觉很快。KV 缓存越小,你就能越大胆地做投机:比如同时预测接下来的 10 种可能动作,只要用户命中其中任何一个就算赚到。Sualeh 把这和 pass@k 联系了起来:单次采样也许平庸,但采样十次,其中有好答案的概率大得多,这也正是强化学习所利用的东西。团队在用强化学习训练 Tab 模型时,实际上是在给许多候选建议打分,看人们真正喜欢哪一个。从架构上看,业界从 multi-head attention 转向 grouped-query 和 multi-query attention,目的是压缩 KV 的大小。这对 prefill 帮助不大,但对受内存带宽限制的生成阶段和更大的 batch 很有帮助。DeepSeek 的 MLA(他们称之为 multi-latent attention)把所有 head 的 key 和 value 压缩成一个隐向量,需要时再展开,用算力换内存带宽。KV 更小,就能缓存更多、支持更长的提示词和更大的 batch,又不会严重拖慢解码延迟。
Arvid 写的那篇影子工作区文章,讲的是如何把算力花在比接下来几行更长的时间跨度上,比如接下来的十分钟,但这只有在模型能拿到反馈信号时才有用。o1 说明,多想一会儿是可行的;带着反馈去迭代,则是另一条路。对程序员来说,最关键的信号来自语言服务器:类型错误、跳转定义、查找引用。它们通过 LSP(语言服务器协议)接入 VS Code,这样编辑器自己就不必内置每一种语言的编译器。影子工作区的做法,是在同一个文件夹上开一个隐藏的 Cursor 窗口。只要 agent 不保存,它就可以随意修改代码,同时仍然能拿到 lint 结果和定义跳转。在 Linux 上,可以把文件系统在内存里做一份镜像,让模型以为自己在改文件,其实改动都在内存里。Mac 和 Windows 上就难得多,这也是这个问题值得琢磨的地方。Aman 倾向于一种更粗糙但有趣的办法:保存时加锁。模型持有磁盘上的锁,你编辑的是只存在内存里、但仍能拿到 lint 提示的影子版本;如果你需要拿回锁,就会收到一条小提示,然后再协商控制权。Aman 进一步判断:几分钟级别、嵌在用户工作流程里的任务,最好留在本地,这样环境才一致;时间更长、规模更大的任务,大概应该放到远程沙箱里,而要让沙箱复现出和真实环境等价的配置,本身就是一场噩梦。
这些模型出人意料地不擅长找 bug,差距主要在于校准
Fridman 想要的不止是写代码。他的播客后期流程里,已经有不少环节由代码驱动,比如 Premiere、YouTube 上传、翻译和配音。在编程本身上,他希望智能体能找出 bug,尤其是大范围的逻辑错误。Aman 的回答很直接:即便是最聪明的模型,包括 o1 在内,只要被直接要求找 bug,校准都“差得惊人”。这反映的是预训练的数据分布。GitHub 规模的代码,以及 Stack Overflow 和 GitHub issue 里的问答,数据量都是万亿级的 token;而“在已有代码里找出真实 bug”这类数据几乎不存在。一旦把模型推向这种少见的目标,比如 Cursor Tab 的下一处编辑预测,或者 bug 检测,它的脆弱之处就会暴露出来。他仍然相信能有迁移效果,就像预训练过的代码模型,稍加引导就能适应 Tab 任务那样。
Sualeh 认为,模型往往知道某段代码有点可疑,却没法判断这个问题到底有多要紧。实验里出几个小 bug 没关系;但如果是 Postgres 或 Linux 里的一个边界情况,就完全不能接受。资深工程师有一种文化记忆,比如知道三年前有段可疑的函数把服务器搞挂过,而模型并没有这种记忆;此外,他们还能感知到这位用户现在有多偏执。Arvid 的做法,Sualeh 觉得很丑,但很管用:如果一个函数可能造成巨大破坏,就在它的每一行都写上全大写的 DANGEROUS,大约重复十遍。人们读文档字符串时常常只是扫一眼,然后就忘了;而今天的模型,在警告足够响亮的时候,也会更加注意。Arvid 说,在形式化验证普及之前,你始终得担心会不会有一个悄无声息的 bug。
他期待的未来是,人们不再需要写测试。你写一个函数,模型提出一份规格说明,你审阅规格,然后一个很强的推理模型去证明实现符合规格。Michael 提出反对:意图本身往往和代码一样难以精确描述,形式化的规格语言会漏掉你真正在意的东西。Arvid 认为规格语言是可以不断演进的,而且原则上整个代码库的形式化验证也是可行的。他举了个例子:已经有工作把 C 代码一直形式化验证到 GCC 编译器,再到 Verilog,直至硬件,这是一套庞大的分层系统,和一个大型代码仓库并没有本质的不同。Aman 追问 Stripe 的 API 怎么办,以及那些把语言模型当作基础原语去调用的程序怎么办。Arvid 愿意想得更远,甚至想到证明一个模型是对齐的。在训练层面,他们在饭桌上聊过一个想法:植入一个看起来合理的 bug,比找出一个 bug 容易,所以可以先训练一个 bug 注入器,再用这些合成数据训练一个反向模型。另一个方向不是让模型盯着代码看得更久,而是给它追踪信息、调试器,并允许它运行代码。Michael 勾勒了两种产品形态:一种是快速的专门模型在后台持续寻找问题,另一种是对已知的 bug 投入大量算力,哪怕要花几十美元,也一次性解决。
Fridman 对 Cursor 在文档一团乱的情况下写出的三个完美的 YouTube API 函数印象深刻,于是提议加一个 5 美元的打赏按钮,作为比“接受”更强烈的信号。Arvid 说,这个想法在公司内部有争议。他比较喜欢的一个版本是:发现 bug 不收费,接受它则要在括号里付一美元。这个方案有明显的问题:复制粘贴就能绕过去,而且在编辑器里放一个美元符号,会破坏你只想专注于代码的心境。与朋友分享一个很棒的生成结果,也许是更自然的回报。Michael 补充说,摆脱这种靠自觉的荣誉制,技术上可以是真正验证 bug 是否修好了。他们目前还没有闭环:在终端里运行、失败、修补、再运行,这一整个过程;他们猜这应该放在前台,或者放进影子工作区里做。这把话题引到了数据库。Sualeh 提到,像 PlanetScale 那样对预写日志做分支,而 turbopuffer 很可能也会加上同样的能力,这样智能体就能在分支上测试。他的口号是:一切都需要分支,包括文件系统。关键在于用巧妙的算法,让这些平行宇宙不会真的占掉太多空间或 CPU。
索引是一棵 embedding 的 Merkle 树,他们不会把产品押在本地模型上
基础设施这一部分,是从一个玩笑式的问题开始的:界面那么糟糕,AWS 为什么还是赢家?Arvid 的回答是,AWS 真的非常好。你知道它一定能跑通,哪怕配置过程像地狱一样;如果出了问题,多半是你自己的问题。Sualeh 说,这就是赢家该有的样子。Cursor 的扩容历程,也是创业公司的常见故事:QPS 每增加一个数量级,就会有一层新的缓存或数据库被击穿,现在连表都开始溢出了。一直让他们头疼的,是检索系统:为代码库建立语义索引,用来回答问题。他们把代码切块,做向量嵌入(embedding),然后只存储向量,不存代码本身,同时加密,并且时刻提防客户端的 bug。最难守住的一条约束是:编辑、删除和切换分支之后,本地状态必须和服务端保持一致。
最朴素的同步方式,是每分钟拉取一次所有文件的哈希,这会把用户的 Wi-Fi 压垮,还会让一个接近 20 TB 的数据库被持续读取。他们的做法是:每个文件有一个哈希,每个文件夹对其子节点的哈希再做一次哈希,层层向上,直到整个项目只剩一个根哈希,这就是 Merkle 树(Merkle tree)。大多数时候,根哈希对得上,就可以停止;对不上,才逐层往下找。Aman 说,成本的大头不在向量数据库,而在 embedding 本身。一家公司里,N 个工程师用的是同一份代码,就没有理由让每个人都重新算一遍 embedding。于是他们把向量缓存起来,缓存的键是代码块内容的哈希。这样,第 N 个同事建立索引时速度很快;切换到只有少量改动的分支时,也不必把整个仓库重新做一遍 embedding;而且原始代码始终不存放在他们的服务器上。用户今天能感受到的好处,是通过代码库聊天进行的那种模糊搜索,比如“我们在哪里做 X?”Arvid 认为,检索的天花板比大家想象的高得多。
为什么不在本地做 embedding,绕开这个分布式难题?Cursor 的用户有 80% 以上用的是 Windows 电脑,其中不少机器性能一般,而要支持本地模型分支,工程上的负担非常大。模型越大,本地就越难做,而非越来越容易。Sualeh 说,问题不只是笔记本太弱:就算是一家成立 20 年的老公司里最强的程序员,用一台配置很高的 MacBook Pro,对那么庞大的代码语料做近似最近邻搜索,也会过得很痛苦,毫无乐趣可言。Aman 补充了模型层面的阻力。混合专家(MoE)模型因为受内存带宽限制,对本地推理有一点帮助,但参数总量正在增长,已经超过单台节点的承载能力,更别说一台笔记本了。写代码的时候,人们想要的是 Sonnet 和 o1,“够用”的模型不在考虑之列。
Arvid 更喜欢的替代方案,仍然处于研究阶段:对语言模型推理做同态加密(homomorphic encryption)。在笔记本上加密输入,让数据中心在密文上运行你自己无法托管的模型,再取回密文,由你解密,只有你能看到答案。目前的开销非常大。他之所以关心这件事,是因为随着模型的经济价值越来越高,世界上越来越多的信息会流经一两个中心化的参与者,这些信息不仅可能被攻破,还可能被以明文的方式监控。安全监控一开始往往有很好的理由,然后换一个人来执掌,你就一步步滑下去了。他认为,云计算不一样:很多时候你可以自己掌握密钥,而且很多个人数据本来就不会交给 AWS。Sualeh 担心的也是同一条线,他提到 Anthropic 的 ASL-3、ASL-4:出于安全考虑,监控所有提示词变得合理,但如果全世界的信息都如此集中,就很可怕。分寸很难拿捏:既不能让模型失控,也不能把每一个提示词都交给三家供应商。
自动上下文代价高昂,而 o1 在编辑器里仍然没有默认位置
Fridman 的烦恼来自日常的 Python 开发:导入的库很多,而 Cursor 对上下文的猜测还不够好。Michael 说,自动上下文并不是免费的。塞进去的 token 越多,请求就越慢、越贵,能发起的后台调用也就越少,而且提示词塞得太满的时候,模型也会犯糊涂,所以相关性的门槛必须定得很高。他们喜欢的几条路径包括:更好的 embedding、更好的重排序器(reranker)。更偏学术的路线,是看模型能不能真正理解一个新的语料库:先是无限长的上下文,再是模型真的会关注这些内容,然后把它们缓存起来,避免每次都重新计算。另一类思路更接近微调,把知识学进权重里,而非靠 in-context learning 临时装进上下文。这种在权重里学到的理解,和在上下文里临时读懂,可能在本质上不一样。这个问题还没有定论。在这之前,Cursor 押的是检索:挑出仓库里正确的那些片段。
Aman 举了一个现成的例子:VS Code 本身。它的代码是公开的,所以前沿模型在预训练时见过它,可能还见过围绕它的问答,再加上指令微调和 RLHF(基于人类反馈的强化学习),于是你问它 VS Code 的问题时,它有时答得不错,有时就开始胡编。那如果专门对一个模型做后训练,让它真正懂这个代码库呢?他给出的粗略方案是:先做持续预训练,把通用代码数据和这个仓库的数据混在一起;然后做指令微调,把标准的代码数据集和关于这个仓库的问题混在一起。这些问题如果能拿到人工标注当然最好,否则就用合成的办法:取最近改动过的代码片段,让模型针对它提问,再把问题和代码配成训练样本。还有一个分岔点仍然悬而未决:到底是让一个模型端到端地在内部完成检索,还是训练一个很强的开源检索器,去为几个月后出现的任何前沿模型提供上下文?
在 Aman 看来,o1 代表的是一条值得关注的新曲线:预训练碰到数据天花板之后,测试时的计算成了新的增长点。有些问题可能需要 100 万亿参数、100 万亿 token 量级的智能才能解决,但这类请求大概只占 0.1%。那就针对 99.9% 的请求训练模型,对难啃的长尾问题让它多想一会儿。在 4o、Sonnet 和 o1 之间做路由,目前还没有解法;Cursor Tab 早期的路由方案也不能明显推广到这种选择上,甚至要先用 o1 级别的智能,才能判断 4o 是否已经力不从心。除了 OpenAI 内部的少数人,外界其实并不清楚 o1 如何运作。公开的线索包括过程奖励模型和树搜索。结果奖励模型只给最终答案打分,过程奖励模型则给思维链的每一步打分。公开文献里,过程奖励模型多用于对采样结果重新排序。真正令人兴奋、却尚未被证实的用法是树搜索:如果每一步的质量与最终质量相关,就可以在中途分叉。Michael 猜测,隐藏 o1 的思维链会让蒸馏变得更难,就像有些 API 收回了 logprobs 的访问权限一样。Cursor 里可以选 o1,但它不是默认选项;他们还没找到每个小时都会想用它的场景,部分原因是它不支持流式输出,你只能盯着一大段文字等它一次性出来。他们有一些想法,但在真正有用之前不会上线。
Fridman 提到网上流传的一个说法:GitHub Copilot 接入 o1 之后,Cursor 就完了。Michael 把它当成玩笑,但玩笑背后有一套认真的主张。这个领域和 2010 年代的软件很不一样:天花板极高,再过三四年,顶尖产品的实用程度会远超当下的水平。护城河和品牌当然可以谈,但如果产品上停止创新,照样会输。这对创业公司是好消息,因为只要做出更好的东西,仍然有机会击败已经占据优势的老牌对手。Aman 补充说,Cursor 额外的价值,主要不在于第一个把 o1 包装上线,而在于那些用户察觉不到的自研模型,以及每个功能背后反复打磨的交互细节。
合成数据分三种,而 scaling law 现在的维度比 Chinchilla 时代多了
Aman 把非自然数据分成三类。第一类是蒸馏:强模型输出 token 或概率分布,较弱的模型用它来训练。你不可能超过老师,但可以把一项昂贵的能力压缩进一个小而快的专门模型里。第二类利用的是“一个方向比反方向容易”:制造一个看起来合理的 bug,比找出一个 bug 容易得多,所以可以让一个较弱的模型去写 bug,再用这份合成数据训练一个检测器。他认为,这对人类可能也成立。第三类是实验室规模的做法:生成那些很容易验证的文本。如果有一个能判断文本是不是莎士比亚水平的验证器,那么一群猴子在打字机上乱敲,最终也能敲出可以用来训练的数据。形式化语言里的数学是最干净的例子;带测试集的 LeetCode 式代码题也很接近。Aman 预计,第三类最有可能带来巨大的收益,但它也最难推广,因为开放式、长周期的任务,很难有一个完美的验证器。Michael 提出了一个折中的办法:让模型去运行程序,做人类那种对输出的质量检查。
Aman 说,RLHF 依赖大量的人类偏好标注。RLAIF 则借助一个前提:验证通常比生成容易,因此可以让一个模型给另一个模型的输出打分。Cursor 实际的做法比教科书里的 RLHF 规模小:Tab 模型往往已经大体正确,只需 50 到 100 条人工样例,就能把它的先验推到团队想要的分布上。如果相信 P 不等于 NP,就意味着有一大类问题,检查起来远比求解来得容易。Fridman 开玩笑说,要是 AI 证明了这件事并拿到菲尔兹奖,奖该归谁?Michael 说,应该归写提示词的人。Arvid 认为,数学是一个封闭、可验证的系统,所以菲尔兹奖会比诺贝尔奖更早被攻下。Aman 觉得,AI 可能在 AGI 之前拿到菲尔兹奖,但他对此的直觉远不如当年对 IMO 那样笃定:那时的路径是看得见的,题目可解,解法也有迹可循;而 Birch and Swinnerton-Dyer 猜想这类开放问题,连一条看得见的路都没有。Sualeh 对菲尔兹奖出现时间的猜测是 2028 到 2030 年。
关于 scaling law,Aman 说,OpenAI 最初那篇论文有些偏差,主要来自学习率调度。Chinchilla 修正了算力最优情况下参数量和 token 数量的配比。之后各家实验室又逐渐偏离了算力最优,转而追求推理预算最优:训练时多花钱,换取部署时更便宜。现在的曲线多了几个维度,包括推理的 FLOPs 和上下文长度。如果你最在乎低延迟的超长上下文,那么即使训练时要多花 10 倍算力才能达到同样的质量,你可能也会选择训练一个 SSM(状态空间模型),因为推理才是你真正的约束。对于原始能力,也就是 Sualeh 所说的“原始智力”,规模越大依然越好。Aman 特别看好蒸馏,认为它是绕过数据墙的一条路:先训练一个昂贵的教师模型,再像 Gemma 那样,用一个 270 亿参数的教师模型,最小化学生模型与教师之间的 KL 散度。这样,每个 token 能给小模型带来的信号,比像 Llama 的做法那样,在一个 70 亿参数的模型上多喂 token 来过度训练要多得多。
Fridman 假设:五年里有 10 万亿美元,你会怎么花?Sualeh 的回答很简单:买 GPU,然后让研究员去调。追问到底是受算力限制还是受想法限制时,他站到了 Arvid 那边:是想法受限,不过算力能让人跑更多实验。Aman 认为,即便资本无限,也变不出足够的人才。研究本身就是苦力活:把文献里的想法串起来是一件事,写出能把 GPU 跑满的 CUDA 代码是另一件事,让模型并行运行在成千上万块 V100 上(他提到了 GPT-3)又是第三件事。要是能让有好想法的人搭起架构的成本降低十倍,并把利用率做到 40% 到 50%,研究的速度会一下子跳上去。Sualeh 主张先摘容易够到的果子:只要规模化还有效,就没必要停下来做实验,哪怕有 10 万亿美元,也得等到真的需要重新评估时再说。四个人都认为,通往 AGI 需要新想法,而这些想法可以先在小规模上检验。实验室的难题在于:核心的规模化配方还在持续产出回报,却又得把稀缺的人才分去搞旁支。
他们要做的是人机混合的工程师,而非能替代工程师的聊天机器人
从几个月到十年,Michael 说,Cursor 最期待的是这样一个未来:程序员能长期坐在驾驶座上,拥有速度、主动权和控制权,可以修改任何东西,还能快速迭代。这和让整个行业着迷的那种想象不同:一个孤零零的输入框,你对它说话,它就像一个工程师,或者像 Slack 上的一个工程部门,替你把一切都做完。他们对这种想象并不兴奋,部分原因是延迟,但更主要的原因是,它意味着放弃控制权。如果你只能像对一个部门那样对机器人说话,那你就等于把大量真正属于工作本身的决策,交给了它。很多离工程比较远的人以为,编程就是把写好的规格敲成代码。而他们真正享受的工程,是成千上万个微小决定,以及在速度、成本和复杂度之间那些不好看的取舍。只要人还在决定要造什么,他们就会想亲自掌握这些决定。
还有一个仍然模糊的想法:控制你看代码库时所用的抽象层级。你可以把代码库消化成伪代码,编辑伪代码,然后让改动落到真正的语言里;同时,你也保留直接进入实际文本的权利。这事到底能不能成,要看时间。对于规格清楚的 bug,Arvid 那种交接式的做法依然有道理;但那并非编程的大部分,也非他们认为人们真正看重的那部分编程。关于热爱编程的年轻人担心这条路没有前途,Michael 的乐观是有具体依据的。2012、2013 年的编程有更多的累赘、样板代码,还有很多棘手的查找。今天的编程更接近“专注的愉悦”。那些吸引人的东西,比如快速造出东西,以及个人掌控感,正在被放大。技能会变。品味和创意会被放大;样板式的文本编辑,甚至今天的一些谨慎,会变得没那么重要。
Arvid 最近的一个例子是:他们要把代码从 Node 的 AsyncLocalStorage 迁移到一个 context 对象上,这是一次痛苦的迁移,动到了整个代码库。他和 Sualeh 为此花了大约五天,而那还是在用今天最强的 AI 工具的情况下。他期待的未来是:只需展示两三个例子,模型就能把同样的改动应用到所有地方,遇到新情况就高亮出来让他示范一次,整件事十分钟就能收尾。这样你就不必站在白板前,一直推演到方案完美为止,因为试错之后再回退的成本很低。Aman 本来就更喜欢这种风格:先动手试一下,看看结构会怎么铺开,再迭代,而不是先想出最优设计,再用有限的工程预算去实现。给学习者的建议,与学哪门语言关系不大,和“原生 JavaScript 会吃掉整个世界”那个玩笑也无关。他说,最好的程序员,是那些单纯热爱编程的人:下班回家打开 Cursor,一直写自己的副业项目到凌晨三点,难过的时候会说,我只是需要写点代码。
Fridman 最后问:如果超级 Tab 做成了,那个只需要一直按 Tab 的人会怎样?Sualeh 和 Arvid 几乎同时回答:这个人会比任何人都更爱 Cursor Tab。“按 Tab”只是一个口号,你其实一直在注入意图:拒绝一个建议,多敲两个字,把正在成形的东西调整成你要的样子。和电脑交流的带宽,因此远远高于逐字敲键。Fridman 读了 Cursor 团队的内部文件《Engineering Genius》:他们是一家应用研究实验室,要打造一个人机协作的程序员,效率比任何一名工程师高出一个数量级,操控轻松,没有低熵的击键,以判断的速度迭代,在工程上超越纯 AI 系统,同时让编程变得更有趣。结尾,他引用了 Reddit 上的一句话,正好概括这个领域:没有什么比一个管用的权宜之计更持久。
同频道的其他文章
3:36:56EN → 简体中文
5:15:51EN → 简体中文
3:12:58EN → 简体中文
3:46:18EN → 简体中文
3:51:47EN → 简体中文
2:53:42EN → 简体中文