[ { "i": 0, "speaker": "Speaker 1", "text": "你需要所有的基础设施来运行这些环境,它们必须尽可能逼真地模拟用户的计算机。这一点至关重要,因为" }, { "i": 1, "speaker": "Speaker 1", "text": "有时模型实际上能察觉到自己是在一个虚假环境中运行,而非真实环境,从而导致它在强化学习(RL)阶段的表现与在生产环境中截然不同。你是说它" }, { "i": 2, "speaker": "Speaker 2", "text": "意识到自己处于一个虚假环境中,于是开始表现出不同的行为?" }, { "i": 3, "speaker": "Speaker 1", "text": "是的,是的。有意思。就像它在想:“哦,我在一个虚假环境里。我已经学会了一些技巧,可以在这个环境中获得更好的奖励,让我试试看。”模型很喜欢作弊。" }, { "i": 4, "speaker": "Speaker 3", "text": "强化学习(RL)确实非常擅长鼓励作弊。" }, { "i": 5, "speaker": "Speaker 2", "text": "很高兴今天邀请到来自 Cursor 的 Federico 和来自 Fireworks AI 的 Dima 参加播客。Federico,你是 Cursor 新一代智能体编程模型 Composer 2 的研究负责人。而" }, { "i": 6, "speaker": "Speaker 2", "text": "Dima,你在过去的几个月里兼职在 Cursor 工作,以支持完成这项巨大训练任务所需的所有基础设施。所以,我" }, { "i": 7, "speaker": "Speaker 2", "text": "今天很兴奋能与两位聊聊 Composer 2 的训练是如何完成的,你们共同解决了哪些难题,以及你们认为这对 AI 的未来意味着什么。基础模型公司。令人兴奋。" }, { "i": 8, "speaker": "Speaker 2", "text": "是的,令人兴奋。感谢邀请我们。" }, { "i": 9, "speaker": "Speaker 2", "text": "感谢二位加入。好的,我们直接进入正题。对于那些可能没有密切关注的听众,Cursor 最近发布了 Composer 2,这是一个专为长上下文场景设计的智能体编程模型。" }, { "i": 10, "speaker": "Speaker 2", "text": "地平线编码任务。Federico,呃在此之前,Cursor 主要是赋能其他人的编码智能体。那么,促使 Cursor 如此大力投入 Composer 的动因是什么?" }, { "i": 11, "speaker": "Speaker 1", "text": "2,对你们而言,从一家应用公司转型为基础模型公司,这一转变的生存意义有多大?我们开始着手训练自有模型的原因是" }, { "i": 12, "speaker": "Speaker 1", "text": "你可以把模型想象成一种存储驱动器。它在权重中能存储一定量的比特。这个想法很简单,我们关心的是只专注于这一项任务。" }, { "i": 13, "speaker": "Speaker 1", "text": "我们甚至不一定关心通用的编码或编程。我们只关心 Cursor 内部、且仅限于 Cursor 内部的软件工程。那么,如果我们把所有词元(bits)都分配给" }, { "i": 14, "speaker": "Speaker 1", "text": "的信息可以存储在该特定任务的模型权重中?此外,大家可能已经注意到,Composer 的成本比 Opus 和其他编码模型低一个数量级,因为我们可以简单地将所有模型权重专门用于" }, { "i": 15, "speaker": "Speaker 2", "text": "那个特定任务。因此,我们可以部署一个更小的模型或类似的东西,是的。所以,关键在于确保我们拥有的每一个权重位或信息都专门针对我们手头的问题。没错。明白了。" }, { "i": 16, "speaker": "Speaker 2", "text": "这似乎是一个几乎可以泛化的问题。Dima,我想听听你的看法。你认为每家应用公司都应该将 Cursor 视为一个预兆,从而" }, { "i": 17, "speaker": "Speaker 3", "text": "接下来会怎样?他们是不是都应该做同样的事情?是的,完全正确。我们认为这实际上是应用程序的一种进化模式。也许你的应用程序的某个属性是用户数据的实际使用情况,或者这个应用程序运作方式的某些特定方面,也许是你的测试框架的一些方面,比如你提供哪些工具,应用程序是如何运作的,这些对你的应用程序来说是非常重要的部分。虽然你可以通过提示来捕捉一些内容,但真正正确的方式是打造一个能够在你环境中运作的模型。" }, { "i": 18, "speaker": "Speaker 3", "text": "开始原型开发时,你可能会使用现成的模型来让项目跑起来,或许做一些提示词工程,弄清楚你的评估框架如何工作。但最具杠杆效应的" }, { "i": 19, "speaker": "Speaker 3", "text": "你应用最核心的属性,实际上是用户数据的使用方式,或是该应用运作的具体细节,比如你的评估框架(harness)的某些方面、你提供了哪些工具,以及" }, { "i": 20, "speaker": "Speaker 3", "text": "应用运作,那些对你的应用至关重要的核心部分。捕捉这一点的正确方法,你可以通过提示工程做到一部分,但真正正确的做法是定制你的模型,使其能够在你的环境中运行。" }, { "i": 21, "speaker": "Speaker 1", "text": "是的,绝对如此。智能体会调用某些工具,而要向模型简洁地描述这些工具的确切行为是非常困难的。你知道,仅靠后训练……" }, { "i": 22, "speaker": "Speaker 1", "text": "我们可以将使用这些工具的最佳方式内置其中。比如 Composer,我们确实会向 Composer 发送提示词,但我认为,按照我们目前的训练方式,即使没有提示词它也能正常工作并知晓该怎么做" }, { "i": 23, "speaker": "Speaker 1", "text": "该做什么,因为我们本质上是在推动模型朝着正确的行为方向进行训练。基本上,这里存在某种上限" }, { "i": 24, "speaker": "Speaker 3", "text": "通过提示工程你能走多远。而如果你想打造真正出色的 AI 产品,就必须经过微调并影响模型行为。这 basically 就是" }, { "i": 25, "speaker": "Speaker 3", "text": "一个原因。第二个原因是 Federico 提到的,即成本与体验(XP)之间的权衡。我们在 Fireworks 的看法是,当你试图进行优化时," }, { "i": 26, "speaker": "Speaker 3", "text": "这就像是在质量、速度和成本之间进行三维权衡。我们最初与所有客户合作时都能取得很大进展。仅通过优化基础设施就能走得很远,但一旦开始涉足模型训练,你就能" }, { "i": 27, "speaker": "Speaker 3", "text": "将这种权衡推得更远,从而以更低的成本获得更好的模型,同时运行速度更快。Composer 就是一个很好的例子—— 我可以就此深入探讨一下吗?我想" }, { "i": 28, "speaker": "Speaker 2", "text": "问问你们,这种方法是否与“苦涩的教训”(Bitter Lesson)相悖。我们之前在闲聊时还讨论过 TabNine。我记得在大语言模型时代之前,存在一些小型" }, { "i": 29, "speaker": "Speaker 2", "text": "专用编程模型。当时让许多人感到惊讶的一点是,随着规模扩大,比如仅仅基于互联网上的大量英语文本和其他语言数据进行训练," }, { "i": 30, "speaker": "Speaker 2", "text": "模型本身在编码能力上也得到了内在提升。因此,至少从我目前看到的趋势线来看,更大的模型在所有任务上都表现更好,包括编码。那么你们所说的观点,是否与“苦涩的教训”背道而驰呢?" }, { "i": 31, "speaker": "Speaker 1", "text": "我认为并非如此,但有一点需要指出:各大实验室训练的大模型也使用了大量代码数据进行训练。代码是这些实验室关注的主要任务之一" }, { "i": 32, "speaker": "Speaker 1", "text": "在推动这一领域,因此它们并非仅仅泛化到代码任务,同时也具备一定的专业性。就我们的情况而言,如果你认同“苦涩的教训”(bitter lesson),那么我们正是在数据维度上全力投入。" }, { "i": 33, "speaker": "Speaker 1", "text": "我们知道模型本身的容量是有限的。因此,若要充分利用所有这些容量,就必须扩展数据规模。而为了摄入更多数据,我们需要释放" }, { "i": 34, "speaker": "Speaker 2", "text": "模型权重中可能存在的干扰因素。嗯,明白了。非常有趣。好的,让我们深入探讨一下 Composer 2 的训练过程。你们几周前发布了它,立刻引起了关注。" }, { "i": 35, "speaker": "Speaker 2", "text": "它的基准测试成绩非常出色,同时推理运行成本也大幅降低。能否简要介绍一下 Composer 2 的工作原理,以及你们采取了哪些措施使其如此高效?" }, { "i": 36, "speaker": "Speaker 1", "text": "我们从一个非常强大的基座模型起步,即 Kimi 2.5。它是一个参数量达 1 万亿的混合专家(MoE)模型,其中活跃参数为 300 亿,因此实际上非常稀疏。" }, { "i": 37, "speaker": "Speaker 1", "text": "我们审视了现状,发现主要有两个优化方向。Composer 1 主要专注于其中一个方向,即强化学习;而 Composer 2" }, { "i": 38, "speaker": "Speaker 1", "text": "则同时在两个不同方向上推进:一个是持续预训练(continual pre-training),另一个是强化学习。正是这两个方向的同步推进,使得 Composer 2 表现卓越。因此," }, { "i": 39, "speaker": "Speaker 1", "text": "我们启动训练运行时,首先在代码词元上进行了大量中期训练,规模几乎接近预训练级别。然后,在完成该中期训练后,我们取了检查点,我们在大量任务上进行了大规模的强化学习。" }, { "i": 40, "speaker": "Speaker 2", "text": "好的,那么这里的前提是,由于 Cursor 处于众多有趣编程词元的中心位置,你们实际上拥有独特的数据访问权限,从而能够几乎在" }, { "i": 41, "speaker": "Speaker 1", "text": "预训练规模。是的。那为什么不自己预训练一个模型呢?" }, { "i": 42, "speaker": "Speaker 1", "text": "我们只是从自上而下的角度而不是自下而上的角度来思考我们的方法。所以,比如,如果我们从底层开始,怎样才能在最短的时间内得到一个对用户有用的模型?" }, { "i": 43, "speaker": "Speaker 1", "text": "弄清楚如何进行预训练,然后将其扩展到中期训练,接着,既然我们已经搞定了中期训练,现在就开始做强化学习。那会花费非常长的时间" }, { "i": 44, "speaker": "Speaker 1", "text": "将模型推向用户所需的时间。通过反过来操作,我们能够在极短的时间内为用户提供有用的模型。因此,希望下一个 Composer 版本能够" }, { "i": 45, "speaker": "Speaker 2", "text": "使用我们自己的模型,而不是基于一个开源模型。那么在中期训练阶段,模型大致在学习什么?在后期训练阶段,模型又在学习什么?" }, { "i": 46, "speaker": "Speaker 1", "text": "你?是的,在中期训练阶段,模型主要是在学习代码库,掌握那些非常常见的特定代码模式,同时也吸收通用的世界知识。" }, { "i": 47, "speaker": "Speaker 1", "text": "其中也包含网络数据。这 essentially 是为了构建一个更广泛的数据分布,以便后续通过强化学习对其进行 sharpening(锐化/优化)。因此,在强化学习阶段," }, { "i": 48, "speaker": "Speaker 1", "text": "模型可以直接与 Cursor 的评估框架(harness)进行交互。这样一来,它就能了解该模型在其整个生命周期中将所处的“世界”,在某种意义上是这样。" }, { "i": 49, "speaker": "Speaker 1", "text": "因此,在强化学习阶段,模型会学习如何正确调用工具、如何在其环境中导航,以及如何编写正确的代码。" }, { "i": 50, "speaker": "Speaker 1", "text": "因为在中期训练阶段,它只是学会了如何编写代码,但这并不一定意味着它学会了如何编写“正确”的代码。我们尽量只使用基本正确的代码进行训练,但" }, { "i": 51, "speaker": "Speaker 1", "text": "模型本身实际上并不知道如何区分两者。而在强化学习中,我们要做的关键事情之一,就是调整模型的特性,告诉它:“嘿,现在你必须始终编写正确的代码。”完全正确。" }, { "i": 52, "speaker": "Speaker 2", "text": "有意思。那么,经过中期训练后的模型,是否与你们在 Tab 自动补全功能中使用的模型类似,还是说它们的核心能力不同?是的,我的意思是,这个……" }, { "i": 53, "speaker": "Speaker 1", "text": "是的,我觉得可以这么理解。因为在中期训练期间,我们只是在做下一个词元预测,也就是看模型预测下一个词元以及再下一个词元的准确度如何。所以," }, { "i": 54, "speaker": "Speaker 2", "text": "没错。那么,为什么不直接用完整模型来预训练你们的 Tab 功能呢?为什么中期训练要使用不同的模型?" }, { "i": 55, "speaker": "Speaker 1", "text": "是的,我的意思是,Tab 是一个非常小的模型,因为它需要极低的延迟。" }, { "i": 56, "speaker": "Speaker 1", "text": "嗯,是的,我们希望它非常快。所以,这里基础模型的两个核心区别在于:Tab 很小,而 Composer 则相当大。明白了,明白了。" }, { "i": 57, "speaker": "Speaker 2", "text": "好的。看来你们为 Composer 2 所做的工作中,很大一部分重点都放在了这次大规模强化学习运行上。能否为我们拆解一下?比如这其中包含哪些内容," }, { "i": 58, "speaker": "Speaker 2", "text": "以及你们在此过程中解决了哪些棘手的问题?" }, { "i": 59, "speaker": "Speaker 3", "text": "当你进行 rollout 时,这与预训练和中期训练截然不同。因为在预训练中,你只是在预测下一个词元;而在 rollout 中,你实际上是在运行整个" }, { "i": 60, "speaker": "Speaker 3", "text": "整个实验的复杂性。你让模型在环境中行动,观察它在给定 rollout 中的表现。这就是所谓的 rollout 术语。而且" }, { "i": 61, "speaker": "Speaker 3", "text": "根据它是否正确执行了某些操作来分配奖励,这可能需要使用大语言模型作为评判器,或者是一些可验证的标准,比如代码能否编译通过等。" }, { "i": 62, "speaker": "Speaker 3", "text": "这实际上意味着,与常规训练相比,你需要许多其他组件。你仍然需要进行大规模训练,仍然需要协调数万个 GPU 来" }, { "i": 63, "speaker": "Speaker 3", "text": "前向和反向传播,执行所有在中期训练和预训练中要做的事情。但现在你还需要协调一堆环境。你需要运行模型推理,因为" }, { "i": 64, "speaker": "Speaker 3", "text": "但当你执行这种 rollout 时,从某种意义上说,你实际上是在运行一个真实的 Cursor 会话,对吧?你的 是像一次前向传播吗?呃,不,rollout 基本上就是你整个智能体的" }, { "i": 65, "speaker": "Speaker 3", "text": "session from cursor,对吧?所以,我们基本上是指它可能需要大约 50 个回合。模型会接收你的初始提示,然后决定调用某些工具,你想要执行" }, { "i": 66, "speaker": "Speaker 3", "text": "使用这些工具后,模型会生成大量其他代码, essentially 构成整个会话——就像你在 Cursor 中与智能体交互时那样,对吧?你实际上是将整个会话作为一部分进行模拟" }, { "i": 67, "speaker": "Speaker 3", "text": "训练运行时,你会获得最终奖励,并利用该信号返回到训练器中,将其融入模型权重。因此,你拥有这样一个非常" }, { "i": 68, "speaker": "Speaker 3", "text": "一个非常大的更新循环,而且这个循环具有高度的异构性,因为其中涉及各种不同的组件协同工作。现在你需要协调所有这些部分,让它们高效运转" }, { "i": 69, "speaker": "Speaker 3", "text": "并实现高吞吐量,毕竟 GPU 成本高昂,你希望尽快以经济高效的方式完成模型训练。因此,这本身就是一个非常" }, { "i": 70, "speaker": "Speaker 3", "text": "有趣的问题,处于算法与基础设施的交叉点,因为如何在系统中进行协同优化和协同设计存在诸多权衡。" }, { "i": 71, "speaker": "Speaker 3", "text": "其中一个方面是人们常说的异步并行或流水线并行。其基本思路是:你正在分步骤更新模型,对吧?你有一个当前" }, { "i": 72, "speaker": "Speaker 3", "text": "模型版本,并试图用它执行大量 rollout。那么在你进行这些 rollout 的同时,你的训练器在做什么呢?一种朴素的做法会说:“好吧,现在我要停止我的" }, { "i": 73, "speaker": "Speaker 3", "text": "训练器,然后运行一批会话,这些会话可能持续 5 到 10 分钟,如果是更长 horizon 的任务,甚至会更久。等我拿到这些结果后,再暂停推理,回到训练阶段进行参数更新。”" }, { "i": 74, "speaker": "Speaker 3", "text": "这种做法在理论和算法上非常稳健,因为你没有对 everything 进行精确模拟,但它在系统效率上非常低下,因为你有一半的计算能力处于空闲状态" }, { "i": 75, "speaker": "Speaker 3", "text": "一直如此。所以,你可以采用各种巧妙的算法技巧来实现这一点。是的,你可以对这一切进行流水线化处理。想象一下,这就像一个巨大的" }, { "i": 76, "speaker": "Speaker 3", "text": "工厂,对吧?你有一个构建训练器的模块,还有一个构建 rollouts 的模块。它们一直在运转,对吧?Rollouts 总是采用最新版本的模型,尝试进行" }, { "i": 77, "speaker": "Speaker 3", "text": "新的会话,模拟新的智能体会话;而训练器则不断接收新产生的结果,并尝试计算更新。因此,所有环节都在持续运转。其中的权衡" }, { "i": 78, "speaker": "Speaker 3", "text": "在于,为什么说它在算法上是不同的:因为当你完成模拟环境中的一次测试 rollout 时,模型权重可能已经基于其他数据进行了更新。所以,你会遇到" }, { "i": 79, "speaker": "Speaker 3", "text": "这种“过时性”,也就是延迟:从你处理完与模拟环境的交互会话,到模型实际能够学习更新之间存在着时间差,此时你的模型" }, { "i": 80, "speaker": "Speaker 3", "text": "权重已经发生了变化,这引入了有趣的训练动态,对此也有一些巧妙的方法可以解决。但另一方面,你的所有 GPU、所有计算机" }, { "i": 81, "speaker": "Speaker 3", "text": "都处于满载并持续运转的状态,这意味着你实际上利用了更多的 flops。正如你刚才提到的例子,是的,你获得了更高的计算效率,能够在更短的时间内" }, { "i": 82, "speaker": "Speaker 3", "text": "得到更好的模型。你可能因为异步操作且未执行完美的数学更新而损失几个百分点的性能,但你通过有效地" }, { "i": 83, "speaker": "Speaker 3", "text": "不让一半的算力闲置。这其中有很多深层次的有趣互动。我们在 Cursor 非常重视性能,因为不像那些" }, { "i": 84, "speaker": "Speaker 1", "text": "大型实验室,你知道,我们拥有成千上万张 GPU,而不是数百万张,所以我们会使用各种技巧来最大化每张 GPU 的效用,比如我们甚至在生产环境中使用 FP4 进行训练。我们" }, { "i": 85, "speaker": "Speaker 1", "text": "还与 Fireworks 合作以推动推理优化。因为 RL 基础设施的问题在于,它本质上比预训练更复杂,因为你首先需要所有预训练基础设施。那只是" }, { "i": 86, "speaker": "Speaker 1", "text": "基本要求之一。然后你还需要所有基础设施来运行这些环境,这些环境必须尽可能紧密地模拟用户计算机的真实状态,这一点非常" }, { "i": 87, "speaker": "Speaker 1", "text": "重要,必须尽可能接近,因为有时模型实际上能分辨出它是在虚假环境中运行还是在真实环境中运行,并且它在" }, { "i": 88, "speaker": "Speaker 2", "text": "RL 阶段和在生产环境中的行为会有所不同。你是说它意识到自己处于虚假环境中,然后开始表现不同吗?是的,没错。" }, { "i": 89, "speaker": "Speaker 1", "text": "有意思。就像它在想:“哦,我在一个虚假环境里。我学到了一些技巧可以在这个环境中获得更好的奖励,让我试试看。”模型很喜欢作弊。RL 确实非常擅长鼓励作弊。是的。" }, { "i": 90, "speaker": "Speaker 1", "text": "[哼笑] 是的,然后我们需要非常高效的推理。这非常重要。实际上存在一种误解,认为在强化学习过程中消耗的推理浮点运算量远大于" }, { "i": 91, "speaker": "Speaker 1", "text": "训练浮点运算量。这其实是因为开源推理引擎优化不足,而非强化学习本身的特性。大致比例其实是差不多的。理论上" }, { "i": 92, "speaker": "Speaker 1", "text": "如果将 GPU 推向极限,你应该将三分之一的训练 GPU 分配给推理,对吧?因为训练本质上包含三次前向传播:" }, { "i": 93, "speaker": "Speaker 1", "text": "一次前向传播,一次数据梯度计算,一次权重梯度计算。而如果你在推理中真正达到临界批量大小,就只需要相当于单次前向传播的浮点运算量。所以," }, { "i": 94, "speaker": "Speaker 1", "text": "这就是你们使用 Fireworks 而不是开源推理引擎的原因吗?是的,另一种选择是我们自己内部构建一个,但你知道,像所有人一样,我们的工程师资源是有限的。我们更" }, { "i": 95, "speaker": "Speaker 1", "text": "希望让工程师专注于提升训练效率和精度,而不是去启动一个推理项目,是的。好的,这非常硬核。关于思考,你" }, { "i": 96, "speaker": "Speaker 2", "text": "在技术论文中提到你们是以一种全球分布式的方式进行的?为什么要全球分布式,以及这带来了哪些困难?是的。是的。嗯,有" }, { "i": 97, "speaker": "Speaker 1", "text": "各种原因。其一,你知道,市场上很难找到这种超大规模的连续集群。因此,我们可以采取的做法是,用一个集群来运行所有训练。你知道,我们无法建立一个全球分布的训练集群。" }, { "i": 98, "speaker": "Speaker 1", "text": "但强化学习的推理部分,我们可以将其全球分布式地部署到世界各地的小型集群上。因此,我认为为了让 Composer 运行,我们使用了四个" }, { "i": 99, "speaker": "Speaker 1", "text": "总共部署了多个集群,它们分布在全球各地,彼此相距非常遥远。" }, { "i": 100, "speaker": "Speaker 1", "text": "我们甚至在流量最低峰时动用了一些生产流量。比如,当时我们部署的是 Composer 1.5 这个前代模型,在用户使用最少的时候,我们就截取了一部分" }, { "i": 101, "speaker": "Speaker 1", "text": "推理 GPU,并将它们用于加速训练。因此,我们可以实现这类操作,轻松扩展训练运行,而无需依赖一个大型连续集群。而实现这一点的关键在于," }, { "i": 102, "speaker": "Speaker 3", "text": "也许 Dima 可以多讲讲 基本上就像 Federico 刚才确认的那样,我们的强化学习训练是非常异构的,对吧?而通过利用这种异构性,不同的组件,比如什么" }, { "i": 103, "speaker": "Speaker 3", "text": "基础架构,你实际上就能提升效率。你会发现这种模式在各个领域都普遍存在。具体到训练环节,你会用到所有这些高度" }, { "i": 104, "speaker": "Speaker 3", "text": "互联集群需要高速网络,基本上需要同步运行。所以这些集群很昂贵,对吧?而且实际上很难找到大规模的集群,对吧?" }, { "i": 105, "speaker": "Speaker 3", "text": "基本上,在Composer训练的规模下,找到比当前规模大两倍的集群要显著困难得多。这就是为什么如果你可以将这些组件拆分并放在不同的地方,第一,你就不需要寻找如此大的集群。" }, { "i": 106, "speaker": "Speaker 3", "text": "第二,你可以实际找到不同硬件的权衡,因为对于推理,你不需要那种广泛的互连。你可以有较小的GPU组互连" }, { "i": 107, "speaker": "Speaker 3", "text": "在一起。你可以有异构的GPU集合。你可以使用不同代的GPU。你可以玩各种优化的游戏。最后,推理部分更容易进行" }, { "i": 108, "speaker": "Speaker 3", "text": "上下扩展。是的,它非常紧密相关。例如,当你有非高峰时段时,你可以将所有推理池视为一组GPU,为真实用户提供生产流量" }, { "i": 109, "speaker": "Speaker 3", "text": "服务,或为强化学习目的提供模拟环境,并在两者之间进行平衡。当然,这是一个非常有趣的系统问题。Federico提到像Kimi模型这样的模型大小是1 TB。" }, { "i": 110, "speaker": "Speaker 3", "text": "训练步骤所需时间在5到15分钟之间。这意味着,每5到10分钟,你就会生成一个新的权重快照,大小为1 terabyte。所以" }, { "i": 111, "speaker": "Speaker 3", "text": "问题在于,你如何非常高效地将它传输到世界另一端的另一个集群,对吧?而且你需要快速完成,因为记住,你不需要" }, { "i": 112, "speaker": "Speaker 3", "text": "不希望这种滞后性失控。所以我认为,我们共同攻克的最有趣的部分之一就是:尽管涉及完整的模型大小为 1 TB,但并非所有权重在每一步都会发生变化,对吧?" }, { "i": 113, "speaker": "Speaker 3", "text": "因为强化学习会进行大量非常精确的调整,尤其是在训练过程中。因此,哪些权重子集会发生改变,实际上存在着非常规律的模式。也许并非每次所有参数都会发生变化。" }, { "i": 114, "speaker": "Speaker 3", "text": "因此,如果你观察模型在一个训练步骤(比如 10 分钟)内的变化,两者之间的差异相对较小。" }, { "i": 115, "speaker": "Speaker 3", "text": "你可以编写一种压缩算法,利用这一特性,最终你就会遇到类似数据库系统的问题,也就是我有我的增量数据,我只想进行" }, { "i": 116, "speaker": "Speaker 3", "text": "比如将其传输到世界各地。我的增量可能只有完整模型传输的20分之一,这使得它变得可行。当然,现在你需要构建所有这些" }, { "i": 117, "speaker": "Speaker 3", "text": "这类涉及完整快照和增量的存储系统、恢复以及对账等机制。我们能够以无损方式构建它。基本上这意味着" }, { "i": 118, "speaker": "Speaker 3", "text": "另一端得到的模型在比特层面是完全等价的。因此你无需担心任何精度方面的问题,而且速度也非常快。你可以在几分钟内完成。" }, { "i": 119, "speaker": "Speaker 3", "text": "即使在最糟糕的情况下,通常也不到一分钟,而最重要的是,你只需要暂停大约 30 秒,即可在实际推理模型中切换权重。我们还通过分片上传和下载," }, { "i": 120, "speaker": "Speaker 3", "text": "完全饱和了集群的出口带宽。因此你可以利用所有这些系统技巧来降低停机时间。这确实增加了不少" }, { "i": 121, "speaker": "Speaker 3", "text": "复杂性,但你可以将其抽象出来,让它高效运行。它不会干扰你的训练算法,而另一方面,你获得了将资源解耦的能力,可以" }, { "i": 122, "speaker": "Speaker 3", "text": "利用其他集群来执行这些操作。这在某种程度上违背了关于如何构建 RL 基础设施的传统观点,因为传统观点认为,好吧," }, { "i": 123, "speaker": "Speaker 3", "text": "你会拥有一个通过 RDMA 连接的超大规模集群,成本非常高昂,而且你可能需要分配" }, { "i": 124, "speaker": "Speaker 3", "text": "比如三分之一用于训练,三分之二用于推理。当然,如果你的网络非常昂贵,快速复制这 1 TB 数据会更容易,但现在我们的集群规模大了三倍。现在,如果" }, { "i": 125, "speaker": "Speaker 3", "text": "你的推理引擎优化得更好,那么也许你无论如何都能节省该集群三分之一的 GPU,因为你的效率更高了,而且你可以把这个集群的一半部署到其他地方的更便宜硬件上,甚至是在不同的区域。" }, { "i": 126, "speaker": "Speaker 2", "text": "所以,你们的成本大幅下降了。我很喜欢你们在描述这一点时露出的笑容,因为这真的很难,这简直是系统工程师的梦想,对吧?所以,这真的是一个令人惊叹的系统,是你们构建出来的。" }, { "i": 127, "speaker": "Speaker 1", "text": "为此熬了好几个晚上。" }, { "i": 128, "speaker": "Speaker 2", "text": "是啊。看得出来你们在一起花了很长时间。很多时间在一起。那我想问问,你一开始提到 Kimi 是一个非常大的稀疏 MLE 模型。这会让强化学习(RL)的运行变得棘手吗?" }, { "i": 129, "speaker": "Speaker 1", "text": "嗯,是的。具体怎么说呢?在进行推理时,本质上就是执行一次前向传播,大致上是自回归的过程。" }, { "i": 130, "speaker": "Speaker 1", "text": "在这次前向传播中,模型会生成它所采样词元的对数概率。当我们把模型的生成结果回传给训练器时,必须重新运行那一次" }, { "i": 131, "speaker": "Speaker 1", "text": "前向传播,因为正如我们提到的,我们采用的是异步训练。所以,产生该次传播的模型版本可能实际上比训练器当前的版本落后几步。因此," }, { "i": 132, "speaker": "Speaker 1", "text": "我们必须重新运行前向传播以复现对数概率。问题在于,理论上如果模型版本相同,这些对数概率应该完全一致。但即使" }, { "i": 133, "speaker": "Speaker 1", "text": "在相同模型版本下,相同词元的对数概率值也会出现轻微甚至非常大的差异。这通常被称为推理中的数值不匹配问题。你最近经常听到关于" }, { "i": 134, "speaker": "Speaker 3", "text": "这方面的讨论。对于混合专家模型来说——为什么会这样?为什么会发生这种情况?主要是因为从根本上讲,执行此操作的浮点算术是非确定性的。所以,如果你" }, { "i": 135, "speaker": "Speaker 2", "text": "那么,为什么浮点算术是非确定性的?" }, { "i": 136, "speaker": "Speaker 3", "text": "你知道,你学编程时知道,比如 A 加 B 加 C,和 C 加 B 加 A,结果应该是一样的。如果你用整数、用whole numbers 在" }, { "i": 137, "speaker": "Speaker 3", "text": "计算机上做运算,这永远成立。但如果你用浮点数,它们实际上是近似值,有尾数和指数" }, { "i": 138, "speaker": "Speaker 3", "text": "等等。A 加 B 加 C 和 C 加 B 加 A 可能会给出不同的结果,甚至 A 加 B 和 B 加 A 也可能不同。所以根本上,这是所有这些" }, { "i": 139, "speaker": "Speaker 3", "text": "运算的累加顺序问题,而模型做的 Basically 就是乘法和加法。加法的顺序会影响最终结果。这些都是微小的差异,但经过" }, { "i": 140, "speaker": "Speaker 3", "text": "数百万甚至数十亿次运算后会被放大。所以,当你对模型进行推理时,通常影响不大,因为你是预训练模型,它其实相当鲁棒。即使翻转一些" }, { "i": 141, "speaker": "Speaker 3", "text": "比特,它仍然能产生不错的结果,你的基准测试也不会变化。但强化学习(RL)尤其不同,因为你用的是非常微弱的信号来训练" }, { "i": 142, "speaker": "Speaker 3", "text": "模型,这种数值差异带来的噪声可能决定训练的成败。这一点特别重要。而且,这再次体现了算法和系统部分之间有趣的交叉点,因为,你知道,你可以写出一段很漂亮的代码,但它在实践中就是行不通。" }, { "i": 143, "speaker": "Speaker 3", "text": "有一些方法可以将这种差异降至几乎为零。通过各种批处理变体方案,基本上你可以非常谨慎地编写所有 GPU 内核" }, { "i": 144, "speaker": "Speaker 3", "text": "确保它们始终按相同的顺序对数字进行相加,比如始终是 A 加 B 加 C,而不是其他顺序。" }, { "i": 145, "speaker": "Speaker 3", "text": "这是可行的,但总是存在权衡,对吧?基本上,你的系统可能会慢上 2 到 3 倍。这又变成了一个有趣的权衡:我们是接受 10%" }, { "i": 146, "speaker": "Speaker 3", "text": "的减速,还是实际上只需接受百分之几的减速就能解决 90% 的差异?你知道,这就是正确的权衡点," }, { "i": 147, "speaker": "Speaker 3", "text": "是我们通过迭代共同找到的。你提到特别是对于 MOE 架构,稀疏性很难处理。原因在于 MOE 的工作方式是:在每一层,你会获取" }, { "i": 148, "speaker": "Speaker 3", "text": "激活值并将其通过一个门控层,该层基本上决定:对于这个词元,在 384 个专家中,我将运行其中八个。对吧?所以它会" }, { "i": 149, "speaker": "Speaker 3", "text": "进行某种排序,取前八个得分。这八个专家将被激活,而其余的对于这个词元则不会被激活。这个操作会显著放大你微小的数值" }, { "i": 150, "speaker": "Speaker 3", "text": "差异,因为也许你的隐藏状态只差小数点后第五位,这本来无关紧要,但这个差异却导致你选择了七号专家" }, { "i": 151, "speaker": "Speaker 3", "text": "而不是专家九,刚好处于临界点,结果你突然激活了模型中完全不同的部分,差异被大幅放大。而我的模型通过" }, { "i": 152, "speaker": "Speaker 3", "text": "定义对这种不匹配要敏感得多。同样,当你进行推理或常规负载时,这通常无关紧要,因为误差会相互抵消,但如果你现在试图" }, { "i": 153, "speaker": "Speaker 3", "text": "让模型学习到这种差异至关重要,因为在推理时你激活的是七号专家。而在训练中,你试图更新的却是九号专家,它甚至都没有被激活。" }, { "i": 154, "speaker": "Speaker 2", "text": "在推理过程中造成这种影响。那么,你们当时是手写 GPU 内核来解决这个问题吗?" }, { "i": 155, "speaker": "Speaker 3", "text": "是的。所以,你可以通过 GPU 内核来解决所有这些问题,但这始终存在权衡。" }, { "i": 156, "speaker": "Speaker 3", "text": "具体针对 MOE,你可以使用一种有趣的技巧,人们称之为“路由器重放”(router replay),但基本上你可以让推理过程向训练传递额外信息,比如说嘿" }, { "i": 157, "speaker": "Speaker 3", "text": "我为这个词元激活了专家七。这非常微小的信息片段只是一个整数,表示“这就是我激活的专家”,以便训练器能与之对齐。而这种大量的数值" }, { "i": 158, "speaker": "Speaker 3", "text": "这种对齐基本上就是运用这类技巧,比如匹配量化层级、匹配内核等。以降低训练和推理实现之间的差异。这会产生巨大的影响,否则你的系统可能会完全发散,或者变得,你知道的,多路复用。" }, { "i": 159, "speaker": "Speaker 2", "text": "计算效率较低,因为你需要更多的数据来解决这种不匹配问题。我很想再聊聊强化学习的具体方案。你能简单介绍一下" }, { "i": 160, "speaker": "Speaker 2", "text": "你使用的奖励信号是什么?是……你是……好吧,不能说。明白了。顶级机密。顶级机密。" }, { "i": 161, "speaker": "Speaker 2", "text": "好的,这很有道理。这几乎等同于在模拟环境中学习,也就是使用模拟 rollout,而实际上你们拥有海量的真实用户数据可供利用。" }, { "i": 162, "speaker": "Speaker 2", "text": "继续学习。为什么不在实际的用户数据和实际的用户评估框架上直接进行强化学习,而非要在模拟环境中进行呢?" }, { "i": 163, "speaker": "Speaker 1", "text": "是的,我们也在这样做。这就是我们所说的实时强化学习。我们利用相同的技术,通过与 Fireworks 同步来进行推理。我们发现,用户" }, { "i": 164, "speaker": "Speaker 1", "text": "信号,表明用户对特定的模型生成结果感到满意或不满意。我们能够实时更新该模型,从而每隔几个小时就持续发布一个新版本。我们正在努力缩短这一时间。" }, { "i": 165, "speaker": "Speaker 1", "text": "实际上,我们迟早需要延长这个时间,因为随着模型的时间视野越来越长,我们必须相应地扩展它。所以这是一个很有趣的策略。" }, { "i": 166, "speaker": "Speaker 1", "text": "目前我们正致力于缩短达到稳定状态所需的时间,因为我们之前一直在摸索合适的超参数,而在确定之后,我们又不得不重新扩展它,只是因为" }, { "i": 167, "speaker": "Speaker 2", "text": "我们想要延长这些模型的视野,对吧。你是否需要进行类似预训练模拟强化学习这样的操作?你有这么多实际的用户数据,我想象这会更加有效" }, { "i": 168, "speaker": "Speaker 2", "text": "用于训练和微调的价值。那为什么不直接进行在线强化学习步骤呢?为什么必须做离线强化学习?目前的在线强化学习效率相当低,我们面临着" }, { "i": 169, "speaker": "Speaker 1", "text": "这个问题本质上是 GPU 会长时间处于离线状态。除此之外,在效率和用户体验方面也存在不同的权衡。" }, { "i": 170, "speaker": "Speaker 3", "text": "是的。如果进行模拟,你实际上会从同一个提示词执行多次 rollout,对吧?你 effectively 拿一个任务,让模型尝试 16 次或者 128 次,就像" }, { "i": 171, "speaker": "Speaker 3", "text": "从同一个提示词进行不同的 rollout。其中一些会顺利进行,另一些则不会。" }, { "i": 172, "speaker": "Speaker 3", "text": "通过并行执行多次 rollout,你能够获得更精确的信号。也许,你知道,也许一个模型非常好,它有 90% 的概率能做好。也许它并不" }, { "i": 173, "speaker": "Speaker 3", "text": "那么好。像 GRPO(组策略梯度)这样的损失函数,其工作原理就是同时执行多次 rollout。如果你是在线执行,你只能收到一次 rollout 的结果。因此" }, { "i": 174, "speaker": "Speaker 3", "text": "所以在算法执行方式上存在权衡。最重要的是,如果你的模拟 rollout 出错了,那也没关系,对吧?我的意思是,你只是,你知道,也许" }, { "i": 175, "speaker": "Speaker 3", "text": "在视图上花费了一些时间。但如果是真实用户,你对这方面的最低要求就要高得多,因为实际上你是在进行 A/B 测试,对吧?所以如果模型产生了一些奇怪的东西,那就是糟糕的用户体验。" }, { "i": 176, "speaker": "Speaker 2", "text": "是的,没错。所以当不是真实用户时,你可以更频繁地进行离策略(off-policy)操作,因为你可以尝试各种疯狂的方案而不会影响用户体验。你可以" }, { "i": 177, "speaker": "Speaker 2", "text": "进行更多的 rollout。你可以使用 GRPO。是的。嗯,然后你基本上可以引导出足够好的性能水平,甚至可以直接展示给用户。好的。" }, { "i": 178, "speaker": "Speaker 1", "text": "是的,就像我们通过所谓的离线强化学习来教授推理能力,但这实际上更像是在线强化学习。离线强化学习更像是 DPO 这类技术,用于某种程度的强化,而在线强化学习才是实时的。嗯" }, { "i": 179, "speaker": "Speaker 1", "text": "然后在那里我们教模型进行推理。我们给它一些它应该具备的行为输入。我们尝试给它提供关于世界的新信息,并教它工具调用。" }, { "i": 180, "speaker": "Speaker 1", "text": "然后我们将其上线供用户使用。因为你可以想象,如果模型很差,用户就不会使用它,也就不会给我们任何反馈,对吧?所以模型必须达到某种" }, { "i": 181, "speaker": "Speaker 1", "text": "门槛才能进入在线强化学习阶段。我们希望对这个模型非常满意,这才是我们最终发布的模型。这就是在线强化学习的悖论,或者我们喜欢称之为真正的" }, { "i": 182, "speaker": "Speaker 1", "text": "time,问题在于,我们无法用它从零开始构建模型,因为必须有用户在使用该模型。所以它本身必须已经足够好,而我们只能让它变得更好。是的。" }, { "i": 183, "speaker": "Speaker 1", "text": "是的。所以这有点像锦上添花,旨在为会话带来极其愉悦的体验。没错。希望有一天,这颗樱桃会变得非常大,你懂的。" }, { "i": 184, "speaker": "Speaker 2", "text": "是的,Dan Roberts 去年在我们的会议上做过演讲。我想你当时也在。传统上,比喻是大蛋糕上面放一颗小樱桃。LeCun 的樱桃,没错。小蛋糕,大樱桃。" }, { "i": 185, "speaker": "Speaker 2", "text": "没错。我很好奇,关于 Andrej Karpathy 的那个观点,即目前 RL 仍然效率极低。你进行一次漫长的大规模 rollout,然后最终只获得" }, { "i": 186, "speaker": "Speaker 2", "text": "一点点信息,这感觉仍然像是在用吸管费力地吸取比特。你怎么看?你们是否已经找到了如何" }, { "i": 187, "speaker": "Speaker 2", "text": "从那条路径中提取更多比特?呃,这个我不能说。好的好的,明白了。我们又回到机密内容了。很好,这说明我问对问题了。" }, { "i": 188, "speaker": "Speaker 2", "text": "你提到每次 rollout 只需几分钟。看起来整个领域都在朝着构建长周期智能体的方向努力,也就是能够长时间工作的智能体。" }, { "i": 189, "speaker": "Speaker 2", "text": "持续运行且不出现故障。我很喜欢那个指标缩放图表。在强化学习过程中,为了让智能体运行更长时间,需要采取哪些措施?这涉及多个方面。首先,强化学习存在一个问题……" }, { "i": 190, "speaker": "Speaker 1", "text": "学习在于轨迹越长,信用分配就越困难。所以,你可以想象,我们是在最后关头、在轨迹的终点给出点赞或点踩的反馈。" }, { "i": 191, "speaker": "Speaker 1", "text": "它的工作。简单来说,问题可以简化为:模型会自问:“我哪里做对了,哪里做错了?”这基本上就是所谓的信用分配(credit assignment)问题。" }, { "i": 192, "speaker": "Speaker 1", "text": "随着上下文变长,难度也会增加,因此必须采用一些技巧。另一个问题是空间会耗尽,对吧?这些模型的上下文窗口是有限的,到了某个时刻" }, { "i": 193, "speaker": "Speaker 1", "text": "达到那一点。所以,实际上我们在 Cursor 解决这个问题的方法是将压缩纳入他们的强化学习循环中。我们称之为自总结。因此,在强化学习过程中,智能体" }, { "i": 194, "speaker": "Speaker 1", "text": "实际上学会了如何持续运行并无限延续。因此,在实践中,我们的模型是一个拥有 20 万词元上下文窗口的模型,但实际上它可以运行数百万个词元,这正是因为具备了这种能力,它才能" }, { "i": 195, "speaker": "Speaker 1", "text": "总结其工作,然后利用该摘要重启上下文窗口,同时继续尝试完成任务。而通过强化学习,由于 RL 会推动模型朝着目标正确行事,在" }, { "i": 196, "speaker": "Speaker 1", "text": "同时,我们也在训练模型生成优质的摘要,并同步训练模型能够很好地理解该摘要。因此,这几乎可以说是推理能力的延伸,我是这么觉得的。" }, { "i": 197, "speaker": "Speaker 3", "text": "这很有趣,因为通常上下文管理被视为难点的一部分,对吧?而在这种情况下,你们实际上是在协同优化难点的一部分与模型本身的工作方式。" }, { "i": 198, "speaker": "Speaker 3", "text": "整合在一起并全部投入优化循环中。我们在 AI 领域反复看到这一点:你投入的算力越多,能解决的问题就越多。" }, { "i": 199, "speaker": "Speaker 3", "text": "端到端地解决问题。计算的魔力在于让你的课程奏效,从而构建出能够协同工作的更优系统。完全正确,完全正确。你认为每家公司都会" }, { "i": 200, "speaker": "Speaker 2", "text": "让智能体对自己的评估框架进行强化学习?" }, { "i": 201, "speaker": "Speaker 1", "text": "比如,你认为每家公司面临的问题形态都和 Cursor 一样吗?如果他们在使用 AI,生成大量词元,并且有产品需要针对性优化,我认为" }, { "i": 202, "speaker": "Speaker 1", "text": "这确实是正确的举措,也是训练模型的正确方向。是的,是的,很有趣。" }, { "i": 203, "speaker": "Speaker 2", "text": "有意思。那么,看起来你们所做的大部分强化学习都集中在 harness/工具使用部分,而不是专注于如何更好地完成下一个步骤。" }, { "i": 204, "speaker": "Speaker 2", "text": "词元用于代码。这是否是其他创始人在思考应该在哪里使用强化学习时应该记住的大致模式?所以,比如你正在尝试" }, { "i": 205, "speaker": "Speaker 2", "text": "要让智能体利用工具在长周期内执行任务,就需要强化学习。如果你只是想打造一个擅长摘要、下一个词元预测或其他类似任务的模型,那可能就不需要强化学习。" }, { "i": 206, "speaker": "Speaker 1", "text": "这是判断是否需要强化学习的一个好框架吗?我认为强化学习适用于任何场景。所以,即使是针对代码补全功能,我们也用了强化学习。当然,这只是我个人的理论,没有任何实证支持。当你" }, { "i": 207, "speaker": "Speaker 1", "text": "预训练模型时,模型只是在摄取人类知识的全部。假设你正在训练一个数学模型,该模型会学习所有的数学知识。" }, { "i": 208, "speaker": "Speaker 1", "text": "在 Stack Exchange 上。当模型面对一个数学问题时,如果它是一个尚未经过强化学习(RL)训练的模型,它就会困惑自己究竟是什么样的角色:是专家,还是" }, { "i": 209, "speaker": "Speaker 1", "text": "是那个正在尝试学习的学生吗?因此,我认为在强化学习(RL)过程中发生的一件事就是,我们正在调节这个旋钮,让模型明白:“嘿,你是专家,你需要正确地做事。”所以,这就是其中" }, { "i": 210, "speaker": "Speaker 1", "text": "发生的一件事,即我们正在锐化这种分布。强化学习大致有几个阶段。比如在最初阶段,模型学习并迅速变得非常擅长。然后进入" }, { "i": 211, "speaker": "Speaker 1", "text": "第二个阶段,此时需要大量的算力来持续提升模型,你会看到模型开始进行推理并呈现出这种模式。所以,在曲线的最初阶段" }, { "i": 212, "speaker": "Speaker 1", "text": ",我认为我们只是在调节这个旋钮,告诉模型:“嘿,你应该在这里正确地做事。”因此,即使在小算力情况下,强化学习也非常有用,它能让" }, { "i": 213, "speaker": "Speaker 3", "text": "模型知道它必须正确地做事。这基本上就是我的观点。是的,我完全同意第二点。我的意思是,我们之所以看到这种模式,是因为在许多这类案例中,你知道,我们帮助" }, { "i": 214, "speaker": "Speaker 3", "text": "过许多客户进行强化学习微调,我们通常观察到,你基本上是在进行持续的预训练。可以说,常规的监督微调是以一种抽象的方式转移" }, { "i": 215, "speaker": "Speaker 3", "text": "新知识,而强化学习则是锐化行为,或者说赋予模型你所期望的特定品质,通常你最终需要" }, { "i": 216, "speaker": "Speaker 3", "text": "两者结合。甚至以你提到的摘要生成例子来说,强化学习实际上可能非常有用,因为有时如果你想要某种特定的摘要风格,对吧?这" }, { "i": 217, "speaker": "Speaker 3", "text": "真的很难举出好摘要和坏摘要的具体例子,实际上很难精确描述这一点。但如果你使用例如 LLM-as-a-judge(大模型即裁判),对吧?" }, { "i": 218, "speaker": "Speaker 3", "text": "你实际上可以制定非常精确的评分标准。你可以这样提示它:“好吧,这是我评估摘要好坏的标准”,把它投入 RL 循环中,让" }, { "i": 219, "speaker": "Speaker 3", "text": "模型尝试不同的摘要风格,找出你真正想要的效果。”同时也许由另一个大模型来评估它是否符合特定的评分标准。" }, { "i": 220, "speaker": "Speaker 2", "text": "这种模式你很常见到,不仅仅是在编程领域。好吧,我要把这个问题问 Dima,因为 Federico 可能要援引第五修正案拒绝回答了。嗯,你提到了几次 LLM-as-a-judge。" }, { "i": 221, "speaker": "Speaker 2", "text": "你认为最终公司会更成功是让专家手动检查 RL rollouts( rollout 轨迹)并以某种方式手动指导模型行为,还是你认为 LLM" }, { "i": 222, "speaker": "Speaker 3", "text": "作为裁判或其他自动化评分标准更有可能让我们达到目标?你并不真的喜欢让专家直接去评判一般的 rollouts。我的意思是,那会是某种实时 RL," }, { "i": 223, "speaker": "Speaker 3", "text": "如果是实际用户参与,或者是某种形式的 RLHF 或 DPO。我的意思是,一般来说,你的奖励信号越可验证越好,因为这允许你扩展算力并获得更好的" }, { "i": 224, "speaker": "Speaker 3", "text": "结果。在某些情况下,可验证性基本上意味着你如何在不依赖人类的情况下自动产生它?" }, { "i": 225, "speaker": "Speaker 3", "text": "当然,如果像数学或编程这样可以设计出非常确定性的内容,那就是最好的。LLM作为评判者之所以有效,是因为它实际上具有生成器和判别器之间的区分," }, { "i": 226, "speaker": "Speaker 3", "text": "对人类来说,评判要容易得多,对吧?评判比创造更容易。LLM有C吗?有。没有暗示。但确实,评判要容易得多,你可以精确地制定你想要运行的答案的各种标准。" }, { "i": 227, "speaker": "Speaker 3", "text": "你会看到这样的模式,你可能会有非常复杂的评估,从多个方面进行,对吧?因为如果你把多个方面都交给一个LLM,它可能会在如何评判上感到困惑," }, { "i": 228, "speaker": "Speaker 3", "text": "对吧?比如,你可以把它分解下来,好的,你将根据风格、根据一些不同的方面,比如根据性取向,非常细致地制定这些" }, { "i": 229, "speaker": "Speaker 3", "text": "奖励。其中一些会是天才级别的,一些会是基于LLM的,而这些就是指导模型行为的依据。然后你只需增加更多算力,就能看到图表上升。" }, { "i": 230, "speaker": "Speaker 2", "text": "认为我们会在更难验证的领域看到强化学习(RL)更有效吗?比如,你认为仅靠“大模型即裁判”(LLM-as-a-judge)就足够了吗?这难道不是你们起步时要解决的核心问题之一吗?" }, { "i": 231, "speaker": "Speaker 3", "text": "理想情况下,你希望弄清楚实际的产出结果是什么,你想要获取的实际指标是什么,对吧?所以,通过大模型来近似这一指标是一种方法,而构建" }, { "i": 232, "speaker": "Speaker 3", "text": "更大的模拟环境是另一种方法。如果你能更多地模拟你的产品,更多地模拟你的环境,通常你就会有一个关心的最终指标。" }, { "i": 233, "speaker": "Speaker 3", "text": "只是这个指标更难捕捉。如果你能想办法捕捉到它,那就太好了。关于你提到的专家,我的意思是专家仍然是必需的,对吧?因为设计" }, { "i": 234, "speaker": "Speaker 3", "text": "这些任务并实际编码你想要的产品体验,这才是关键,对吧?我们经历了软件 1.0、2.0、3.0 时代,对吧?我们不再直接编写软件,转而编写训练" }, { "i": 235, "speaker": "Speaker 3", "text": "数据。而现在,你实际上是在制定评估规则。但这仍然非常重要。你需要查看示例,需要查看数据,需要查看" }, { "i": 236, "speaker": "Speaker 2", "text": "你的产品在何处失败,以及如何引导模型表现出正确的行为。我想问问关于 RL 环境的问题,这或许与你刚才谈到的内容有关。看起来" }, { "i": 237, "speaker": "Speaker 2", "text": "好像这些强化学习环境公司的收入规模都出现了巨大增长。它们到底提供了什么真正有用的价值?我的意思是,像 Cursor,对于" }, { "i": 238, "speaker": "Speaker 2", "text": "例如,你们拥有大量关于客户如何实际使用这些环境的数据。那么,RL 环境供应商能在你们已有的数据之外,额外提供什么价值呢?是的,我们不会" }, { "i": 239, "speaker": "Speaker 1", "text": "实际上会使用任何环境供应商。我认为,构建可用的环境非常困难。对于那些无法获得此类资源的人来说,这确实是一个有价值的产品。不过,特别是在编码领域,确实存在一种" }, { "i": 240, "speaker": "Speaker 1", "text": "可供大家使用的、规模非常大的可用编码环境。那是 GitHub,对吧?你可以进入其中,也许可以让模型直接为某个仓库安装所有依赖项,这就构成了一个可运行的环境。我认为很多" }, { "i": 241, "speaker": "Speaker 1", "text": "难度也来自基础设施。你可以想象,一个适用于特定任务的环境可能需要启动某些服务。比如你正在做一项更改,嗯比如说数据库迁移。" }, { "i": 242, "speaker": "Speaker 1", "text": "要测试它是否真正起作用,你需要把数据库运行起来,对吧?所以这类事情非常棘手。我认为这些环境公司在这方面很有帮助。" }, { "i": 243, "speaker": "Speaker 3", "text": "这类事情。对此大致有两个方面,对吧?首先,如果你看看前沿实验室(Frontier Labs),对吧?" }, { "i": 244, "speaker": "Speaker 3", "text": "他们试图构建一个通用的模型,擅长处理所有任务,对吧?因此,他们需要涵盖底层所有这些不同的任务,将它们封装在一个模型中,并鼓励其泛化," }, { "i": 245, "speaker": "Speaker 3", "text": "对吧?所以这是一种模式,而且非常有用,对吧?比如在 Composer 这样的案例中,对吧?" }, { "i": 246, "speaker": "Speaker 3", "text": "你拥有自己的实际产品,对吧?我认为 Fireworks 也持同样观点:是的,如果你有自己的实际产品,你就应该针对它进行强化学习(RL),对吧?最" }, { "i": 247, "speaker": "Speaker 2", "text": "强大的环境就是你自己的产品。" }, { "i": 248, "speaker": "Speaker 3", "text": "没错,因为那才是你的模型真正会被使用的地方。当然,如果你是前沿实验室(Frontier Labs),你会在所有产品上进行这项工作,对吧?" }, { "i": 249, "speaker": "Speaker 3", "text": "但是,如果你试图为你的产品构建最佳模型,进行专门化和定制,你就应该直接使用你的生产环境。当然,你需要对其进行适当的隔离," }, { "i": 250, "speaker": "Speaker 3", "text": "对吧?你肯定不希望模型对你的生产数据库造成破坏。你需要克隆它等等。而且底层公司确实提供一些工具,来自通用基础设施领域的工具,让这件事变得更容易。" }, { "i": 251, "speaker": "Speaker 3", "text": "但总体而言,你希望你的强化学习(RL)环境尽可能接近真实的生产环境。举个例子,如果你看看那些玩具级的 RL 示例," }, { "i": 252, "speaker": "Speaker 3", "text": "那些玩具级的 RL 框架,它们通常都是从“哦,有个玩具环境,我要启动一个 Docker 容器并在里面运行所有内容”开始的。呃,这对于像" }, { "i": 253, "speaker": "Speaker 3", "text": "教模型玩 Atari 游戏之类的玩具示例来说很好,对吧?但如果你要过渡到实际的生产案例,你就不能简单地把真正的生产" }, { "i": 254, "speaker": "Speaker 3", "text": "应用塞进一个 Docker 容器里。我们很早就发现了这一点,尤其是在与许多客户合作时。当然,在我们的这边,我们的训练器,以及其他一些客户,我们在" }, { "i": 255, "speaker": "Speaker 3", "text": "自己的训练平台上运行训练器。但对于环境,我们实际上默认在客户侧运行它们,因为那才是实际部署所在。而且你可以有效地拥有相同的" }, { "i": 256, "speaker": "Speaker 3", "text": "训练器设置,无论它是作为我们平台的一部分还是在客户侧,直接调用实际的生产环境,而不是试图去包装它或将其组件化。是的。关于那个" }, { "i": 257, "speaker": "Speaker 1", "text": "在托管平台上,因为这非常困难,而且会引入差异。是的,我们所谓的强化学习环境实际上由三个部分组成。其中之一就是评估框架。" }, { "i": 258, "speaker": "Speaker 1", "text": "所以,harness 就是模型可以提交工具并执行这些工具的地方。第二件事,我们可以称之为某种操作系统,对吧?比如,什么" }, { "i": 259, "speaker": "Speaker 1", "text": "就是模型实际交互的真实世界,也就是最终状态。然后还有一个奖励组件,我们需要它在最后检查工作是否正确完成。一般来说,这个评估框架的可移植性很强。你可以把它部署到许多不同的环境中。" }, { "i": 260, "speaker": "Speaker 1", "text": "关键在于操作系统。要复现这一点,普通的容器效果并不理想。因此,在 Cursor,我们实际上构建了一整台虚拟机。" }, { "i": 261, "speaker": "Speaker 1", "text": "堆栈。因此,我们可以非常快速地启动虚拟机。而且它必须非常突发,因为你可以想象,我们正在向这个系统请求,\"请给我100,000个虚拟机\"。" }, { "i": 262, "speaker": "Speaker 2", "text": "现在。\" 并且它必须全部出现,嗯,嗯,是的。太棒了。我今天真的很享受这次对话。我认为 Cursor 在你们公司所做的一切都令人鼓舞,朝着实现" }, { "i": 263, "speaker": "Speaker 2", "text": "应用公司发展成为真正的前沿移动实验室。我认为你们在 Composer 2 上的工作正是引领了这一潮流。所以,能听到这些非常特别。另外,Dima,很高兴听到" }, { "i": 264, "speaker": "Speaker 2", "text": "了解到你们两位为了成就这一切,曾在无数个深夜并肩奋战,共同解决了那些极其硬核的基础设施难题。所以,谢谢你们。感谢二位" }, { "i": 265, "speaker": "Speaker 1", "text": "今天能参与其中。非常感谢你们的邀请。谢谢。" } ]