机器之心报道
编辑:佳琪、蛋酱
最近一段时间,AI 编程工具 Cursor 火遍全球,风头一时无两。
Cursor 是一款基于 VS Code 的代码编辑器,它为 AI 辅助编程添加了许多强大的功能,吸引了编程界和人工智能界的关注和兴奋。
近日,知名播客节目主持人 Lex Fridman 与四位 Cursor 团队成员进行了一场技术对谈,揭示了这个团队在做的以及未来要做的探索。
视频地址:https://youtu.be/oFfVt3S51T4?si=pCvBgWm5X-W8xt4n
以下是 Lex Fridman 与 Cursor 团队创始成员 Michael Truell、Sualeh Asif、Arvid Lunnemark 和 Aman Sanger 的对话,机器之心进行了核心内容的整理:
Cursor 的起源
Cursor 的起源故事是什么呢?
2020 年左右,OpenAI 发布了有关缩放损失的论文。那一刻,该领域似乎取得了明显可预测的进展,即使我们没有更多的想法,但看起来如果你有更多的计算和更多的数据,你就可以让这些模型变得更好。
顺便说一句,我们可能会就缩放损失这个话题讨论三到四个小时。但总结一下,这是一系列论文中的一篇,这些论文提出了一系列观点,认为在机器学习领域,模型大小和数据大小越大越好。
它更大更好,但可以预见的是它会更好。这是另一个话题。
好的,这是另一个话题。
是的。那段时间,我们中的一些人进行了很多概念性讨论:它会是什么样子?对于所有这些不同的知识工作者领域来说,这项技术的发展将如何让他们变得更好?有那么几个时刻,那篇论文中预测的理论收益开始变得非常具体,我们开始觉得,如果你想在人工智能领域做有用的工作,你实际上可以直接去,而不必攻读博士学位。感觉现在有一整套可以构建的真正有用的系统。
下一个让一切都变得顺理成章的重要时刻实际上是提前获得 GPT-IV 的使用权。所以,大约在 2022 年底,我们开始修改这个模型,升级能力令人感觉非常强大。在此之前,我们一直在从事几个不同的项目。由于 Copilot、由于 scaling odds、由于我们之前对这项技术的兴趣,我们一直在修改程序员工具,但这些工具非常具体。因此,我们正在为必须在 Jupyter Notebook 中工作的金融专业人士构建工具,或者尝试使用这些模型进行静态分析。
然后 GPT-IV 的升级让我们感觉,看,这确实使之前预测的理论收益具体化。感觉你可以在那个时间点立即构建更多东西。而且如果我们保持一致,感觉这真的不仅仅是一个点解决方案。所有编程都将流经这些模型,需要不同类型的编程环境,不同类型的编程。所以我们开始构建一种更大的愿景。
代码差异
Cursor 有一个非常酷且引人注目的功能,那就是整个 diff 接口情况。因此,模型用红色和绿色表示我们将如何修改代码,你可以在聊天窗口中应用它,它会向你显示 diff,你可以接受 diff。
我们可能会有四五种不同的 diff。我们针对自动完成功能优化了 diff,因此它具有与检查较大代码块时不同的 diff 接口。然后,我们正在尝试优化另一个 diff 功能,以适应处理多个不同文件的情况。从高层次来看,区别在于你使用自动完成功能时,读取速度应该非常非常快。实际上,在所有情况下读取速度都应该非常快,但在自动完成功能中,你的眼睛会集中在一个区域,人类不能看太多不同的地方。
我们尝试了三四次才让这个东西正常工作,第一次尝试是使用蓝色划线。在它变成侧面的方框之前,它曾经以 Google Docs 样式显示要删除的代码,你会看到一条划线,然后会看到新代码。这容易让人分心。然后我们尝试了许多不同的方法,有删除,有尝试红色突出显示。
然后,在下一次迭代中,这有点搞笑,你会按住 Mac 上的选项按钮。所以它会突出显示一段代码,向你显示可能会有什么东西出现。所以在这个例子中,输入和值都会变成蓝色。蓝色是为了突出显示人工智能为你提供了建议。所以它不是直接向你显示东西,而是暗示人工智能有一个建议,如果你真的想看到它,你会按住选项按钮,然后你就会看到新的建议。如果你释放选项按钮,你就会看到你的原始代码。
是的,这是用户体验设计工程中非常迷人的领域。所以你基本上是在试图引导人类程序员完成他们需要阅读的所有内容,仅此而已,这是最佳的。
你需要智能模型来做这件事。目前,不同的算法就像普通算法一样。没有智能。算法的设计需要智能,但你并不关心它是这个还是那个,因为你希望模型来做这件事。
一个问题是,这些模型会变得更加智能。随着模型变得更加智能,它们能够提出的改变也会更大。因此,随着改变越来越大,人类必须做越来越多的验证工作。
人类不想把所有的时间都花在审查代码上。我认为可以使用语言模型显著改善审查体验,例如,某种技巧可能会将你指向真正重要的区域。我还认为,如果代码是使用这些语言模型生成的,而不是由其他人生成的。代码审查体验是为审查者和生成代码的人设计的。如果编写代码的人是语言模型,那么你就不必太在意他们的体验,你可以围绕审阅者设计整个过程,让审阅者的工作尽可能有趣、轻松、高效。
机器学习细节
Cursor 的编辑器让我有点感受到 AGI 的存在,能不能谈谈让它运行的机器学习细节?
Cursor 实际上是基于我们训练的定制模型和前沿模型组成的集成模型来运行的。一些 Cursor 广受好评的功能,比如 Tab 和 Apply,都是微调起的效果。
这些前沿模型非常擅长生成修改代码的意见与草稿,但在实际生成代码改动的细节时,往往会遇到困难,特别是,当用这些模型(如 Sonnet、o1)处理大型文件时,常常会出现搞串行这样的低级错误。
为此,我们采取了一个策略:首先让模型生成一个粗略的代码块,简单描述代码需要如何修改;然后再训练另一个模型,将这些代码修改应用到实际文件中。
补充一下,Apply 功能是模型会查看你的代码并给出新建议。根据新建议对代码进行修改,对人类来说看似很简单,但对模型而言其实并不那么容易,对吗?
可能有很多人认为 Apply 功能背后的算法是「确定性的」,也就是说它有一套固定的规则或流程,但实际上并不是。
是的,其他 AI 编程工具也有 Apply 功能的「平替版」,但它们往往会崩溃。很多人以为可以通过确定性的匹配来实现这些功能,但实际情况是,至少有 40% 都会失败。
我认为整体趋势是,模型会变得越来越智能。而 Apply 的另一个优势在于,它可以让最智能的模型在生成代码时,使用较少的 tokens,从而降低延迟和成本。
具体来说,你可以给模型一个粗略的代码草稿,然后模型负责具体实现,相比于让模型从零开始写完整的代码,给一个大致草稿让模型去完善要简单得多。我相信这一趋势将继续发展,随着负责规划的模型越来越智能,具体实现的细节可能交由相对简单的模型来处理。也许会有 o1 或更强大的模型来生成高层次的规划,再由定制的模型递归地执行。
如果你感兴趣,我们可以聊聊如何让它更快。
那你们是如何提升 Cursor 的处理速度的呢?
让速度变快的一个要点是「投机编辑」(speculative edits),它是从投机解码(speculative decoding)衍生出来的。你可以利用投机解码的一个优势:大部分情况下,尤其是在语言模型生成时受内存限制的情况下,一次处理多个 tokens 比逐个生成 tokens 更快。因此,当你查看每秒生成的 tokens 数量时,会发现处理 prompt tokens 的速度远快于逐个生成 tokens。
我们的方法与传统的投机解码不同。传统方法是用一个很小的模型预测代码,然后由更大的模型来验证。但是因为我们对已有代码的样子、格式和逻辑足够熟悉,所以可以直接把原始代码片段输入到模型中,让模型去判断哪些部分需要改动。绝大多数情况下,模型会认同:「这些代码没问题,可以直接复制。」
因此,你可以并行处理所有代码行,并对足够多的代码片段进行同样操作。最终,当模型预测的文本与原始代码出现不一致时,它会生成新的 tokens,我们则根据匹配程度判断何时重新对代码块进行推测。
GPT vs Claude
哪个 LLM 更擅长编码?GPT 和 Claude 在编程方面谁更胜一筹?
大模型编程能力排行榜
我认为没有哪个模型可以称霸于所有模型,这意味着在我们认为重要的所有类别中,Pareto 模型都表现更好,这些类别包括速度、编辑代码的能力、处理大量代码的能力、长上下文、其他一些方面以及编码能力。我现在认为最好的模型是 Sonnet。o1 非常有趣,而且推理能力很强。因此,如果你给它一些非常难的编程面试风格问题或引导代码问题,它可以做得很好,但感觉它不像 Sonnet 那样理解你的大致意图。
如果你看看许多其他前沿模型,它们在基准上的表现都非常好,但是当你将它们推到更远的地方时,我认为 Sonnet 是保持相同性能的最佳选择。
正常的编程体验与基准测试所代表的体验之间有什么区别?当我们评估这些模型时,基准测试的不足之处在哪里?
这是一个非常非常困难且至关重要的细节,它说明了基准测试与真实编码之间的区别,真实编码不是面试风格的编码。人类有时会说半生不熟的英语,有时你会说:「按照我之前做的做。」有时你会说:「添加这个东西,然后为我做另一件事,然后制作这个 UI 元素。」然后很多事情都是依赖于上下文的。抽象地说,面试问题非常具体。它们很大程度上依赖于规范,而人类的东西则不那么具体。
基准测试中实际可以建模的内容与实际编程之间存在偏差,有时很难概括,因为实际编程非常混乱,有时无法很好地指定什么是正确的,什么不正确。但是由于公共基准测试的问题,这也变得更加困难。因为公共基准测试有时是爬坡测试,也是因为从模型中获取公共基准测试数据非常非常困难。
例如,最受欢迎的基准之一 SWE-Bench 确实受到这些基础模型的训练数据污染。因此,如果你要求这些基础模型解决 SWE-Bench 问题,但实际上没有为它们提供代码库的上下文,它们就会产生幻觉的文件传递,产生幻觉的函数名称。
这种情况下,它可以针对文字问题或拉取请求本身进行训练,也许实验室会开始做得更好,或者他们已经在净化这些东西方面做得很好,但他们不会忽略存储库本身的实际训练数据。这些都是一些最流行的 Python 存储库。SimPy 就是一个例子。我不认为他们会在 SimPy 和所有这些流行的 Python 存储库上设置他们的模型,以便在这些基准测试中获得真实的评估分数。
鉴于基准测试中的缺陷,使用这些模型构建系统或构建这些模型的地方实际上会使用一些有趣的「拐杖」来了解它们是否朝着正确的方向发展。在很多地方,人们实际上只是让人类来玩这些东西并对这些提供定性反馈。一些基础模型公司都有人负责这项工作。在内部,我们也对这些模型进行定性评估,实际上除了我们拥有的私人电子邮件外,我们还非常依赖这些评估。
提示工程
一个好的提示词能起什么作用?你曾写过一篇关于提示词设计的博客。
这取决于你正在用哪个模型。每个模型对不同的提示反应也不同,比如 GPT-4 就对提示词非常敏感,但问题是,当空间有限时,你如何决定哪些信息应该被放入提示词中呢?
针对这个问题,我们内部有一个系统叫做 Preempt。它有点像你在制作一个网站:你希望在移动端和桌面端都能正常显示网站的页面。但你需要考虑一些动态的信息,毕竟网页设计不像杂志排版是固定的。网站和提示词的输入都是动态的,你需要确保格式始终适用,输入量很大时,需要剪裁一些内容。因此,我们从设计网站的思路中提取了灵感。
我们非常喜欢 React 以及声明式的方式,比如你可以在 JavaScript 中使用 JSX,然后直接声明:「这就是我想要的,我认为这个部分比其他部分具有更高的优先级或更高的 Z 轴顺序。」
在网页设计中,渲染工作由渲染引擎来完成,而在 Cursor 中,这个任务由 Preempt 渲染器负责,它将所有内容布局到页面上。你只需说明你想要的效果,渲染器会自动帮你实现。
我们发现这种方法非常有用,而且它的角色也在不断演变:最初它是为了适应较小的上下文窗口,而现在它在拆分进入提示词的数据和实际生成方面发挥了很大作用。因此,调试起来更加简单,因为你可以修改提示词,并在旧的提示词上进行测试,直接查看你的修改是否真的提升了整个评估集的表现。
所以你们真的在用 JSX 来写提示词吗?
没错!Preempt 看起来就像 React。它还有一些组件,比如文件组件,它会获取光标的位置。在代码编辑器中,光标在的那行代码可能是最重要的一行,因为你正在查看它。那么就可以基于此为不同的代码行设置优先级。光标所在的那一行优先级最高,离它越远的行,优先级依次递减。最终在渲染时,系统会计算出能显示多少行代码,并以光标所在的行为中心进行呈现。
这也太棒了!
你还可以实现更复杂的功能,比如当整个代码库中有许多代码块时,可以通过检索、嵌入和根据得分重新排序等方式,为这些组件设定优先级。
那么,人类在提问时,是否也应该尝试使用类似的方式?在提示中写 JSX 会有好处吗,还是说想到哪里就问什么这种方式更好?
我认为我们的目标是,你可以随意提问,而我们的任务是找到合适的方式检索出与你想法相关的信息。
我之前和 Perplexity 的 CEO Aravind Srinivas 聊过这个问题,他的观点是提问者越懒越好。这种思路是极好的,但我觉得对于程序员来说,你应该可以提更高的要求,对吧?
没错。如果你说「随便你怎么问」,人往往是懒惰的。这就产生了一种张力:一方面是人们可以随意提问,另一方面它也在鼓励人们在提示词中传达更有深度的想法。
我的观点是,即使 AI 已经足够智能,但你仍无法传递足够明确但意图来指引模型该做什么。有几种方法可以解决这种意图不明确定问题。一种是让模型问你:「基于你的查询,我不确定如何处理这些部分,你可以明确一下吗?」另一种方法可能是,如果有五六种可能的生成方式,「鉴于目前查询中的不确定性,不如我们把这些生成的结果都展示给你,然后让你来选择。」
对于模型来说,让它主动发问有多难呢?
我们最近为 Cursor 添加了一个加入文件的功能。当你在编辑代码或输入内容时,模型会尝试预测你正在做什么,如果模型发现有不确定的地方,它会猜测你可能在编写某种 API。然后,模型会查看你的历史记录,推测哪些文件与当前的编辑内容相关。
这里有一个技术上的难题,就是如何在所有历史记录中找到相关的信息,判断在当前的提示词下哪些文件最重要。虽然这个功能还处于试验阶段,但相信我们会逐步完善它,但我们想展示出这个想法:「你是否想添加这个文件、那个文件,以便模型帮你编辑?」
比如你正在编写一个 API,同时,你也需要编辑使用这个 API 的客户端和服务器代码,那么 API 发生变化时,客户端和服务器代码也需要相应更新。
Cursor 可以做的是,当你在编写提示或代码时,在按下「回车」之前,模型可以帮你找到这些可能需要一起修改的部分。这样做的好处是,可以提前解决一些不确定性,确保所有相关的代码都被正确更新,而不需要手动去查找和同步这些改动。
上下文
关于上下文,当我用 Python 编写代码时,会导入一堆东西。如果想知道我想在上下文中包含哪些东西,自动找出上下文有多难?
这很棘手。我认为未来我们可以在自动计算上下文方面做得更好。需要注意的一点是,包含自动上下文是有代价的。
首先,为这些模型包含的上下文越多,它们的速度就越慢,请求的成本就越高,这意味着您可以减少模型调用,并在后台执行更少的花哨操作。此外,对于许多这些模型,如果提示中包含大量信息,它们会感到困惑。因此,包含的上下文的准确性和相关性标准应该相当高。
我们已经在产品的某些地方做了一些自动上下文。这是我们希望做得更好的事情。我认为有很多很酷的想法可以尝试,包括学习更好的检索系统,例如更好的嵌入模型、更好的重排序器。
还有一些很酷的学术理念,我们已经在内部尝试过,你能否让语言模型达到这样一种境界,即模型本身就可以理解新的信息语料库?最流行的版本是,你能否让上下文窗口无限?那么,如果你让上下文窗口无限,你能否让模型真正关注无限上下文?然后,在你让它关注无限上下文之后,让它在某种程度上切实可行,你能否对无限上下文进行缓存?你不必一直重新计算。但是,还有其他很酷的想法正在尝试中,它们更类似于在模型权重中实际学习这些信息的微调。如果你在权重级别上做更多的事情,而不是在上下文学习级别上做,那么你实际上可能会获得一种定性的不同类型的理解。
我们真的对更好的检索系统和挑选与你正在做的事情最相关的代码库部分感到兴奋。一个有趣的概念证明是使用 VS Code 直接在权重中学习这些知识。所以我们在 VS Code 分支和 VS Code 中。代码都是公开的。因此,这些预训练模型已经看到了所有代码。他们可能还看到了有关它的问题和答案。然后他们进行了微调和 RLHF,以便能够回答有关代码的一般问题。因此,当你问它关于 VS Code 的问题时,有时它会产生幻觉,但有时它实际上可以很好地回答问题。我认为这只是…… 它碰巧没问题,但如果专门训练或后训练一个模型,使其真正构建为理解这个代码库,会怎么样?
这是一个开放的研究问题,我们对此非常感兴趣。此外,还有一个不确定性,你是否希望模型成为端到端完成所有工作的东西,即在内部进行检索,然后回答问题、创建代码,或者你是否想将检索与前沿模型分开,也许你会在几个月内得到一些真正强大的模型,这些模型比最好的开源模型要好得多?然后,需要单独训练一个非常好的开源模型作为检索器,作为将上下文输入到这些更大模型的东西。
能否再多谈谈训练模型后如何理解代码库?这是什么意思?这是一个合成数据方向吗?
是的,有很多方法可以尝试。当然,想法是无穷无尽的。问题只是去尝试所有方法,然后根据经验判断哪种方法最有效。一个非常幼稚的想法是尝试复制 VS Code 和这些前沿模型所做的事情。所以让我们继续进行预训练。某种持续的预训练,包括一般代码数据,但也加入了你关心的某些特定存储库的数据。然后在后训练中,让我们从指令微调开始。你有一个关于代码的正常指令微调数据集。然后,你会在该存储库中提出很多关于代码的问题。
因此,你可以获得基本事实数据,这可能很难,或者你可以使用合成数据执行您暗示或建议的操作,即让模型询问有关各个近期代码片段的问题。因此,你可以获取代码片段,然后提示模型或让模型针对该代码片段提出问题,然后将其添加为指令微调数据点。然后从理论上讲,这可能会解锁模型回答有关该代码库的问题的能力。
OpenAI o1
你们怎么看 OpenAI o1?这种能在测试时计算的系统将在编程中将扮演什么角色?
对于预训练模型模型,Scaling law 效果拨群,但我们现在已经遇到了「数据壁垒」,因此,通过增加推理时使用的 flops 来提升模型性能,是一种有趣的方法。传统上,我们必须训练更大的模型来使用更多的 flops,但现在我们或许可以在相同规模的模型上运行更长时间,来达到大型模型的质量。
我觉得还有一点很有趣,有些问题可能需要一个拥有 100 万亿参数、训练了 100 万亿 tokens 的超大模型才能解决,但这样的问题可能只占所有查询数量的 1% 甚至 0.1%。那么,你会花费大量的计算资源去训练一个如此昂贵的模型,却只为极少的查询提供服务吗?这样做感觉很浪费。
所以更好的方法是,训练一个能够处理 99.9% 查询的模型,然后对于那些需要极高智能的问题,在推理时运行更长时间,以获得更好的答案。
如果你要构建一个能和 o1 pk 的模型,你会怎么做?
待做事项之一肯定是要训练一个「过程奖励模型」(process reward model)。
或许我们可以深入讨论一下「奖励模型」、「结果奖励模型」与「过程奖励模型」的区别。结果奖励模型是传统用于语言建模的奖励模型,它只关注最终结果,比如一个数学问题答对了,模型就能获得对应的奖励。
而过程奖励模型则试图对「思维链」中的每一步进行评分。OpenAI 在去年夏天发表了一篇论文,他们利用人工标注员构建了一个包含几十万条「思维链」数据的大型数据集。目前来看,除了在样本选择中起作用外,过程奖励模型还有什么应用,我还没看到。
真正让人觉得有趣、也让大家期望能起作用的是结合过程奖励模型进行「树搜索」(tree search)。因为如果你能对「思维链」的每一步都进行评分,那么你就可以分支,并对这个思维链中的多条路径进行探索,再利用过程奖励模型来评估每个路径。
OpenAI 曾提到他们正在隐藏模型的「思维链」,并表示这是一项艰难的决策。他们选择让模型总结思维链,而不是直接展示给用户。同时,OpenAI 在后台监控这些思维链,以确保模型不会尝试操控用户,不管怎样,你对隐藏思维链怎么看?
我对 OpenAI 的一个猜测,纯属臆测,可能是他们不想让人们从他们的模型中提炼出 o1 的能力。如果你能看到隐藏的思维链,复制这项技术可能会变得更容易,因为你能够看到模型为得到最终结果所采取的每一步,这可是非常重要的数据。
那你也可以基于这些来训练模型吗?
之前也有类似的情况,虽然这只是猜测:过去,这些 API 可以很方便地获取生成 tokens 及提示 tokens 的对数概率。但后来,这个功能被移除了。依然是猜测,背后的原因可能是,如果你能获取这些对数概率,就如同看到隐藏的思维链一样,这会让你更容易从这些 API 和大型模型中提炼出其能力,并将其转移到你自己的模型中。
另外,补充一点我们之前关于整合 o1 模型的讨论:我们现在还在摸索如何使用这个模型。所以我们把 o1 整合到 Cursor 中,是因为我们一拿到这个模型就非常想试试,我想很多程序员也会很感兴趣。
o1 并不属于 Cursor 默认体验的一部分,我们至今还没有找到一种每天、甚至每小时都能在编辑器中使用 o1 的方法。因此,我觉得如何使用 o1 的最佳方式还没有定论。我们也还没有看到明确展示其实际用例的例子。有一些明显的方向,它可以让你更容易地在后台运行一些任务,或让模型在循环中运行,赋予它们 agent 的能力。但我们还在探索中。
需要澄清的是,我们确实有一些想法,只是在公开之前,我们需要确保能做出真正有用的东西。
但 o1 也有一些明显的限制。暂且不谈它的能力问题,它并不支持流式输出。这意味着,当你需要监督输出时,使用起来会非常不方便,你只能等待整段文本一次性显示。此外,这感觉像是测试时计算和搜索的初级阶段,o1 更像是一个 v0 版本,还有很多需要改进的地方。我猜想,在增加预训练数据量、扩展模型规模以及探索预训练技巧的同时,还会有另一条路径来不断优化搜索功能。
最近有传言说,GitHub Copilot 可能会以某种方式整合 o1,有一些评论说:「这是否意味着 Cursor 完了?」你们怎么看呢?
是时候关停 Cursor 了。
没错 Cursor 是该倒闭了。
所以你们真的觉得是时候把 Cursor 关了吗?
我认为这个领域与过去 2010 年左右的软件领域有些不同,因为这里的上限真的非常高。我认为再等 3-4 年,那时最好的 AI 编程产品可能比现在的要实用得多。
当然,你可以谈论护城河、品牌、优势等等,但如果你在产品创新上止步不前,就会被甩在后面。这对初创公司和想进入这个市场的人来说都是好消息,因为只要你能打造出更好的产品,就有机会超越那些拥有大量用户的竞争者。因此,我认为接下来的几年关键在于打造最好的产品和系统,不仅包括模型引擎的改进,还包括优化编辑体验。
没错,我认为 Cursor 相比其他产品的额外价值不仅仅在于能快速整合 o1 这样的新模型。更重要的是,Cursor 的定制模型在各个方面提供了深入支持,这些模型可能在你不知情的情况下默默发挥作用,每个功能都为用户体验进行了精心设计。