没有训练补全的LLM模型,而是使用CatBoost构建的轻量级训练模型,它是一个2.5 MB文件,预测时间仅为1-2毫秒。
如果你一直在关注我们的进展,你可能已经阅读了我们最近的博客文章Complete the Un-Completable: The State of AI Completion in JetBrains IDEs。从那篇文章中,你可能还记得关于代码补全的酷炫图表。在四月份,发生了一些令人兴奋的事情:我们的接受率上升了,而显式取消率下降了。
在这篇博客文章中,我们将详细解释为什么以及如何在不重新训练生成模型的情况下取得这些结果。
人不能只靠LLM生存
提供代码建议的LLM是AI驱动的代码补全的核心,但它并不是全部。幕后还有很多事情在发生,特别是在插件方面,比如决定:
- 何时显示建议。
- 建议应该是单行还是多行。
- 显示或隐藏哪些建议——例如,建议可能在语义上不正确,得分太低,或者使用了冒犯或不恰当的语言。
但有时,定义过滤规则并不那么简单。
我们的目标
简单来说,我们只想向你展示你实际会使用的建议。这意味着减少你不想要的建议——那些你会取消、编辑或删除的建议——同时不失去我们代码补全功能的力量。在指标方面,我们正在努力:
- 提高接受率。
- 降低显式取消率和编辑/删除建议的百分比。
- 保持或增加完成代码的比例。
你只需要日志
那么,我们如何实现所有这些目标呢?显而易见的答案是改进补全模型。
然而,事情并不那么简单:
- 这既昂贵又耗时。训练一个更好的模型需要大量资源。
- 我们无法看到问题出在哪里。我们不存储用户的代码,因此无法分析错误的建议。
- 仅靠上下文是不够的——用户行为以及建议如何与附近行匹配也很重要。
轻量级本地过滤模型
我们没有走改进补全LLM的漫长道路,而是采取了不同的方法:轻量级本地过滤模型。
该模型在补全LLM之上运行,并使用匿名日志进行训练。
该模型通过分析以下内容来决定是否应显示建议:
- 上下文:文件/项目上下文(如使用的语言以及导入的数量和类型)和补全上下文(如描述插入位置的特征)。
- 用户行为:打字速度和自上次打字以来的时间。
- 建议本身:引用是否已解析,建议是否重复或与周围行相似,以及额外的模型输出,如标记分数和标记熵。
轻量级本地过滤模型的工作很简单:它根据你的操作决定是否接受或拒绝建议。然而,我们在训练过程中对模型进行了一些指导。我们为显式用户操作(如显式接受或取消建议)赋予了额外的权重。如果你在接受建议后对其进行编辑或删除,我们将其视为较少的胜利——你修改得越多,它的权重就越低。
从技术上讲,该模型是使用CatBoost构建的,它效率高且不需要大量数据。该模型专门设计为轻量级——一旦训练完成,它就成为一个紧凑的2.5 MB文件,并直接在用户的机器上以Kotlin运行,预测时间仅为1-2毫秒。
我们取得的成果
我们在EAP中的A/B测试显示了出色的结果,而且它们还在不断改进。过滤模型将接受率提高了约50%,并将显式取消率降低了约40%,同时保持完成代码的比例稳定。
我们正式在2024.1版本的JetBrains IDE中推出了过滤模型,支持多种语言,包括Java、Kotlin、Python、PHP、JavaScript/TypeScript、Go、CSS和Ruby。在后续版本中,我们还覆盖了C#、C++、Rust和HCL,以及用于Python、Java和Kotlin的Mellum云补全的本地过滤模型。我们计划很快覆盖更多语言。
与此同时,本地代码补全模型和轻量级本地过滤模型都在不断发展和改进。
我们学到的经验
即使你的LLM已经做得很好,也总有改进的空间。你并不总是需要庞大、复杂的模型来产生影响。有时,巧妙地使用日志等额外数据就能奏效。那么,AI驱动的代码补全下一步是什么?我们能把它推到多远?