CodePlan

CodePlan论文解读

最近在看老师给的LLM-Agent论文,在这记录一下

CodePlan: Repository-level Coding using LLMs and Planning【论文】

  • 旨在解决储存库级别的coding task,提出一个框架called CodePlan
  • 综合多步骤的编辑链,其中每个步骤都导致对代码位置的LLM调用,该代码位置具有来自整个存储库的上下文
  • Codeplan基于增量依赖性分析(用于识别和分析软件系统中的增量变化对其他部分的影响和依赖关系)
Intro
  • 给定一个自然语言意图或者周围代码的上下文来进行补全or编辑通常针对小范围内的代码

  • 但是软件工程的“Outer loop”涉及到整个代码库,可能存在外部api的调用和依赖(牵一发而动全身)be like:

    CodePlan_第1张图片

  • 因此,为了达到这样的效果, 我们需要一个系统来自动生成编辑的派生规范

  • codeplan综合了一个多步骤计划来解决储存库级别的编码任务

    CodePlan_第2张图片

  • 如图,codeplan的输入是一个储存库a task with seed specifications(确定任务的起点和任务需求) expressed through a natural language instruction or a set of initial code edits, a correctness oracle and an LLM.

  • CodePlan构建了一个平面图,每个节点表示LLM需要执行的代码编辑任务,CodePlan监视代码编辑,并且自适应的扩展计划图,merge模块把LLM生成的代码合并到储存库当中

  • Oracle对储存库分析,没错的话标记为完成任务,否则生成错误报告,用于执行下一轮计划生成和执行的种子规范

    在软件工程中,"Oracle" 是一个术语,指的是用于验证软件系统行为是否正确的标准或机制。它作为一个参考点或期望结果,用于判断软件的输出是否符合预期。
    
  • codeplan优于Oracle引导的修复技术

Design
  • 算法维护的核心数据结构是一个规划图G,这是一个多个根节点的有向无环图

  • 算法也维护一个依赖图,结构如下
    CodePlan_第3张图片

  • 规划图里每个节点是一个元组

  • AdaptivePlanAndExecute函数:主要的work-horse:迭代的掉选每个待决策节点并进行处理,workflow如下:

    • line-19:提取要编辑的代码片段
    • l-21: 收集编辑的上下文
      • 空间上下文:区块B中调用的方法等相关代码
      • 时间上下文:之前相关编辑
    • 根据提取的片段构造prompt,调用LLM获取编辑后的代码片段
    • merge到储存库
    • 自适应规划,将当前编辑的影响传播到依赖的代码块上
  • 静态分析组件:

    • DependencyGraph:依存分析,分析代码元素之间的各种依赖关系
    • ClassifyChanges:pattern-matching更改前后代码,标注出哪里改了,改了什么
    • UpdateDependencyGraph:根据ClassifyChanges更新计算图
    • GetAffecttedBlocks:识别收到更改后模块影响的模块
  • 适应性规划和计划执行

    • PlanGraph

    • ExtractCodeFragment

    • GetSpatialContext

    • GetTemporalContext

      -----以上都是基于之前的静态分析(不用LLM),然后基于此去make prompt-----

    • MakePrompt

    1. 自适应规划(Adaptive Planning):在确定受影响的代码块后,CodePlan 通过创建变更义务(change obligations)来保持依赖代码与变更的一致性。这是一个迭代的过程。
    
    2. 计划图(PlanGraph):计划图 P = (,) 是一个有向无环图,其中是一组义务(obligations),每个义务是一个三元组 ⟨, , ⟩,其中 B 是一个代码块,I 是一条指令,status 表示待处理或已完成。中的边记录了源义务和目标义务之间的原因和依赖关系。换句话说,边标签标识了在表1中的变更可能影响规则(change may-impact rule)中的哪个 Rel 子句导致创建目标义务。
    
    3. 提取代码片段(ExtractCodeFragment):提取代码块 B 的代码时,简单地提取代码是次优的,因为它会丢失上下文信息。ExtractCodeFragment 函数接受代码块所属的整个类,保留 B 的完整代码,并只保留类的声明和其他类成员的声明。这样做是有用的,因为类和其他成员的名称和类型为 LLM 提供了额外的上下文信息。LLM 经常需要进行多个同时变更。例如,在一些案例研究中,LLM 需要添加字段声明,将参数传递给构造函数,并在构造函数中使用它来初始化字段。将周围代码的草图作为代码片段提供给 LLM 可以让 LLM 在正确的位置进行这些变更。代码片段提取逻辑通过遍历 AST 并“折叠”掉草图的子树(例如方法体)来实现。正如在第1节中所述,即使存在多个同时变更,这种草图表示也允许我们将 LLM 生成的代码放回 AST 中而不产生歧义。
    
    4. 获取空间上下文(GetSpatialContext):CodePlan 中的空间上下文指的是代码块在代码库中的排列和关系,有助于理解类、函数、变量和模块的结构和交互。它对于进行准确的代码更改至关重要。CodePlan 利用依赖图提取空间上下文,将代码表示为节点,将它们之间的关系表示为边。这个图使得 CodePlan 能够遍历代码库,识别相关的代码块,并保持对它们的空间上下文的意识。因此,在生成代码编辑时,依赖图使得 CodePlan 能够进行与代码的空间组织一致的、具有上下文意识的代码修改,提高了代码编辑能力的准确性和可靠性。
    
    5. 获取时间上下文(GetTemporalContext):计划图记录了所有变更义务及其相互依赖关系。提取时间上下文是通过线性化从计划图的根节点到目标节点的所有路径来实现的。每个变更是一对变更前和变更后的代码片段。时间上下文还说明了连接目标节点与其前置节点的“原因”(记录为边标签)。例如,如果节点 A 与 B 通过一个 CalledBy 边相连,则 B 的时间上下文是 A 的变更前/后代码片段和一条说明“B 调用 A”的语句,这有助于 LLM 理解最新的时间变更(对 A 的变更)与当前义务(对 B 的变更)之间的因果关系。
    
    6. 计划执行(Plan Execution):CodePlan 迭代地选择计划图中的一个待处理节点,并调用一个 LLM 来完成变更义务。
    
    7. 构建提示(MakePrompt):在提取要编辑的代码片段以及相关的空间和时间上下文后,我们构建一个提示(prompt)传递给 LLM,其结构如下所示。首先是任务特定的说明(Task Instructions),然后是到目前为止在代码库中进行的与要编辑的片段相关的编辑(Earlier Code Changes),接下来是说明每个出现在 Earlier Code Changes 中片段与要编辑的片段的关系(Causes for Change),然后是相关代码块(Related Code)和要编辑的代码片段(Code to be Changed Next)。通过编辑“Code to be Changed Next”并生成“Changed Code”,根据“Task Instructions”对“Code to be Changed Next”进行编辑,使其与“Earlier Code Changes”、“Causes for Change”和“Related Code”一致。如果不需要进行任何更改,则输出“No changes.”。
    
    8. Oracle 和计划迭代(Oracle and Plan Iterations):当计划图中的所有节点都被标记为完成且不再添加新节点时,一个存储库级别的代码编辑迭代就完成了。如图2所示,在存储库上调用 Oracle。如果 Oracle 标记出任何错误(例如构建错误),则将错误位置和诊断信息作为下一次迭代的种子变更添加,并且自适应规划再次开始。如果 Oracle 没有标记出任何错误,CodePlan 终止执行。
    
Future work
  • 扩展适用性到更多编程语言
  • 处理动态依赖的挑战

你可能感兴趣的:(AI,深度学习,人工智能,神经网络,自然语言处理)