Z Potentials 2024年11月11日
深度|Cursor团队3万字深度访谈:即使拥有所有计算资源,以及所有数据,最终仍然受到的限制不仅仅是想法,而是优秀的工程技术
index_new5.html
../../../zaker_core/zaker_tpl_static/wap/tpl_guoji1.html

 

Cursor是基于VS Code的代码编辑器,增加了许多AI辅助编程功能。它能预测程序员下一步操作,将指令转化为代码,还具有代码差异等功能。文章探讨了其开发过程、优势及相关技术细节。

Cursor能充当快速同事,预测程序员下一步动作

它可帮程序员领先AI一步,将指令转为代码

Cursor Tab旨在消除低熵操作,实现快速编辑

代码差异功能通过颜色显示修改部分,且在界面方面不断改进

Lex Fridman 2024-11-10 13:27 北京

“我们的目标是让你做最自然的事情,使你的思维方式有意义。”

图片来源:youtube

Z Highlights

Lex:接下来是与Cursor团队创始成员的对话,成员包括Michael Truell、Sualeh Asif、Arvid Lunnemark和Aman Sanger。Cursor是基于VS Code的代码编辑器,增加了许多强大的AI辅助编程功能,吸引了编程界和AI界的广泛关注。所以,这是一个深入探讨AI在编程中应用的绝佳机会。这是一个超级技术性的话题,远远不止只关于一个代码编辑器,它涉及到编程的未来,以及人类在设计复杂强大的系统时如何与AI协作的未来。

代码编辑器的基础

Lex:首先一个比较宽泛的问题,代码编辑器的意义是什么?  

Michael:代码编辑器是你主要构建软件的地方,很长一段时间以来,代码编辑器是指对编程语言进行文本编辑的地方。对非程序员而言,代码编辑器可以被理解为一种为程序员量身定制的增强版文字处理器。之所以称为增强版,是因为代码具有很多结构。因此,这个“文字处理器”,即代码编辑器,可以为你做到很多普通文字处理器在编辑文本时无法做到的。  

传统意义上,代码编辑器包括从在代码中为你提供能让你快速浏览的Token视觉区分,让你像在互联网上用超链接导航一样在代码库中跳转的功能,再到查看你正在使用的定义、错误检查等。随着软件构建方式可能会发生的变化,未来10年内代码编辑器的定义也会改变很多。

Lex:我觉得代码编辑器还应该是有趣的。  

Arvid:是的,这非常重要。实际上这是我们决定构建什么功能时被低估的一个方面。我们开发了很多东西,如果发现不够有趣,我们就会把它丢弃。有趣的一个重要部分就是在要够快,快就是乐趣。

Michael从根本上说,很多人被吸引来到计算机上构建东西是因为这种令人难以置信的迭代速度。在其他学科中,你可能会受到资源或能力的限制。而编程是一件很了不起的事情,因为你只需要你自己和计算机,就能快速构建出非常酷的东西。  

GitHub Copilot

Lex:对于不知道的人来说,Cursor是一个非常酷的新编辑器,它是VS Code的一个分支。听听你们开发这个编辑器的过程会很有意思。我想你们所有人都是VS Code和Copilot的超级粉丝。你们是如何遇到VS Code的?这个过程又是如何引导你们走上Cursor的道路的?  

Aman:我想我们很多人最初都是Vim用户。  

Sualeh:纯Vim用户。  

Aman:纯Vim,对。没有Neovim,只有纯粹的Vim和终端。就我个人而言,大概是在2021年Copilot发布的时候,当时我真的很想试试。然后我就开始使用VS Code,这是唯一一个可以使用Copilot的代码编辑器。尽管我非常喜欢使用Vim,但VS Code加上Copilot的体验同样足够好,所以在我们开始开发 Cursor之前,我一直都在用VS Code。

Lex:也许我们应该解释一下Copilot的功能。这是一个非常棒的自动补全工具。当你开始编写代码时,它会补全一到三行代码建议给你。这种体验非常有趣,就像你有一个亲密的朋友会帮你补全句子一样。这个功能如果做得好的话,会有一种亲密感。也许“亲密”这个词不太准确,但你会有一种“哇,它懂我”的很酷的感觉。而当它不懂你时,用起来就会不太舒服。尽管如此,对很多人来说,“它懂我”的感觉远远胜过“它不懂”的感觉。  

Arvid:我觉得其实Github Copilot还有一个被低估的地方,即使它出错了也只是有点烦人,但并没有那么糟糕。因为你只需要再敲一个字符,可能它就懂你了。

Sualeh:你可以通过迭代来修正它。我是指,Copilot另一个被低估的地方是,它是第一个真正的AI产品,第一个面向消费者的语言模型产品。  

Lex:所以Copilot算是语言模型的第一个杀手级应用。  

Michael:是的,它的beta版在2021年发布。  

Lex:那么Cursor的起源是什么呢?  

Michael:大概在2020年,OpenAI发布了关于Scaling Laws的论文,意味着这个领域取得了明显的、可预见的进展。尽管我们没有更多的想法,但只要有足够的算力和数据,就能让这些模型变得更好。

Lex:关于Scaling Laws的话题,展开聊我们可能会花三到四个小时。但简而言之,这一系列观点主张在机器学习领域模型规模和数据量越大,模型效果可能越好。  

Sualeh:不仅是更大更好,而且是可预测地更好。

Lex:好吧,这是另一个话题。  

Arvid:是的,没错。  

Michael:那段时间,我们中有些人进行了很多关于这项技术形态的概念性讨论。对于不同知识领域的工作者来说,技术的进步将如何改善他们的工作?

然后我们总结几个时刻,论文中的理论预测开始让人觉得非常具体,我们可以不必去攻读博士学位就能在AI领域做出有用的工作;感觉现在就有一整套系统可以构建,能真正发挥作用。第一个这样的时刻就是我刚才提到的,试用Copilot beta版的时候,那种感觉真是不可思议。

一切真正开始结合起来的关键时刻是在我们获得了GPT4的提前访问权限时。在2022年底,我们开始微调这个模型,当时它的能力提升非常显著。在此之前,我们一直在进行一些不同的项目。由于Copilot、Scaling Laws以及我们对这项技术的兴趣,我们一直在为程序员开发一些具体的工具。比如,我们为那些需要使用Jupyter Notebook的金融专业人士构建工具,或者研究如何用这些模型进行静态分析。

GPT-4的升级给人的感觉是,它确实将我们之前预测的理论成果具体化了。在当时感觉可以立刻构建出更多的东西。而且如果我们能保持一致性,这绝对不会仅仅是是一个局部解决方案的问题,所有的编程都将通过这些模型进行,而这就需要一种不同类型的编程环境和编程方式。所以从那时起,我们着手构建这种更大的愿景。

Sualeh:我清楚地记得有一个特别的时刻。我的室友是IMO(International Mathematical Olympiad,国际数学奥林匹克)的金牌得主。美国有一个比赛叫PUTNAM,相当于给大学生的IMO,难度非常高。我记得是2022年6月,Shengtong和Aman打了个赌,赌2024年6月或7月能否通过模型在IMO上赢得金牌。  

Arvid和我也都参加了这个比赛,因此这对我们来说有些个人意义。当时我心想,这不可能发生。尽管我相信进步的可能性,但我觉得在IMO上拿金牌,Aman是在痴心妄想。坦白说,我当时错得很离谱。但这也许是我们团队里最有远见的赌注之一。

Lex:根据DeepMind的新结果,事实证明你是对的。  

Arvid:技术上来说不完全对。  

Aman:技术上错了,还差一分。  

Michael:Aman当时对这些东西非常有热情,他之前有一件印有“Scaling Laws”的T恤,上面有相关的图表和公式。  

Lex:所以你感受到了AGI或者Scaling Laws的力量。  

Aman:是的,在我还没有深入、批判性地思考Scaling Laws之前,我曾和Michael有过一次讨论。他提了一个问题:为什么Scaling不是你所需要的全部?或者说为什么Scaling不能带来巨大的进步?我经历了从愤怒、否认,最后才开始认真思考,到接受。从那之后,我一直对进步保持希望和乐观的态度。

但我想补充一点的是,这也取决于在哪些领域你会看到进步。数学是一个很好的领域,尤其是形式定理证明,因为你能够获得一个非常明确的信号来验证结果是否正确。因此,像RL(Reinforcement Learning,强化学习)这样的技术在这个领域表现非常出色。你可以拥有在数学上超越人类的系统,但它们在技术上还不具备AGI。

Cursor

Lex:好的,我们来谈谈Cursor。什么是Cursor?它是VS Code的一个分支,而VS Code是长时间以来最受欢迎的代码编辑器之一。每个人都爱上了它,大家纷纷从Vim转向VS Code,我自己也放弃了DMAX转用VS Code,可以说它在某种程度上统一了开发者社区。接下来你们观察到了技术趋势,分析了Scaling Laws,发现AI正变得越来越强大,于是你们觉得仅仅在VS Code上写扩展是不够的,这会有很多局限性。如果AI在不断进步,我们需要重新思考AI在变成中扮演的角色。于是你们决定分支VS Code,并开始构建我们接下来将谈到的许多强大的功能。那么,做出这个决定的过程是怎样的?因为VS Code中有许多扩展都在进行一些AI相关的工作,包括Copilot。是什么促使你们决定直接对VS Code进行分支?

Michael:对我们来说,开发一个编辑器的决定是显而易见的,至少对于我们想要做的事情和实现的目标来说是这样。当我们开始开发编辑器时,想法是这些模型会变得越来越强大,它不仅会带来巨大的生产力提升,甚至软件构建的方式也会发生巨大的变化。而作为现有的编码环境中的一个插件,能够控制的部分非常有限,我们不希望被这些局限性所束缚。我们想要构建最有用的东西。

Lex:那么VS Code与Copilot可以说是竞争对手,你们如何取胜?依靠速度和功能质量吗?

Aman:是的,这是一个相当有趣和独特的领域。如果你回顾以往的科技浪潮,可能只有一个主要的突破推动了新一轮公司的出现。但现在每年都会有新的模型能力提升,这解锁了新功能和可能性,尤其是在编程领域。

所以在AI编程领域,哪怕只领先几个月,更不用说领先一年,都会让你的产品更加有用。未来一年的Cursor需要让今天的Cursor看起来过时。而且虽然微软做了很多了不起的事情,但我并不认为他们能够像初创公司那样不断创新和推动技术发展。

Lex:不断快速实现新功能。

Aman:是的,并且进行必要的研究和实验,以真正推动技术的上限。

Sualeh:我更多是从程序员的能力角度来考虑它的。随着新的o1模型发布,我相信未来还会有更多不同类型的模型,比如可以处理更长上下文、更快的模型。有很多疯狂的想法可以尝试,而我们希望其中10%的想法能够变成真正有用的东西,并且尽早交到用户手中。换句话说,一个被低估的事实是,我们正在为自己开发产品。

当我们开始开发Cursor时,真的能感受到挫败感:模型在不断进步,但Copilot的体验没有变化。我们会想,这些人为什么没有推出新功能?天花板越来越高,为什么没有新东西?为什么没有alpha功能出现?它卖得很好,是一项不错的业务,但它没有让我们感到兴奋。我是那种很想要尝试和使用新东西的人,但很长时间内都没有新东西了。

Lex:是的,这很有趣。我不知道该怎么形容,但当你比较Cursor和Copilot时,Copilot很快就会让人感觉有些过时。

Arvid:是的,我们有一个优势是,Cursor某种程度上是在同步进行所有的工作,即我们在开发UX(用户体验)和模型交互方式的同时,也在努力让模型给出更好的答案。比如如何构建Prompt,如何找到上下文,以及对于Cursor Tab功能,如何训练模型。所以这些工作以及我们团队紧密的合作,这使得我们的产品像一个完整的整体。

Sualeh:是的,负责UI的人和训练模型的人坐在一起,距离不到18英尺。甚至经常是同一个人。如果你们不进行沟通、不实验,就很难创造出那些通过非传统方式实现的东西。

Lex:你们正在用Cursor编写Cursor,对吧?

Arvid & Michael:当然。

Lex:好的,那我们来谈谈一些功能。我们聊聊这个无所不知、无所不能、被誉为自动补全升级版的Tab。Tab是怎么工作的?它到底是什么?

Michael:总结来说,Cursor目前最擅长做两件事,当然它还有其他功能,但有两个方面特别能帮助到程序员。其一是充当一个快速的同事,可以“站在你的肩膀上”,输入并预测你下一步要做什么。这也是自动补全功能最初的想法,好的自动补全的内核是预测你下一步要做什么。但我们可以把这个概念做得更宏大,不仅仅预测下一个字符,还要预测你接下来的整个更改,甚至是接下来要跳转的位置。

另一个方面Cursor非常擅长的事情是,它能帮你领先AI一步,告诉AI该做什么,并将指令转化为代码。对于这两方面,我们都做了大量的工作,以使这些功能的编辑体验更加符合人体工学,并且更加智能和快速。

Cursor Tab

Sualeh:我们真正想要的其实是希望模型能够为我们编辑代码,这更像一个愿望。而在我们拥有一个能够为用户编辑代码的模型之前,我们进行了多次尝试。在我们有了一个好模型后,我们付出了很多努力来让推理速度更快,体验更好。正如Michael提到的这种跳转到不同位置的功能,这种跳转能力源于一种感受,即一旦你接受了一次编辑,模型应该显而易见地知道下一步该去哪里。就像我刚刚做了这个更改,模型应该知道下一个要去的地方是在18行之后。如果你是一个VIM用户,你可以按“1-8-J-J”或者其他按键。但我为什么要这么做?模型应该知道它该做什么。

所以我们的想法是,你只需按Tab键,它就会向下跳18行,并显示你接下来的编辑内容;然后你不断再按Tab键,它就能继续下去,直到你完成编写。所以内部的竞争是看我们能让用户按多少次Tab键,它足够让人印象深刻吗?更抽象地说,要考虑的是编辑如何实现零熵。一旦你表达了你的意图,编辑本身已经没有新的信息需要完成你的想法了,但你仍然需要输入一些字符让计算机理解你真正的想法。那么也许模型应该能读懂你的想法,所有这些零熵的部分都应该通过按Tab键自动完成。这就是抽象版本的想法。

Aman:有趣的是,如果你查看语言模型在不同领域的损失,每字节比特数,也就是代码的字符归一化的损失,它比语言要小。这意味着通常在代码中有很多Token和字符都是非常可预测的。这一点在不仅仅是自动补全代码,还包括预测用户基于现有的代码接下来会如何编辑。所以Cursor Tab的目标是消除你在编辑器中进行的所有低熵操作。当你下定决心时,让你直接跳到下一步,跳过不必要的步骤。

Lex:那么,如何实现下一个Cursor预测的推理和技术细节是什么?这种跳跃对于人们来说并不是那么直观。

Aman:是的。我可以讲一些实现的技术细节。模型的延迟非常低,所以需要针对这个任务训练一个小模型。特别是,它对预填充Token的需求很大,这意味着它需要非常长的Prompt,在这个Prompt中它会看到你大量的代码,但实际上只生成少量Token。因此,最适合的方式是使用稀疏模型,也就是MOE模型。这是我们做出的一个突破,大大提高了它在处理长上下文时的性能。另一个突破是我们开发的推测性编辑(Speculative edits),是推测性解码的一个变种。这两个都是实现质量高和速度快的关键要素。

Lex:好的,所以MOE输入很大,输出很小。

Aman:对。

Lex:好的。那么还有什么其他方法可以提高?缓存是否起到了作用?

Aman:缓存起到了巨大的作用。因为你要处理很多的Token输入,如果你在输入每一个字符时都必须重新运行模型并传入所有这些Token,不仅会显著增加延迟,还会让GPU过载。所以需要设计实际的Prompt给模型,使它能对缓存有感知。然后需要在请求之间重复使用KV缓存(Key-Value cache,键值缓存),这样可以减少计算量和工作量。

Lex:那么Tab在短期内能够做些什么呢?生成代码、填补空白区域、跨行编辑代码、在同一个文件中跳转不同的位置?

Sualeh:希望它也能在不同的文件中跳转。如果你在一个文件中做了一个编辑,可能你需要去另一个文件完成你的想法,它应该要能跳到第二个文件。

Arvid:更全面的说法应该是下一步行为的预测。有时你需要在终端中运行一个命令,它应该能够根据你写的代码建议命令;又或者有时它会建议一些内容,但你很难知道它是否正确,因为你还需要一些额外的信息来验证。所以实际上,它应该先让你看到内容的定义,然后再让你回来看它的建议,这样你就拥有了理解它提供内容的所需知识。

Lex:所以它在为人类提供知识。

Arvid:是的。

Lex:我刚认识了一个叫Primeagen的人,我相信他可以通过SS订购咖啡。

Arvid & Sualeh:我们做过。

Lex:所以模型也能做到这些事情,给你提供咖啡?好的。所以这就是总体框架。

Michael:是的。编程是一种奇怪的学科,有时接下来五分钟你要做的事情,其实是可以根据你最近做的事情预测出来的。当然不是总是这样,但有时候是。所以你将进入这样的一个世界:接下来的五分钟要么是你放手让模型自己进行,要么是你稍微多看一下下一步它会做什么,你说“好的,这不错,这不错......”,然后你就可以通过点击来实现这些更改。

代码差异

Lex:我想提一下Cursor的一个非常酷且引人注目的功能,就是整个代码差异界面的操作过程。模型会用红色和绿色显示代码修改的部分,你可以在聊天窗口中应用它,看到代码差异并接受它。所以也许你可以谈谈这个功能的方向?

Sualeh:我们可能会有四到五种不同类型的代码差异。自动补全的代码差异我们已经优化了,因此它有一个和浏览大段代码时不同的界面。然后我们正尝试为处理多个不同文件时优化另一种代码差异。它的区别在于,当你使用自动补全功能时,读取速度必须非常快。实际上,在所有情况下读取速度都应该非常快,但在自动补全中,你的眼睛集中在一个区域,人类不能同时看太多地方。

Lex:所以你在说的是界面方面的改进?

Sualeh:对,界面方面的改进。目前它在这一侧有一个窗口。我们有当前的框架,如果你在某个地方删除代码并尝试添加其他代码,它会在旁边显示一个弹窗。

 图片来源:youtube

Sualeh:我们尝试了三四次才让它正常工作。最初的尝试是用蓝色的删除线。在它变成旁边的方框之前,它曾经以Google Docs的形式显示删除的代码,你会看到一条划掉的线,然后看到新代码,这样很容易分散注意力。然后我们尝试了很多不同的方案,有删除的,有红色高亮的。

有一个有趣的迭代版本是,你可以按住Mac上的option键,它会高亮一段代码,Prompt可能会有改动。在这个例子中,输入和值部分可能会变蓝。蓝色表示Prompt AI向你提出了建议。它不会直接向你展示内容,但会提示你;如果你真的想看,可以按住option键,然后你就会看到新的建议;而当你松开option键时,你会再次看到原始代码。

Lex:这个功能很不错,但你得知道要按住option键。

Aman:对。

Arvid:我个人非常期待在这个领域做很多改进。我们经常将其称为验证问题,这些代码差异对于小规模编辑来说很棒,但对于大段编辑或多个文件的情况,要检查到这些差异实际上比较困难。所以我们的一个想法是,一部分差异的内容非常重要,信息量很大,而另一部分内容则熵很低,重复性很强;因此,也许可以高亮重要部分,把不重要的部分用灰色标记。又或者可以用一个模型来检查差异,发现bug之后用红色波浪线标记出来,提示你应该检查这部分代码差异。类似的想法让我觉得很兴奋。

Lex:是的,这是一块非常有趣的用户体验设计。你基本上是在引导人类程序员只阅读他们需要的内容,不多不少,最优地完成任务。

Arvid:我们希望能用智能模型来做这件事。目前的代码差异算法只是普通的算法,并不具备智能。虽然设计这些算法时融入了智能,但在执行时它并不关心认识具体的问题,而你希望模型能够做出这种判断。

Sualeh:一个问题是,随着模型将变得越来越智能,它们能够提出的修改会越来越大,人类需要做的验证工作也会越来越多。这会让任务变得更加繁重。我不想花所有的时间在检查代码上。

Lex:你能多谈谈跨多个文件代码差异的情况吗?

Aman:GitHub试图通过Code Review(代码审查)来解决这个问题。当你进行Code Review时,你需要跨多个文件检查多个代码差异。但正如Arvid早些时候提到的,我们可以做得比Code Review更好。Code Review有点糟糕,你要花大量时间去理解这些通常对你而言很陌生的代码,而且往往并不能真正发现多少错误。可以用语言模型来显著改善代码审查的体验,比如Arvid提到的那些技巧,也许能引导你关注那些真正重要的部分。

此外,Code Review应该是为了审查者和代码编写者设计的。如果代码是由语言模型生成而不是其他人编写的前提下,就不必太在意模型的体验,你可以完全围绕审查者来设计流程,让审查者的工作变得尽可能有趣、轻松、高效。我觉得这就是目前的局限所在,只是在简单地模仿代码审查。而实际上可以做的更具创意,突破现有的界限。

Arvid:另一个想法是,顺序很重要。通常当你审查一个PR(Pull Request,拉取请求)时,你会按照文件列表从上到下看。但实际上你可能首先想理解的应该是逻辑上最开始的部分,然后再去理解接下来的部分。你并不想自己搞清楚这个顺序,你希望模型来引导你。

Lex:创建的步骤会越来越多地转向自然语言化吗?

Arvid:有时候是的,但我不认为所有编程都会变成自然语言编写。假如,我和Sualeh一起编程,而Sualeh在操作电脑和键盘。当我在主导时,我对Sualeh说“嘿,帮我实现这个函数”就可以了。但有时要和他解释我想让他做什么实在太过麻烦,我会直接接管键盘展示给他看,我通过写一部分示例让他明白,这是沟通的最简单方式。我觉得对于AI来说也是一样的有时候和AI沟通最简单的方式就是给它一个示例,然后它就会在其他地方完照做。

如果你在制作一个网站,向AI展示你想要效果的最简单的方式不是告诉它该做什么,而是通过拖动或绘制元素来展示你想要的东西。也许最终我们会实现脑机接口或其他技术,这样AI就可以理解你的想法。所以自然语言会有一席之地,但它绝对不会成为大多数人编程的主要方式。

机器学习细节

Lex:我在这个编辑器中真的感觉到了AGI的影子。感觉背后有很多机器学习在运行。能跟我讲讲一些让它运作起来的机器学习技术吗?

Aman:Cursor的原理实际上是我们在训练了一组自定义模型,这些模型在处理复杂推理任务上表现得和前沿模型一样出色。Cursor Tab就是一个很好的例子,它展示了你可以将这个模型专业化,使其在我们设定的任务评估上甚至比前沿模型表现得还要好。

另一个令人惊讶但确实需要自定义模型且运行良好的领域是应用。前沿模型在代码规划和生成变更的大致框架方面相当擅长,但实际上相对比你的训练模型而言,前沿模型在创造差异上是相当困难的。当你尝试使用Sonnet、o1或任何前沿模型来做这个,它们通常会搞砸一些简单的事情,比如在超大的文件中计算行数。所以我们做的改进是,让模型先勾勒出这块代码所需要的修改,然后我们训练一个模型来实际将更改应用到文件中。

Lex:应用是指模型查看你的代码,并给你一个非常棒的新建议。而将这两者结合起来,对于人类来说看似是一个简单的步骤,但你是说这并不那么简单?

Sualeh:与普遍的看法相反,这并不是一个确定性的算法。

Aman:你在其他地方会看到一些浅层的应用副本,它们大多数时候都会崩溃。因为你以为你可以尝试做一些确定性匹配,但40%的结果都会失败,这就导致了非常糟糕的产品体验。总的来说,模型会变得越来越智能。因此,应用能实现的另一件事是让你用更少的Token与最智能的模型交互。生成这些Token既昂贵又耗时,所以提供一个粗略的框架,然后用一个小模型去实现它会简单得多。这个趋势将继续下去,你可以用越来越智能的模型来进行规划,而实现细节可以交给不那么智能的模型处理。也许你可以用o1甚至更强大的模型给出一个更高级的计划,然后递归地通过Sonnet和应用模型来实现。

Sualeh:或许我们应该谈谈如何让它变快,如果你感兴趣的话。速度始终是一个有趣的细节。

Arvid:快速总是好的。

Lex:你是怎么让它变快的?

Aman:实现快速的一个大组成部分是推测性编辑。推测性编辑是推测性解码的一个变体,或许简要介绍一下推测性解码会有所帮助。推测性解码的工作原理是,你可以利用这样一个事实:在语言模型生成时内存受限的大多数情况下,如果你一次处理多个Token,它比一次生成一个Token要快得多。这也是为什么如果你查看提示Token和生成Token的每秒Token数,提示Token的速度要快得多的原因。

我们不使用推测性解码通常所用的小模型来预测初始Token,然后用更大的模型进行验证和编辑。我们对现有的代码有很强的先验知识,而且这个先验实际上就是完全相同的代码。所以你可以做的是将原始代码块重新输入到模型中,模型大部分时间都会同意说,“好的,我会将这些代码原样输出。”这样,你就可以并行处理所有这些代码行,只需对足够多的代码块进行这样的处理。最终你会到达一个分歧点,此时模型将预测出与原始代码不同的文本。它将生成这些Tokens,然后我们会在足够多的Token与原始代码匹配后重新开始以代码块为单位进行推测。

实际上,这看起来就像是普通代码编辑的更快版本。所以它看起来像是模型重写所有代码的更快的版本。我们可以使用与代码差异相同的界面,但它会流式处理得更快。

Sualeh:当它流式处理时,你也可以在代码完成前开始审查代码,这样就不会有大的加载。这可能是其中的优势之一。

Lex:也就是说,用户可以在任务完成前就开始阅读。

Sualeh:我觉得这里有个有趣的想法是,推测在如今是一个相当常见的概念。不仅仅在语言模型中,在CPU中有推测,在数据库中有推测,推测无处不在。

GPT与Claude

Lex:我来问个比较荒谬的问题:哪种LLM在编程上更强?是GPT,还是Claude?在编程的背景下,谁会胜出?我相信答案可能更复杂,因为听起来每个部分都涉及到不同的模型。

Aman:没有一个模型能在所有重要类别中帕累托最优于其他模型,这些类别包括速度、编辑代码的能力、处理大量代码的能力、长上下文处理能力,以及编程能力等。我目前认为综合表现最好的模型是Sonnet,我觉得这也是大家的共识。o1非常有趣,特别擅长推理。如果你给它一些难度较大的编程面试题或LeetCode问题,它表现得很好,但它对你大致意图的理解不如Sonnet。

如果你观察其他一些前沿模型,有一个问题是,虽然它们在基准测试中表现非常好,但它们在实际场景中的表现并不一定出色。我不是说它们专门针对基准测试进行训练,但它们相对其他模型在基准测试中表现得很好。然而,当你稍微超出基准的范围时,Sonnet是能够保持相同能力的模型之一,无论是在基准测试中,还是在实际编程任务中,它的表现都很稳定。

Lex:另一个荒谬的问题是,日常编程体验与基准测试的区别是什么?你认为在评估这些模型时,基准测试有什么不足?

Sualeh:这实际上是一个非常重要且复杂的细节,基准测试与真实编程有很大的不同。真实编程不是面试风格的编程。人类有时会说半吊子的英语,比如有时会说“做我之前做过的事”,有时你会说“添加这个功能,然后为我做另一个功能,还要做一个UI元素。”很多内容都依赖于上下文。你需要真正理解人类的意图并满足他们的需求。抽象地说,面试问题非常具体,依赖于规范,而人类的需求则较为模糊。

Michael:我觉得这个基准测试问题很复杂,这个问题在于如何在基准测试中建模以克服和真实编程的偏差。这有时很难概括,因为真实的编程非常混乱,很多时候正确与否并没有明确定义。而且公共基准测试的问题也加剧了这个困难。这不仅是因为公共基准测试有时被作为“攀比”对象,而且也很难从这些基准测试中提取出有效的数据。

比如,一个最受欢迎的Agent基准测试SWE-Bench,其基础模型的训练数据受到了非常严重的污染。所以,如果你让这些基础模型解决一个SWE-Bench问题,但不给它们提供代码库的上下文,它们可能会“幻觉”出正确的文件路径或函数名。因此,公共基准测试的问题相当复杂。

Aman:在这种情况下,它可以针对文字问题或拉取请求本身进行训练,也许一些实验室会在去除这些污染方面做得更好;或者已经做得很好,但他们不会忽略仓库本身的训练数据。这些都是最受欢迎的Python库。SimPy就是一个例子。为了在这些基准测试中获得真实的评估分数,他们不会在处理SimPy和所有这些流行的Python仓库时对其模型进行限制。

Michael:鉴于基准测试中的缺陷,有些构建这些系统或模型的地方使用了一些有趣的辅助措施来评估模型的方向是否正确。在很多地方,人们实际上会让人类与这些模型交互,并提供定性的反馈。有一两家基础模型公司,他们的团队里有专门负责这部分工作的人。我们内部也对这些模型进行定性评估,并且非常依赖这些反馈,除了我们的私人评估。

Lex:这就像一种“感觉”。

Arvid:就是感觉。

Lex:感觉基准,人类基准,依靠人类来进行“感觉检查”。

Arvid:是的。

Lex:这就是我做的。我会阅读网上的论坛、Reddit和X上的评论。我不知道该如何准确地吸收这些人的意见,因为他们会说类似“我觉得Claude或者GPT变蠢了”之类的话。他们会说“我感觉…”然后有时我自己也会有这种感觉,但我不知道是模型的问题还是我的问题。

Aman:关于Claude有一个有趣的观点,我听说AWS有不同的芯片,我怀疑它们的数值计算方式与Nvidia GPU有些不同,有人推测Claude的性能下降可能与AWS基岩上使用的量化版本有关,而不是Anthropics的GPU上的版本。

Lex:我采访过很多人,有很多阴谋论。我很高兴你提到了这个“阴谋论”。

Sualeh:这与其说是阴谋论,不如说是人性。人类就是这样,会注意到很多细节。而且在处理大量运算时,芯片设计也很复杂,你难免会遇到bug,要避免bug是非常难的。

Prompt工程

Lex:在这一切中,一个好的Prompt的作用是什么?我们提到基准测试使用的是结构化且精心制定的Prompt。你曾写过一篇关于Prompt设计的博客。

Arvid:这取决于你使用的是哪种模型,它们对不同Prompt的反应也略有不同。GPT-4和其他早期的原始模型就对Prompt非常敏感,而且它们的上下文窗口很小。代码库中有许多信息可能与Prompt相关,例如文档、你添加的文件和对话历史。但问题是,当你在有限空间的情况下,如何决定将哪些内容放入Prompt中?即便是今天的长上下文模型,填满整个上下文窗口会导致处理速度变慢,甚至有时模型会因此混淆。

针对这个问题,我们内部有一个系统叫Preempt。它在上下文窗口只有8000个Token的时期就构建了。有点类似于你在制作网站时,你希望在移动端和桌面端都能正常显示网站的页面,但你需要考虑一些动态的信息,毕竟网页设计不像杂志排版是固定的。网站和Prompt的输入都是动态的,你需要确保格式始终适用,输入量很大时,需要删减一些内容。

因此,我们从设计网站的思路中提取了灵感。我们非常喜欢React 和声明式的方式,比如你可以在JavaScript中使用JSX,然后直接声明:“这就是我想要的,这个部分比其他部分具有更高的优先级或更高的Z轴顺序。”

在网页设计中,渲染工作由渲染引擎来完成。而在Cursor中,这个任务由Preempt负责,它将所有内容布局到页面上。你只需说明你想要的效果,它会自动帮你实现。

我们发现这种方法非常有用,而它的角色随着时间的推移已经发生了变化:最初它是为了适应小的上下文窗口,而现在它在拆分进入Prompt的数据和实际生成方面发挥了很大作用。因此,调试起来更加简单,因为你可以修改Prompt,并在旧的Prompt上进行测试,直接查看你的修改是否真的提升了整个评估集的表现。

Lex:所以你们真的用JSX写Prompt吗?

Arvid:对,Preempt看起来像React。我们有一个组件是文件组件,它会获取光标位置。通常光标所在的那一行是最重要的,因为它停留的地方通常是你正在关注的内容。你可以给出优先级,这一行的优先级最高,然后离它越远的行优先级逐渐降低。最终,当Prompt被渲染时,系统会计算出能显示多少行代码,并以光标所在的行为中心进行呈现。

Lex:这太棒了。

Aman:你还可以做一些更复杂的操作,比如整个代码库中有很多代码块时,可以通过检索、嵌入和重新排序分数来为这些组件自动添加优先级。

Lex:那么人们在提出问题时是否也应该尝试使用这样的方式?用JSX写Prompt会有帮助吗,还是说Prompt应该保持松散和自由的风格?

Arvid:我们的目标是让你做最自然的事情,我们的工作是弄清楚如何检索相关的事件,使你的思维方式有意义。

Lex:我与Perplexity的Aravind讨论过这个问题,他的观点是应该让人类尽可能懒惰,这很好。但我觉得对程序员你可以要求更高,不是吗?

如果你告诉他们“你随便做”,人往往是懒惰的。懒惰与提供更多信息之间存在一种张力:一方面人们可以随意提问,另一方面系统应该鼓励你提供更有深度的想法,不仅仅是句子语法,而是在Prompt中表达出更多的意图。

Aman:即使AI统接近某种完美水平,你仍无法传递足够明确的意图来指引模型该做什么。有几种方式可以解决这一问题。一种是是让模型问你:“根据你的查询,我不确定如何处理这些部分,你能明确一下吗?”另一种方式是,如果有五六种可能的结果,模型可以告诉你:“鉴于你目前的查询有不确定性,我们可以展示所有的这些选项供你选择。”

Lex:模型在应对不确定性时选择对话反馈有多难?是选择询问更多信息,还是在不确定的情况下直接给出结果?

Sualeh:最近我们增加了一项功能,它会尝试建议你添加文件。当你编写代码时,模型会尝试预测你正在做什么,当它发现不确定的时候,它会查看你的历史记录,推测哪些文件和当前编辑的内容相关,这在客户端和服务器的编辑都非常有用。

这涉及一个技术难题:如何在所有历史记录中找到相关的信息,判断在当前的Prompt下哪些文件最重要。虽然目前这个功能还处于试验阶段,未来我们会逐步完善。我们的想法是向用户展示:你是否想添加这个文件、那个文件,以便模型帮你编辑?

如果你正在编写一个API,你可能还需要编辑API的客户端和服务器的代码。因此,在你编写Prompt时,也许我们可以提前帮助解决一些不确定性。

AI Agent

Lex:你们在多大程度上使用Agent?Agent有多有用?

Arvid:我们认为Agent真的非常酷。Agent有点像人类,你能感觉到你离AGI更近了。目前Agent在许多事情上还不是非常有用。我觉得我们正在接近能够真正有用的地方,所以在某些类型的任务中,拥有一个Agent会非常不错。

我很想拥有一个Agent。例如,如果我们有一个bug,有时候在我们的聊天输入框中你无法使用Command+C和Command+V,这个任务非常明确。我只想用两句话说:“这个不工作,请修复它。”然后我会希望有一个Agent可以去做这件事,然后一天后我回来看结果。

Lex:你的意思是它去找到正确的文件?

Arvid:是的,找到正确的文件,尝试重现bug,修复bug,然后验证这是正确的。这可能是一个耗时的过程。所以我希望有这样的Agent。然后很多编程中,人们常常认为Agent会接管所有编程。我不认为情况是这样的,因为很多编程中,很多价值在于迭代,或者你实际上不想事先指定一些东西,因为你不知道自己想要什么,直到你看到了初始版本,然后你想在此基础上进行迭代,然后你提供更多的信息。

所以对于很多编程,你实际上想要的是一个即时的系统,它能快速给你一个初始版本,然后你可以非常非常快速地迭代。

Lex:那么像最近推出的Agent,那种能够设置开发环境、解决软件包、安装配置一切、配置数据库并实际部署应用程序的那种Agent呢?这也是你梦寐以求的事情之一吗?

Arvid:是的,这样的功能会非常酷。

Lex:这是Cursor的范围之内吗?

Arvid:我们目前并没有积极地在做这件事,但我们绝对是希望让程序员的生活更轻松、更有趣。有些事情真的很繁琐,你需要经过一堆步骤,你希望把这交给一个Agent。然后有些事情,你实际上可以在你工作时有一个Agent在后台。例如,你有一个涉及前后端的PR,你正在处理前端部分,然后你可以有一个后台Agent在工作,了解你在做什么。然后当你到达PR的后端部分时,你就会有一些初始的代码可以进行迭代。这也会很酷。

Lex:我们之前谈到过速度,我想我们可以再多停留在这方面。讨论一下Cursor中让这一切变得非常快的各种技术细节。Cursor的大多数方面都让人感觉非常快。就我而言,应用可能是最慢的事情。

Arvid:我知道。我们正在努力修复它。

Lex:大约一秒或两秒,这感觉很慢。这实际上表明其他所有事情都非常快。那么有没有一些关于如何让这些模型、让聊天变得快速、让代码差异变得快速的技术细节可以分享一下?

Aman:是的。我们可以讨论我们使用的许多策略。一个有趣的事情是缓存预热。如果用户正在输入,你可以预测用户将要使用某些上下文,而你可以在用户完成输入之前知道这一点。因此,正如我们之前讨论的,重用KV缓存会降低延迟,降低成本,跨请求。因此,当用户开始输入时,你可以立即用当前文件的内容预热缓存,然后当他们按下回车键时,实际上需要预填充和计算的Token非常少,随后开始生成。这将显著降低TTFT(Time to first Token,首Token延迟)。

Lex:你能解释一下KV缓存是如何工作的吗?

Aman:Transformer不仅能独立查看每个Token,还能看到之前的Token,这得益于注意力机制中的键(Key)与值(Values)。一般而言,注意力机制的运行方式是,针对当前Token和query,你有所有之前Token的键与值,这些键与值是模型内部对所有先前的Token和Prompt的某种表征。在默认情况下,当你进行聊天交流时,模型需针对每一个Token,执行完整的前向传递过程来遍历整个模型,这个过程涉及大量的矩阵乘法运算,效率很低。

相反,如果你已经完成了这个步骤并且存储了键和值,并将它们保存在GPU中。那么假设我需要对最后n个Token进行排序,如果我现在想计算n+1个Token的输出,就不需要将这前n个Token通过整个模型进行处理,因为我已经拥有了所有这些键和值。所以你只需要对最后一个Token进行前向传播,然后在你进行注意力操作时,重用那些已经计算出的键和值,这是transformer中唯一的顺序部分或顺序依赖部分。

Lex:是否还有其他更高级的缓存,比如缓存提示等,这些东西是否能有所帮助?

Aman:是的,还有其他类型的缓存可以使用。对于Cursor Tab来说,你可以预测用户会接受建议,然后触发另一个请求。这样你就在完成缓存的同时也进行了预测,这是一种预测和缓存的结合。模型在预测如果用户接受了建议会发生什么,然后就有这个缓存的值。当他们按下Tab键时,下一条建议就会立即出现。这是一个巧妙的方法,利用更高级的缓存,尽管模型没有发生任何变化,仍然能让用户感觉速度很快。

Sualeh:如果你能缩小KV缓存的大小,一个好处是你可以进行更多的预测。比如,“这里是10个可能有用的东西,预测接下来的10个”,然后用户命中其中之一的概率会比点击确切的某一个更高;也许他们会输入其他字符并命中了缓存中的其他内容。这里的普遍现象是,这对于RL也非常有用,也许来自模型的单个样本不是很好,但如果你预测10个不同的东西,实际上其中一个正确的概率会更高。

你可以这样理解,模型在内部对哪些关键内容是正确的,或者哪个关键内容是人类想要的,存在一定的不确定性。当我们对Cursor Tab模型进行RL时,我们在做的事情之一是在预测模型生成的100个不同建议中哪些更符合用户的期望。也许有些地方模型可以预测得非常远,也许有些地方则只能预测一点点,或者介于两者间的某个地方。你可以给这些用户更喜欢的内容给予奖励,而对那些不喜欢的内容进行惩罚,从而训练模型输出人类更喜欢的建议。

Aman:这与速度稍微不同,但从技术上讲,因为如果你对小模型进行强化训练,可以使其性能与较大的模型相同。

正如我之前提到的关于减少KV缓存的大小,还有其他一些技术对于提升速度也非常有帮助。两年前大家主要使用MHA(Multi-Head Attention,多头注意力机制),现在已经向更高效的注意力方案迁移,比如GQA(Group Query Attention,分组查询注意力机制)或MQA(Multi-Query Attention,分组查询注意力机制)。这对于处理大批量数据,从而更快生成Token非常有帮助。有趣的是,这现在对首次Token预填充速度没有影响。这对生成Token的速度很重要。

为什么会这样?因为在生成Token时,你不再受限于对所有Token进行高度并行的矩阵乘法运算,而是受限于在处理长上下文和大批量数据时,你读取缓存、键和值的速度有多快。

这就是内存带宽的问题,那么我们如何能让它更快呢?我们可以尝试压缩这些键和值的大小。MQA是这些方法中最激进的一种,在常规的MHA中,你有一些注意力头和一些查询头。MQA只保留查询头,去掉所有的键值头。因此,只存在一种键值头,而其余的都是查询头。在GQA时,你则保留所有的查询头,键值头的数量会减少,但并不会减少到只有一个。无论如何,这里的关键点都是你在减少KV缓存的大小。

Arvid:然后是MLA(Multi-head Latent Attention,多头潜在注意力)。

Aman:这有点复杂。它的工作方式是将所有注意力头的键和值整合为一个潜在向量,这个向量会随着时间的推移而扩展大小。

Sualeh:MLA来自DeepSeek公司。这是一个相当有趣的算法。也许关键思想在于,无论是在MQA还是其他地方,你所做的都是在减少键值头的数量,但理论上你希望每个键和值实际上是不同的。所以一种减少的方法是,为所有的键和值保留一个大的共享向量,然后为每个Token保留较小的向量。这样,你只需要存储较小的部分,作为一种低秩压缩(low-rank reduction)。而在最终计算时,你的内存带宽仍然有足够的计算能力来处理这些事情。如果你能够将潜在向量扩展回原来的大小,那么这种方法会更加高效,因为你可能将向量的大小从32减少到了你所保留的大小。

Aman:是的,拥有一组单独的键值和查询相互匹配,相较于将所有内容压缩为一个,可能在某种交互中有更丰富的优势。

Lex:好的,这一切都在处理内存限制的问题。最终,这如何映射到用户体验上?

Aman:这两件事情的映射是:首先,你现在可以让缓存变得更大,因为你为KV缓存分配的空间减少了。也许你可以更积极地缓存更多的东西,这样你就会有更多的缓存命中,对减少首次生成Token的时间很有帮助,原因在之前已有描述。其次,当你开始处理更多的请求和更大批次的推理时,你在生成Token时不会看到太大的减速。

所以你的KV缓存的大小是所有提示的大小乘以并行处理的提示数量。因此,你可以增加这两个维度中的任何一个,批次大小或提示大小,而不会降低生成Token的延迟。

后台运行代码

Lex:Arvid,你写了一篇博客文章《Shadow Workspace: Iterating on Code in the Background(影子工作区:在后台迭代代码)》。是发生了什么吗?

Arvid:明确一点,我们希望后台有很多事情在同时进行,并且我们在尝试很多方法。目前,除了缓存预热和找出适合你命令提示的上下文之外,还没有其他的内容。这个想法是,如果你能在后台进行计算,那么你可以在更长的时间视野上帮助用户预测,比如接下来10分钟内用户会做什么,而不仅仅是预测将要写的下一几行代码。通过在后台进行处理,你可以花更多的计算资源来完成这个任务。所以实现Shadow Workspace(影子工作区)的想法是,为了能真正在后台做事情,你需要有某种反馈信号给模型,否则你可以仅仅通过让模型思考更长时间来提高性能,o1就是一个很好的例子。

改善性能的另一种方式是让模型进行迭代并获得反馈。当你是程序员时,一个非常重要的反馈就是语言服务器,它存在于大多数不同的语言中,每种语言都有一个单独的语言服务器。它可以告诉你,“你在这里使用了错误的类型”,然后给出错误提示,或者允许你跳转到定义并理解你代码的结构。语言服务器是一个扩展,TypeScript语言服务器由TypeScript团队开发,Rust语言服务器由Rust团队开发,然后它们都通过语言服务器协议与VS Code进行接口。因此,VS Code不需要将所有不同的语言内置到VS Code中,而是可以使用现有的编译器基础结构。

Lex:是出于linting(代码检查)目的吗?

Arvid:这是用于linting、跳转到定义和查看你所使用的正确类型。

Lex:所以它也在进行类型检查。

Arvid:是的,进行类型检查和查看引用。当你在一个大型项目中工作时,你确实需要这个。如果没有它,在一个大型项目中编程是非常困难的。

Lex:在Cursor内部是如何使用语言服务器协议进行通信的?

Arvid:在Cursor中它和在VS Code一样。但我们的想法是希望以某种方式将这些信息展示给模型,即IM模型(Instant messaging model,即时通讯模型),并且希望以不影响用户的方式来完成这一点,即在后台进行。所以Shadow Workspace的想法是,我们可以创建一个隐藏的单独的Cursor窗口,它会有隐藏标志,用户可以设置使其隐藏。在这个窗口内,AI Agent可以随意修改代码,只要用户不保存,因为仍然是同一个文件夹;然后模型可以从linting工具中获得反馈,跳转到定义,并对代码进行迭代。

Lex:所以从字面上看,所有操作都在后台进行,甚至可能运行代码。

Arvid:这是最终的版本,是我们想追求的。博客文章的大部分内容实际上是关于如何使这些成为可能,毕竟这有点困难。你希望在用户的机器上进行,以便镜像能确切地反映用户的环境。在Linux上,你可以做这个很酷的事情,你可以镜像文件系统让AI对文件进行修改,它认为自己是在文件级别操作。但实际上,这是存储在内存中的,你可以创建一个类似内核扩展来使其工作。而在Mac和Windows上会稍微困难些,但这是一个有趣的技术问题,也是我们探讨它的原因所在。

Aman:一个或许有点粗糙但又有趣的想法是锁定存储。基本上,你可以让语言模型锁定保存到磁盘,而不是让你在真正的文件上操作,你实际上是在之前的“影子工作区”中工作,虽然你仍然会收到错误提示,并且可以进行编码,但这些未保存的内容只存在于内存中。当你尝试运行代码时,可能会出现一个小警告,提示有一个锁定。然后,如果你尝试并发操作,就需要从语言服务器或影子工作区中回收锁定。

Lex:顺便说一句,这真是一个令人兴奋的未来。这有点离题,但允许模型更改文件对人们来说有点吓人,但这真的很酷。能够让Agent执行一系列任务,然后你第二天再回来观察,就像和一个同事一起工作一样。

Aman:在可运行性方面可能有不同的版本。对于那些在几分钟内代表用户进行的简单操作,在他们的机器上做一些事情并在本地运行是合理的。而对于更复杂的任务,涉及较大更改且耗时较长,可能需要在某种沙盒远程环境中进行。这是另一个非常棘手的问题,如何精确重现或大致重现用户的环境,以使其在这个远程沙盒中运行代码时有效等效。

代码调试

Sualeh:我很好奇你希望在编码中使用什么样的Agent。你希望它们找到bug吗?你希望它们实现新功能吗?你希望有哪些Agent?

Lex:顺便说一下,当我想到Agent时,我不仅仅会考虑编码,也会考虑到视频编辑。如果你看看Adobe,你会发现它的背后有很多代码。这些代码记录得很不完整。但你可以通过代码与Premiere进行交互基本上所有的上传,我在YouTube上所做的一切,你可能想象得到的一切,我都是通过代码完成的,包括翻译、配音等等。

所以我设想了所有这些任务,将许多与编辑无关的任务自动化。这就是我的想法。但在编码方面,我会从根本上考虑bug查找,比如多层次的bug发现,同时还有逻辑bug的查找。或者说是一种像实现的大方向之类的东西。

Sualeh:让你找到bug。

Aman: 是的,实际上这些模型在查找bug方面确实很糟糕。当被简单提示去寻找bug时,它们的表现非常差。

Arvid:即使是最聪明的模型。

Aman:没错,就是那样。

Lex:你如何解释?有没有什么好的直觉?

Aman:这些模型很好地反映了预训练的分布情况。而且随着损失的降低,它们的泛化能力提高了。但我并不认为损失足够低以至于它们能在代码中完全泛化。就像我们用这些东西做的前沿模型一样,它们擅长的其实是代码生成和问题解答。

这些在预训练中存在大量数据,包括GitHub上的所有代码和数万亿个Token,还有Stack Overflow等网站上的问题和答案,也许还有GitHub上的问题。因此,当你尝试推测一些实际在网上并不常见的东西时,举个例子,Cursor tap的目标是预测下一次编辑,考虑到目前已经完成的编辑,其脆性可见一斑。

bug检测也是一个很好的例子,实际上,真正能检测出真正bug的例子并不多,并且还要提出修复建议,模型在这方面真的很吃力。但这是模型转移的问题。就像你从预训练模型转移到一般代码上那样。从代码到光标标签目标,你会发现广义模型也有非常非常相似的地方。这些模型都非常擅长从代码到bug的检测,只需要在这个方向上稍加点拨。

Sualeh:需要明确的是,它们对代码的理解其实非常透彻。在预训练期间,模型建立的表示几乎可以肯定是在某个阶段,模型意识到可能有些地方不太对劲。但实际上引导出这种不确定性,部分原因在于需要对人类认为哪些bug真正重要有很好的判断。并不仅仅是说有些东西看起来不太对劲。这就好比,这个不太对劲的事情是微不足道的?还是说会导致服务器崩溃?部分原因可能是文化知识。

为什么一名资深工程师会是资深工程师?因为他们知道三年前有人写了一段非常不靠谱的代码,导致服务器崩溃。而不是说,这也许只是一个实验,所以一些bug是可以接受的。你只是想做个实验,找找感觉。

如果模型在你编写实验时变得很烦人,那是非常糟糕的。但如果你是在写一些超级生产的东西,比如说在写数据库,或者在Postgres或Linux中写代码,像Linus Torvalds一样。在这种情况下,即使是一个边缘案例也是不可接受的。只需了解用户的偏执程度就可以了。

Aman:但即便如此,如果你把最大的偏执程度放进去,它仍然不太理解。

危险代码

Lex:但对人类来说,理解哪一行代码重要、哪一行不重要也很困难。你们网站上的一条原则说过,如果一段代码可能造成很大损害,应该添加注释说明这一行代码很危险。在函数内的每一行代码上都是这样。这是非常深刻的。这说明了人类的一些问题,因为工程师会离开。即使是同一个人,也可能忘记一个函数能否引发灾难。通过观察一段代码,可能不会直观地意识到。

Arvid:是的,这对今天的AI模型也是适用的,如果你在每一行代码上写下“危险,危险,危险”,模型会更关注这个地方。并且更可能找到这个区域的bug。

Lex:这实际上是标记代码时很好的实践,说明这段代码可能造成多大的损害。

Arvid:是的,但有些人认为这很丑陋。

Sualeh:从美学上讲,我不喜欢这样,但我确实认为这对模型和人类都是非常有用的。因为人类会遗忘很多东西,很容易犯一个小错误,导致服务器崩溃。我们当然进行了很多测试,但总是会有这些需要非常小心的事情。

Aman:是的,比如说普通的DOC字符串。人们在进行更改时常常会匆匆浏览,并认为:哦,我知道怎么做。你确实需要提醒他们,以免遗漏。

Lex:是的,你必须提醒自己可能造成很大损害。我们其实并没有真的考虑到这一点。我们思考的是,好的,我如何弄清楚这个如何运作,以便我可以改进它?你不会考虑到另一种可能性。

Arvid:直到我们对一切都有正式的验证,如果证明通过了,确保你没有引入bug,然后你可以随心所欲。

Aman:但具体来说,你认为未来会是什么样子?

Arvid:人们不会再写测试了。模型会建议你写一个函数或规范,然后你进行审查。同时,智能推理模型会计算出一个证明,确保实现符合规范。这适用于大多数函数。

Michael:你觉得这是否涉及到你之前提到的关于软件意图规范化的困难?有时候,这可能是因为意图确实很难明确表达。这样一来,证明它确实符合你的意图也会变得非常困难。

Arvid:你认为规范很难生成吗?

Michael:是的,或者说能否进行形式验证?这里还有很多值得深入探讨的地方。

Arvid:即使你有规范呢?

Michael:即使你有规范,那个规范是用自然语言写的吗?

Arvid:不,规范应该是正式的。

Michael:那么你关心的事情在规范语言中并不容易明确定义。

Arvid:我明白了。

Michael:也许这就是反对形式验证的一个论点。

Aman:是的,问题是会有一个庞大的文档。

Michael:替代单元测试之类的东西。

Arvid:你可能还可以发展规范语言,以捕捉当前无法很好捕捉的一些东西。我也不知道。我觉得这非常令人兴奋。

Lex:而且你说的不仅是单个函数,而是整个代码库。

Arvid:整个代码库更难,但这是我非常想要的。我觉得这是可能的。因为最近有很多工作,甚至可以证明,形式验证可以深入到硬件。比如你形式验证C代码,然后通过GCC编译器进行形式验证,再通过Verilog直到硬件。这是一个非常庞大的系统,但实际上是可行的。

大代码库在某种程度上是类似的,因为它们是多层次的系统。如果你能够对其进行分解并形式验证每个部分,那么这是可行的。我觉得规范问题是真正的问题。

Aman:你如何处理副作用,或者说如何处理外部依赖,比如调用Stripe API?

Sualeh:也许Stripe会为他们的API编写一个规范。

Aman:但这并不是说你能为你使用的所有东西都这样做。像如果有一种语言,比如人们会把语言模型当作他们编写程序中的基本元素,而且会对其产生依赖。那么你现在如何将其纳入其中?

Arvid:你可能仍然能够证明这一点。

Aman:关于语言模型你能证明什么?

Arvid:这感觉是可行的。比如你可以证明一个语言模型是对齐的,或者你可以证明它确实给出了正确的答案。

Sualeh:这就是梦想。

Lex:是的,如果这是可能的,那就是你所说的“我有一个梦想”的演讲。如果这是可能的,那肯定会帮助确保你的代码没有错误,也确保AI不会摧毁人类文明。所以这是AI安全的全谱,从简单的bug查找到更复杂的任务。你提到模型在bug查找上有困难,那希望在哪里?

Sualeh:我最初的希望是,它应该能够帮助捕捉那些简单的错误。它应该能很快发现那些简单的错误,比如偏差错误。有时候你在评论中写了某个东西,结果却反了。这种情况很常见。我经常会在评论中写“少于”,但实际却可能写成“到”。模型会说,这看起来有点可疑,你确定要这样做吗?但最终它应该也能捕捉到更复杂的错误。

Michael:是的,重要的是要注意,拥有良好的bug发现模型对于实现AI在编程上做更多工作是必要的。如果AI在为你构建越来越多的系统,你不仅需要生成代码,还需要验证代码。如果没有bug发现模型,我们之前讨论的用这些模型编程的问题将变得无法解决。所以不仅仅是为了人类,像我或是你写bug,还要找到AI生成的代码中的bug,这也非常重要。

Arvid:那么你如何实际做到这一点呢?我们在晚餐讨论中也有很多争议,如何实际训练一个bug模型。一个非常受欢迎的想法是,介绍一个错误可能比实际发现错误容易得多。因此,你可以训练一个模型在现有代码中引入错误。然后你可以训练一个反向错误模型,用合成数据来发现错误。这是一个例子,但还有很多方法。

Michael:你还可以做很多工作,不仅在模型层面取最大的模型。然后可能给它们访问很多信息,不仅仅是代码。看着一个文件并说“哪里有bug”是一个难题,这对于人类来说往往也很困难。所以你通常需要运行代码,并能够查看跟踪和逐步调试。

还有另一种方向,这也正在朝这个方向发展。可能有两种不同的产品形式。你可能有一个非常专业的模型,运行得很快,在后台尝试寻找错误。有时候就像Sualeh和Arvid之前提到的恶意输入框错误。有时候你会想,要解决这个bug。你不是在无假设地检查,而是说这是一个问题,我真的想解决它。你会倾注大量计算资源去解决这个bug,甚至愿意花50美元或更多。

Lex:你有没有想过把钱整合进这个整个体系中?如果你找到一个错误,或者生成的代码让我非常满意,我可能会愿意支付一笔钱。几天前我就有过这样的体验。当我开始使用Cursor时,它生成了三个完美的函数,用于与YouTube API交互,更新字幕和进行不同语言的本地化。

API文档并不好,代码的来源也很杂乱。我在网上找了很久,结果我找不到确切的答案,信息非常混乱。而Cursor生成的代码完美无瑕。我当时坐在那里,阅读代码时心想:这没错。我测试了一下,结果也是正确的。

我当时就想,我希望有一个按钮可以给个小费,给5美元。一个是为了支持公司和这个接口,另一个则可能发出一个强烈的信号,比如“干得好”。这比仅仅接受代码要强烈得多。对于bug发现,显然有很多人愿意为发现一个bug付出巨额资金,比如类似悬赏的事情。你们是否考虑过这个?

Arvid:是的,这在公司内部是个有争议的想法。这很大程度上取决于你对人性的信任程度。如果你不花一分钱就能找到一个bug,那会很酷。如果没有发现bug,你就花了0美元;如果发现了bug,点击接受后,括号里显示像是1美元。那样你就花了1美元接受bug。

当然,还有担忧,比如说,我们消耗了大量计算资源,可能会有人直接复制粘贴,这是一个担忧。还有一种担忧是,钱的引入可能会让产品失去趣味。你会变得在意金钱,而不是代码本身。所以也许实际上将其分开更有意义。比如每月支付一些费用,然后你就能免费得到所有这些服务。

Lex:但可能会有一个小费的组成部分。

Arvid:只要还有那个美元符号,我觉得就没问题。不过我也理解,或许你不想引入这一点。

Aman:是的,我想说的是,感觉人们会在分享时做这些事情。当他们有一个出色的例子时,就会和朋友分享。

Michael:还有一个潜在的世界,是在技术层面有解决方案。比如在我们的系统问题中,如果我们能够在理解系统输出方面达到一个新的水平,比如我们之前讨论的通过LSP进行错误检查,再运行代码。但如果你能达到一个地方,可以实际验证“哦,我修复了bug”,那么悬赏系统可能就不需要依赖于信任系统了。

文件系统分支

Lex:终端与代码之间的交互有多大?如果你在终端中运行代码,可以获得多少信息?你是否可以使用一个循环来运行代码,并在代码运行时出现错误时建议如何更改代码?现在它们完全是两个不同的世界。我知道你可以在终端中使用控制K来帮助你编写代码。

Aman:你也可以在checkmk中使用终端上下文来处理一切,几乎所有的东西都可以。我们还没有循环部分,所以我们怀疑像这样的东西可能会很有意义。还有一个问题是它是否也会在前台发生,或者像我们讨论的那样在后台发生。

Lex:当然,后台的确很酷。比如我们以不同的方式运行代码。此外,还有数据库方面的问题。你怎么防止它修改数据库?

Sualeh:我觉得那里面确实有很酷的解决方案。现在正在开发一个新的API,它不在AWS上,但我知道它应该是在PlanetScale。我不确定PlanetScale是否是第一个进行编辑的。它的稳定性能够向数据库添加分支,如果你正在开发一个功能并想要在一个大数据库上进行测试,但又不想直接在大数据库上测试,你可以向数据库添加一个分支。做到这一点的方法是向正确的头日志添加一个分支,当然,正确地做到这一点会有很多技术复杂性。

我想数据库公司需要新的事情可做。现在它们的数据库已经很好了。我觉得我们使用的TurboBuffer可能会添加分支到正确的头日志。所以也许AI Agent会使用分支,比如说,在某个分支上进行测试。这可能会成为数据库支持分支的一种要求。

Aman:如果你能给文件系统分支,那会很有意思。

Sualeh:是的,我觉得一切都需要分支。

Lex:这就像多元宇宙的问题。如果你在所有事物上都进行分支,那就太多了。

Sualeh:显然有一些超级聪明的算法,可以确保你不会实际使用太多空间或CPU资源。

Lex:这是个问基础设施的好环境。你们大多使用AWS,有哪些有趣的细节?有什么有趣的挑战?你们为什么选择AWS?为什么AWS仍然处于领先地位?

Arvid:AWS真的是非常好。使用AWS的产品时,你知道它一定能正常工作。虽然设置过程可能让人觉得很痛苦。

Lex:为什么界面如此糟糕?

Arvid:它实在是太好了,它的实力好到没必要优化界面。

Lex:这就是成功的本质?

Sualeh:正是如此,这就是成功的本质。

Arvid:但你总是可以信任AWS,它总是能正常工作。如果有问题,那有可能是你的问题。

扩展挑战

Lex:好吧,有什么有趣的挑战吗?你们作为一家新的初创公司,如何获得扩展以适应这么多人?

Michael:是的。我觉得这是一个有趣的旅程,随着每秒的请求数增加一个零,我们在缓存和数据库等常规组件中会遇到所有的这些问题,随着规模的扩大都会显现出来。现在我们的规模已经到了会遇到表溢出等问题的地步。而且我们还建立了一些自定义系统,比如我们用来计算代码库语义索引并回答代码库问题的检索系统。这一直是一个比较棘手的扩展问题。

Sualeh:我有几个非常资深的工程师朋友,他们常说,预测系统在哪会崩溃非常困难。当你扩展它们时,你可以尝试提前预测,但总会有一些奇怪的事情发生。当你增加这个零时。你以为你考虑到了所有问题,但实际上并没有。我觉得对于那个特定的系统来说,具体来说,我们的做法是,上传所有代码,然后将代码分块嵌入,将嵌入存储在数据库中,但实际上不存储任何代码。

我们这样做的原因是为了确保不引入客户端错误,因为我们非常担心客户端错误。我们将大部分细节存储在服务器上,一切都是加密的。所以一个技术挑战始终是确保本地索引、本地代码库的状态与服务器上的状态相同。最终做到这一点的方法是对每个文件保持一个哈希值,对每个文件夹保持一个哈希值,这个哈希值是其所有子项的哈希值。你可以递归地这样做,直到最顶层。

你可以为每个文件保持一个哈希值。每分钟你可以尝试下载服务器上的哈希值,找出哪些文件在服务器上不存在。也许你刚创建了一个新文件,也许你刚删除了一个文件,也许你检出了一个新分支,尝试协调客户端和服务器之间的状态。

但这会引入巨大的网络开销,在客户端也是如此。如果你正在使用Cursor的话,我想没有人希望我们不断占用他们的Wi-Fi,而且这也会在数据库上引入巨大的开销。它每秒读取数10TB的数据库,接近20TB左右的数据库。这实在是太疯狂了。你绝对不想这样做。

所以我们就只试图协调项目根目录的单个哈希值。如果有不匹配的地方,我们就去找出所有不一致的地方。也许你查看子项,看看哈希是否匹配。如果哈希不匹配,就继续查看它们的子项,依此类推。但你只有在出现不匹配的情况下才这样做。对于大多数人来说,大多数时候哈希是匹配的。

Lex:所以这有点像分层协调。

Sualeh:是的,差不多。

Aman:这被称为默克尔树。

Lex:是的,看到你们必须考虑所有这些问题真是很酷。

Sualeh:之所以变得困难,就是因为使用它的人数增加,一些客户有非常大的代码库。我们最初编写的jar代码库是很大的。但这远不及一些存在了20年的公司的规模,那种公司拥有巨大的文件数量。

你想要在程序员之间扩展,这里面有很多细节,比如构建一个简单的东西是容易的,但将它扩展到很多人、很多公司,显然是一个独立的难题。这是我们扩展现有解决方案的一部分,同时我们也在不断提出新的想法。然后在过去几周、几个月中进行扩展。

Aman:是的,还有很多聪明的办法,比如说进入这个索引系统的附加内容。例如,成本的瓶颈不在于将内容存储在数据库的工厂数据库中,而实际上是在嵌入代码。你不想为每个使用相同代码的公司中的每个人重新嵌入代码库,除了他们可能在不同的分支上有一些不同的文件,或者他们做了一些本地更改。

所以因为嵌入是瓶颈,你可以用一个聪明的技巧,避免在其他数据库中处理分支的复杂性,只需在实际计算的向量上有一个缓存,基于给定块的哈希。这样,当公司里的第n个人去嵌入他们的代码库时,速度会非常快。而且你可以在我们的服务器上完全不存储任何代码数据。我们只存储向量在向量数据库和向量缓存中。

Lex:目前,从索引代码库中获得的最大收益是什么?出于好奇问一句,用户有什么好处?似乎从长远来看,用户会获得越来越多的好处。但是在短期内,代码库有什么用处?

Arvid:最明显的一点就是,你在这里想要找出你大型代码库中发生的事情。你大概记得“我想找到我们做XXX的地方”,但不知道在正常文本搜索中应该搜索什么,于是你向聊天机器人提问。你使用代码库聊天功能,按住命令键并回车提问,然后它通常会找到你心中所想的地方。

Aman:正如你提到的,在未来,这只会变得越来越强大,我们正在努力提高检索质量。这个上限远远高于人们所给予的认可。

Lex:这里有一个值得探讨的问题。你们有没有考虑过,为什么没有在本地做一些工作?我们刚才讨论的似乎都是特别难做到的,云端迁移、缓存等所有因素。有大量程序员使用同一个代码库的大型代码库,你必须解决这个难题。大部分软件的这些重计算任务都是在本地完成的。你们有没有考虑过在本地进行嵌入?

Arvid:我们考虑过,在本地做会很酷,但真的很困难。需要注意的是,有些用户使用最新的MacBook Pro。但大多数用户,比如超过80%的用户,都在Windows机器上,其中许多机器性能并不强大。因此,本地模型只能在最新的电脑上运行。而且,构建它也需要很大的开销。所以即使我们愿意这样做,目前这还不是我们能够专注的事情。有些人正在这样做,这很好。但随着模型越来越大,你想要做更复杂的事情,比如更大的模型,在本地做就变得更难了。

Sualeh:这不是电脑性能较弱的问题。例如,如果你是某个大公司,你有一个大公司的代码库,即使是在最强大的MacBook Pro上,处理大公司的代码库也是非常困难的。所以即使你不是学生或什么的,如果你是某个大公司里最好的程序员,如果你在本地做所有的事情,你仍然会有一段糟糕的经历。你可以这样做,并且勉强应付。但再次强调,这不再有趣了。

Aman:是的,比如近似最近邻搜索和这个庞大的代码库会消耗你的内存和CPU。让我们也谈谈建模方面,正如Arvid所说,本地模型面临着巨大的挑战。其中一点似乎趋向于MOEs,其中一个好处可能是它们可能更多地受到内存带宽的限制,相较于使用GPU或NVIDIA GPU,这更有利于本地。但缺点是这些模型总体上更大,它们通常需要多个节点才能容纳,甚至无法在非常好的MacBook上运行。

特别是对于编程来说,这并不是一个模型是否足够好以做到这些事情的问题,然后我们就满足了。这也许是其他问题的情况,也许是本地模型大放异彩的地方。但人们总是想要最好的、最智能的、最有能力的东西。这几乎对所有人来说,在本地运行都将是极其困难的。

Sualeh:你难道不想有一个最强大的模型吗?

Lex:我喜欢你向我推销的方式。你会满足于一个次级的模型吗?是的,我也是那种人。但确实有一些人喜欢在本地做事情,特别是,显然有一个开源运动在抵制。这是好事,因为你想抵制那些日益增长的中心权力。

Arvid:我对本地模型的一个替代方案特别感兴趣。这仍然处于研究阶段,但你可以想象使用同态加密进行语言模型推理。你可以在本地机器上加密你的输入,然后发送上去。然后服务器可以使用大量的计算,他们可以在加密数据上运行你无法在本地运行的模型,但他们无法看到数据。

然后他们发送回答案,你解密答案,只有你才能看到答案。这仍然是一个非常研究性的话题。所有这些都是在尝试降低开销,因为现在的开销真的很大。但如果能实现这一点,这将非常酷,也将非常有影响力。

因为真正令人担忧的是,随着这些模型越来越好,它们将变得越来越具有经济价值。因此,越来越多的世界信息和数据将通过一个或两个集中的行为者。因此,人们担心传统的黑客攻击,但也产生了这种可怕的部分,即如果所有世界的信息都以纯文本形式流经一个节点,你就可以以非常糟糕的方式进行监控。

有时这可能是出于好的原因,比如人们想要尝试保护免受坏人以不良方式使用AI模型的影响。然后你会在其中添加一些监控代码,然后其他人会介入。你就会陷入一个滑坡,然后你开始用大量世界的数据做坏事。所以我非常希望我们能解决语言模型推理的同态加密问题。

Lex:进行隐私保护机器学习。但我想说,这就像我们今天所有的软件所面临的挑战一样。云计算提供了很多功能,我们越来越依赖它,让我们的生活变得很棒。但也有一些缺点,你需要依赖非常好的安全措施来保护以免受基本攻击。但只有少数公司控制着这些数据,他们显然有优势,他们可以通过各种方式被渗透。这就是我们生活的世界。

Sualeh:是的,我实际上非常担心的是,Entropic有这种负责任扩展政策,我们处于低ASL(Entropic安全级别)的模型上。但当我们达到所谓的ASL3、ASL4等模型时,虽然这些模型非常强大,但出于合理的安全考虑,你想要监控所有提示。

但这是可以理解的,因为每个人都从自己的角度出发。但如果所有世界的信息都受到如此严重的监控,那就太糟糕了。这太集中了。这就像在一条非常细的线上行走,一方面,你不想模型失控。另一方面,像人类一样,我不知道我是否信任所有世界的信息都通过像Entropic这样的三个模型提供商。

Aman:是的。你认为这与云服务提供商有什么不同?

Arvid:因为很多数据本来就不会流向云服务提供商。这通常是,你想要给EIA模型更多的数据,你想要提供个人数据,你本来就不会在线上提供给这些公司或这些模型。这也集中了控制权,因为现在对于云服务提供商来说,你通常可以使用自己的加密密钥,AWS无法真正做什么。但这里集中了可以看到所有纯文本信息的行动者。

上下文

Lex:关于上下文的话题,这实际上是我在用Python写代码时遇到的一个摩擦。有很多东西被导入。你或许可以凭直觉判断出我想在上下文中包含什么样的内容。比如自动确定上下文有多难?

Michael:这很棘手。我们可以在未来做得更好,自动计算上下文。需要注意的是,包含自动上下文有一些权衡。首先,你包含的上下文越多,它们运行得越慢,请求的成本也越高,这意味着你可以做更少的模型调用,并在后台做更少的花哨事情。此外,对于许多模型来说,如果你在提示中有大量信息,它们会感到困惑。

因此,你包含的上下文在准确性和相关性方面应该有一个相当高的标准。但我们已经在产品的一些地方做了一些自动上下文。这肯定是我们想要做得更好的事情。有很多酷的想法可以尝试,包括更好的检索系统、更好的嵌入模型、更好的重排器。

还有许多学术想法,我们在内部尝试过,但这个领域正在广泛地探讨如何让语言模型真正理解新的信息库。最热门的讨论版本是,你能否让上下文窗口无限大?如果你让上下文窗口无限大,你能否让模型真正关注无限大的上下文?如果你能让它关注无限大的上下文,让它变得可行,你能否为无限大的上下文进行缓存?这样你不必每次都重新计算它。

但还有其他一些很酷的想法正在尝试中,这些想法更类似于对模型的信息和权重进行微调。如果在权重层面上进行学习,可能会比在上下文学习层面上进行学习,得到质的不同的理解。这个旅程仍然有点不确定最终会怎样。但作为一家公司,我们非常兴奋地看到更好的检索系统,挑选出与你的工作最相关的代码库部分。我们可以做得更好。

Aman:比如,直接在权重中学习这些知识的一个有趣的概念证明就是是与VS Code的集成。我们正在做VS Code的分支,VS Code的代码都是公开的。所以这些模型在预训练中已经看到了所有代码。它们可能也看到了关于它的问答。然后它们被微调并经过RLHF处理,以便能够回答关于代码的一般性问题。所以当你问它关于VS Code的问题时,有时它会胡说八道,但有时它实际上回答得相当不错。

这只是一个偶然的好结果。但如果你能真正训练或后训练一个模型,使其真正理解这个代码库,那会怎么样?这是一个开放的研究问题,我们对此非常感兴趣。然后还有关于不确定性的问题,比如,你是否想让模型从头到尾做所有事情,即它做检索、内部处理,然后回答问题、生成代码?

或者你是否想将检索与前沿模型分开?也许在几个月内,你会得到一些非常强大的模型,它们在少数领域比最好的开源模型要好。然后你将想要单独训练一个非常好的开源模型作为检索器,作为向这些大型模型提供上下文的东西。

Lex:你能更详细地谈谈后训练模型以理解代码库吗?这是什么意思?这是合成数据方向吗?

Michael:是的,你可以尝试很多可能的方法。当然也不乏各种想法。问题在于你要去尝试所有的方法,并根据经验判断哪种方法最有效。一个非常简单的方法是尝试复制VS Code和前沿模型所做的事情。所以让我们继续预训练,包括一些通用代码数据的预训练,但也包括一些你关心的特定存储库的数据。

然后在后训练中,意味着在正常的指令微调数据集上,你添加了大量关于该存储库代码的问题。所以你可以得到一些真实的答案,这可能很难,或者你可以做你暗示的或建议的事情,即使用合成数据,让模型对代码的不同部分提出问题。

所以你取代码的不同部分,然后提示模型或让模型为该代码部分提出问题,然后将这些作为指令微调的独特数据点。理论上,这可能会解锁模型回答关于该代码库问题的能力。

OpenAI o1

Lex:我想问一些关于OpenAI o1的问题。你认为当这种测试发生时计算系统在编程中扮演什么角色?

Aman:我觉得测试时计算非常有趣。我们经历了预训练阶段,随着数据量和模型规模的增加,性能会不断提升,无论是在损失值上,还是在下游基准测试上,或用它进行编程或其他任务时的整体表现上。但我们开始遇到一些数据瓶颈,这意味着在继续扩大这一阶段上将会变得困难。

因此,扩展测试时间计算是一个有趣的方法,它可以增加推理时间的计算量,同时随着推理时间所使用的计算量的增加,模型的性能也能相应提高。传统上,我们只能通过训练一个更大的模型来使用更多的计算量。但现在,我们或许可以使用同样大小的模型,并延长运行时间,从而获得接近更大模型质量的答案。

这个问题特别有趣的是,有些问题可能需要一个一百万亿参数的模型,在一百万亿个Token上进行训练。但这可能只占所有查询的1%甚至0.1%。所以,你是否会花费如此巨大的精力和计算资源去训练一个成本如此高的模型,然后让它在很少的情况下使用呢?

这看起来非常浪费,假设你训练出一个能够处理99.9%查询的模型,然后你有一种在推理时延长运行的方式,以满足那些真正想要最大智能的少数人。

Lex:你怎么判断哪个问题需要什么样的智能水平?是否可以动态地判断何时使用GPT-4,何时使用小模型,以及何时需要o1?

Aman:这显然是一个开放的研究问题。还没有人真正解决这个模型路由问题。我们想做到这一点。我们在Cursor Tab上有初步的实现,但在4.0 SONET和o1之间的转换就有点棘手。还有一个问题是,你需要什么样的智能水平来判断某个问题对于4.0模型是否过于困难?或许你需要o1级别的模型。这真的不太清楚。

Lex:但你提到过预训练过程和后训练过程,还有测试时计算,这些都是为了区分开来。那么最大的收益在哪里?

Aman:这有点奇怪,因为测试时计算需要整个训练策略来使其发挥作用。更奇怪的是,除了大实验室,甚至也许只是OpenAI,外面没人真正知道这到底是如何工作的。有一些非常有趣的论文显示了一些他们可能在做的事情。也许他们在用树搜索结合过程奖励模型。但问题在于我们并不确切知道它的具体样子,所以很难对它的定位发表评论。我会把它归类为后训练,但也许为了让测试时间计算模型所花费的计算量最终会让预训练相形见绌。

Lex:所以我们甚至不知道o1是否只是使用了思维链的URL,我们不知道他们如何使用这些,也不知道任何情况。

Aman:这很有趣,可以猜测。

Lex:如果你要构建一个竞争模型,你会怎么做?

Aman:一件事是,可能需要训练一个过程奖励模型。我们可以谈谈结果奖励模型与过程奖励模型,结果奖励模型是为语言模型训练的传统奖励模型。它只是关注最终结果。所以如果你在解决某个数学问题,就看你最终完成的结果来打分,我们认为这个结果值得的奖励有多大;而过程奖励模型则试图对思维链的每一步进行评分。

OpenAI去年夏天发布了一篇关于过程奖励模型的初步论文,利用人工标注者收集了几十万的数据集,对思维链进行评分。最终,我觉得我还没有看到关于如何使用过程奖励模型的有趣应用,除了作为影响我们从多个样本中选择最佳答案的一种手段。

因此,研究人员在所有这些论文中做的工作是,从语言模型中采样多个输出,然后使用过程奖励模型对所有生成结果进行评分,同时可能还结合其他启发式方法,最终选择最佳答案。

人们认为有效的一个有趣想法是用这些过程奖励模型进行蒙特卡洛树搜索。如果你真的能对思维链的每一个步骤进行评分,你就可以在这个链中分支出去,探索多条路径,然后使用这些过程奖励模型来评估你所选择的分支的优劣。

Lex:是的,当分支的质量与最终结果的质量有强相关时,你就有了很好的模型来判断选择哪个分支。因此,这不仅仅是在短期内有效,长期来说也是有效的。

Aman:人们在如何正确训练过程奖励模型方面所做的有趣工作,或者在如何以更自动化的方式训练过程奖励模型方面所做的工作,可能在开放源代码的方面更为显著。我可能错了,因为我没有看到特别好地利用过程奖励模型进行创造性树搜索和编码的东西。

Lex:这是一个关于人工智能安全的问题,也许还有一点哲学问题。OpenAI表示,他们将思维链隐藏起来,并且表示这是一个艰难的决定。他们不是向用户展示思维链,而是要求模型对思维链进行总结。他们在后台还表示,他们会监控思维链,以确保模型不试图操纵用户,这真是个令人着迷的可能性。那么,你怎么看待隐藏思维链这件事?

Michael:OpenAI可能考虑的一个因素(这纯属推测)是,他们希望让人们难以从他们的模型中提炼出这些能力。如果你能接触到隐藏的思维链,可能更容易复制这项技术。因为那是非常重要的数据,看到模型达到最终结果所采取的步骤。

Lex:所以你也可以基于这些进行训练。

Michael:这与一些大型语言模型提供商有些相似的情况,这也是推测。但其中一些应用程序接口(API)曾经为它们生成的所有Token提供了便捷的日志概率访问,同样还有对提示Token的日志概率。后来有些API又把这些功能移除了。同样,这完全是猜测,但其中一个想法是,之所以取消这些功能,是因为如果你能接触到日志概率,类似于这个隐藏的思维链,那么就能让你获取更多信息,从而试图从这些API和这些大型模型中提炼出能力。

补充一下之前关于我们整合o1的讨论,我们仍在学习如何使用这个模型。因此,我们在Cursor中提供了o1,因为我们在获取模型时真的很想尝试一下。很多程序员也会对它感兴趣。但o1并不是Cursor体验的默认部分,我们仍然没有找到一种方式将其集成到编辑器中,以便我们能够在每小时甚至每天都能使用它。

所以,关于如何使用这个模型,我们仍在探索阶段。我们还没有看到人们发布似乎非常明确的示例,比如“哦,这就是现在的使用案例”。最明显的可能是这可以让你更轻松地运行后台任务,使这些模型在循环中工作,使这些模型具有Agent能力。但我们仍在探索中。

Sualeh:明确地说,我们有想法。我们只是需要尝试,在把它公之于众之前,先确保有些非常有用的东西。

Aman:但它确实有显著的局限性,甚至在功能限制方面,它并不支持流式输出。这意味着在你想监督输出的情况下,它的使用是非常痛苦的,你只能等待一大段文本出现。而且,这似乎也是测试时计算和搜索的早期阶段,这非常基础,很多东西都不太对劲。随着人们不断增加预训练数据量和模型规模,并在预训练中寻找技巧,接下来你会看到另一条线程在不断优化搜索的效果。

Lex:看起来GitHub Copilot可能会以某种方式集成o1。我想我看到了一些评论说,这是否意味着Cursor已经结束?

Arvid:我看到了,说Cursor该关停了。

Lex:那么,是时候关停Cursor了吗?

Michael:这个领域与2010年代的其他软件领域略有不同,这里的天花板真的非常高。因此,三到四年后,最好的产品将比今天的最佳产品要有用得多。你可以空谈品牌,这是我们的优势。但最终,如果你停止创新产品,你就会失去市场。这对于初创公司来说也很棒,因为这意味着你有机会通过构建更好的东西来赢得已有大量用户的竞争者。所以,在接下来的几年里,关键是构建最佳产品、构建最佳系统。这既包括模型引擎的侧面,也包括编辑体验。

Aman:是的,Cursor与市场上其他所有产品相比,额外的价值并不仅仅在于快速集成新模型如o1,而是来自于所有深入的定制模型,这些模型在产品的每一个方面都在为你工作,以及在每一个功能上的深思熟虑的用户体验。

合成数据

Lex:好吧,从那个深刻的回答中回到技术层面,你提到你有一个合成数据的分类法。

Aman:哦,是的。

Lex:你能解释一下吗?

Aman:首先要说明是普通数据,即非合成数据,这只是自然生成的数据,通常是由人类的活动产生的。所以,这些数据是从某种人类过程获得的。合成数据主要有三种类型。

合成数据的第一种类型是蒸馏。通过语言模型输出Token或Token的概率分布,然后你可以在此基础上训练一些能力较弱的模型。这种方法不会使你得到一个比生成Token的原始模型更有能力的模型,但如果你想从某个非常昂贵、高延迟的模型中提取某种能力,这种方法是非常有用的。

第二种类型是当一个方向的问题比反向更容易。例如,之前提到的bug检测就是一个很好的例子,引入看起来合理的bug要比实际检测它们容易得多。人类在这方面可能也是如此。因此,你可以让一个没有训练太多数据且不太聪明的模型在代码中引入一堆bug,然后你可以用这些合成数据训练一个能够很好地检测错误的模型。

最后一种类型,是大实验室在合成数据方面主要做的,就是用语言模型生成可以轻松验证的文本。举个极端的例子,如果你有一个能检测语言是否达到莎士比亚水平的验证系统,而你有一群猴子在打字机上打字,最终你可以得到足够的训练数据来训练一个莎士比亚水平的语言模型。

这个情况在数学领域尤其明显。在正式语言中,验证其实非常简单。我们可以用一个还不错的模型生成大量的模拟结果,然后选择那些已经证明了基本真理的结果来进一步训练。

在编程方面也有类似的方法,比如解决一些类似LeetCode的问题,如果你有一组测试,通过这些测试意味着问题实际上被解决了。我们可以做同样的事情:验证输出是否通过了测试,然后训练那些通过测试的模型。在所有领域,尤其是开放式的杂项任务中,获得完美验证器会有些棘手,因为这实在很难做到,即使在编程任务中也是如此。

Lex:这可能是因为你没有Arvid那么乐观。但确实,第三类任务需要有一个验证器。

Aman:是的,验证似乎在你确实知道结果正确的情况下效果最好。而且,使用的不是语言模型来验证,而是使用测试或正式系统。

Michael:或者运行这个东西,进行一种人类形式的验证,也就是手动质量控制。但语言模型版本的验证则是让模型实际理解过程,这大致上处于两者之间。

Aman:是的,这类方法最有可能带来巨大的收益。

RLHF vs RLAIF

Lex:反馈方面的强化学习呢,RLHF和RLAIF之间有什么区别?在提升模型性能方面,它们各自的角色是什么?

Aman:RLHF是当你使用的奖励模型是基于人类反馈标签进行训练的。如果你有能力收集大量人类反馈,这种任务的效果会很好。RLAIF则很有趣,因为它依赖于这样一个假设:验证实际上比生成要容易得多。这会让人觉得,你在做什么?你在使用语言模型来查看其输出,然后验证语言模型的正确性。但实际上,这可能是可行的。如果语言模型在验证某些解决方案时比生成它们更容易,那么你可能会得到这种递归循环。

这不会完全是这样的。还有另一种做法是,我们可以结合RLAIF和RLHF的一些特点,通常情况下模型是相当正确的。这就像在Cursor tab中,在两个可能的生成结果之间选择哪个更好。然后,它只需要一些人类的微调,可能只需要50到100个示例来让模型的先验与我们想要的结果对齐。这与普通的RLHF看起来有些不同,因为普通的RLHF通常需要在大量示例上训练这些奖励模型。

Fields Medal for AI

Lex:当你比较生成和验证,或者生成和排序时,你的直觉是什么?排序是不是比生成容易得多?

Aman:应该是的。这就像回到一个问题:如果你相信P不等于NP,那么有一大类问题验证起来要比证明容易得多。

Lex:我想知道同样的事情是否能证明P不等于NP或P等于NP。

Arvid:那样的话,确实很酷。

Lex:那将是AI获得的某种菲尔兹奖。谁来获得这个荣誉?另一个开放的哲学问题。

Sualeh:我其实很想知道AI获得菲尔兹奖的最佳时机是什么时候。

Lex:诺贝尔奖还是菲尔兹奖先?

Sualeh:菲尔兹奖。

Lex:菲尔兹奖会先到。好吧,你当然会这么说。

Arvid:但这也是一个孤立的系统,能够验证并且……

Aman:我觉得在这方面我还有很多要做的。达到IMO的路径似乎更清晰,因为它已经能够解决一些IMO问题。而且当时的文献中有很多潜在的策略可以采用。第一,我对当前正在改进的领域了解得少得多;第二,关于我们距离解决这些非常难的开放问题还有多近,我也缺乏直觉。

Lex:所以你认为会是菲尔兹奖先到?而不会是物理学奖?

Sualeh:哦,100%。这更有可能会实现。对于像BSD这样的直接猜想,或者黎曼假设,或者任何这些困难的数学问题,实际上都非常困难。我们甚至不知道解决方案的路径是什么,更不用说……

Arvid:这是一个孤立的系统,你可以建立一个良好的奖励系统,似乎训练起来更容易。

Aman:我觉得我们可能在AGI之前就会获得菲尔兹奖。

Sualeh:我很高兴听到这个。但我不确定,我觉得可能是2028年或2030年。

Lex:菲尔兹奖?

Sualeh:菲尔兹奖。

Lex:好的。考虑到事物发展的速度,这听起来似乎遥不可及。

尺度定律

Sualeh:说到事物发展的速度,我们来谈谈尺度定律。对那些不了解的人来说,可能需要谈谈这个尺度定律的概念。它们是什么?你觉得现状如何?未来又将如何发展?

Aman:我觉得OpenAI最初的尺度定律论文有些错误,因为他们在学习率调度方面遇到了一些问题,然后Chinchilla展示了一个更正确的版本。从那以后,人们又偏离了计算最优的做法,因为人们开始更注重在特定的推理预算下让事情运行得更好。但这些曲线的维度远比我们最初使用的计算、参数数量和数据要多。推理计算是显而易见的一个维度,而上下文长度是另一个显而易见的维度。

因此,如果你关心推理计算和上下文窗口这两个方面,也许你想训练的模型是一种SSM(ZP注:Spring+SpringMVC+MyBatis,常作为数据源较简单的web项目的框架),因为它们在超长上下文下便宜得多且运行更快。即使在训练期间,其扩展特性是原来的10倍,你可能需要花费10倍的计算资源来训练这个模型,以获得相同的能力水平。但这是值得的,因为你最关心的是在非常长的上下文窗口上的推理预算。因此,看看人们如何玩转这些维度将会很有趣。

Lex:是的,你提到多个维度,显然最初的概念只是关注模型的参数规模和数据规模(以Token数量来衡量),并观察这两者之间的比率。这个概念确实很吸引人,似乎有一个数值,或者至少有一个最小值在出现。你是否仍然相信“越大越好”这个观点?

Aman:就原始性能和原始智能而言,规模越大当然越好。人们可能会采取的路径是,我特别看好蒸馏,也就是说,如果我们花费大量资金进行训练,如何获得最有能力的、便宜的模型,这真的非常重要,因为最简单的做法是最大限度地关注推理时间计算,正如人们在7B模型上训练时所做的那样,过度训练其在许多Token上的表现,远远超过最优的需求。

但如果你真的很关心,或许可以做的事情是像Gamma那样,不仅仅是在Token上训练,而是字面上训练以最小化Gamma 2070的分布之间的KL散度,也就是知识蒸馏。因此,你实际上是在花费计算资源来训练这个270亿、拥有10亿个参数的模型,利用所有这些Token来获得一个更小的模型。

Lex:而蒸馏可以让你得到一个更快的模型。更小意味着更快。

Aman:是的,蒸馏理论上是在从你训练的数据中提取更多信号。这也许是克服数据壁垒的另一种方式——因为你只能用有限的数据进行训练,所以让这个非常大的模型在所有这些Token上进行训练,然后将其蒸馏成一个更小的模型,也许我们可以从这个更小的模型中的每个Token获得更多的信号,而不是最初训练时的情况。

Lex:所以如果我给你10万亿美元,你会怎么花?我的意思是,你不能买一个岛之类的。你会如何分配这些资金,以提升大型模型,还是说,也许是为RLHF付费?

Aman:是的,在训练这些大型模型方面有很多秘密和细节,我通常不知道这些内容,这些信息对大型实验室来说才是私密的。如果我尝试这个,我可能会浪费很多钱,因为我不了解这些事情。如果你说你必须利用你现在所掌握的有限信息来进行操作,那你就得放下很多不信任感。假设你有相关的知识,或者说你必须在当前有限的信息下进行操作。

Lex:不,实际上我会说你要尽可能获取所有的信息,所有的小技巧,所有的小参数,所有定义训练过程的参数。如果我们看看如何在未来五年内投资,最大化你所说的原始智能,该怎么做?

Sualeh:答案其实很简单。你只需要尽可能获得更多的计算资源。归根结底,你需要购买的只是GPU,研究人员可以找到各种方法,你可以调整是想要一个大模型还是小模型。

Aman:这就引出了一个问题:你真的被计算和金钱所限制吗?还是说你受限于其他方面?

Sualeh:我更倾向于相信Arvid的观点,我们在某种程度上是被理想限制的,但总是有可能的。

Arvid:但如果你有大量计算资源,你可以进行很多实验。

Lex:所以你是说你会进行很多实验,而不是把这些计算资源用于训练一个巨大的模型?

Arvid:我会,但我确相我们的想法是有限的。

Aman:是的,即使拥有所有这些计算资源,以及世界上能够收集到的所有数据,最终仍然受到的限制不仅仅是想法,而是优秀的工程技术。即使你拥有世界上所有的资本,你真的能汇集足够多的人来做出改变吗?

研究中有大量工作需要付出极大的工程努力。如果你看看最初的Transformer论文,你就会知道有多少工作是把文献中很多非常有趣的概念结合在一起,然后再去编写所有代码,比如说CUDA kernel,或者一些我不知道最初是否在GPU或TPU上运行的东西,以确保充分利用GPU性能,让工程师更容易进入并完成所有这些代码。

而Nome可能是世界上最优秀的工程师之一,或许他还能更进一步,下一代模型中有很多要素,比如实现模型并行性,并在成千上万的V100上进行扩展。GBD3可能就是这样。所有这些事情都需要付出大量的工程努力,才能使其正常工作。如果你真的把这个成本降低到,比如说,不是零,但减少十分之一的难度,让那些拥有非常好想法的人能够立即实现他们梦想中的新架构,并在GPU上达到50%或40%的利用率。这将大大加快研究进展。

Sualeh:如果你看到明显的改进路径,你应该总是优先选择低垂的果实。OpenAI和所有其他实验室做对了,首先选择了低垂的果实,低垂的果实就是像这样逐步扩展到GPT-4.25规模,然后继续扩展,事情会越来越好。尝试新想法没有意义,因为一切都在正常运转,你应该充分利用现有资源。也许当你确实需要新想法时,如果你要花10万亿美元(你可能会想花这么多),你就可以重新评估你的想法,因为到那时你的想法可能是有限的。

Aman:我们所有人都相信,新想法可能是实现AGI过程中必不可少的。我们也可能都相信存在在小规模上测试这些想法的方法,并对其效果有相对高的信心。只是在目前的情况下,实验室很难将他们有限的研究和工程人才投入到探索这些新想法中,因为这些核心任务可能会在一段时间内提高性能。

原文:Cursor Team: Future of Programming with AI | Lex Fridman Podcast

https://www.youtube.com/watch?v=oFfVt3S51T4

编译:Sunny Ouyang,Zicko Wan

-----------END-----------

我们正在招募新一期的实习生

我们正在寻找有创造力的00后创业者

关于Z Potentials

跳转微信打开

Fish AI Reader

Fish AI Reader

AI辅助创作,多种专业模板,深度分析,高质量内容生成。从观点提取到深度思考,FishAI为您提供全方位的创作支持。新版本引入自定义参数,让您的创作更加个性化和精准。

FishAI

FishAI

鱼阅,AI 时代的下一个智能信息助手,助你摆脱信息焦虑

联系邮箱 441953276@qq.com

相关标签

Cursor AI编程 代码编辑器 代码差异 机器学习
相关文章