360 lines
16 KiB
Markdown
360 lines
16 KiB
Markdown
---
|
||
id: "2026-03-24-harness-engineering-analysis"
|
||
title: "Harness Engineering 分析 — learn-claude-code 仓库逆向解读"
|
||
slug: "harness-engineering-analysis"
|
||
status: "inbox"
|
||
content_type: "article"
|
||
channels: ["wechat", "x"]
|
||
language: "zh-CN"
|
||
source_urls:
|
||
- "https://github.com/shareAI-lab/learn-claude-code"
|
||
assets: []
|
||
cover_image: ""
|
||
template: "article"
|
||
owner: "content-forge"
|
||
created_at: "2026-03-24T00:00:00+08:00"
|
||
updated_at: "2026-03-24T00:00:00+08:00"
|
||
published_at: null
|
||
tags: ["harness-engineering", "agent-friendly", "claude-code", "agent-loop", "MCP"]
|
||
---
|
||
|
||
# Harness Engineering 分析
|
||
|
||
> 来源仓库:[shareAI-lab/learn-claude-code](https://github.com/shareAI-lab/learn-claude-code)
|
||
> 定位:将 Claude Code 架构逆向工程为 12 课的 Harness Engineering 教程
|
||
|
||
---
|
||
|
||
## 一、核心论点
|
||
|
||
### 1.1 Agent = Model,不是代码
|
||
|
||
```
|
||
Agent 的历史证据链:
|
||
|
||
2013 DeepMind DQN → 一个神经网络学会玩 49 款 Atari 游戏
|
||
2019 OpenAI Five → 五个网络打败 Dota 2 世界冠军 OG
|
||
2019 AlphaStar → 星际争霸 II 登顶 Grandmaster(前 0.15%)
|
||
2019 腾讯绝悟 → 王者荣耀 5v5 击败 KPL 职业选手
|
||
2024 LLM Coding Agents → 读代码库、写实现、调试、团队协作
|
||
|
||
共同真相:Agent 从来不是代码,Agent 始终是模型。
|
||
```
|
||
|
||
### 1.2 Harness = 驾驶舱,不是司机
|
||
|
||
```
|
||
Harness = Tools + Knowledge + Observation + Action + Permissions
|
||
|
||
模型决定。Harness 执行。
|
||
模型推理。Harness 提供上下文。
|
||
模型是司机。Harness 是车辆。
|
||
```
|
||
|
||
### 1.3 对 "Prompt Plumbing" 的批判
|
||
|
||
仓库明确批判了一整个行业:拖拽工作流构建器、无代码 "AI Agent" 平台、Prompt 链编排库——它们不是 Agent,是"带有幻想的 shell 脚本"。
|
||
|
||
> "You cannot engineer your way to agency. Agency is learned, not programmed."
|
||
|
||
---
|
||
|
||
## 二、12 课架构
|
||
|
||
### 2.1 全景层级图
|
||
|
||
```
|
||
Phase 1: 循环 Phase 2: 规划与知识
|
||
┌───────────────────┐ ┌───────────────────┐
|
||
│ s01 Agent Loop │ │ s03 TodoWrite │
|
||
│ 30 行 Python │ │ 模型自管计划 │
|
||
│ = 完整 Agent │ │ 一次一个 in_prog. │
|
||
│ │ │ │
|
||
│ s02 Tool Use │ │ s04 Subagent │
|
||
│ 调度映射表 │ │ 上下文隔离 │
|
||
│ 路径沙箱 │ │ 子任务清洁上下文 │
|
||
│ │ │ │
|
||
│ │ │ s05 Skills │
|
||
│ │ │ 两层按需加载 │
|
||
│ │ │ │
|
||
│ │ │ s06 Compact │
|
||
│ │ │ 三层上下文压缩 │
|
||
└───────────────────┘ └───────────────────┘
|
||
|
||
Phase 3: 持久化 Phase 4: 团队
|
||
┌───────────────────┐ ┌───────────────────┐
|
||
│ s07 Task System │ │ s09 Agent Teams │
|
||
│ 任务 DAG 磁盘持久 │ │ 持久化队友 + 邮箱 │
|
||
│ 依赖自动解锁 │ │ │
|
||
│ │ │ s10 Protocols │
|
||
│ s08 Background │ │ 结构化握手协议 │
|
||
│ 后台线程异步执行 │ │ shutdown/plan │
|
||
│ 通知队列注入 │ │ │
|
||
│ │ │ s11 Autonomous │
|
||
│ │ │ 自组织领取任务 │
|
||
│ │ │ 60s 空闲自动退出 │
|
||
│ │ │ │
|
||
│ │ │ s12 Worktree │
|
||
│ │ │ Git worktree 隔离│
|
||
│ │ │ 控制面 + 执行面 │
|
||
└───────────────────┘ └───────────────────┘
|
||
```
|
||
|
||
### 2.2 每课核心机制
|
||
|
||
| 课 | Harness 层 | 核心机制 | 代码量 |
|
||
|---|-----------|---------|--------|
|
||
| s01 | Loop | `while True` + `stop_reason != "tool_use"` 退出 | 3.6KB |
|
||
| s02 | Tool dispatch | `{tool_name: handler}` 调度映射 + `safe_path()` 沙箱 | ~5KB |
|
||
| s03 | Planning | TodoManager 状态机(pending→in_progress→completed),一次一个 | ~7KB |
|
||
| s04 | Context isolation | 子 Agent 清空 messages,只返回摘要文本 | ~9KB |
|
||
| s05 | Knowledge | 两层注入:系统提示含索引(~100 token/skill)+ load_skill 工具返回全文 | ~11KB |
|
||
| s06 | Compression | 三层压缩:每轮微压 → 50K token 自动压 → 手动压缩工具 | ~14KB |
|
||
| s07 | Persistence | JSON 文件 DAG,blockedBy/blocks 依赖,完成自动解锁 | ~17KB |
|
||
| s08 | Async | 守护线程 + 通知队列,每次 LLM 调用前排空队列 | ~19KB |
|
||
| s09 | Teams | 持久化队友 + JSONL 邮箱,WORKING↔IDLE↔SHUTDOWN 生命周期 | ~21KB |
|
||
| s10 | Protocols | request_id FSM(pending→approved/rejected),一个状态机两种协议 | ~23KB |
|
||
| s11 | Autonomy | IDLE 轮询(5s 间隔)+ 任务板自主领取 + 身份重注入 | ~25KB |
|
||
| s12 | Isolation | Git worktree 绑定 Task ID,控制面(.tasks/) + 执行面(.worktrees/) | 25.9KB |
|
||
|
||
### 2.3 设计不变量
|
||
|
||
每一课都叠加在 s01 的循环之上,**循环本身从不改变**:
|
||
|
||
```python
|
||
# s01: 永不改变的核心循环
|
||
while True:
|
||
response = client.messages.create(
|
||
model=model,
|
||
system=system_prompt,
|
||
messages=messages,
|
||
tools=tools
|
||
)
|
||
|
||
# 模型决定何时停止
|
||
if response.stop_reason != "tool_use":
|
||
break
|
||
|
||
# Harness 执行工具调用
|
||
for block in response.content:
|
||
if block.type == "tool_use":
|
||
result = dispatch[block.name](block.input)
|
||
messages.append(tool_result(block.id, result))
|
||
```
|
||
|
||
---
|
||
|
||
## 三、Harness Engineering 七原则
|
||
|
||
### P1: 循环永不改变(The Loop Never Changes)
|
||
|
||
每一课在循环**周围**添加机制,而非**修改**循环。Agent(模型)拥有循环;Harness 拥有机制。
|
||
|
||
### P2: 工具是 Agent 的手(Tools Are Hands)
|
||
|
||
原子、可组合、描述清晰。调度映射模式(`{name: handler}`)意味着添加能力无需改变核心。
|
||
|
||
### P3: 知识按需加载,不预加载(Knowledge On-Demand)
|
||
|
||
两层 Skill 加载——系统提示中的廉价索引(~100 token)+ tool_result 中的昂贵内容(~2000 token)——是标准模式。
|
||
|
||
### P4: 上下文是珍贵资源(Context Is Precious)
|
||
|
||
三种策略保护上下文:子 Agent 隔离(s04)、三层压缩(s06)、磁盘持久化(s07)。
|
||
|
||
### P5: 约束聚焦,非限制(Constraints Focus, Not Limit)
|
||
|
||
"一次一个 in_progress"(s03)、"只读子 Agent"(s04)、"路径沙箱"(s02)——都是让模型性能**更好**的护栏。
|
||
|
||
### P6: 持久化跨越会话(Persistence Outlives Sessions)
|
||
|
||
磁盘任务(s07)、团队配置 JSON(s09)、事件 JSONL(s12)——Harness 维护模型上下文窗口无法持有的状态。
|
||
|
||
### P7: 信任模型(Trust the Model)
|
||
|
||
最强主题。不预设工作流。不构建决策树。给工具和知识,让模型推理。
|
||
|
||
> "You are not writing intelligence. You are building the world intelligence inhabits."
|
||
|
||
---
|
||
|
||
## 四、附带 Skills
|
||
|
||
### agent-builder
|
||
|
||
核心哲学:"模型已经知道如何做 Agent。你的工作是让开。"
|
||
|
||
三要素:Capabilities(能做什么)+ Knowledge(知道什么)+ Context(发生了什么)
|
||
|
||
渐进复杂度:从 3-5 个能力起步。大多数 Agent 不需要超过 Level 2(规划)。
|
||
|
||
反模式清单:过度工程、工具太多、刚性工作流、预加载知识、微管理。
|
||
|
||
### mcp-builder
|
||
|
||
MCP Server 构建模板(Python + TypeScript)。最佳实践:清晰工具描述、输入验证、错误处理、默认异步、安全、幂等。
|
||
|
||
### code-review
|
||
|
||
五维审查:安全(Critical)→ 正确性 → 性能 → 可维护性 → 测试。结构化输出:摘要 + 关键问题 + 改进 + 亮点 + 结论。
|
||
|
||
### pdf
|
||
|
||
PDF 读取(pdftotext/PyMuPDF)、创建(pandoc/reportlab)、合并/拆分。实用工具检测 + 大文件逐页处理。
|
||
|
||
---
|
||
|
||
## 五、与 Agent Friendly 开发规约的对照
|
||
|
||
### 5.1 同一枚硬币的两面
|
||
|
||
```
|
||
┌──────────────────────────────────────────────────────────┐
|
||
│ │
|
||
│ Agent Friendly 规约 Harness Engineering │
|
||
│ (被调用方视角) (构建方视角) │
|
||
│ │
|
||
│ "怎么让 Agent 用好 "怎么给 Agent 建好 │
|
||
│ 你的系统" 运行环境" │
|
||
│ │
|
||
│ ┌──────────┐ ┌──────────┐ │
|
||
│ │ 你的 API │◀── MCP ──────────▶│ Agent │ │
|
||
│ │ 你的工具 │ A2A │ Harness │ │
|
||
│ │ 你的文档 │ │ 循环+工具 │ │
|
||
│ └──────────┘ └──────────┘ │
|
||
│ │
|
||
│ 规约约束: Harness 约束: │
|
||
│ - Schema-First - 循环永不改变 │
|
||
│ - 工具设计 7 子规约 - 工具原子可组合 │
|
||
│ - 10 条安全约束 - 路径沙箱 │
|
||
│ - 25 条 NEVER - 信任模型 │
|
||
│ │
|
||
└──────────────────────────────────────────────────────────┘
|
||
```
|
||
|
||
### 5.2 概念映射表
|
||
|
||
| Harness Engineering 概念 | Agent Friendly 规约对应 | 关系 |
|
||
|---|---|---|
|
||
| **Agent Loop**(s01)| — | Harness 独有概念,规约不涉及 Agent 内部循环 |
|
||
| **Tool dispatch map**(s02)| §2 Tool Design 7 子规约 | 构建方的调度 = 被调用方的 Schema |
|
||
| **safe_path() 沙箱**(s02)| §4.1 Least Agency | 同一约束的两侧实现 |
|
||
| **TodoWrite 一次一个**(s03)| P2 约束>能力 | 约束聚焦的典型实例 |
|
||
| **Subagent 上下文隔离**(s04)| §4 安全 / Sandbox | 隔离是双方共识 |
|
||
| **Skill 两层加载**(s05)| §5 文档发现层 (llms.txt) | 索引层+内容层 = 同一模式 |
|
||
| **Context Compact**(s06)| — | Harness 独有(管理 Agent 内部记忆) |
|
||
| **Task DAG 磁盘持久**(s07)| Agent Skills 标准 | 持久化知识的不同形式 |
|
||
| **Background tasks**(s08)| — | Harness 独有(异步执行管理) |
|
||
| **Team mailbox**(s09)| A2A 协议 | 邮箱 = 简化版 A2A |
|
||
| **Shutdown/Plan protocols**(s10)| HITL + Agent 协商 | 结构化握手 = Agent 间礼仪 |
|
||
| **Autonomous task claiming**(s11)| Agent Card 发现 | 自组织 = 去中心化发现 |
|
||
| **Worktree isolation**(s12)| §4 Sandbox / MicroVM | 目录隔离 ≈ 轻量级沙箱 |
|
||
| **"Trust the model"**(全局)| P2 约束>能力 | 同一哲学的不同表达 |
|
||
| **mcp-builder skill** | §2 + §3 全部 | MCP Server 构建 = 规约的执行 |
|
||
|
||
### 5.3 互补关系全景
|
||
|
||
```
|
||
Agent Friendly 完整画面
|
||
────────────────────────
|
||
|
||
被调用方(你的系统) 构建方(Agent Harness)
|
||
════════════════ ═══════════════════
|
||
|
||
§5 发现层 s05 Skill 两层加载
|
||
llms.txt / Agent Card 系统提示索引 + 按需加载
|
||
│ │
|
||
│ Agent 找到你 │ Agent 获取知识
|
||
▼ ▼
|
||
§2 工具设计 s02 Tool dispatch
|
||
Schema / 描述 / 注解 调度映射 + 沙箱
|
||
│ │
|
||
│ Agent 理解你 │ Agent 执行工具
|
||
▼ ▼
|
||
§3 API 设计 s01 Agent Loop
|
||
10 条 AX 原则 while True 核心循环
|
||
│ │
|
||
│ Agent 调用你 │ Agent 决策
|
||
▼ ▼
|
||
§4 安全规约 s04/s12 隔离
|
||
10 条安全约束 子 Agent + Worktree
|
||
│ │
|
||
│ Agent 安全运行 │ Agent 安全执行
|
||
▼ ▼
|
||
§6 评估规约 agent-builder skill
|
||
Postman 48 / 10 项评分 渐进复杂度 + 反模式
|
||
│ │
|
||
└───────────┬───────────────┘
|
||
│
|
||
▼
|
||
┌────────────────┐
|
||
│ Agent 成功完成 │
|
||
│ 用户的任务 │
|
||
└────────────────┘
|
||
```
|
||
|
||
### 5.4 核心差异
|
||
|
||
| 维度 | Agent Friendly 规约 | Harness Engineering |
|
||
|------|-------------------|-------------------|
|
||
| **视角** | 被调用方(API/工具提供者) | 构建方(Agent 运行环境) |
|
||
| **关注点** | 接口契约、发现性、安全 | 循环、上下文、持久化 |
|
||
| **不涉及** | Agent 内部循环和记忆管理 | API/工具的 Schema 设计 |
|
||
| **核心动词** | "暴露"、"描述"、"约束" | "加载"、"隔离"、"持久化" |
|
||
| **评估方式** | 量化评分(48 Checks) | 12 课渐进验证 |
|
||
| **共识** | 约束 > 能力;信任模型;Schema-First | 约束聚焦;信任模型;循环不变 |
|
||
|
||
---
|
||
|
||
## 六、整合洞察
|
||
|
||
### 6.1 Agent Friendly 的完整定义(整合后)
|
||
|
||
```
|
||
Agent Friendly = 被调用方友好 + 构建方友好
|
||
|
||
被调用方友好(规约):
|
||
让 Agent 能发现、理解、调用、验证你的系统
|
||
|
||
构建方友好(Harness):
|
||
让 Agent 有清晰的感知、精准的行动、丰富的知识、安全的边界
|
||
|
||
两者的交汇点:
|
||
工具设计 ←→ 工具调度
|
||
文档发现 ←→ 知识加载
|
||
安全约束 ←→ 沙箱隔离
|
||
Agent 协议 ←→ 团队通信
|
||
```
|
||
|
||
### 6.2 为什么两个视角都需要
|
||
|
||
```
|
||
只有规约(被调用方):
|
||
→ Agent 能找到你的 API,但不知道怎么高效使用
|
||
→ 好的菜单,但没有好的厨房
|
||
|
||
只有 Harness(构建方):
|
||
→ Agent 有好的运行环境,但外部工具难以对接
|
||
→ 好的厨房,但食材(API)质量参差不齐
|
||
|
||
两者结合:
|
||
→ Agent 能发现好的工具 + 在好的环境中高效使用它们
|
||
→ 好的厨房 + 好的食材 = 好的菜
|
||
```
|
||
|
||
### 6.3 共享的哲学根基
|
||
|
||
两个视角共享三条根本信念:
|
||
|
||
**信念 1:模型比你想的更聪明**
|
||
- 规约:不要猜测 Agent 的意图,给它好的 Schema 它会自己搞定
|
||
- Harness:不要预设工作流,给它工具和知识让它推理
|
||
|
||
**信念 2:约束是最好的礼物**
|
||
- 规约:NEVER 清单比功能列表更重要(§10.7 约束>能力)
|
||
- Harness:一次一个 in_progress 让模型更专注(s03)
|
||
|
||
**信念 3:好设计是透明的**
|
||
- 规约:好的工具描述让 Agent 像读文档一样理解接口
|
||
- Harness:好的循环设计让你几乎忘记它的存在
|