蚂蚁CodeFuse代码大模型技术解析:基于全仓库上下文的代码补全

背景

2023年CodeFuse完成了百亿级别的代码大模型从0到1的预训练,配合指令微调、量化部署等一系列配套技术,成功将AI大模型能力应用到多个下游研发场景,助力生产提效。在众多下游产品中,CodeFuse代码补全插件直接触及研发过程中最核心的编码场景,因此对开发效率的影响最显著。目前,CodeFuse代码补全插件是CodeFuse系列产品中用户数量最多、留存率最大,调用AI能力最多的产品。

目前,大部分代码语言模型在预训练阶段以文件为基本单位,随机选择代码文件拼接固定长度后组成训练样本。常见的代码评测数据集(HumanevalX、MBPP)也以单文件为主:基于待补全位置(Task Hole)的前缀(Prefix)使用Left-to-Right方式推理,或者同时使用前缀(Prefix)和后缀(Suffix)采用FIM(Fill In the Middle)方式推理。然而,实际的开发场景通常以代码仓库(Repository)为基本单位。在目前常见的业务设计模式下,大量与当前编辑文件存在依赖关系的内容散落在仓库内的的其他文件中,模型仅使用当前编辑文件内容预测会存在上下文不足的问题,从而导致补全结果存在幻觉、不准确等问题。目前,比较常见的解决思路是使用RAG的方法抽取一定代码片段作为上下文指导模型推理,但此方案同时会带来"上下文-延迟困境"的挑战。即丰富的上下文带来的效果提升和更长的提示内容增加的推理时间之间的权衡,这种权衡在IDE场景中可能会影响用户的实际体验。

为了解决上述问题,本文提出一种仓库级别代码补全框架RepoFuse:通过对实际编程的总结抽象,我们的方法从仓库中抽取了两种关键的跨文件上下文:基于代码相似性分析的相似上下文(Similar Context),用于识别功能相近的代码段;以及语义上下文(Semantic Context),提供类别分类和API交互的语义理解。然而,如此大量的信息可能导致模型的输入过于冗长,影响推理生成的效率。为此,RepoFuse采用了一种基于相关性引导的上下文选择策略(Relevance-Guided Context Selection)指导模型Prompt的构建。这种技术有选择地筛选出与当前任务最相关的上下文,将上下文精炼为简洁的Prompt,既能适应有限的上下文长度,又能确保高完成度的准确性。本文使用常见的开源代码模型在CrossCodeEval的Java和Python数据集上进行了实验,结果表明在完全匹配指标(Exact Match)上RepoFuse有3.01到3.97的提升(与当前主流开源工具的SOAT对比)。

相关工作

目前业界的相关工作主要沿用RAG的思路,代表工作如下表所示。具体来说,每一个方法需要回答以下三个问题:搜什么、怎么搜以及怎么用:

名称

搜什么

怎么搜

怎么用

RLPG

启发式搜索规则

判别模型选择搜索规则

Prompt Engineering

RepoFusion

同RLPG

同RLPG

Fusion-In-Decoder

ReACC

外部知识库相似片段

相似度搜索

Prompt Engineering

RepoCoder

仓库内相似片段

生成 + 相似度迭代搜索

Prompt Engineering

CrossCodeEval

仓库内相似片段

相似度搜索

Prompt Engineering

RepoBench

语义依赖信息

AST

<think>我们讨论的问题是如何将整个代码仓库作为上下文输入到大模型中。从引用[2]中可以看出,蚂蚁CodeFuse代码大模型采用了基于仓库上下文代码补全。他们提到了使用Fill-In-The-Middle(FIM)方式进行推理,并且模型支持8k的最大长度。然而,整个代码仓库的大小通常远超过现有大模型的最大上下文长度(例如,即使是支持100k的模型,对于大型代码仓库也可能不够)。因此,我们需要一种策略来处理这个问题。方法一:使用长上下文模型引用[3]中提到,长上下文LLM的数量显著增加。我们可以选择支持更长上下文的模型,比如支持32k、100k甚至更长上下文的模型。例如,我们可以使用像CodeLlamaLong(支持100k)这样的模型。但即使这样,如果代码仓库超过100k,我们仍然无法部放入。方法二:分块处理与上下文选择如果整个仓库太大,我们可以将代码仓库分成多个部分(例如按文件或按模块),然后逐次输入。但这样可能会丢失跨文件的依赖信息。方法三:检索增强(RetrievalAugmentedGeneration,RAG)在推理时,我们可以使用检索机制,从整个仓库中检索出与当前任务相关的代码片段(比如通过代码相似性、调用关系等),然后将这些相关片段作为上下文输入。这样我们不需要一次性输入整个仓库。引用[2]中提到的仓库上下文可能也是通过某种检索方式选取了与当前文件相关的其他文件(但他们的描述并没有明确说明,因为他们的模型最大长度为8k)。方法四:使用模型微调(Fine-tuning)或预训练(Pre-training)如果我们希望模型“记住”整个代码仓库,可以在仓库代码上对模型进行微调(比如使用LoRA技术)。引用[4]中提到了一种改进的LoRA(LoRA+)用于长上下文场景的适应。但是微调通常用于训练阶段,而推理时则不需要输入整个仓库。注意:微调可以让模型学习整个仓库的知识,但并不能在推理时提供整个仓库上下文(因为推理时上下文长度限制依然存在)。因此,在实际应用中,我们通常结合使用长上下文模型和检索增强技术:1.在推理阶段,我们使用一个检索器(retriever)从整个仓库中找出与当前问题最相关的代码片段(例如,当前编辑的文件,以及通过静态分析得到的依赖文件,或者通过代码相似性检索得到的相关函数等)。2.然后将这些相关片段作为上下文,输入到支持长上下文大模型中,进行代码生成或补全。引用[2]中的实验采用了最大长度8k的模型,因此他们不太可能将整个仓库的所有代码都放入上下文。他们可能使用了检索方法选取了部分相关文件,或者他们仅以当前文件为中心,加上少量相关文件(总长度不超过8k)。总结:直接输入整个代码仓库在目前的技术水平下是不现实的(除非仓库非常小)。更可行的方法是使用检索增强技术,选择与当前任务最相关的代码片段作为上下文。以下是一个简单的示意图:整个代码仓库-->构建索引(如使用BM25、Embedding相似性等)-->当用户需要补全某个位置的代码时,根据当前代码片段查询索引,获取最相关的代码片段(可以是多个文件中的)-->将查询到的代码片段(加上当前文件的内容)组合,截断或压缩(如果超过模型长度)后输入模型。这里需要注意的是,模型需要支持Fill-in-the-Middle(FIM)模式,这样才能在中间位置补全代码。引用[2]中提到的模型(StarCoder,CodeLlama,DeepSeek-Coder)都支持FIM,因此我们可以采用上述流程。最后,如果希望更好地理解整个仓库,预训练或微调是另一种思路,但这需要在训练阶段进行,且对于用户当前的代码仓库进行微调需要额外的计算资源。因此,对于用户的问题:如何将整个代码仓库作为上下文提供给大模型进行训练或推理?训练(预训练/微调):可以将整个仓库代码作为训练数据,对模型进行训练,这样模型能够学习到仓库中的知识。推理:由于上下文长度限制,我们通过检索相关代码片段,只输入一部分(当前最相关的)上下文。需要注意的是,在训练阶段,即使使用整个仓库,也可能需要分块(因为仓库可能很大,而训练时的序列长度也是有限的),但训练阶段可以使用多个训练样本覆盖整个仓库。但是用户的问题更侧重于推理阶段,即如何将整个仓库作为上下文输入给模型?答案是通过检索相关片段来模拟“整个仓库”的信息,而不是真的部输入。引用:[^1]提供了论文协作的框架,但本问题不直接相关。[^2]提供了基于仓库上下文代码补全方法,他们使用FIM和最大8k的模型,但并未说明如何将整个仓库放入,因此推断他们使用了检索。[^3]说明长上下文模型是趋势,但目前最长的上下文也很难覆盖大型仓库。[^4]提到通过微调技术(如改进的LoRA)来增强模型对长上下文的适应能力,这有助于在推理时处理更长的上下文,但前提是模型本身支持长上下文。因此,在实际操作中,我们最可能采用的方法就是检索增强(RAG)加上长上下文支持模型。</think> 要将整个代码仓库作为上下文输入大模型进行训练或推理,需解决**长上下文处理**和**跨文件关联**两大核心问题。以下是具体方法及技术要点: --- ### 🔍 核心方法 1. **长上下文模型适配** - 选用支持超长上下文窗口的模型(如 **CodeLlama-100k**、**DeepSeek-Coder**),其上下文容量可达10万tokens以上[^3]。 - 对模型进行微调: - **改进LoRA技术**:如引用[4]所述,更新嵌入层和归一化层参数(`LoRA+`),显著提升模型对长上下文的适应能力(参数仅占0.004%,但性能提升明显)[^4]。 - **位置编码优化**:采用旋转位置编码(RoPE)或插值扩展,避免上下文截断。 2. **分块策略与信息融合** - **文件级分块**:将仓库文件按功能划分(如模块、类、工具函数),为每个文件生成语义嵌入(Embedding)向量。 - **依赖感知组装**: - 静态分析代码调用链,构建依赖图。 - 输入上下文时优先组合强关联文件(如:`.py`主文件 + 其引用的`.util.py` + 配置文件)。 - **检索增强(RAG)**: 实时检索相关代码块(如相似函数、同模块文件),动态扩展上下文[^2]。 3. **Fill-In-The-Middle(FIM)推理优化** - 如引用[2]所示,用FIM模式处理跨文件上下文: ```python [前缀:当前编辑文件] + [后缀:依赖文件] → 模型生成中间代码 ``` - 工具栈示例: - **索引层**:FAISS/ChromaDB存储代码向量 - **检索层**:基于AST解析代码相似性匹配 - **推理层**:StarCoder/CodeLlama等支持FIM的模型[^2] --- ### ⚙️ 技术实践流程 1. **预处理仓库** ```mermaid graph LR A[代码仓库] --> B[AST解析依赖图] B --> C[文件分块+向量化] C --> D[向量数据库] ``` 2. **训练阶段** - **输入构造**:组合强关联文件块作为训练样本,避免随机截断 - **微调策略**:`LoRA+`更新嵌入层 + 位置编码扩展 + FIM任务训练[^4] 3. **推理阶段** - 用户编写代码时触发检索,动态加载相关文件 - 上下文合并公式: `最终上下文 = 当前文件(2000 tokens)+ 前K个相关文件(≤模型最大长度)` --- ### 🌟 优化方向 1. **压缩技术** - **抽象语法树(AST)压缩**:将代码转化为精简语法结构后再输入模型 - **Token剪枝**:移除注释/空白符等低信息量内容 2. **层级注意力机制** - 对核心文件(如`main.py`)分配更高注意力权重 3. **分布式上下文** - 多模型协作:拆分仓库到多个专用模型处理,汇总结果 > 📌 **实践建议**: > 优先采用 **检索增强(RAG) + FIM支持模型**(如CodeLlama),配合轻量级微调(LoRA+)。对大型仓库(>100k tokens),需依赖高效检索系统保证相关覆盖率[^2][^4]。 ---
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值