GitHub Copilot代码搜索能力升级:全新嵌入模型技术解析

本文详细介绍GitHub Copilot全新嵌入模型的技术突破,该模型使VS Code中的代码搜索速度提升2倍,内存占用减少8倍,检索质量提升37.6%,通过对比学习和困难负样本训练实现更精准的代码语义匹配。

GitHub Copilot在代码搜索方面变得更智能:深入了解我们的新嵌入模型

快速找到正确的代码至关重要。在听取社区反馈后,我们推出了新的Copilot嵌入模型,使VS Code中的代码搜索更快、内存占用更少且准确性更高。这意味着检索到您实际需要的代码片段,而不是近似的结果。它实现了检索质量37.6%的提升,吞吐量提高约2倍,索引大小缩小8倍,因此GitHub Copilot聊天和代理响应更准确,结果返回更快,VS Code中的内存使用更低。

为什么这很重要

优秀的AI编码体验依赖于找到正确的上下文:与您意图匹配的代码片段、函数、测试、文档和错误代码。“查找"步骤由嵌入提供支持,这些是向量表示,即使在不完全匹配确切词语的情况下也能检索语义相关的代码和自然语言内容。

更好的嵌入带来更好的检索质量,从而提供更好的GitHub Copilot体验。

我们发布了什么

我们训练并部署了一个专为代码和文档定制的新嵌入模型。它现在为GitHub Copilot聊天的上下文检索以及代理、编辑和询问模式提供支持。

影响:

  • 改进的检索质量:在我们的多基准评估中,相对提升+37.6%(平均得分从0.362提高到0.498)(图1)。对于VS Code中的C#开发者,我们看到代码接受率提升了+110.7%——对于Java开发者,我们看到代码接受率提升了+113.1%。

图1:多个代码检索基准测试上的模型得分比较

  • 更高效率:约2倍的嵌入吞吐量提升减少了检索延迟(图2),约8倍的索引内存大小改善改善了客户端和服务端的扩展性(图2)。

图2:模型效率比较

以下示例展示了新模型在检索质量方面的改进:

开发者提示:“哪个方法被调用来按名称在项目中查找单个命名空间?”

使用Copilot嵌入模型检索的顶部代码片段包含findOne函数(如下加粗所示),这是正确的:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
class Namespace extends K8Object {
  /*...*/
  static findOne(params = {}, options = {}) {
    return Model.findOne(params, options).then((namespace) => {
      console.log(namespace);
      if (namespace) {
        return new Namespace(namespace).setResourceVersion();
      }
    });
  }
  /*...*/
}

使用先前模型检索的顶部代码片段包含find函数(如下加粗所示),这是不正确的,但在语义上类似于findOne函数:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
class Namespace extends K8Object {
  /*...*/
  static find(params = {}, options = {}) {
    return Model.find(params, options).then((namespaces) => {
      if (namespaces) {
        return Promise.all(
          namespaces.map((namespace) =>
            new Namespace(namespace).setResourceVersion()
          )
        );
      }
    });
  }
  /*...*/
}

Copilot嵌入模型提供了对提示和指令的改进响应。它还能更好地区分有些相关和高度相关的搜索结果。

开发者受益的其他场景包括:

  • 在大型单体仓库中搜索测试函数
  • 查找分布在多个文件中的辅助方法
  • 调试代码:“显示这个错误字符串在哪里被处理”

我们如何训练

我们的目标是在保持延迟和内存在预算范围内的同时,优化实际开发者工作负载的检索质量。

我们使用带有InfoNCE损失的对比学习和Matryoshka表示学习来优化检索质量——这种方法帮助嵌入区分几乎相同的代码片段,同时支持多种嵌入大小以提供灵活性。

一个关键要素是使用困难负样本进行训练:这些代码示例看起来正确但实际上不是。代码搜索中的大多数失败来自这些"近似错误”,因此教模型区分"几乎正确"和"实际正确"带来了最大的质量提升。我们从大型多样化语料库(公共GitHub和Microsoft/GitHub内部仓库)中挖掘困难负样本,并使用LLMs来发现棘手的近似错误。这帮助我们减少了捷径学习并改善了泛化能力。

以下示例展示了带有困难负样本的对比学习如何训练模型区分相关代码和近似相关代码样本。对于一个询问停用词表如何填充的查询,最相关的代码样本显示了从文件加载停用词表的函数。用于将单词加载到表中的函数或从文件读取停用词的函数被用作不回答查询的困难负样本。(以下示例的查询是"停用词表是如何填充的?")

我们训练数据中前五种编程语言包括:

语言 数据混合比例
Python 36.7%
Java 19.0%
C++ 13.8%
JavaScript/TypeScript 8.9%
C# 4.6%
其他语言 17.0%

评估套件

我们使用多基准评估,而不是单一测试来覆盖代码检索的不同方面。这些包括:

  • 自然语言(NL)到代码:用相关函数/片段响应NL查询
  • 代码到NL:代码的自然语言摘要
  • 代码到代码:相似函数搜索(重构或翻译的代码)
  • 问题到代码:将问题描述转化为建议的代码修复

下一步计划

新的Copilot嵌入模型是使AI编码助手不仅更智能,而且为日常开发更可靠的一步。展望未来,我们正在:

  • 将训练和评估数据扩展到更多语言和仓库
  • 改进困难负样本挖掘流程以获得更好的质量
  • 利用效率增益部署更大、更准确的模型

想要尝试我们改进的代理搜索体验吗? 在VS Code中尝试GitHub Copilot >

致谢

衷心感谢GitHub和Microsoft的工程师和研究人员,他们构建了训练流程、评估套件和服务堆栈——以及GitHub Copilot产品和工程团队为顺利推出所做的努力。

comments powered by Disqus
使用 Hugo 构建
主题 StackJimmy 设计