---
title: Agent 需要什么样的基础工具集合
date: 2026-05-27
summary: shell 能解决 Agent 工具集的 80%，但剩下 20%——编辑的精确性、patch 格式与模型能力的匹配、长任务的调度抽象——恰恰决定了 Agent 能不能从 demo 走向真正可用的系统。
type: post
tags:
  - agent
  - tool-design
  - holon
  - codex
  - claude-code
topics:
  - Agent 工程
syndication:
  - platform: X / Twitter
    url: ""
  - platform: Weibo
    url: ""
---

看到大家在聊 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 又根据自己的场景做了不同的取舍，这中间可以探索和改进的点，还很多。
