本章目标:引入全书最核心的概念——Agent Harness(运行时框架)。在第 2 章「LLM Application 的基本架构」和第 3 章「Agent Loop 是最核心的 100 行代码」的基础上,本章回答一个承上启下的问题:把模型、上下文、工具、循环这些”零件”装配成一台能自主工作的机器的,到底是什么?答案就是 Harness。理解 Harness 的定义、边界与职责,是读懂后面 Claude Code 源码分析(Part III)和动手实现 Mini Claude Code(Part IV)的前提。
4.1 Harness 的定义
在给出定义之前,先回到第 2 章的结论。第 2 章讲了 LLM 应用的七大组成:Model、Prompt、Context、Tool、Memory、State、Runtime。其中,前六个是”零件”,而 Runtime 是把它们装配成能跑的机器的流水线。
但第 2 章讲的 Runtime 是”最简陋”的形态——它只负责组织请求、调用模型、执行工具。对于一个只需”一问一答”的 LLM 应用,这已经够用了。可一旦应用进化成 Agent,模型要自主地、循环地、安全地操作真实世界,这个 Runtime 就必须扩展成一个更完整的系统:它要管循环(第 3 章)、要管权限、要管会话、要管成本。这个”扩展后的 Runtime”,就是 Harness。
Harness 这个词的原意是**”马具”**——套在马身上的缰绳、鞍具,用来驾驭和控制马匹。这个隐喻极其精准:
模型是一匹极其聪明但不可控的马,Harness 就是驾驭它的那一整套缰绳和鞍具。
由此可以给出 Harness 的工程化定义:
Agent Harness 是包裹在 LLM 之外的运行时框架,它负责把模型的推理能力,转化为可靠的、安全的、可控的、有状态的真实世界行动。
更技术化地讲,Harness 是连接”模型”与”真实世界”之间的一整套软件系统。它要做四件事,而这四件事恰好对应第 2 章说的”模型无状态、只能文本进文本出”这一根本约束:
- 翻译进:把”要做什么”翻译成模型能理解的文本(上下文)。
- 翻译出:把模型的”意图”翻译成真实的动作(工具执行)。
- 翻译回:把”动作的结果”翻译回模型能理解的文本(工具结果)。
- 控制与记录:确保前三件事可靠、安全、可观测、可恢复(循环、权限、会话、记忆、可观测性)。
这里有一个容易被忽视但极其重要的认知:Harness 不是一个可有可无的”包装层”,而是模型从”会说”到”会做”的必经桥梁。 没有它,模型永远只是一个”很会聊天的文本生成器”;有了它,模型才成为一个”能完成任务的 Agent”。
为了更直观地理解”Runtime 如何扩展成 Harness”,看一个从简单到复杂的演进例子。假设你要让一个 LLM 应用从”回答天气问题”进化到”自主帮我处理一天的待办”:
| 演进阶段 | 需要的 Runtime 能力 | 对应的 Harness 职责 |
|---|---|---|
| 一问一答 | 组织请求、调用模型 | 仅最基础的 Runtime |
| 调用一次工具 | 工具定义 + 工具执行 | Tool Runtime |
| 连续做多件事 | 循环”生成→执行→观察” | Agent Loop |
| 记住用户偏好 | 跨会话持久化 | Memory |
| 不让它乱删文件 | 权限校验 | Permission |
| 崩溃后能恢复 | 状态持久化 | Session |
| 事后能审计 | 记录每一步 | Observability |
可以看到,每一次能力的跃迁,都不是”模型变聪明了”,而是 Runtime 增加了一项职责。当这些职责累积到一定程度,这个 Runtime 就不再是第 2 章那个”简陋的胶水层”,而是一个完整的 Harness。这也解释了为什么 Harness 是”长出来”的,而不是”凭空发明”的。
注:第 1 章给出过
Agent = LLM + Harness的公式。请把这里的”LLM”理解为”模型”的泛指(Anthropic 的 Claude、OpenAI 的 GPT、Google 的 Gemini,以及本地部署的 Llama、Qwen、DeepSeek 等),而非特指某一家。Harness 与具体模型无关,这正是它作为”基础设施”的价值所在。
4.2 Model vs Agent vs Harness
这是全书最需要厘清的一组概念。很多人把三者混为一谈,但它们分属三个不同的抽象层次。第 1 章已经给过公式,本节做更精确的工程化区分。
4.2.1 Model(模型)
模型是一个纯函数:输入 token 序列,输出 token 序列。第 2 章已经强调过它”无状态”——不记得上一次调用、不保存任何状态、不产生任何副作用。
模型的价值在于推理:理解、规划、判断、生成。但模型不能自己读文件、执行命令、修改数据库。
4.2.2 Agent(智能体)
Agent 是一个行为主体:它能感知环境、做出决策、执行动作。按第 1 章的定义:
Agent = LLM + Harness
Agent 的价值在于完成目标:给定一个目标,它能自主地分解、执行、验证,直到目标达成。
4.2.3 Harness(运行时框架)
Harness 是基础设施:它提供 Agent 运行所需的全部”环境”。它不思考、不直接执行,它负责”思考之外、执行之间”的一切。
4.2.4 三者关系的一个类比
| 抽象 | 类比 | 它做什么 / 它不做什么 |
|---|---|---|
| Model | CPU | 只做纯计算,不认识内存与文件 |
| Harness | 操作系统 | 管理内存、文件、进程、权限、信号 |
| Agent | 跑在 OS 上的程序 | 由 OS 提供环境,由 CPU 提供计算 |
这个类比贯穿全书(第 54 章会完整展开”Harness ≈ 操作系统”)。它揭示了一个关键认知:Model、Agent、Harness 是三个不同的抽象层次,而不是同一个东西的三个名字。 混淆它们,会导致架构设计上的方向性错误——比如以为”换个更强的模型”就能解决”Agent 不可靠”的问题,而忽略了真正该改进的是 Harness。
4.2.5 一个来自 Claude Code 源码的实证
“模型是被 Harness 调用的对象”这个判断,不是文字游戏,而是有源码支撑的。在 Claude Code(2026-03-31 版本,源码目录 D:\Work\ClaudeCode\claude-code-20260331)中,Harness 的核心引擎是 QueryEngine 类,它启动时需要注入一整套依赖:
<em>// src/QueryEngine.ts: QueryEngineConfig(节选)</em>
<em>// 这是 Harness 启动时需要的"环境注入"——每一项都对应 Harness 的一项能力</em>
export type QueryEngineConfig = {
cwd: string <em>// 工作目录</em>
tools: Tools <em>// 工具注册表</em>
mcpClients: MCPServerConnection[] <em>// MCP 客户端</em>
agents: AgentDefinition[] <em>// 子智能体定义</em>
canUseTool: CanUseToolFn <em>// 权限裁决函数</em>
getAppState: () => AppState <em>// 应用状态(读写)</em>
maxTurns?: number <em>// 最大轮次</em>
maxBudgetUsd?: number <em>// 成本预算</em>
taskBudget?: { total: number } <em>// 任务预算</em>
abortController?: AbortController <em>// 全局中断信号</em>
userSpecifiedModel?: string <em>// ← 模型只是“可替换的字符串标识”</em>
fallbackModel?: string <em>// ← 而非引擎里写死的一部分</em>
<em>// ...</em>
}
注:这段代码的关键不在于每个字段的名字,而在于模型不是以”引擎内置组件”的形式存在,而是以可配置的字符串标识(
userSpecifiedModel/fallbackModel)出现,真正的模型客户端由服务层(deps)解析。这说明模型是被 Harness 调配的可替换资源,而非反过来。把 Harness 理解成”可依赖注入的运行时框架”,意味着可以通过替换依赖(换模型、换工具、换权限策略)而非修改框架来调整 Agent 能力——这正是 Harness Engineering 区别于 Prompt 调优的关键所在。
4.3 Harness 的核心职责
Harness 到底负责什么?可以用下面这张图看清它的完整职责边界:
┌───────────────┐
│ LLM │
└───────┬───────┘
│
Reasoning / Tool Call
│
┌─────────▼─────────┐
│ Agent Harness │
├───────────────────┤
│ Agent Loop │
│ Context Manager │
│ Tool Runtime │
│ Permission │
│ Memory │
│ Session │
│ Hooks │
│ Subagents │
│ Observability │
└─────────┬─────────┘
│
┌─────────────┼──────────────┐
▼ ▼ ▼
Files Shell Network
这张图揭示了 Harness 的九大核心职责。每一项职责,本质上都在回答一个具体的问题:
| 职责 | 回答的问题 | 本书展开章节 |
|---|---|---|
| Agent Loop | Agent 如何持续推进任务? | 第 3、12、20 章 |
| Context Manager | 模型能看到什么? | 第 6、14、21 章 |
| Tool Runtime | 模型能做什么? | 第 7、13、19 章 |
| Permission | 模型不能做什么? | 第 8、22、31 章 |
| Memory | Agent 能记住什么? | 第 42 章 |
| Session | 运行状态如何保存、断点续跑? | 第 14、28、42 章 |
| Hooks | 如何扩展 Agent 的行为? | 第 12、26、40 章 |
| Subagents | 如何并行处理多个子任务? | 第 16、25 章 |
| Observability | Agent 到底做了什么? | 第 49 章 |
这九大职责可以归纳成一句话:
Harness 是”模型”和”真实世界”之间的一整套「翻译 + 控制 + 记录」系统。
翻译(Context、Tool),控制(Loop、Permission、Session),记录(Observability、Memory),扩展(Hooks、Subagents)。缺了任何一个,Agent 要么”做不了”、要么”会闯祸”、要么”不可知”。
这里值得强调一个判断:这九大职责,每一项都不是”可有可无的加分项”,而是”缺一不可的地基”。一个没有 Permission 的 Harness 是危险的;一个没有 Context Manager 的 Harness 是低能的;一个没有 Observability 的 Harness 是失控的。这正是第 4.6 节要论证的——Harness 不会随模型变强而消失,因为这九件事里,有太多是模型永远做不了的。
4.3.1 九大职责的源码落点
陈述边界:下面这张对照表是Claude Code 2026-03-31 源码匹配出来的,属于源码观察事实,而非概念推测。如果你想自己验证,对每一项用
grep都能在对应目录查到实体。
| Harness 职责 | Claude Code 中的对应源码实体 |
|---|---|
| Agent Loop | src/query.ts(约 1730 行,含 while(true) 主循环) |
| Context Manager | src/services/compact/(多种压缩策略) |
| Tool Runtime | src/services/tools/toolOrchestration.ts、tools: Tools |
| Permission | src/utils/permissions/、canUseTool: CanUseToolFn |
| Memory | src/services/SessionMemory/(会话存储与记忆) |
| Session | AppState(会话状态)、会话 JSONL 文件 |
| Hooks | src/hooks/、在查询循环中以 Pre/Post 形式嵌入 |
| Subagents | agents: AgentDefinition[]、src/tasks/、src/tools/AgentTool/ |
| Observability | src/utils/telemetry/、@opentelemetry/* 依赖 |
这张表的价值在于:它把”Harness 九大职责”从一个概念框架,落到了真实的文件与代码上。读者读完 Part III 的源码分析后回看这张表,会对 Harness 的组成有更扎实的理解。
4.4 Harness 为什么比 Prompt 更重要
一个流传甚广的误解是:”只要 Prompt 写得好,Agent 就能用得好。” 这个说法在 Agent 语境下是错误的,而且错得很危险。
第 2 章 2.1.2 节讲过一句关键判断:“Prompt 决定模型’想做什么’,而上下文决定模型’能知道什么’。” 现在把这句话再往上一层推:Prompt 决定的是”上限”(模型想做得多好),Harness 决定的是”下限”(模型实际能做到多少、会不会闯祸)。
举一个具体的例子。假设你写了一个极其精妙的 Prompt,让模型”帮我重构这个项目,提升性能”。然后:
- 如果 Harness 没有文件工具 → 模型只能”说说”,什么都做不了。
- 如果 Harness 没有权限控制 → 模型可能删掉重要文件。
- 如果 Harness 没有上下文压缩 → 重构到一半,上下文爆了,前功尽弃。
- 如果 Harness 没有测试执行 → 模型改完代码,你无法验证它改对没有。
更尖锐的说法是:Prompt 是”一次性”的,Harness 是”系统性”的。 Prompt 只影响”这一次对话”,而 Harness 决定了”每一次交互的天花板”。你可以为一个任务精心打磨 Prompt,但如果没有可靠的 Harness,那个 Prompt 再好也落不了地。
这就是为什么本书把 Harness 放在比 Prompt 更核心的位置。一个更深层的原因是:Prompt Engineering 会随着模型能力提升而逐渐贬值(模型越来越”听得懂人话”,不再需要费尽心思地”教”它),而 Harness Engineering 会随着 Agent 复杂度提升而越来越重要(Agent 越普及、越深入生产环境,安全、可靠、可观测的要求就越高)。
4.5 Harness Engineering
既然 Harness 如此重要,就应该有一门专门研究”如何构建 Harness”的工程学科。本书称之为 Harness Engineering(运行时框架工程)。
4.5.1 核心问题域
Harness Engineering 的核心问题域,覆盖第 4.3 节的九大职责(部分职责合并为同一问题域):
- 上下文工程:如何在有限的上下文窗口内,放入最有价值的信息?(第 6、14、21 章)
- 工具工程:如何设计、组织、调度工具,让模型高效可靠地使用它们?(第 7、13、19 章)
- 权限工程:如何在”让 Agent 有用”和”让 Agent 安全”之间找到平衡?(第 8、22、31 章)
- 循环与可靠性工程:如何让 Agent 持续推进任务,并在面对错误、超时、崩溃时依然可靠?(第 3、12、20、27、28 章)
- 记忆与状态工程:如何让 Agent 跨会话积累知识、可靠地断点续跑?(第 15、23 章)
- 扩展工程(Hooks):如何通过钩子等扩展点定制 Agent 的行为?(第 12、26、40 章)
- 多智能体工程(Subagents):如何用子智能体并行处理多个子任务?(第 16、25 章)
- 可观测与评估工程:如何追踪、调试、评估 Agent 的行为?(第 29、30 章)
4.5.2 与传统工程学的差异
Harness Engineering 与传统的后端工程、分布式系统工程有很深的渊源,但又有独特之处:它的核心对象是一个非确定性的智能体,而不是确定性的代码。 这让它的很多工程问题都是全新的——
- “如何防止模型被提示词注入(Prompt Injection)攻击?” —— 没有现成的输入校验模式可循(第 51 章)。
- “如何评估一个非确定性的 Agent 做得好不好?” —— 单元测试的传统断言无效(第 50 章)。
- “如何判断一个循环是’卡住了’还是’在思考’?” —— 经典超时机制失效(第 48 章)。
4.5.3 一个贯穿全书的类比
Harness Engineering 之于 Agent,就像操作系统工程之于计算机。
操作系统工程师不关心”CPU 有多快”(那是硬件的事),而关心”如何管理内存、调度进程、保证安全”。同样,Harness 工程师不关心”模型有多聪明”(那是模型厂商的事),而关心”如何管理上下文、调度工具、保证安全”。
这个类比也解释了 Harness Engineering 的一个特征:它的价值会随 Agent 复杂度上升而上升。 单机时代,操作系统是”锦上添花”;互联网时代,操作系统是”生死攸关”。Agent 越复杂、越普及,Harness Engineering 就越重要。
4.5.4 从”能用”到”生产可用”的鸿沟
一个值得警惕的现象是:大量 demo 级 Agent 项目停留在”能跑通一个用例”的阶段,却无法进入生产。这个鸿沟的本质,恰恰就是 Harness 的缺失。
作者观点:从”能用”到”生产可用”,需要补齐五件事——① 错误恢复(崩溃后能续跑);② 成本治理(不会把预算烧光);③ 权限边界(不会越权执行);④ 可观测(能追溯每一步);⑤ 可评估(能批量对比效果)。这五件事全部属于 Harness。也就是说:“能不能用”靠模型,”能不能进生产”靠 Harness。
这也呼应了第 4.4 节的判断——很多人把 Agent 项目失败归咎于”模型不够强”,实际上更常见的原因是 Harness 没搭好:没有权限,Agent 闯祸了;没有成本治理,Agent 把预算烧光了;没有可观测,出了问题无从排查。当你发现一个 Agent 项目”时灵时不灵”,先检查 Harness,再怀疑模型。
4.6 Model 能力提升后 Harness 是否会消失?
这是 Harness 领域最常被追问的问题:“既然模型越来越强,未来是不是就不需要 Harness 了?模型自己就能搞定一切?”
陈述边界:本节是作者观点,不是已被验证的事实。论证依据是 Claude Code 当前 Harness 的规模与职责划分,而非某种可量化的预测。
我的判断是明确的:Harness 不会消失,但它的形态会持续演变。 理由有三。
4.6.1 模型再强,也改变不了”它只是文本进、文本出”的事实
无论模型多聪明,它本质上仍然是一个只能接收文本、输出文本的黑盒。它不能自己读文件、不能自己执行命令、不能自己连接数据库。“模型生成意图,系统执行意图” 的架构分工,不会因为模型变聪明而改变。
这就好比:CPU 越来越快,但操作系统不会消失——因为 CPU 再快,也需要操作系统来管理内存、调度进程、提供文件系统。模型(CPU)和 Harness(操作系统)之间的分工,是由”计算单元 vs 系统环境”的本质差异决定的,而不是由能力强弱决定的。
4.6.2 安全责任永远在人,不在模型
模型没有法律主体性,无法承担”删库跑路”的责任。无论模型多聪明,只要 Agent 在操作真实世界,就必须有权限边界、审计日志、人机审批。这些安全机制,属于 Harness,不属于模型。
一个反例场景:一个被提示词注入攻击的模型,即使它”很聪明”,也会被诱导去执行危险操作。 这时候,能拦住它的不是”模型的聪明”,而是 Harness 的权限系统。安全不取决于模型多聪明,而取决于 Harness 多严密。 这一攻击向量在第 51 章”提示词注入防护”中展开。
4.6.3 一个反直觉的事实:Harness 代码规模巨大,并未随模型变强而缩水
源码观察:如果 Harness 真的会随模型变强而消失,我们应该能看到 Harness 代码规模递减。但实际恰恰相反——Claude Code 2026-03-31 源码里,仅 Harness 部分(不含模型调用、不含 UI)就涉及多达几十万行代码(单版本快照,证明”规模巨大”,而非”仍在增长”):
| 文件 | 行数 | 职责 |
|---|---|---|
src/QueryEngine.ts | 约 1297 | 会话生命周期与状态管理 |
src/query.ts | 约 1730 | 主循环 |
src/services/tools/toolOrchestration.ts | 约 189 | 工具编排 |
src/services/compact/ | 多文件 | 上下文压缩 |
src/utils/permissions/ | 多文件 | 权限系统 |
src/hooks/ | 多文件 | 钩子扩展点 |
src/services/mcp/ | 多文件 | MCP(模型上下文协议) |
Harness 代码规模远大于模型调用代码规模——这个事实强烈支持”Harness 不会消失”的判断。
4.6.4 但 Harness 的”重量”会转移
虽然 Harness 不会消失,但它的内部重心会随着模型能力提升而变化:
- 模型弱时:Harness 要花大量精力”引导模型”(写复杂 Prompt、做严格输出校验、大量自我纠正(Self-correction))。
- 模型强时:Harness 可以把更多”决策”交给模型,自己专注于”执行、安全、可靠性”这些模型永远做不了的事。
换句话说:Harness 会从”手把手教模型做事”,进化到”给模型搭一个安全可靠的工作台”。 前者会随模型变强而减轻,后者会随 Agent 应用变复杂而加重。
4.7 Harness 的边界
最后,必须清醒地认识到 Harness 的边界——它不是什么,它不能做什么。理解边界,比理解能力更重要,因为它决定了你不会把 Harness 神化,也不会过度设计它。
- Harness 不能替代模型的推理能力。Harness 提供的是”环境”,不是”智能”。如果模型本身推理能力不足,再好的 Harness 也救不了——让一个能力不足的模型配上顶级的 Harness,它仍然写不出合格的产品需求,因为它对”需求”这个概念的理解本身不到位。
- Harness 不是银弹。它不能把”糟糕的模型”变成”优秀的 Agent”,也不能把”不合理的需求”变成”可完成的任务”。
- Harness 的复杂度有代价。每增加一个机制(权限、压缩、子智能体),就增加一分复杂度和维护成本。一个过度设计的 Harness,可能比一个简单的 Harness 更难用、更容易出错。
- Harness 应该”恰到好处”。最好的 Harness 不是”功能最多”的,而是”刚好满足当前任务需要”的。这需要工程师对”要解决什么问题”有清晰的判断,而不是盲目堆砌功能。
一个务实的工程原则是:从最简单的 Harness 开始,只有当真实问题出现时,才增加相应的机制。 这正是 Part IV”从零实现 Mini Claude Code”所遵循的方法论——先写一个 100 行的 Agent,然后一步一步地、为解决真实问题而演进它。
这个”恰到好处”原则的反面是”过度工程”(Over-engineering)。很多团队在 Agent 项目里一上来就上”微服务 + 多智能体 + 完整可观测性”,结果连”让 Agent 可靠地读一个文件”都还没做好。Harness 的复杂度应该由真实需求驱动,而非由”看起来高大上”驱动。
本章小结
本章引入了全书最核心的概念——Agent Harness,核心要点:
- Harness 的定义:包裹在 LLM 之外的运行时框架,负责把推理能力转化为可靠、安全、可控、有状态的真实世界行动。隐喻是”马具”——模型是聪明的马,Harness 是驾驭它的缰绳和鞍具。
- Model / Agent / Harness 的清晰边界:Model 提供大脑(纯文本函数),Agent 提供行为(目标导向),Harness 提供基础设施(环境与安全)。三者是三个不同的抽象层次,混淆会导致方向性错误。
- Harness 九大职责:Loop、Context、Tool、Permission、Memory、Session、Hooks、Subagents、Observability——本质是「翻译 + 控制 + 记录」。每一项在 Claude Code 源码中都有对应实体。
- Harness 比 Prompt 更重要:Prompt 决定上限,Harness 决定下限;Prompt 是一次性的,Harness 是系统性的。
- Harness 不会随模型变强而消失(作者观点):从源码看,Harness 代码规模巨大;但其内部重心从”引导模型”转向”提供安全可靠的工作台”。
- Harness 应恰到好处:从最简单开始,按需演进,避免过度工程。
核心公式:Agent = LLM + Harness
LLM 负责理解、推理与生成;Harness 则负责将模型能力转化为可运行、可控制、可观测、可评测、可交付的 Agent 系统,包括任务编排、上下文与记忆、工具调用、权限控制、执行环境与沙箱、状态管理、观测、评测、错误恢复以及交付治理。
模型能力决定 Agent 的上限,而 Harness 能力决定 Agent 能否真正进入生产环境。
理解了 Harness 是什么、由哪些部分组成、边界在哪里,下一章我们将横向对比主流 AI Agent 架构(Claude Code、OpenAI Agents、LangGraph、Cline 等),在比较中更深刻地理解 Harness 的设计取舍。
更多内容:
《AI Agent 架构设计与工程实践指南》——从 LLM、Agent、Harness 到 Mini Claude Code – 编程开物
Comment