TL;DR: 在 Augment,我们正在通过最新且最复杂的功能——Next Edit——推动开发者 AI 的边界。在这篇博客中,我们将深入探讨我们面临的 AI 挑战——理解用户意图、确定更改位置以及执行这些更改——以及我们如何克服这些挑战来构建 Next Edit。
Next Edit 将代码补全功能扩展到光标之外,覆盖整个工作区。它理解你试图完成的任务,并在后台工作,建议编辑以帮助你更快、更全面地完成任务。
为什么构建 Next Edit 如此困难?
对我们来说,将补全功能扩展到光标之外是理所当然的。但要以一种真正让开发者保持流畅的方式进行,却比预期的要复杂得多。我们必须解决三个不同的研究挑战:
- 弄清楚用户试图完成的任务
- 确定在哪里进行这些更改
- 弄清楚如何进行编辑
这些问题之所以复杂,是因为编码工作流程的动态性和非线性、现代代码库的规模以及对速度和准确性的需求。让我们深入探讨这些挑战,并探索我们如何解决它们。
1. 弄清楚用户试图完成的任务
理解用户的意图是 AI 中最难的问题之一,尤其是在用户活动很少简单的编码环境中。
挑战
- 非线性编辑历史: 开发者的编码工作流程通常是非线性和复杂的。他们可能会复制一段代码,粘贴到其他地方,并立即对其进行重大修改。他们还可能快速连续进行多次编辑,频繁切换文件或函数,或者在尝试不同实现时撤销和重做更改。这些非线性工作流程创建了一个混乱的更改轨迹,可能会误导试图推断开发者真实意图的模型。
- 无意中的偏见: 通过分割给定任务中的差异块来天真地采样训练数据,可能会将无意中的偏见引入模型。例如,模型可能会学会避免触及已经包含最近更改的代码库部分。这是有问题的,因为这些区域可能正是需要进一步编辑的地方。
- 意图幻觉: 模型可能会产生意图幻觉,建议与用户最近编辑无关的更改。当模型试图过于主动,旨在覆盖所有可能的相关编辑(高召回率)时,可能会产生嘈杂和破坏性的建议。相反,如果模型过于保守——只关注它高度自信的建议(高精度)——它可能会变得被动,错过帮助开发者的机会。在“有帮助但嘈杂”和“准确但被动”之间存在着微妙的平衡。
我们的解决方案
我们精心设计了一个数据管道,从 GitHub 提交和拉取请求(PR)中合成常见的用户交互。这包括:
- 模拟常见编辑场景: 通过分析提交消息、初始提交状态和最终提交状态,我们开发了一种复杂的算法来模拟反映常见开发者行为的现实编辑场景。这使我们能够创建与实际编码工作流程复杂性密切相关的训练数据。
- 优化差异粒度: 我们教会模型读取细粒度的编辑事件,同时仔细优化提示中呈现的差异粒度。如果模型看到的差异过于细粒度,它可能会被用户编辑历史中的噪音分散注意力。如果它看到的差异过于粗糙,它很难区分新更改和旧更改。通过平衡粒度,我们使模型能够有效地解释更改的上下文,而不会被嘈杂的编辑历史误导。
- 避免撤销用户的最近更改: 我们发现,模型有时有强烈的倾向撤销用户的最近更改,这可能会导致令人沮丧的体验。为了解决这个问题,我们特别努力改进训练样本,以阻止这种行为。通过精心策划训练数据,我们确保模型尊重用户的最新编辑,并专注于提供有用的建议,而不会覆盖最近的工作。
结果
通过模拟现实的用户交互并精心设计我们的训练数据,我们提高了模型准确推断用户意图的能力,而不会被混乱的编辑历史误导。这使得 Next Edit 能够提供与用户试图完成的任务相关的有用建议。
2. 确定在哪里进行这些更改
在整个代码库中识别应用更改的位置是一项艰巨的任务,尤其是在包含数万个文件的大型单体仓库中。
挑战
- 可扩展性: 定位机制需要可扩展,以高效处理大型代码库,而不会消耗过多资源。
- 速度: 它需要非常快,以支持高度交互的使用模式,在用户进行新更改时立即提供建议。
- 相关性: 它必须准确识别相关位置,而不会用不必要的建议淹没用户或错过重要的建议。
我们的解决方案
与之前严重依赖大型语言模型进行导航决策的方法(如 OpenDevin)不同,我们采取了不同的路径:
- 使用训练过的检索器进行快速定位: 通过将我们的检索基础设施与专门设计用于识别可能需要更新的代码位置的检索器模型相结合,我们实现了速度和准确性。该模型使用当前上下文高效定位相关文件和代码部分。
- 效率和可扩展性: 这种方法具有高度可扩展性,可以在包含数万个文件的大型单体仓库上运行,而不会显著降低性能。
- 编辑周围代码: 用户光标周围的代码始终被添加到候选位置列表中并首先处理,确保提供即时且上下文相关的建议。
结果
通过使用基于检索的方法,我们实现了一个既可扩展又快速的定位机制。这使得 Next Edit 能够高效地识别在大型代码库中应进行更改的位置,提供及时且相关的建议,而不会减慢开发过程。
3. 弄清楚如何进行编辑
一旦我们弄清楚用户试图做什么以及需要在哪里进行更改,最后的挑战就是确定如何准确高效地进行这些编辑。
挑战
- 超出光标插入的复杂编辑: 现有模型不擅长进行涉及大规模更改的编辑,而不仅仅是用户光标旁边的简单插入。
- 延迟限制: 生成这些编辑应该很快,允许实时建议而不会产生显著的延迟。天真地生成大量标记会使该功能在实际使用中变得太慢。
- 代码库意识: 建议需要符合项目的编码标准、约定,并正确使用自定义 API,这要求模型了解整个代码库的上下文。
我们的解决方案
我们开发了创新技术来克服这些挑战:
- 新颖的差异解码方案: 我们教会模型一种专门的差异格式,这种格式既紧凑又明确适用于原始代码。这种格式允许模型简洁地表示复杂的编辑,最大限度地减少生成的标记数量,并实现大文件的高效处理。这将延迟从几秒减少到几百毫秒。
- 代码库感知建议: 我们利用我们强大的检索增强生成(RAG)基础设施(之前用于我们的补全和聊天功能),为 Next Edit 添加代码库特定的上下文。通过检索代码库的相关部分,模型可以提出符合项目特定编码标准并正确与自定义 API 交互的建议。这确保了编辑不仅与用户试图完成的任务一致,而且与现有 API 和编码模式一致,从而产生准确且在代码库内连贯的建议。
结果
我们的方法使模型能够快速生成准确且上下文适当的编辑。通过将高效的解码方案与代码库感知的上下文检索相结合,Next Edit 提供了高质量的建议,而不会牺牲速度。
结论
构建 Next Edit 意味着要解决三个核心 AI 挑战:在混乱的编辑历史中捕捉开发者意图、在庞大的代码库中精确定位相关更改,以及以最小的延迟生成准确的编辑。我们的解决方案——专门的定位模型、深度代码库检索和新颖的差异解码方案——实现了无缝、上下文感知的更新,远远超出了手动光标放置的范围。查看我们与 Cursor 的 Tab 功能的并排比较,了解 Next Edit 的表现。
我们现在正在努力扩展 Next Edit 以处理更大规模的更改,从增强模型理解更广泛上下文和依赖关系的能力,到支持跨多个文件的同时批量编辑。我们还在探索与我们的聊天功能进行更深入的集成,这可以为编辑建议提供额外的上下文,并实现更具交互性的问题解决工作流程。
我们继续从开发者在日常工作中使用 Next Edit 的现实使用模式和边缘案例中学习。如果你有兴趣尝试 Next Edit 或讨论我们方法的技术细节,我们很乐意听取你的意见。