从零实现 GeekAgent —— Day4 文件工具与注册表

💡 原文中文,约17300字,阅读约需42分钟。
📝

内容提要

本文介绍GeekAgent开发第4天:将文件读写从shell中拆出,新增ls、read、glob三个免确认只读工具,以及write、patch两个展示diff后确认的写工具,并统一注册到工具注册表。通过唯一文本片段锚定修改,用前缀/后缀修剪生成diff预览,实现“读→改→验证”闭环,代码净增211行。

🔎

延伸解读

为什么读和写要分开

文章指出,把读和写都放在同一个 shell 工具里,会导致无害的读操作频繁被确认,而危险的写操作却难以预览。将读操作拆成免确认的只读工具,写操作拆成展示 diff 的专用工具,既提高了效率,又让确认更有针对性。这种设计思路对构建安全的工具调用系统有参考价值。

patch 锚点的选择

patch 工具使用唯一文本片段作为锚点,而不是行号或正则。这是因为模型刚读过文件,直接引用原文更可靠,且能避免行号偏移和正则转义的麻烦。实现时通过检查片段在文件中出现的次数来保证唯一性,找不到或匹配多处都会返回明确错误,引导模型调整锚点。

简单 diff 的取舍

文章没有实现复杂的 diff 算法,而是用前缀/后缀修剪来生成预览。这种方法只覆盖最常见的单处修改场景,对于多处分散修改会降低可读性,但信息不失真。同时设置了 100 行上限防止刷屏。这种“够用就好”的务实态度,避免了过度设计。

工具注册表的价值

随着工具数量增加,平铺数组容易导致重名覆盖和入口混乱。引入注册表后,新增工具必须显式注册,重名直接报错,且所有访问都通过统一出口,保证了清单与分发的一致性。这为后续扩展工具集打下了良好基础。

Q&A

GeekAgent Day4 新增了哪些文件工具?

Day4 新增了五个文件工具:三个只读工具 ls、read、glob,以及两个写工具 write、patch。

为什么 GeekAgent 要把读写从 shell 中拆出来?

因为 shell 工具 run_shell 需要确认,读文件这种无害操作也被频繁确认,而写操作通过 shell 无法预览 diff,确认粒度粗且改错代价静默。拆出后,读工具免确认,写工具展示 diff 再确认,更安全高效。

GeekAgent 的 patch 工具如何定位要修改的位置?

patch 工具使用唯一文本片段作为锚点,要求每个 old 片段在文件中恰好出现一次。找不到或匹配到多处都会报错,提示模型调整锚点。

GeekAgent 的 diff 预览是如何实现的?

diff 预览采用前缀/后缀修剪的简单算法:将新旧文本按行拆分,砍掉完全相同的公共前缀和后缀,中间部分即为改动,前后各留 3 行上下文,并限制最多展示 100 行。

GeekAgent 的工具注册表有什么作用?

工具注册表将工具统一收口,新增工具必须通过 registerTool 注册,重名会抛错,避免静默覆盖。toOpenAITools 和 execTool 两个出口都从注册表读取,保证清单与分发一致。

GeekAgent 的 write 和 patch 工具在写入前如何确认?

两者都通过 commitWrite 函数,先读取旧内容,用 simpleDiff 生成 diff 预览,然后调用 confirm 请求用户确认,输入 y 后才真正写盘。

GeekAgent Day4 明确没有实现哪些功能?

Day4 没有实现权限与目录隔离、撤销/回滚、标准 diff 能力(仅前缀后缀修剪)、以及二进制文件支持(只处理 UTF-8 文本)。

🏷️

标签

➡️

继续阅读