引子

“今天你 Harness 了吗?”

2026 年,“Harness"大概是 AI Agent 领域被用得最多的一个词,也伴随着巨大的误解。反观过去这 2-3 年内 AI 发展,伴随的是如雨后春笋般出现的各式各样 agent 框架、脚手架和编排工具,大多也深陷技术债的泥潭,从此销声匿迹。

在本文中,先不谈宏大的 Harness Engineering(笔者认为这个词更多包含了让 Agent 自我迭代优化的含义),只聊聊 Harness 本身。

这篇文章只回答一个问题:一个面向未来的、最小化的 Agent Harness,到底由哪些不可替代的核心组件构成?

以及,在当下的技术语境里,如何摆脱过去两年积累的技术债,选择或开发一个合适的 Agent Harness。

造好 Harness,Agent 会完成剩下的。

正本清源:Harness 到底是什么

要搞清楚 Harness 到底是什么,需要先做一点简单的赛博考古。

在传统软件工程中,Test Harness(测试自动化框架) 指的是为了执行测试而建立的自动化环境,核心目标是“去人工化”。

而在 LLM、Agent 领域,harness 起初更多被用在 LLM 评测语境下,如 SWE-bench 等复杂的评测基准中,单纯的 LLM 无法拿高分,需要一套外置循环和工具来辅助测试。此时,Harness 仅限于 Eval 领域。

image.png

直到 Claude-Code 等应用的出现,agent harness 逐渐有了新的含义:支撑 AI 工作的底座。

目前能找到最早的来源, 2025 年 9 月 23 日,开发者 Vivek Trivedy 在博客中首次系统阐述“agent harness”。

“Agent Harness: External set of functionality to enhance a model’s runtime execution. …

而真正的爆火,来自 Anthropic: Effective harnesses for long-running agents (Nov 26, 2025) 和 OpenAI: Harness engineering: leveraging Codex in an agent-first world (Feb 11, 2026) 的两篇文章。

image 1.png

简单来说,如果用一句话定义: Harness 就是包裹在 LLM 外面的软件外壳——它把一个只会说话的模型,变成一个能做事的 Agent,甚至是能持续运行数小时的 long-running Agent。

包括 LangChain 在内的各种生态为了跑马圈地,创造了无数概念把人搞得云里雾里,所以,Agent Frameworks, Runtimes, scaffolding, Harnesses 这些词究竟有什么区别?

结合 LangChain 的文章:Agent Frameworks, Runtimes, and Harnesses - oh my!

  • Runtime:解决“agent 怎么在生产里稳定、可持久地跑”的底层基础设施。

  • Framework:提供一套抽象和编程模型,帮你“更容易写 agent 应用”。

  • Harness:在 framework 之上加上默认配置、工具和工作流,做成“拿来就能跑任务的高层套件”。

Pasted 2026-04-05-19-23-57.png

(概念都是人造的,都是先有了物,才有了概念)

设计哲学:Less is More

从 How To Be A World-Class Agentic Engineer 以及 Learning the Bitter Lesson 中所总结的经验和教训便是:Less is More。各种人为加入的结构或偏置虽然短期有用,却会在长期成为限制,应随着模型和计算能力提升逐步去除。

具体来说,The Bitter Lesson 在 Agent 领域的推论:

在 Harness 中写的每一行"聪明"的控制逻辑,都是在和未来的模型能力对赌。如:

  • 2024 年你写了精巧的 ReAct 状态机 → 2025 年模型原生支持多轮工具调用,你的状态机成了负担

  • 2025 年你写了复杂的 Planning 模块 → 2026 年模型的 reasoning 能力足以自主规划,你的 Planner 成了天花板

这不是说不需要 Harness,而是说:Harness 的每一个组件都应该问自己——“这个东西,模型自己能不能学会?”

如果答案是"迟早能”,那它就是辅助组件,写的时候就要预留拆除的口子。 如果答案是"不可能"(因为它涉及的是 LLM 外部的物理世界),那它就是核心组件。

换句话说,极简的、最小化必要的组件,才是一个能扛住未来 3-6 个月模型迭代的 Harness 的核心。

具体的,如果以 “Long-running”为目标,Harness 的组件可以被划分为两类:

  • 核心组件: Agent-loop、Context 管理、原子化核心工具、File-system 、Hooks 与 Subagent 隔离(或者是task管理)

  • 辅助组件(短期内的补丁,长期会被取代的)

核心组件

Agent Loop

所有关于 Agent 的故事都始于 Agent-Loop。一个好的 Agent-Loop 必然是极其简洁的,由 LLM 主导决策,而非人为预设路径。

从底层来看,LLM 依然是一个预测下一个 Token 的自回归模型。这个基本盘在长远来看是成立的。Agent-Loop 的作用仅仅是:执行工具 → 捕获结果 → 追加上下文 → 再次调用 LLM 。

def agent_loop(query):
    messages = [{"role": "user", "content": query}]
    while True:
        response = client.messages.create(
            model=MODEL, system=SYSTEM, messages=messages,
            tools=TOOLS, max_tokens=8000,
        )
        messages.append({"role": "assistant", "content": response.content})

        if response.stop_reason != "tool_use":
            return

        results = []
        for block in response.content:
            if block.type == "tool_use":
                output = run_bash(block.input["command"])
                results.append({
                    "type": "tool_result",
                    "tool_use_id": block.id,
                    "content": output,
                })
        messages.append({"role": "user", "content": results})

(from learn-claude-code)

这就是 agent 的核心循环。所有的"智能"都来自同一个地方:LLM 预测下一个 token 时的内在推理。Harness 只是把 tool response 喂回去,让这个推理过程能够持续。

当然,从工程角度和生产级考虑,agent-loop 本质上仍是这个 while-true 循环,但需要增加大量的防御机制来提升韧性。

据非官方流出的 claude-code 源码分析,queryLoop(src/query.ts:241)围绕核心循环构建了超过 1700 行的防御层,包括:

  • Streaming 处理

  • 权限检查

  • Tool 格式处理、校验

  • 错误恢复

  • …

Context 管理

过去半年多,“Context Engineering"这个词开始频繁出现。它指的不是简单的 Prompt 调优,而是解决一个更根本的矛盾:不断累加的 Message 同 LLM 有限的 context-length 和注意力之间的矛盾。在 Long-running 状态下,持续 append 的 messages 最终会导致:

  • Context 溢出:超出 LLM context-window 的物理上界

  • Context Rot: 在窗口内,不代表模型能有效处理,无效信息过多会严重干扰模型的推理

优秀的 Harness 如何处理 Context?

Context 管理不仅仅是拼接修剪 Prompt,其中最核心的原则是 token 成本,或者说是 KV-cache 的缓存命中率。也就是说,在保证缓存命中的前提下,进行 context 的优化。

1. Microcompact

处理掉前几轮 tool-using 产生的 tool result 中间结果。据源码分析,Claude-code 分成了两种处理方式:

  • Time-based Microcompact:当用户离开一段时间后回来,服务端的 prompt cache 已经过期,此时无需保护缓存,直接构造新的消息对象替换旧的工具结果内容。

  • Cached Microcompact(Context editing):在 cache 存活期间不能替换消息内容,而是通过 Anthropic API 的 Context editing 机制,在 API 层面删除指定工具的 tool_result。

2. Summary、Compact、Auto-Compact

当手动或自动触发阈值时,Harness 会调用 LLM,根据现有的 context 进行总结和摘要并替换掉之前的 context。以 Claude Code 为例,摘要中通常包含:

// 摘要必须包含以下9个部分
1. Primary Request and Intent      // 主要请求和意图
2. Key Technical Concepts          // 关键技术概念
3. Files and Code Sections         // 文件和代码段
4. Errors and fixes                // 错误和修复
5. Problem Solving                 // 问题解决
6. All user messages               // 所有用户消息
7. Pending Tasks                   // 待处理任务
8. Current Work                    // 当前工作
9. Optional Next Step              // 可选下一步

在 Anthropic Claude API 中,system prompt 与 Messages 是独立的,因此可以采用"完全 summary"模式——把历史消息整体替换为摘要。

相比之下,OpenAI 的 Codex 采用"初始上下文 + 最近用户消息(最多 20k tokens)+ 摘要"的分层模式:

Pasted 2026-04-06-16-00-03.jpg

3. Offload

不同于 compact 的有损压缩,offload 利用 file-system,将 context 写入文件中永久保存,然后释放对应的 context 窗口,在后续按需加载,实现无损压缩。

4. Isolation

对于存在大量工具调用和探索的过程,将大任务拆解成多个小任务,分别由 subagent 完成,从而实现 context 的独立和隔离,避免 context 的污染。

Context 管理的目标:在信息完整度 × KV-Cache 命中率 × Token 成本 之间取最优解

原子化工具

严格来说,LLM 所谓的 tool-using,并不是真正在“使用工具”。模型本身只是在输出一种特殊格式的工具调用文本;真正的工具执行,是由 Harness 去解析这些文本后,转化为对环境的真实调用。

然而,工具并非越多越好。
过多的工具不仅会降低调用准确率,还会占用宝贵的上下文,带来明显的 Context Rot。对于 Agent 来说,真正重要的不是工具数量,而是工具是否具备:

  • 原子性

  • 正交性

  • 完备性

  • 可组合性

换句话说,工具层应该尽可能“原语化”——每个工具只做一件明确的事,但这些工具之间可以自由组合,从而构建出复杂行为。

无论是 Manus 的三层工具设计,还是 Anthropic 提出的 tool-search-tool 与 programmatic tool calling,背后的核心问题其实是同一个:

对 Agent / LLM 而言,什么才是“原生工具”?

所谓原生工具,不是工程师为了业务方便封装出的高度特化接口,而是那些模型更熟悉、更容易理解、也更容易稳定调用的工具形式。也可以说,它们是 agent-oriented tools。

bash is all you need

像 Bash、文件读写、文本编辑、正则处理这类底层能力,本来就是 Linux 和软件工程世界中最常见的操作接口;它们在训练数据中出现频率极高,也更容易进入 agentic RL 的训练分布。相比之下,那些人为定义、语义暧昧、接口风格各异的自定义工具,往往会显著增加 Agent 的理解与选择负担。

因此,与其为 Agent 提供几百个高度特化的第三方插件,不如优先提供少量稳定、低层、可组合的基础能力。

(面向 Agent 的 CRUD?)

File System

在 Agent 系统里,file system 的意义远不只是“保存文件”。

一方面,file system可以将原本停留在上下文窗口中的信息持久化下来,包括中间结果、计划、草稿、观察记录,以及工作记忆(也就是上文所提到的context offload)。

另一方面,file system本身也是最自然的执行环境之一。尤其在 coding agent 场景下,代码、配置、日志、测试输出、脚本和文档,本来就是围绕文件来组织的。相比额外发明一套新的记忆接口或工具抽象,直接提供 read、write、edit 等基础操作,更符合 Agent 的使用习惯,也更贴近操作系统级的真实工作流。

因此,在 harness 中,file system 往往承担至少三类关键角色:

  • 工作记忆(Working Memory):保存中间状态、任务计划、阶段性结论和临时产物

  • 执行环境(Execution Environment):承载代码、脚本、配置、输入输出和运行结果

  • 隔离边界(Sandbox):通过受控目录、虚拟文件系统或沙箱环境限制 Agent 的操作范围与权限

在这篇文章中 Everything is Context: Agentic File System Abstraction for Context Engineering,借用了Unix 哲学中的“Everything is a file” 理念,之于 agent的file-system中。

Subagent

Subagent 最初是 context isolation 的手段,进一步则演化为一种任务调度与多 Agent 协作的基本单元

在很多任务里,主 agent 的上下文是非常宝贵的资源。像搜索大型代码库、运行测试、排查错误、做长时间分析这类任务,往往会产生大量过程性噪音。如果把这些中间过程全部塞进主对话,不仅会污染主线上下文,也会降低后续推理和决策的质量。

因此,一个自然的做法是:spawn 一个 subagent,让它在独立的上下文中完成这些“脏活”。

主对话不需要消费完整过程,只需要接收一个总结性的结果。从 main-agent 的视角看,它只是调用了一个高阶工具AgentTool,然后等待(或稍后收到)一段总结文本,再将这段文本作为 tool_result 写回自己的上下文。换句话说,subagent 的引入并没有改变核心的 queryLoop 结构。

进一步看,它也是一种任务调度机制。

这种调度通常有两种形式:

  • 同步 subagent:像普通工具一样调用,阻塞等待结果

  • 异步 subagent:作为后台任务运行,主对话继续推进,结果稍后回收

一旦进入异步模式,系统就必须维护一个全局任务注册表(例如 Claude Code 中的 AppState.tasks),在后台持续运行,完成后通过信息注入的方式加入到主 agent 的 agent-loop 中。

当多个后台 subagent 同时运行时,subagent 的价值就不再只是 context isolation,也是 multi-agent orchestration 的起点。

Hooks

为了保持 agent-loop 的简洁,新的能力不应该继续往 loop 内部堆。

否则,一个本来只有“执行工具 → 捕获结果 → 追加上下文 → 再次调用LLM”四步的循环,很快就会被各式各样的业务逻辑拖成一个巨大的 if-else 状态机。

Hooks 的意义,就在于把这些复杂性移到 loop 外部。

通过 PreToolUse、PostToolUse、PreCompact、SubagentStop 等事件,harness 可以在关键节点捕捉状态、注入上下文、拦截风险、验证结果,而不必让 loop 自己理解所有规则。

因此,hooks 的本质不是“多几个扩展点”,而是把机制和策略分离:

  • loop 负责推进执行

  • hooks 负责施加控制

表面上看,hooks 只是提供了一堆事件名;但更重要的是,这些事件定义了 Agent 系统中的关键边界。

一旦边界清晰,很多能力就不再需要直接修改 loop 本身,而是可以通过外部策略注入:

  • 安全策略可以挂在工具调用前后

  • 记忆治理可以挂在 compact 前后

  • 任务编排可以挂在 subagent 生命周期上

  • …

边界组件

除了上文提到的六大核心组件,还有一些常被讨论的概念。它们并非每个都是必需品,但理解它们的位置有助于避免过度设计。

Checkpointing / Recovery

对于 Long-running Agent 来说,错误恢复和状态检查点确实重要。但从 Harness 的视角看,Checkpointing 更像是一种跨组件的横切能力:File System 负责持久化,Hooks 负责在关键节点触发保存,Agent Loop 负责从断点恢复。它很难被单独抽象为一个独立的"组件”,而是各个核心组件协作的产物。

Planner / Todo-list

还记得 2026 年初,Claude Code 取消了内置的 todo-list 工具。原因很直接:新版本模型的 reasoning 能力已经足够强,不再需要人为维护一个显式的待办列表。这恰好印证了 Bitter Lesson 的预言——你今天写的 Planning 模块,很可能就是明天第一个被拆除的辅助组件。如果一定要做,请确保它能被干净地剥离,而不是和 Loop 深度耦合。

Skills

Skills 本质上是核心组件的组合产物:一个 Command Registry 加上按需的 Message Injection,以及一堆md文件。它不属于 Harness 的底层,而是 Harness 之上的应用层。

MCP / Plugins

MCP是一个协议层,不是 Harness 本体。支持 MCP 当然是个加分项,但它解决的是"如何暴露外部资源"的问题,而非"Harness 应该具备哪些核心能力"的问题。

Memory

Memory 无疑是重要的,但截至目前,业内尚未形成共识的形态。无论是 OpenClaw 还是 Claude Code,普遍采用基于 Markdown 文件的轻量级记忆方案。这种"文件即记忆"的方式虽然朴素,却恰好符合 Harness 的极简哲学——与其造一个复杂的记忆数据库,不如让 Agent 用最熟悉的文件接口来管理自己的长期状态。

Agent Team and Multi-agent

扩展到多 Agent 时,每个 Agent 内部的 Harness 组件完全不变——同样的 agent loop、同样的 context 管理、同样的原子工具。唯一新增的是 Agent 之间的连接方式。

如果你的 Harness 为单 Agent 设计得足够好,扩展到 team 时,90% 的基础设施可以直接复用。Subagent 和 Agent Team Member 的区别可以用下表概括:

维度 Subagent Agent Team Member
生命周期 任务完成 → 销毁 跨任务存活,可能运行数小时
身份 匿名(只有 task 描述) 有角色身份(“reviewer”、“coder”、“tester”)
状态 无状态,结果返回后消失 有持久状态(自己的 context 历史、记忆文件)
生成方式 主 agent spawn 预先定义 / 动态 spawn 均可

从 Harness 的角度,多 Agent 系统需要额外提供:

  • Agent 注册表:谁在跑、角色是什么、当前状态

  • 生命周期钩子:on_spawn、on_idle、on_terminate

  • 优雅退出与资源回收:这是最容易被忽视、也最关键的一点

Subagent 是单向的(主 agent 发任务 → subagent 返回结果),而 Agent Team 需要双向甚至多向通信。但通信方式的设计,依然应该遵循"贴合 LLM 习惯"的原则:共享文件系统本身就是最自然的通信通道。

Harness Engineering = Bigger Loop

受限于篇幅,这里不展开太多 Harness Engineering 的内容。借用这篇文章 Harness Engineering 在讨论什么:三个 Scaling 维度的统一框架 的观点,Harness Engineering 的核心关键词是 Scalability——时间的延展、空间的扩展、以及交互方式的进化。

从笔者的角度,私认为Harness Engineering 和compound-Engineering 是同义词,真正的价值在于 如何让 Agent 越跑越好?

这一切的前提,都是一个好用的 Harness 加上一个更大的 Loop。

一个完整的 Agent 系统存在两个循环:

  • Inner Loop(Agent Loop):单次任务内的"工具调用 → 结果捕获 → 上下文追加 → 下一步决策"循环。这是本文的核心讨论对象。

  • Outer Loop(Evolution Loop):跨任务的"执行 → 评估 → 反馈 → 改进"循环。这是 Harness Engineering 的核心讨论对象。

这些内容在 Andrej Karpathy 的autoresearch 或者是 Ralph Loop 中都能看到。

Outer Loop 不需要另起一套架构,它是 Inner Loop 的核心组件在更大时间尺度上的复用。 Hooks 提供观测点,File System 提供持久化记忆,Subagent 提供并行实验能力,Context 管理保证运行不会失控。

好 Harness 的设计原则

1. 极简性 (Minimality)

能不加的组件就不加。每个组件都问自己:

“如果去掉它,agent 是完全不能跑,还是只是跑得没那么好?”

前者是核心,后者是辅助。

2. 可拆卸性 (Removability)

辅助组件必须能被干净地移除,而不是和核心组件纠缠在一起。

这是 Bitter Lesson 的工程实践:你今天写的东西,

要让六个月后的自己能轻松删掉。

3. 模型无关性 (Model Agnosticism)

Harness 不应该为某个特定模型的怪癖做特殊适配。

好的 harness 换一个模型,改个 API 调用就能跑。

(当然,针对特定模型的 prompt 优化是另一回事)

4. 面向进化 (Evolution-Ready)

Harness 的终极目标不是"跑一个任务",

而是"提供一个让 agent 越跑越好的环境"。

每个组件的设计都应该考虑:

它如何为 Outer Loop 贡献数据、反馈、或可调参数?

结语

Agent Harness 不是越复杂越好。恰恰相反,它的价值在于克制。

2023-2026 年的 Agent 发展史,本质上是一部"人为控制逻辑不断被模型能力淘汰"的历史。Harness 的真正使命,是为模型提供一个稳定、安全、可进化的运行环境,然后把决策权交还给模型本身。

更多阅读

Anthropic: Effective harnesses for long-running agents

learn-claude-code

OpenAI: Harness engineering: leveraging Codex in an agent-first world

Learning the Bitter Lesson

Agent Frameworks, Runtimes, and Harnesses - oh my!

Harness design for long-running application development

Difference Between Agent Harnesses & Agent Frameworks

Harness Engineering Is Cybernetics

The importance of Agent Harness in 2026

The Claude Code SDK and the Birth of HaaS (Harness as a Service)

Agent design lessons from Claude Code

Agent Harness is the Real Product

Harness capabilities

Agents 2.0: From Shallow Loops to Deep Agents