Mechanically Strong, Cognitively Weak:我对 Agent Harness 的一次认知修正
目录
- 一、我最初为什么追求“极简工具集”
- 二、Bash 能做一切,不代表一切都应该交给 Bash
- 三、弱 Harness,不是能力弱
- 四、工具应该增强模型的机械能力,而不是代替模型思考
- Workspace 能力
- Web 能力
- 五、我依然会对工具数量保持克制
- 1. 是否高频
- 2. 是否能显著降低失败率
- 3. 是否能够提供结构化、有限的输出
- 4. 是否需要 Harness 提供额外保证
- 5. 是否具有明显副作用
- 6. 是否比 Bash 的总交互成本更低
- 六、Bash 应该是通用逃生舱,而不是所有能力的唯一接口
- 七、为什么我更倾向 Skill,而不是 MCP
- 八、为什么我也不打算做 Subagent 和 Agent Team
- 九、上下文管理,才是丰富工具的必要前提
- 十、我期待中的 Onemore 工具集依然会很小
- 十一、我现在如何理解 Harness 的“强”与“弱”
- 机械强度
- 认知强度
- 结语:不是替模型思考,而是让模型做得到
最近,我一直在开发自己的 Coding Agent 项目 Onemore。
它的仓库在:onemore
它是基于:zerone 继续开发的
Onemore 最初是从一个刻意保持简单的教学基线演化而来的。经过一段时间的开发,它已经逐渐拥有了相对稳定的模型调用、Tool Call、上下文管理、压缩、会话恢复、取消、转向以及工具执行机制。
但在继续学习和实践 Agent 的过程中,我发现,自己过去对“弱 Harness”的理解存在一个很大的偏差。
我原本认为:
弱 Harness,就是极少的 System Prompt,加上一套极简的工具。
现在我认为,这个理解只对了一半。
极少的 System Prompt,或者更准确地说,减少 Harness 对模型认知过程的干预,这个方向仍然是对的。
但“弱 Harness 等于极简工具集”,却是一个错误。
我现在更愿意用一句话描述 Onemore 想要走的方向:
Mechanically strong, cognitively weak.
**机械能力强,认知干预弱。
一、我最初为什么追求“极简工具集”
最开始设计 Agent 时,我非常警惕复杂度。
现在的很多 Agent Framework 都在不断增加东西:
- 更长的 System Prompt;
- 更细致的任务流程;
- 更多的专用工具;
- Planner、Executor、Reviewer 等角色;
- Subagent;
- Agent Team;
- MCP Server;
- Tool Search;
- 复杂的任务编排;
- 各种隐藏的启发式策略。
这些东西确实可以让 Demo 看起来更强,但它们也会迅速把 Agent 变成一个复杂的 Workflow Engine。
模型本来应该是决策中心,Harness 却开始不断替模型决定:
- 什么时候制定计划;
- 计划应该分成几步;
- 什么时候搜索;
- 什么时候反思;
- 什么时候调用评审 Agent;
- 什么时候把任务交给 Subagent;
- 什么时候终止;
- 什么结果才算完成。
最终,很难判断任务究竟是模型完成的,还是 Harness 中大量硬编码规则共同“拼”出来的。
所以我最开始选择了相反的方向:
- 尽量少的 System Prompt;
- 尽量少的内置认知规则;
- 一个稳定的 Agent Loop;
- 一套极简工具;
- 让模型自己决定下一步。
Onemore 当前拥有的核心工具大致是:
read
write
list
bash
load_skill
update_plan
从理论上说,这套工具已经足够强。
有 read、write 和 list,模型可以操作工作区;有 bash,模型原则上可以完成搜索、Git 操作、运行测试、下载安装工具、请求网页以及调用任何 CLI;有 load_skill,模型可以按需获得领域知识;有 update_plan,模型可以维护自己的任务计划。
从“图灵完备”或者“理论可达性”的角度看,这似乎没有问题。
但真实使用一段时间后,我逐渐意识到:
理论上可以操作环境,不等于模型能够低成本、稳定、流畅地操作环境。
二、Bash 能做一切,不代表一切都应该交给 Bash
bash 是 Agent 最强大的工具之一。
通过 Bash,模型可以执行:
rg "ToolRegistry" src
git diff
cargo test
find . -name "*.rs"
curl https://example.com
jq '.results[]'
因此,一个很自然的设计倾向是:
既然 Bash 已经能做,为什么还要增加专用工具?
这个问题本身没有错。
事实上,我现在仍然认为,大量低频操作不应该被包装成专用工具。为每一个命令都提供一个 Tool,只会增加工具描述、参数 Schema、模型选择成本和 Harness 的维护成本。
例如,下面这些能力通常没有必要成为 Onemore 的一等工具:
cargo_test
npm_install
format_code
count_lines
find_todos
create_commit
download_file
unzip_file
parse_json
它们通过 Bash 已经可以非常自然地表达。
但问题在于,并不是所有操作都适合通过 Bash 完成。
例如,模型当然可以用 rg 搜索代码,但它还需要负责:
- 正确构造 Shell 命令;
- 处理路径和引号;
- 选择合适参数;
- 限制输出数量;
- 排除无关目录;
- 解析文件名和行号;
- 区分“没有匹配”与“命令失败”;
- 处理 Windows 与 Unix 环境差异;
- 避免一次返回几万行结果;
- 在结果被截断后想办法继续读取。
这些工作本身并不困难,但它们会持续消耗模型的推理和上下文预算。
更重要的是,它们会产生大量没有实际价值的失败。
因此,专用工具的价值并不是提供 Bash 无法完成的能力,而是:
把高频、易出错、高噪声的环境操作,转换为低歧义、结构化、可预算、可恢复的 Agent Action。
这也是我现在对“工具”的重新理解。
三、弱 Harness,不是能力弱
我过去把两个概念混在了一起:
弱认知干预
和:
弱环境能力
实际上,这两者不仅不是一回事,甚至在某种程度上是相反的。
如果我希望模型自主完成任务,那么模型就必须能够充分地观察和操作环境。
否则,所谓“让模型自主决策”,只是把模型关在一个只有几个按钮的房间里,然后要求它自行解决复杂问题。
现在我认为,一个好的弱 Harness 应该是:
强执行
强观察
强恢复
强权限边界
强上下文管理
弱认知干预
或者说:
Harness 在机械层面应该很强,在认知层面应该尽量克制。
模型负责:
- 理解用户目标;
- 判断当前状态;
- 决定是否需要计划;
- 决定下一步做什么;
- 选择工具;
- 判断证据是否充分;
- 判断任务是否完成;
- 在失败后调整方向。
Harness 负责:
- 让模型看到准确的环境状态;
- 让模型执行明确的操作;
- 保证工具输出可理解;
- 限制危险副作用;
- 管理上下文和输出规模;
- 保存事实与执行轨迹;
- 支持取消、恢复和重试;
- 在冲突出现时明确地告诉模型。
这就是我理解的:
Mechanically strong, cognitively weak.
这里的“weak”不是简陋,也不是不完善。
它指的是 Harness 不应该过度介入模型的思考过程。
四、工具应该增强模型的机械能力,而不是代替模型思考
确定这个方向之后,Onemore 的下一阶段就变得更清晰了。
我不会简单追求更多工具,而是会开始补齐一些真正有意义的环境能力。
目前优先考虑的是两类:
Web 能力
Workspace 能力
Workspace 能力
首先是代码库的观察能力,例如:
search
glob
git status
git diff
这些操作虽然都可以通过 Bash 完成,但它们有一些共同特征:
- 使用频率很高;
- 输出很容易过大;
- 结果天然适合结构化;
- 需要稳定的截断和分页;
- 跨平台行为可能不同;
- 失败原因应该明确;
- Harness 可以提供比原始 stdout 更好的上下文。
例如,一个 search 工具不应该只是 rg 的换皮。
它真正应该提供的是:
{
"matches": [
{
"path": "src/agent.rs",
"line": 103,
"column": 8,
"text": "..."
}
],
"truncated": false
}
模型不再需要从混杂的 stdout 中解析路径、行号和正文,也不需要自己判断输出是否被截断。
同样,git diff 的价值也不只是执行一条 Git 命令。
它是 Agent 修改代码后最重要的自我观察接口之一。
一个 Coding Agent 完成修改之后,应该能够顺畅地形成这样的闭环:
搜索代码
→ 阅读相关文件
→ 修改代码
→ 运行构建或测试
→ 查看错误
→ 检查 Git Diff
→ 修复问题
→ 再次验证
这个闭环中,模型应该负责判断和决策,Harness 则应该保证每一步的观察结果清晰、稳定且具有足够的信息密度。
Web 能力
另一类是网络能力:
web_search
web_fetch
模型当然可以通过 Bash 调用 curl,也可以直接请求搜索服务的 API。
但搜索与网页阅读有明显的结构化价值。
web_search 可以统一不同搜索提供商的返回格式:
title
url
snippet
published_at
score
web_fetch 则可以负责:
请求网页
→ 判断内容类型
→ 提取正文
→ 去除导航和广告
→ 转换为 Markdown
→ 控制输出长度
→ 保留来源信息
这样,模型不需要把大量 Token 消耗在 HTML、导航菜单、脚本和无关页面元素上。
这类工具不是在替模型进行研究。
恰恰相反,它们只是为模型提供更高质量的搜索结果和网页内容。
至于如何拆分问题、搜索什么、相信哪些来源、是否继续搜索、如何综合结论,仍然由模型决定。
五、我依然会对工具数量保持克制
认识到“极简工具集”可能限制模型,并不意味着我要走向另一个极端。
Onemore 不会因为一个操作可以被命名,就把它做成独立工具。
我现在倾向于用下面的标准判断一个能力是否值得成为一等 Tool。
1. 是否高频
如果绝大多数任务都会使用这个能力,那么专用工具的常驻成本更容易被摊薄。
2. 是否能显著降低失败率
如果 Bash 表达已经清晰、稳定,就没有必要增加工具。
反过来,如果模型经常在参数、转义、输出解析或平台差异上失败,那么专用工具可能有价值。
3. 是否能够提供结构化、有限的输出
如果 Harness 能把几千行噪声压缩成几十条结构化结果,这个工具实际上是在节省 Token。
4. 是否需要 Harness 提供额外保证
例如:
- 工作区边界;
- 原子写入;
- 冲突检测;
- 稳定错误码;
- 输出分页;
- 权限检查;
- 进度事件;
- 完整结果的持久化。
5. 是否具有明显副作用
副作用越大的操作,越有必要通过明确的工具边界进行权限控制和审计。
6. 是否比 Bash 的总交互成本更低
这里不能只比较单次工具描述的 Token 数量。
更完整的计算应该是:
总交互成本
=
工具描述成本
+ 参数生成成本
+ 输出阅读成本
+ 失败概率
+ 错误恢复成本
+ 额外调用轮次
如果一个专用工具的 Schema 很长,而 Bash 只需要一条简单命令,那么应该使用 Bash。
但如果 Bash 经常返回大量噪声、造成重复调用或者引入平台差异,那么即使专用工具需要一些描述 Token,它仍然可能更便宜。
所以我的原则不是:
Bash 能做的就绝不做 Tool。
而是:
如果专用 Tool 不能显著改善总交互成本、执行可靠性、结果质量或安全边界,就继续使用 Bash。
六、Bash 应该是通用逃生舱,而不是所有能力的唯一接口
我仍然非常重视 Bash。
事实上,Bash 可能一直会是 Onemore 最重要的工具之一。
它负责承接所有长尾能力:
- 项目特有的构建命令;
- Git 的复杂操作;
- 各种语言和生态的 CLI;
- 临时数据处理;
- 自定义脚本;
- 调试网络请求;
- 用户已经安装的本地工具;
- Onemore 不知道、也不应该知道的环境能力。
专用 Tool 与 Bash 并不是相互替代关系。
我的目标是形成这样一种结构:
专用 Tool
负责高频、结构化、需要 Harness 保证的操作
Bash
负责低频、灵活、可组合的长尾操作
Skill
负责领域方法、使用说明和操作经验
例如,Onemore 没有必要为 GitHub 的每一种操作都增加工具:
github_create_issue
github_update_issue
github_add_label
github_get_pull_request
github_request_review
相比之下,一个 GitHub Skill 可以告诉模型如何使用已有的 gh CLI:
gh issue create
gh pr view
gh api
真正的执行仍然通过 Bash 完成。
这既保留了环境的开放性,也避免让 Harness 感知 GitHub 的完整业务模型。
七、为什么我更倾向 Skill,而不是 MCP
我目前仍然会拒绝繁重的 MCP 接入。
这并不是说 MCP 没有价值。
对于需要大量连接器、企业授权、远程数据源和跨客户端协议兼容的平台来说,MCP 有非常明确的作用。
但它并不适合所有 Agent。
MCP 一旦成为核心能力,Harness 很容易开始承担:
连接管理
认证管理
服务发现
Schema 动态加载
工具命名冲突
工具搜索
权限映射
断线恢复
服务生命周期
第三方错误兼容
第三方输出控制
同时,第三方 Tool 的质量并不由 Harness 控制:
- Tool 描述可能很差;
- 参数 Schema 可能很大;
- 输出可能没有边界;
- 错误可能只是普通字符串;
- 工具可能语义重叠;
- 副作用可能不明确;
- 幂等性可能没有定义。
Harness 为了兼容这些不确定性,必然会逐渐变重。
然后又需要进一步加入:
Tool Search
Tool Ranking
Tool Filtering
Tool Context Management
但 Provider 对 Tool Search 和动态工具加载的支持并不统一。不同接口之间也存在很大差异。
这条路线最终可能会把 Onemore 变成一个工具平台,而这不是我想要解决的问题。
相比之下,Skill 更符合 Onemore 的设计方向。
Skill 可以按需提供:
- 领域知识;
- 操作方法;
- 推荐命令;
- 验证步骤;
- 输出要求;
- 项目约定;
- 必要的脚本和模板。
它不需要永久占用 System Prompt,也不需要向模型常驻注入大量 Tool Schema。
模型在发现自己需要某种能力时,可以主动加载对应 Skill,然后使用已有的工作区工具和 Bash 完成任务。
因此,在 Onemore 中,我更愿意让三者保持明确边界:
Tool
= 可执行的原子环境能力
Skill
= 按需加载的方法论与领域知识
Bash
= 通用的长尾执行接口
Skill 并不能在协议意义上完全替代 MCP,但它可以覆盖 Onemore 真正关心的大部分使用场景。
剩下那些必须依赖复杂远程连接器才能完成的任务,可以明确不属于 Onemore 的目标范围。
八、为什么我也不打算做 Subagent 和 Agent Team
Onemore 暂时也不会引入 Subagent 或 Agent Team。
多 Agent 经常被描述为一种能力扩展方式:
- 一个 Agent 负责搜索;
- 一个 Agent 负责编码;
- 一个 Agent 负责测试;
- 一个 Agent 负责评审;
- 最后由主 Agent 汇总。
但多 Agent 同时会引入全新的复杂度:
任务应该如何拆分
上下文应该如何分配
事实应该如何共享
进度应该如何同步
重复工作如何避免
结果冲突如何处理
失败如何传播
取消如何传播
预算如何分配
最终责任属于谁
很多时候,多 Agent 并不是在解决任务本身的复杂性,而是在弥补其它问题:
- 单 Agent 的上下文管理不够好;
- 主 Agent 缺乏足够的环境能力;
- 任务在进入 Agent 前没有被充分定义;
- Harness 无法稳定支持长任务;
- 工具结果无法有效压缩和恢复。
我更希望先把这些基础问题解决好。
Onemore 假设它的用户在任务开始前已经完成了必要的产品判断和前期调研,能够给出相对明确的:
目标
背景
约束
验收标准
模型可以在执行过程中继续研究代码、制定计划和调整方向,但它不应该承担一个完整组织中所有角色的职责。
这是一种有意选择的用户边界。
如果一个任务必须临时组织多个自治 Agent 才能确定“究竟应该做什么”,那么这个任务或者这类用户,可能本来就不适合 Onemore。
Onemore 仍然允许一个 Agent 拆分任务和维护计划:
一个 Agent
一个上下文主线
一个事实日志
一个统一计划
多个工具调用
但不会把这些步骤委派给多个拥有独立上下文和状态的 Agent。
对我来说,这种结构更简单、更透明,也更容易验证。
九、上下文管理,才是丰富工具的必要前提
工具变多之后,一个很容易被忽略的问题是:工具输出会迅速污染上下文。
搜索结果、Git Diff、构建日志、测试日志和网页正文都可能非常大。
如果只是把所有结果原样追加到对话里,那么工具越强,Agent 反而越容易失去方向。
因此,“机械能力强”不能只包含更多操作能力,还必须包含更强的上下文管理能力。
在我的理解里,Harness 至少需要区分:
事实日志
模型当前视图
UI 展示
完整工具结果
压缩后的上下文
工具结果也不应该只是一根字符串。
同一个 Tool Call 的结果可能需要面向不同消费者:
- 模型需要短而准确的结果;
- 用户界面需要易于阅读的摘要;
- 调试和恢复需要完整细节;
- 上下文压缩需要稳定事实;
- 后续操作可能需要游标或 Artifact 引用。
这也是 Onemore 目前比较重视的一部分。
如果 Harness 无法保存和压缩可靠的执行事实,那么模型的行动能力越强,累积的上下文问题就越严重。
因此,更完整的定义应该是:
Mechanically strong
=
强观察
+ 强执行
+ 强反馈
+ 强上下文管理
+ 强恢复能力
它绝不仅仅意味着“有更多工具”。
十、我期待中的 Onemore 工具集依然会很小
即使完成下一阶段的扩展,我预计 Onemore 的工具数量仍然不会很多。
可能会长期维持在十几个左右:
工作区:
- read
- write
- list
- glob
- search
执行:
- bash
代码状态:
- git status / diff
网络:
- web_search
- web_fetch
认知辅助:
- load_skill
- update_plan
以后只有在真实使用中出现明确需求时,才可能继续加入:
apply_patch
diagnostics
process control
artifact read
我不希望 Onemore 最后拥有几十个语义重叠的工具。
对模型来说,工具数量并不等于能力。
真正重要的是:
- 每个工具都有明确边界;
- 每个工具都能被轻松理解;
- 每个结果都可以控制规模;
- 每个错误都有稳定语义;
- 每个副作用都可以审计;
- 工具之间能够自然组合;
- 长尾任务仍然可以回退到 Bash;
- 领域知识可以通过 Skill 按需加载。
所以,我现在所说的“开始增加工具”,更准确的表达应该是:
把少数能够显著改善观察质量和执行可靠性的能力,从 Bash 中提升为一等接口。
这不是工具扩张,而是能力提纯。
十一、我现在如何理解 Harness 的“强”与“弱”
经过这次认知修正,我不再用代码量、工具数量或者 System Prompt 长度来判断 Harness 是强还是弱。
我更愿意用两个维度来描述它:
机械强度
Harness 是否能够:
- 准确观察环境;
- 稳定执行操作;
- 控制输出规模;
- 处理失败和取消;
- 保存完整事实;
- 管理上下文;
- 约束危险副作用;
- 给模型提供清晰反馈。
认知强度
Harness 是否在替模型决定:
- 如何理解任务;
- 如何制定计划;
- 下一步应该做什么;
- 什么时候反思;
- 应该相信什么;
- 哪种工作流必须被遵循;
- 什么结果才算完成。
Onemore 希望位于这样一个位置:
机械强度:高
认知强度:低
也就是:
赋予模型充分的行动能力,但不过度规定模型应该如何思考。
结语:不是替模型思考,而是让模型做得到
现在回头看,我最初追求极简工具集,实际上混淆了“保持架构克制”和“限制模型能力”。
真正值得克制的,不是环境能力,而是 Harness 对模型认知过程的干预。
我仍然相信,随着模型能力增强,越来越多的计划、判断和反思应该交还给模型。
但模型能力越强,它越需要一个高质量的环境接口。
这个接口应该:
- 足够强,让模型做得到;
- 足够清晰,让模型看得懂;
- 足够稳定,让模型可以恢复;
- 足够克制,不替模型做决定;
- 足够开放,让 Bash 承担长尾能力;
- 足够轻量,让 Skill 按需提供领域知识。
这可能就是我目前对 Agent Harness 最核心的理解:
A good harness should not think more for the model. It should make the world more operable to the model.
或者用 Onemore 下一阶段的设计原则来表达:
Mechanically strong, cognitively weak.
**不是替模型思考,而是让模型拥有充分、可靠且低摩擦的行动能力。
评论
评论加载中……