用了大半年 Claude Code,我才搞懂:关键往往不在模型,而在 harness

我每天用 Claude Code 写代码。用得越久,越有一个感受跟主流的讨论对不上:大家聊 AI coding,话题几乎全在模型上——Opus 还是 GPT、新版本涨了几分、谁更会写代码。可我自己用下来,决定「这个 agent 顺不顺手」的,多半不是模型本身,而是模型外面那层东西。

它有个不太起眼的名字:harness。字面意思是「挽具」,就是套在牲口身上、把那股力气导出来干活的一套带子。我觉得这个词用得挺准——模型是那股力气,harness 是把力气接到现实世界、让它真能拉动东西的那套结构。

一、模型自己什么都干不了

这件事我是想明白了才敢往下说的。一个语言模型,本质就是个「文本接龙」的东西:给它一串 token,它预测下一个 token,仅此而已。它没有手,没有眼睛,也没有记忆。

所以一个很自然的问题是:它凭什么能读我的代码库、改我的文件、跑我的测试?

答案是——它不能。干这些事的根本不是模型,是模型外面那层程序。模型顶多在输出里写一句「我想读 src/index.ts 这个文件」,真正动手去把文件读出来、再把内容塞回去给它看的,是 harness。

左边是一个只会文本进文本出的纯模型,右边是被 harness 包住、能真正干活的 Agent

把这层看清楚之后,很多说法就能落地了。所谓 agent,粗暴点说就是这么个公式:

Agent ≈ 模型 + 一个循环 + 一组工具 + 一个能动手的环境

模型只占其中一块。后面那三样——循环、工具、环境——全是 harness 的事。

二、核心是一个循环:边想边做

harness 最核心的零件,是一个循环。

跑起来大概是这样:模型先输出一段话,里面可能夹着一个工具调用(「帮我跑一下 pnpm build」);harness 把这段输出解析开,认出这个调用,真的去执行;执行完拿到结果——一段日志、一个报错、一堆文件内容——再把这个结果(observation)塞回上下文,交还给模型;模型看着新结果接着想下一步。这么一圈一圈转,直到模型自己判断「活干完了」,循环才跳出来。

agent loop 示意:模型输出,harness 解析并执行工具,结果回填上下文,再交回模型,循环往复,直到模型判断完成才跳出

这里有个我一开始没意识到的点:模型本身不会「循环」。模型每被调用一次,都是一次性的、无状态的——它不记得上一轮发生了什么。所谓「它在连续地干活」,其实是 harness 每一轮都把之前的全部历史再一股脑喂回去,制造出一种连贯的错觉。真正在跑那个 while 的,是 harness。

这套「推理一步、动手一步、看结果再推理」的思路,最早被系统地讲清楚的是 2022 年那篇 ReAct 论文(Reasoning + Acting)。今天市面上几乎所有的 coding agent,骨子里都是这个循环的变体。理解了这个圈,你就抓住了 agent 的主心骨;剩下的全是在这个圈上加料。

三、harness 到底由哪几块拼成

循环只是骨架。真正让一个 agent 从「能跑」到「好用」的,是挂在循环上的那些零件。我用下来,大致能数出这么几块:

harness 的组成:工具、上下文管理、权限与安全、子代理、扩展点,每一块都是把模型变成可用 agent 的关键

工具(tools)。 读文件、改文件、跑命令、搜网页——每一样都是 harness 定义好、并且真正去执行的动作。工具写得好不好,对体验的影响有时候比模型聪明不聪明还大。一个「编辑文件」的工具,是让模型整篇重写、还是只改它指定的那几行,差别是天壤之别:前者动不动就把你别的代码冲掉,后者稳得多。这些都是 harness 的设计,跟模型本身没关系。

上下文管理(context)。 这块我觉得是最被低估的。上下文窗口就那么大,活儿一长就装不下。这时候 harness 得替模型操心:旧的对话要不要压缩、要不要总结成几句话;一大堆工具不可能全塞进去,得「按需加载」——先告诉模型有哪些工具的名字,真要用了再去取它的完整定义;该提醒模型的事(「你现在在这个目录」「别忘了还有这条规矩」),要适时地插进对话里。同一个模型,上下文管得好不好,直接决定它能不能扛住一个长任务而不「失忆」。

权限与安全(permissions)。 harness 在模型和你的机器之间设了一道闸。模型想 rm -rf 也好,想往外发请求也好,危险的操作得先过这一关——要么停下来问你一句,要么压根就够不到你不许它碰的东西。这道闸是 harness 的,不是模型的自觉。

子代理(subagents)。 harness 还能再开一个带独立上下文的小 agent,派它去干一段相对独立的活,干完只把结论带回来。好处是主对话的上下文不会被一堆中间过程污染。我上一篇写的 dynamic workflows,底子就是这个——那次 12 个子代理并行搭 MVP,每个子代理的中间折腾都留在它自己那儿,最后只把结果汇总给我,主上下文才占了 13%。

扩展点(hooks / skills / memory)。 这是 harness 留给你的几个口子,让你不碰模型也能改 agent 的行为:钩子(在某个动作前后跑你自己的脚本)、技能(一包可复用的指令和资源,用到了再加载)、记忆(跨会话存下一些事实)。Anthropic 专门写过一篇讲技能这套机制,思路就是:与其把所有本事都硬塞进模型,不如让 harness 在需要时动态地把对应的「说明书」喂给它。

四、模型不是关键

把上面这些摆在一起,结论就比较清楚了:同一个模型,套不同的 harness,用起来能差出十万八千里。

你可以自己拿 API 写个最朴素的 while 循环、配几个工具,跑起来确实也是个 agent。但它跟 Claude Code 的体验,差的不是模型——模型可以一模一样——差的全是那层壳:工具糙不糙、上下文会不会爆、危险操作拦不拦、长任务能不能拆。

这事 Anthropic 自己其实也认。他们把 Claude Code 那套 harness——agent loop、工具、上下文管理——单独抽出来做成了 Claude Agent SDK,对外卖的就是这层壳。换句话说,「壳」本身已经被当成产品的一大半了。他们那篇文章里有句话我印象很深,大意是:给 agent 一台电脑,让它像人一样干活——而「一台电脑」这件事,恰恰是 harness 在提供。

另一篇更早的 Building effective agents 则反复强调一个我很认同的态度:用最简单能 work 的方案,别为了「看起来很 agent」就把系统搞复杂。harness 不是越花越好,能稳稳跑通你那个循环,比堆一堆用不上的机制实在得多。

五、碎碎念

「harness 比模型重要」这话别走极端。 它俩是乘法,不是加法。模型是其中一个因子,归零了,壳套得再花也白搭——模型不会推理,循环转一万圈也转不出正确答案。我想说的只是:在模型已经够强的今天,harness 这个因子被严重低估了,而它恰恰是产品方、甚至是你自己最能动手优化的那一项。

harness 不是免费的。 上下文管理、子代理这些,省的是你的事,花的是 token。我上次那个 31 分钟搭出来的 MVP,16 分钟就烧了 42 万 token。壳越「贴心」,背后的开销往往越大,这笔账得自己算。

这层东西在快速变。 我今天看到的「按需加载工具」「子代理」「技能」,过几个月很可能就换了实现,甚至换了名字。所以别把某个具体机制当成永恒,记住「模型 + 循环 + 工具 + 环境」这个骨架就够了——具体零件怎么演化,是它们的事。

小结

模型是内核没错,但你每天真正打交道的那个「能读你代码、能跑命令、能自己把 bug 修了」的 agent,一大半是外面那层 harness 撑起来的。

挑工具、调工作流的时候,大多数情况下其实是在挑、在调 harness,而不是在挑模型。想清楚这一点,很多选择会变得简单——别老纠结哪个模型分高一两个点,先看看谁家的壳,把你要干的那类活伺候得更顺。

想往深里读,我推荐这几篇一手资料:Anthropic 讲设计哲学的 Building effective agents、把这层壳产品化的 Claude Agent SDK 介绍,以及 Claude Code 的官方文档——把文档当成「这层壳都给我开了哪些口子」的清单来读,会很有收获。