让 GPT-4 修改文件,真的太难了!( 二 )

  • 在训练数据(从网上获取的数据)中很常见,因此大型语言模型非常了解它们 。
  • 可以处理引号和换行符 , 这些符号在代码中很常见 。XML 不像 JSON 那样需要对符号进行转义 。此外,XML 的结束标记通常很少出现 。
  • 大型语言模型很难破坏 XML 格式 。
  • 例如,向上面的 Flask API 端点添加更多示例数据,GPT-4 会给出:
    而插入新的代码,比如删除端点,GPT-4 会给出:
    GPT-4 无法复制行号
    当然,我们在提示中添加了代码的行号,以帮助模型正确计数 。然而,即便如此,GPT-4 也会复制不正确的行号 。这可能导致代码缺失一行或多出一行,如下所示,缺少 return 语句:
    让 GPT-4 修改文件,真的太难了!

    文章插图
    或者产生重复的代码行,如下所示:
    我们尝试了一些办法,但都无法很好地解决这个问题:
    1、删除重复行:如果出现重复较小的行,我们将尝试去除重复行 。不幸的是,这并不完全可的 , 有时会错误删除有意重复的代码 。而且它无法处理缺失行的情况 。
    2、通过另一个模型运行以修复代码:我们将代码输入到 GPT-3.5-16k 中 , 以验证更改并修复应该修复的内容 。不幸的是,这会导致复制中的随机错误 , 并偶尔出现随机的“#Rest of code” 。所以这条路也行不通 。
    我们还尝试了其他方法 , 但感觉不太自然,即从文件中复制旧的代码行,然后自然地编写剩下的部分,如下所示:
    让 GPT-4 修改文件,真的太难了!

    文章插图
    但同样会受到错误行号的影响 。
    版本 3:aider diff
    这个时候,我们碰巧看到了 aider 创建者的博客文章,aider 是类似于 Sweep 的工具 , 但是它在本地运行 。Aider 要求 GPT-4 生成以下格式的搜索和替换对:
    然后只需在代码中搜索原始代码块,并用新代码块替换 。例如 , 为了生成更多的测试数据,它可能生成如下内容:
    让 GPT-4 修改文件,真的太难了!

    文章插图
    这种新方法在我们以前的尝试中效果明显更好,我认为主要原因是:
    1、对于 LLM 来说,复制代码比选择正确的行号要容易得多 。
    2、一旦代码被复制到ORIGINAL代码块中,Sweep 就可以非常容易地修改代码,因为 ORIGINAL 原始代码更接近 GPT-4 编写的代码的地方,并且可以用作参考 。很有可能,位置嵌入减少了 LLM 在修改代码块过程中的噪声 。
    这种格式与 git 合并冲突的格式相似,这可能是 GPT-4 的训练数据的一部分 。
    然而 , 我们仍然有一些问题:
    • 可能无法正确地复制 ORIGINAL 代码 。
    ○最初,我们考虑构建一个模糊匹配算法 。然后,我们构建了 V4 来进一步解决这个问题 。
    • ORIGINAL 代码块可能会多次出现在代码中 。
    ○默认情况下,我们会匹配第一个项 。
    ○我们还提示 Sweep 在 ORIGINAL 代码块前后多复制几行以消除歧义 。
    ○此外,通常不建议在多个地方重复使用中等大小的代码块,而是应该使用辅助函数 。
    • 在重新编写较长的部分时,它仍然偶尔会写入“#Rest of code” 。
    ○我们提示 GPT-4 进行多个小的更改,而不是较大的更改 。
    • 代码仍然太长 。
    ○对于超过 600 行的文件,我们会要求 GPT-4 一次处理 400 行代码 。由此产生了一些与上下文相关的问题,但这解决了目前的问题 。有关此问题的更多信息,请参见下文 。
    版本 4:搜索并替换
    我们目前的算法是在 Aider diff 的基础上进行了一些扩展 。主要问题是,对于中等大小的文件,Sweep 经常会复制错误的行 。
    Aider diff 存在的问题
    例如,如果要求 Sweep 向端点添加日志:
    让 GPT-4 修改文件,真的太难了!

    文章插图
    此处,ORIGINAL 代码块中的 create_task 被无意间更改为 start_task 。本质上是 GPT-4 错误地复制了行,然后在错误复制的行上应用了转换 。
    更准确地说,GPT-4 本来想把子字符串 S 替换成 R(S),其中 R: str → str 是需要进行的变换 。但是,它生成了 S',然后替换成了 R(S') 。这就导致 S 被替换成了 R(S'),这经常会导致代码无法编译,或者导致不可预见的错误 。
    aider diff 的改进
    一个解决方案是更早地开始流式传输,即使用 200 行的块而不是 400 行的块,但这会导致更多的问题,如算法缺少上下文、性能较差和成本较高 。


    推荐阅读