什么是 Harness?
在 Claude Code 中,Harness(直译「线束」)是指包裹在 AI 模型外面的整个编排层。它不负责「思考」,而是负责「调度」——接收你的输入、调用模型、执行工具、检查权限、管理上下文窗口、处理错误。
如果 Claude 大模型是一位飞行员,那 Harness 就是整个驾驶舱——仪表盘、操纵杆、通信系统、安全系统。飞行员做决策,但驾驶舱确保这些决策能安全正确地执行。
大模型本身只是一个「输入文本 → 输出文本」的函数。让它变成一个能读文件、跑命令、管理 Git 的编程助手,靠的全是 Harness 这一层工程。
整体架构
Harness 分为四个层次,从外到内依次是:
有两个入口:CLI 模式通过 main.tsx 启动终端交互,SDK 模式通过 QueryEngine 类提供 headless 调用。两者最终都进入同一个 queryLoop。
核心循环 — queryLoop
整个 Harness 的心脏是 query.ts 中的 queryLoop() 函数——一个 async function*(异步生成器),用 while(true) 驱动每一轮对话。
async function* 的 yield 既能向外传递流式事件(让 UI 实时更新),又能在等待工具结果时暂停循环。这比回调或 Promise 链更自然地表达了「流式 + 多轮」的控制流。
循环维护一个 State 对象,每轮迭代在顶部解构读取,在 continue 点整体替换:
let state: State = { messages, // 消息历史 toolUseContext, // 工具执行上下文 autoCompactTracking, // 压缩追踪 turnCount, // 轮次计数 transition, // 跳转控制 ... }
消息管道
消息在送到 Claude API 之前,要经过一条 6 级处理管道。这是 Harness 最精巧的部分——因为上下文窗口有限,必须在有限空间里装下最有价值的信息。
想象你的书桌只能放 10 本书。每次工作前,你会:扔掉用完的草稿纸(Snip)→ 把笔记压缩成卡片(Micro Compact)→ 合并重复资料(Collapse)→ 如果还是放不下,把所有内容总结成一页纸(Auto Compact)。
工具执行
Claude 模型输出 tool_use 块时,Harness 负责实际执行这些工具(读文件、写文件、跑命令等)。有两种执行模式:
⚡ 流式执行
模型还在输出时就开始执行工具。不等完整响应。用 StreamingToolExecutor 实现。
// 模型流式返回 tool_use block 时 // 立即提交给执行器 for (const toolBlock of msgToolUseBlocks) { streamingToolExecutor.addTool( toolBlock, message ) }
📦 批量执行
等模型完整输出后再依次执行所有工具。通过 runTools 函数。更保守但更安全。
每个工具执行前后,都会经过 Hook 拦截和权限检查(下面两节详述)。
Hook 生命周期
Hook 是 Harness 的扩展机制——在关键节点插入自定义逻辑,不修改核心代码。一共有 7 个生命周期钩子:
Hook 就像生产线上的质检站。产品(消息/工具调用)在流水线上移动时,经过每个质检站都可能被检查、修改甚至退回。
权限系统
每次工具调用前,Harness 通过 canUseTool() 回调检查权限。权限模式决定了检查的严格程度:
Auto 模式下有一个 yoloClassifier(分类器),根据工具类型和参数判断操作是否安全。比如读文件几乎总是安全的,但 rm -rf / 就需要拦截。
// 权限检查的调用链 canUseTool(toolName, toolInput) → checkPermissionMode(mode) → yoloClassifier(tool) // auto 模式 → showPromptUI() // 需要确认时
Feature Gate
Claude Code 用 Bun 打包器的 feature() 函数做编译时功能开关。这不是运行时 if/else,而是在打包时直接删除代码(死代码消除)。
// 编译时决定:保留还是删除这段代码 const reactiveCompact = feature('REACTIVE_COMPACT') ? require('./reactiveCompact.js') : null
主要的 Feature Gate:
编译时消除意味着外部发布版本完全不包含实验性代码——不是隐藏,是物理删除。零运行时开销,零泄露风险。
错误恢复
Harness 内建多重恢复策略,确保对话不会因为一次错误就中断:
主模型高负载时,自动切换到 fallback model 重试
max_output_tokens 被截断时,自动重试(最多 3 次)
prompt 过长时,触发 reactive compact 或 context collapse 后重试
附件超限时移除图片、调整大小后重新发送
降级/重试时通过 tombstone 事件清理 UI 中的孤立消息
就像飞机有多套冗余系统——液压失灵用电动,主发动机停了还有辅助动力。Harness 的恢复策略确保单点故障不会让整个对话崩溃。
设计哲学
从源码中可以提炼出 Claude Code Harness 的 5 个核心设计原则:
🌊 异步生成器驱动
async function* 的 yield 既传数据又让出控制权,天然适配「流式输出 + 多轮工具调用」的场景。比回调地狱和 Promise 链都更优雅。
🔁 单循环 + 状态机
所有复杂性都收敛在一个 while(true) 中。通过 State 对象和 continue 跳转管理状态转换,避免了分散在多处的控制流。
🧱 编译时 Feature Gate
用 Bun bundler 的死代码消除做功能开关。不是运行时判断,是构建时物理删除。零开销,零泄露。
💉 依赖注入
核心循环通过 QueryDeps 接口注入 API 调用、压缩等依赖。测试时可以替换为 mock,不需要真实的网络请求。
🎣 Hook 扩展点
7 个生命周期钩子覆盖完整的 Agent 循环。用户可以在不修改核心代码的情况下,通过 settings.json 配置自定义行为。
以上分析基于 Claude Code 开源代码
generated by Claude Code