【Harness Engineering】01_为什么需要给 AI 代理造一个驾驶舱
源码地址https://github.com/wquguru/harness-books如果你最近在关注 AI 编程工具一定听说过 Claude Code。很多人把它看作一个“能跟你聊天、顺手改代码的 CLI”。但如果只看到这一层就错过了它设计里最有价值的部分。真正让 Claude Code 区别于“挂了个工具调用的 ChatGPT”的是一整套看不见的控制结构。作者在源码里把它称为Harness Engineering——你可以理解为给 AI 代理造一个驾驶舱。本文从工程视角聊清楚一个核心判断代理系统的关键能力不是“模型有多聪明”而是“系统有多能约束执行”。一、问题本质1.1 核心矛盾一个 LLM 如果只能输出文本最坏的情况是“它说得不太对”。但当它能访问 Shell、Git、文件系统和网络时问题性质就变了——从“回答不够好”变成了“执行可能造成实际破坏”。Harness Engineering 要处理的就是这个底层现实模型天然不值得信任。这不是对 AI 的道德评判而是一个工程前提。忽视它的系统最后多半会在事故记录和回滚日志里付出代价。1.2 设计目标所谓 Harness Engineering就是把一个不稳定的核心部件约束成可管理系统的那一套制度化控制平面。它要处理的现实只有一条模型并不天然值得信任。这个判断未必轻松但通常有用。二、第一层 Harness分层控制结构很多人对“控制 AI”的理解还停留在写一段漂亮的 system prompt。但 Claude Code 在实现上把 prompt 放进了运行时的控制结构里——它不只是“告诉模型该怎么做”而是规定了执行边界、失败行为和报告责任。2.1 身份与运行时分离从源码的组织方式可以看得很清楚系统先定义身份和总任务再补上关于工具、权限、系统提醒和上下文压缩的系统级说明最后补上做任务时的工程约束比如不要越权改动、不要把验证说成已经完成这说明了一个朴素的工程事实一个真正可用的代理系统不能依赖一段“万能提示词”解决所有问题。它必须把控制拆成层把层次拆成职责。否则新增一条禁令和旧规则冲突时系统行为会变得不可预测。2.2 分段拼装与优先级规则代码里很清晰地展示了这一点系统提示词是分段拼装的静态部分和动态部分严格分离memory、language、output style、MCP instructions 等内容按段注入默认 prompt、自定义 prompt、agent prompt 和 append prompt 之间有明确的优先级规则2.3 不变式三条硬约束1. 身份 ≠ 运行时 —— prompt 的分层必须完整 2. 工具受调度 —— 任何工具调用前必须经过调度决策 3. 错误进主路径 —— 可恢复错误必须走规定的恢复或终止路径这三条一旦被越过后面所有关于循环、工具、上下文和恢复的机制都会变得不可靠。三、第二层 Harness持续循环状态如果说 prompt 规定了系统“应该成为什么样的东西”那么 query loop 规定了它“实际上如何运行”。3.1 状态跨轮次传递Claude Code 的核心不在某个单独的 API 调用而在一个持续运行的 query loop。这个循环把以下内容全部放进同一个跨迭代状态里messages消息历史toolUseContext工具使用上下文autoCompactTracking自动压缩追踪maxOutputTokensRecoveryCount输出令牌恢复计数turnCount轮次计数transition状态转换一旦这么设计就等于正式承认上一轮留下的问题会进入下一轮系统必须有能力持续处理。3.2 Harness 思维的核心问题真正的问题不在于模型能不能答对这一轮而在于系统能不能在连续多轮里保持行为一致有没有预算概念有没有恢复概念有没有上下文膨胀后的自救机制有没有在工具调用失败后继续推进任务的能力缺少这些结构所谓的“智能体”就只是一个不稳定的执行者。3.3 调用前收回控制权这个循环在每轮调用前还会处理消息裁剪工具结果预算历史片段微压缩上下文塌缩处理自动压缩这些实现细节共同指向一点Claude Code 在调用发生前就尽量把控制权收回到运行时一侧。这也是为什么 Harness Engineering 不能被看作 prompt engineering 的附属品——前者关心状态机后者关心措辞。措辞当然重要但状态机决定系统行为最终由谁负责。四、第三层 Harness工具调用调度模型一旦能调用工具风险就从修辞层面跳到执行层面。这时候最核心的问题是谁决定工具怎么跑4.1 并发调度纪律Claude Code 的答案很明确运行时会根据工具属性决定并发还是串行。工具调用先经过分组系统读取工具 schema判断一个工具是否适合并发执行能并发的归一批不能并发的按顺序逐个执行并发路径中上下文修改器会先缓存再按原始顺序回放4.2 核心原则这背后有一个重要原则工具没有被当成模型能力的自然延伸而是被当成需要调度纪律的受管执行单元。缺少调度纪律的工具系统只会把模型的不稳定性放大到外部世界。尤其是在涉及文件、终端和权限的场景里保守的调度策略往往比激进的并发更可靠。4.3 为何保守并发如果不受约束就会扩大事故半径。Claude Code 在这一点上采取了偏保守的策略——在会碰到文件、终端和权限的场景里这种保守通常更可靠。五、第四层 Harness高风险工具的高密度约束在所有工具里Bash 最值得警惕。它几乎不受领域边界约束可以直接接触文件、进程、网络和 Git 仓库还会带上重定向、管道等复杂 shell 语义。5.1 操作规约Claude Code 对 Bash 的态度体现在一段详细的操作规约里不要乱改 git config不要跳过 hooks不要随手git add .不要在 pre-commit 失败后用--amend连带修改上一条提交不要在没有明确要求时提交不要默认 push5.2 核心原则有人会觉得这些规则过于细碎。但高风险接口天然需要高密度约束。Bash 一旦进入真实工作流很多规则必须明确写出来不能靠模型的“常识”去判断。Harness Engineering 的一个重要原则就是能力越强控制越细。原因很简单外部世界不会因为模型语气坚定就自动原谅一次错误执行。六、第五层 Harness失败是主路径很多软件把失败路径看作“例外”把成功路径看作“正文”。代理系统不能这么做。6.1 失败稳定存在代理系统的失败是稳定存在的不是偶发的模型会超 token会触发prompt too long会撞上max_output_tokens会遇到工具拒绝、用户打断、API 重试还会遇到 hook 阻塞等各种中断6.2 结构化处理如果这些情况都只在最后用几个catch打发掉系统表面上在运行实际上只是不断把麻烦往后滚。Claude Code 在 query loop 里把失败当作结构性条件来处理——在调用发生前就尽量把控制权收回到运行时一侧。6.3 与普通助手的差别普通助手先回答错了再道歉Harness 先约束再执行出错按恢复路径处理不靠临场发挥补救。一个会道歉的系统不一定成熟。一个知道何时不该开始、何时该重试、何时该中止、何时该准确汇报失败的系统才更接近成熟。七、总结7.1 五个源码位置指向同一结论源码位置结论constants/prompts.tsprompt 是控制平面的一部分不是人格装饰utils/systemPrompt.ts系统行为必须有清楚的分层优先级query.ts代理运行依赖持续的循环状态不是单次问答services/tools/toolOrchestration.ts工具调用必须服从调度纪律tools/BashTool/prompt.ts高风险工具必须伴随高密度约束7.2 Harness Engineering 不神秘它只是坚持了几条常被忽视的工程常识模型会犯错工具会扩大错误后果上下文会膨胀状态会污染下一轮用户会打断你失败会反复出现7.3 最终结论系统不能靠“聪明”维持秩序只能靠结构维持秩序。结构不像聪明那样显眼但通常更可靠。