本文作者 ClackyAI 创始人李亚飞。OpenClacky 是他们推出的开源 AI Agent 项目。

Harness,正在被越来越多的团队重视。

简单说,Harness 是 Agent 除了大模型之外的一切工程,包括 prompt 怎么组装、工具怎么设计、上下文怎么管理、成本怎么控制等等。模型能力再强,但 Harness 做得差,账单和效果都会很难看。

ClackyAI 团队近期拿 4 家 Agent 做了一次横向测评,结果发现:

同样的 prompt、同样的模型、同样的任务,成本最高可以相差 6 倍,且能与 ClaudeCode 保持同等能力。也再次印证了,Harness 工程的水平,才是 Agent 产品真正拉开差距的地方。

打开网易新闻 查看精彩图片

这篇文章,是 ClackyAI 团队在 Harness 工程实践上的实践复盘。ClackyAI 的开源 Agent 项目 OpenClacky,在 Harness 工程上摸索了两年,经历了两代失败,最后用 Ruby 从零完成了第三代重写。(OpenClacky:https://www.openclacky.com/)

在这篇文章中,他们复盘并总结了影响成本和效果的 7 个关键决策。对于正在做 Agent 产品的团队来说,值得一读。

⬆️关注 Founder Park,最及时最干货的创业分享

Founder Park 正在持续寻找值得被看见的 AI 团队与项目。

我们将通过「AI 产品市集」、内容报道、社群分发等方式,帮你触达早期用户、获得真实反馈,以及建立关键连接。

如果你正在做 AI 相关的事,欢迎和我们聊聊。

01踩过两次坑:搞 RAG、做多 Agent 工作流

在讲决策之前,先讲两段失败。现在回头看失败得很彻底,但这两个弯路我感觉还有很多团队在走。

第一代:RAG / 知识库。把用户代码库、文档、历史会话全部 embedding 进向量库,检索 + 重排 + 改写查询。听起来合理,实际跑下来三个致命问题:向量更新成本高且实时性差;90% 的召回率听着不错但对 Agent 场景完全不够用(我判断 97% 才刚刚够用);多了一个会挂的部件,延迟也上来了。

结论:不要搞 RAG。如果你要上 Agent,直接上 Agent,外加一个适合 AI 阅读的文档站就够了。

第二代:多 Agent 工作流Planner、Coder、Reviewer、Tester 各一个 agent,消息总线编排。结果:每个 sub-agent 各有 cache 命名空间,交接一次就 miss 一次。单 agent 4 分钟能完成的任务,多 agent 编排到 14 分钟,成本翻 6 倍。SWEBench 分数能刷上去,但实际用户体验脱节得厉害。

结论:不要做多 Agent 编排。人类的分工逻辑不适用于 AI——AI 不需要「一个人想、一个人写、一个人审」,一个足够好的 agent 加一套足够好的 harness 就够了。Benchmark 跑分也不重要,模型每半年跨一个台阶,用工作流堆出来的分数会被下一代模型 + 朴素 harness 直接抹平。

第三代从零重写,围绕两件事组织:Cache 局部性工具集稳定性。以下 7 个决策都属于这一代。

027 个关键工程决策决策 1:双 Cache 标记

大模型的 prompt cache 是按前缀匹配的——前缀里改一个字节,从那里往后全部失效。所以前缀的层次结构和标记位置,决定了下一轮还能命中多少。

最直觉的做法是每轮在消息末尾打一个标记。但这个做法在三个场景下会失效:历史消息追加后原标记位置的内容变了;模型回退一次工具调用后标记直接作废;切换模型时标记抖动导致额外的 miss。

我们的做法是每轮标两条连续消息,形成一个滚动双缓冲:任何时刻都持有两个断点,一个读一个写。下一轮把「读」再读一次,在新尾部写一个新的。这样即使模型回退了一步,倒数第二个标记仍然落在有效消息上——单步回退仍能命中。

为什么是 2 不是 3?因为双标记正好覆盖「旧尾部 / 新尾部」这一个边界,第三个标记落在更前面的位置,对应的 cache 段永远会被前两个覆盖——多写一次白花钱。

决策 2:System Prompt 字节冻结

OpenClacky 的 system prompt 在 session 启动时一次性构建,之后一个字节都不动。这是 cache 命中率的第一道地基——system prompt 一变,后面所有 cache 全废。

但日常运行中至少有四类信息「天然想插进 system prompt」:当前时间、当前模型、新装的 Skill、用户偏好更新。如果真写进去,任何一次变更都是全量失效。

我们的做法是把这些动态信息写成一条普通消息插进对话历史,打上「系统注入」标签。它不会被 cache 标记选中,不会被算作真实用户轮数,压缩时也不会原样搬进新历史。同一天内只注入一条,跨天或切模型时再插一条新的。

代价是:session 中途装的新 Skill,当前 session 里看不到,要开新 session 才能用。我们接受这个摩擦——装 Skill 是低频操作,cache 命中是每轮都在享受的收益。

决策 3:Skill 子 Agent 架构

invoke_skill 是整个 OpenClacky 最核心的设计。它启动一个子 agent,子 agent 拥有跟主 agent 完全相同的工具集,执行完后把结果返回给主 agent。主 agent 的历史里只看到一对「调用 → 结果」消息。

这个设计一口气解决了好几个问题:

状态隔离。做代码审查的 Skill 可能需要读几十个文件、跑大量搜索、输出长篇分析。这些中间过程隔离在子 agent 的 session 里,主 agent 的历史没有被污染——cache 命中率不受影响,压缩也不会被提前触发。

动态加载,不改工具列表。装新 Skill 就是放一个文件到指定目录。invoke_skill 这个工具本身始终存在,Skill 的内容是调用那一刻才读取的。不需要改 system prompt,不需要改工具 schema,不需要重启 session。

能力可以无限扩展,但工具数始终是 16 个。代码探索、记忆召回、PPT 生成、部署上线——这些能力全部是 Skill,通过 invoke_skill 这一个工具入口调用。主 agent 的 system prompt 里只需要列出 Skill 名称和描述,不需要为每个能力增加独立工具。

决策 4:固定 16 个工具

工具 schema 紧贴 system prompt 之后,在 cache 前缀里。每多一个工具,不只多了 schema 的 token 成本,还多了「下次改工具时全量失效」的风险面。但工具太少也有代价:模型本来一步能做完的事要分好几步,轮次上去了,每轮都在付钱。

我们的答案是 16 个:文件读写 3 个、代码搜索 2 个、终端 1 个、浏览器 1 个、网络 2 个、任务管理 4 个、用户交互 1 个、Skill 调用 1 个、安全删除 1 个。

设计原则是:参数尽量少(减少模型出错),粒度刚好够用(不冗余也不过度合并),每个工具有充分的测试覆盖(1600+ 测试用例)。

那些「看起来需要专用工具」的能力——代码库分析、记忆读写、浏览器多动作、sub-agent 编排、定时任务——全部通过 Skill 实现(决策 3),不占工具位。这一套跑了 4 个月,没有需要加第 17 个工具的时候。

决策 5:压缩不换模型,空闲时做

上下文窗口再大也会填满。压缩不可避免,但压缩是 cache 命中率最大的单点威胁:老消息被替换成摘要,前缀从那一刻起就不一样了,必然 miss。

不换模型压缩。很多 agent 开一个独立的 LLM call 用小模型做摘要。问题是这个独立 call 跟主 session 没有任何共享前缀,压缩本身就是 100% miss;压完之后主 session 的历史也变了,又是一轮 miss。等于每次压缩付两笔钱。

我们的做法是把压缩指令作为一条消息插进当前对话末尾,走正常请求路径。压缩 call 命中现有 cache(只有尾部几百 token 的指令是冷的),压完后重建历史只 miss 一轮。对比独立 call 方案,一次 50K token 会话的压缩事件,冷 token 从 50000 降到 500。

空闲第 3 分钟启动压缩。大模型厂商的 cache 有 TTL,一段时间无请求就过期。我们跑了一个后台计时器:用户停止输入 90 秒后检查,如果历史接近阈值就立刻压缩——此时 cache 还是热的,代价极低。用户思考几分钟回来,看到的是一个已经压缩好、cache 已经 warm 的 session。不做这一步的话,用户回来面对的是 cache 过期的长历史,单那一轮可能就是 10 倍成本。

积极压缩而非用满上下文。「百万 token 上下文」听起来性感,但模型在超长上下文里注意力会分散,而且你真用不起——100 万 token 即使全部 cache hit,一轮也要付 10 万 token 等价的钱。我们的策略是压缩后保持历史在 1 万 token 以内。短历史 + 高命中率,比长历史 + 偶尔 miss 便宜得多,效果也更可控。

决策 6:工具自进化

PDF、Excel、Word、PPT 的读取是 Agent 高频需求。内置专用工具会让工具列表膨胀(违背决策 4),做成 Skill 让用户手动装体验又差。

我们选了第三条路:首次安装时把一组 Python 脚本复制到用户目录,agent 需要读文档时用终端工具跑这些脚本。工具列表没有增加。如果脚本跑不过(缺依赖、格式变了),agent 自己修改脚本、装依赖,下次就不会出问题。

处理文档的能力不是写死在代码里的,它活在用户目录的脚本里,agent 自己可以维护和进化。

决策 7:内置浏览器,接管已有 Chrome

浏览器自动化越来越重要。主流做法是 Headless 浏览器或外接 MCP 服务,我们两种都不用——内置了一个 MCP Client,直接接管用户已经在跑的 Chrome / Edge。

Headless 的问题是「看不见」:用户不知道 agent 在干什么,出了问题无法判断,登录态和 cookie 也拿不到。外接 MCP 的问题是安装成本高、稳定性不可控、工具 schema 不可控(外部 MCP 可能暴露几十个细粒度工具,直接打进工具列表就违背了决策 4)。

接管已有浏览器的好处是:用户看得见 agent 的操作、登录态和 cookie 直接可用、对外只暴露一个 browser 工具(snapshot / click / type / navigate 等动作都是这一个工具的参数),schema 稳定。代价是需要维护 daemon 的生命周期管理,但这是一次性的工程投入。

03把工程预算花在 Harness 上,把智能预算留给模型

回到文章开头的这张表。

打开网易新闻 查看精彩图片

这 7 个决策背后其实只有一句话:把工程预算花在 Harness 上,把智能预算留给模型。

不做 RAG,不做多 Agent 编排,不做工具堆叠——不是因为这些东西没用,而是因为模型在快速变好。半年前需要 4 个 agent 协作才能通过的任务,今天一个 agent + 一套好的 harness 就能做得更快更便宜。

我们选择把精力放在那些不会随模型进步而过时的事情上:cache 命中率、工具稳定性、安装体验、压缩策略。这些是 Harness 层面的基础设施,不管模型换到哪一代都用得上。

OpenClacky 七个核心工程决策,让它成为了和 ClaudeCode 同一梯位的 Agent 产品,与其他同类 Agent 拉开了较大距离。

OpenClacky 完全开源,免费使用,MIT 协议,支持自用 LLM Key。如果你是工程师,欢迎 Github 点赞支持,深入了解源码。如果你用过其他 Agent 账单起飞想要一个更省钱的 Agent,欢迎试用。如果你是新人,无须犹豫,立刻下载安装。

  • 安装指引和产品文档:openclacky.com

  • 4 家 Agent 横评的完整数据、产物对比、录像回放:openclacky.com/benchmark

  • Github 地址:github.com/clacky-ai/openclacky

打开网易新闻 查看精彩图片
打开网易新闻 查看精彩图片

转载原创文章请添加微信:founderparker