Post
Agent 需要什么样的基础工具集合
shell 能解决 Agent 工具集的 80%,但剩下 20%——编辑的精确性、patch 格式与模型能力的匹配、长任务的调度抽象——恰恰决定了 Agent 能不能从 demo 走向真正可用的系统。
看到大家在聊 Agent 工具集的问题——是不是提供一个 shell 就都搞定了?做了 holon 之后发现,其实没有那么简单。
读:为什么放弃了 Read/Glob,全走 shell
holon 的工具集改了几个版本,最后废弃了类似 Claude Code 提供的 Read(读文件)、Glob(模式搜索)这类专用工具,读取和查找全部通过 shell 来完成。这和 Codex 的路线一致——Codex 的 ExecCommand 一把梭,读文件就是 cat,搜代码就是 rg,不再单独给每种"读"操作定义一个工具。
这样做的理由很朴素:shell 是 LLM 最熟悉的"编程语言"。与其让模型去学你定义的 Read 工具的参数语义,不如直接让它写已经训练了几十亿次的 shell 命令。每多一个专用工具,模型的认知负担就加一层;而 shell 这个界面,模型已经足够熟练了。
但全走 shell 有一个代价:输出截断。框架为了避免 shell 返回值太长撑爆上下文,会给每个命令设输出上限。Agent 用 cat 读一个大文件,可能只拿到前半截,剩下的在 artifact 文件里,还得再 cat 一次甚至多次才能读完。Claude Code 的 Read 工具压缩阈值比通用 shell 高很多,读大文件一步到位,少了好几个来回。本质上是取舍:少定义工具降低认知负担,但专用工具在边界场景效率更高。
写:从 sed 到 ApplyPatch,以及 free grammar tool 的难题
但写操作就无法完全用 shell 搞定。
如果让 Agent 全用 sed 做编辑,就会发现遇到复杂的多行匹配很难处理——换行、转义、缩进,任何一层出了问题都会导致编辑失败。所以很多系统会提供 Replace String 这样的编辑工具,让 Agent 传一大段 old_string 来精确匹配并替换成 new_string。虽然笨拙,但比 sed 稳得多。
Codex 则走得更远,发明了自己的 ApplyPatch 工具,让 Agent 直接生成 patch,一次搞定批量编辑。holon 就借鉴了这个思路。
但落地的时候踩到一个坑:Codex 用的是一套 OpenAI 自己定义的简化 patch 格式,并且搭配了一种叫做 free grammar tool 的特殊工具机制来解决格式传递问题。
为什么要专门搞一种新机制?因为 LLM 的标准工具定义都是 tool(args) 这种 JSON 参数格式。如果把 patch 作为 JSON 字符串参数传递,会牵扯到大量的转义——换行要变 \n,引号要加反斜杠,缩进也得小心处理。Agent 写 patch 时本身就容易出错,再叠一层 JSON 转义,出错概率翻倍。free grammar tool 的思路是把 patch 的原始文本直接作为 tool 的输入体,不经过 JSON 参数编码,模型写什么就是什么。这大幅降低了模型生成 patch 时的出错率。
而这套机制目前只有 OpenAI 的 Codex 接口支持。holon 是要兼容多模型提供方的,没法只靠这一条路。
于是 holon 的做法是:根据模型注入不同的 ApplyPatch 定义。对支持 free grammar 的模型,直接走原始 patch 格式;对其他模型,就接收标准的 git diff 格式。我觉得 LLM 经过 GitHub 上几十亿次 diff 的训练,对 git diff 格式应该相当熟练。实践下来效果还可以——虽然也常出错,但多数时候能改对,而且随着训练数据积累,这个能力只会越来越好。不过我还是建议各家模型厂商都支持一下 free grammar tool,这对 Agent 写代码的场景确实是刚需。
调度:长时间命令和 task 抽象
第三个问题是 Agent 执行的 shell 命令不一定会很快结束——启动 dev server、跑测试、构建项目,都可能跑很久,甚至根本不退出。早期的 Agent 框架处理得很粗暴:要么同步阻塞把自己卡死,要么所有命令一律丢后台,结果 Agent 把同一个命令反复执行很多遍。
现在业界逐渐收敛到一个基本共识:不给 Agent 暴露"前台/后台"的选择——这件事 Agent 自己判断不准。更好的方式是设置一个时间阈值,命令超时自动转后台,对 Agent 完全透明。Agent 不需要预判这个命令该不该放后台,runtime 自己处理就行。
但自动转后台只是第一步。转后台之后,真正的工程问题才浮出来——而这些问题,目前业界还没有标准答案。
首先是输出怎么读。后台任务可能还在跑也可能已经结束,输出可能很大。但各家 API 的语义并不统一——有的走轮询,有的走事件推送——Agent 在不同系统间迁移时,这套心智模型没法复用。
其次是任务怎么停。各家都有取消机制,但取消是即时 kill 还是优雅退出、已产生的部分输出要不要保留,各家行为不同,Agent 没法假设一种统一语义。
最后是谁来叫醒 Agent。Agent 把任务丢后台以后休眠了,任务结束那一刻谁来叫醒它?这要求 runtime 和 Agent 调度深度绑定,不是独立工具层能解决的。
这三件事——读输出、停任务、叫醒 Agent——合在一起,就是后台任务完整的生命周期管理。各家都实现了"能后台跑",但管理面还没有标准化方案,这可能是下一阶段 Agent 工具链演进的关键节点。
还没到无脑用一个现成模式的时候
所以回到开头的问题:shell 能解决 80%,但剩下 20%——编辑的精确性、patch 格式与模型能力的匹配、长任务的调度抽象——恰恰决定了 Agent 能不能从 demo 走向真正可用的系统。
工具集的选择远不止"封装一个 shell"那么简单,也远没到大家可以无脑套用一个现成模式的时候。这也是为什么 Codex 和 Claude Code 在这些基础问题上给出了不同的答案,而 holon 又根据自己的场景做了不同的取舍,这中间可以探索和改进的点,还很多。