LLM代理EDIT工具的替代方案:标记校验与CRC32权衡
LLM代理的EDIT工具替代方案
antirez 2小时前 1834次浏览。 EDIT:当然这过去已经被做过了!我有点怀疑,但人们刚刚在Twitter上向我证实了这一点 :) 不过,请继续阅读:最后提到的CRC32折衷方案是一个有趣的权衡,而且总体而言这是一个值得讨论的好话题。
现在我正在为我的DS4项目开发一个代理。本地推理的token很贫瘠,这是一个优化至关重要的战场。我惊讶地发现,目前每个人都使用的EDIT工具强制LLM逐字输出旧版本的文本。这种CAS(检查和设置)操作模式,其中我说EDIT old="foo" new="bar",是必要的,因为经常存在冲突的编辑(用户也在编辑,或者检出了不同的分支等等),也因为LLM可能幻觉某一行具有特定的内容。
这意味着,基本上仅仅使用行号非常脆弱:比如说,将第22行改为new="foobar"并不好。然而,我不希望我的本地LLM每次重新编写旧文本来浪费token,尤其是因为有时旧文本包含大量特殊字符和空格,模型可能会搞错;在这种情况下工具会失败,迫使LLM再次进行相同的编辑。所以我(重新)设计了一个基于标签的EDIT工具,它仍然是CAS风格,但token效率更高。
READ和SEARCH工具返回类似这样的内容:
10:Q8fA int count = 10; 11:rA3_ if (count > limit) { 12:Kq9z count = limit; 13:PX0b }
所以有行号和标签。标签是4个字符,平均2.5个LLM token,代表该行的校验和。现在LLM可以像这样编辑:
{ "tool": "edit", "path": "/tmp/example.c", "line": 10, "tag": "Q8fA", "new": "int count = 11;" }
或者多行,像这样:
{ "tool": "edit", "path": "/tmp/example.c", "lines": "11:rA3_\n12:Kq9z\n13:PX0b", "new": "if (count > limit)\n return limit;" }
节省量是显著的,尤其是当代理删除大量文本时,但在一般情况下也是如此。然而,由于我们有了行号和标签,会有一些开销。存在潜在的权衡,也许标签应该是8个字符,并将行号包含在哈希中,需要准确检查冲突的可能性和分词情况以确定这有多大收益,但我喜欢行:标签格式,因为稍后LLM通常能够以多种方式利用行信息,例如在后续工具调用中获取范围。也许还有其他方式可以利用标签,比如:这一行还是dj4_吗?
有趣的是,DeepSeek v4 Flash 能够非常有效地使用这个工具,所以显然它对此很自然。虽然我没有测量确切的节省量,但我现场观察到编辑速度更快,甚至更可靠。
另一种替代方案是每次只返回整个文件的CRC32(基本上标签变成了文件标签,即使对于部分读取也是如此)。这样我们只能使用行号+CRC工作,编辑只需指定11,12,13,14。当然token更少。但这样每次需要重新计算文件的CRC32,不过对于合理大小的文件来说成本足够低。然而这种方法有局限性:即使发生了不相关的更改,我们也会编辑失败,因此存在一个强烈的权衡。公平地说,对于整个文件方法,它允许指定范围如10:23,这是一个巨大的优势。
我感觉只有通过足够的实践证据才能决定哪种更好,通过使用ds4-agent在多个会话中运行两种系统。目前也许第一步应该是添加一个命令行来切换编辑模式。
博客评论由Disqus提供动力