type
Post
status
Published
date
Apr 3, 2026
slug
Harness-Engineering-002
summary
搭建Mini Harness
tags
Agent
category
Harness Engineering
icon
password
手搓 Mini Harness:用 11 个机制从零搭建一个生产级 AI Agent 控制框架
不用 LangChain,不用 LangGraph,不用任何 Agent 框架。用最裸的 Python + OpenAI SDK,从零搭建一个包含 11 个安全机制的 AI Agent 控制平面,并诚实回答一个问题:Harness 到底值不值?
一、背景:Agent 不是智能体,是一个脆弱的循环
一个基本事实:AI Agent 不是智能实体,而是一个由代码组成的、可以反复调用 LLM 的 while 循环。 这个循环本身非常脆弱——它会循环失控、会吞掉工具报错、会在长会话中把自己搞傻、会无声无息地烧掉你的钱。
这些脆弱点被归纳为 八大故障模式:
编号 | 故障模式 | 典型表现 |
① | 循环失控 | Agent 陷入无限循环,反复调用同一个工具 |
② | Context 溢出 | 长会话中上下文窗口被撑爆 |
③ | Cache Miss | 重复计算导致成本飙升 |
④ | Tool 错误吞 | 工具执行失败被静默忽略,Agent 基于错误结果继续推理 |
⑤ | 状态丢失 | 任务中断后无法续跑,前功尽弃 |
⑥ | 缺权限闸 | Agent 可能执行危险命令(如 rm -rf) |
⑦ | 缺自动化评审 | LLM 自审等于作者自审,天然有偏差 |
⑧ | 成本失控 | 异常循环导致 API 费用无限增长 |
针对这八大故障模式,Harness Engineering 使用了 11 个机制(8 核心 + 3 扩展):
编号 | 机制 | 救的故障模式 | 实现文件 |
① | Agent Loop | ① 循环失控 | core.py |
② | Tool Use | ④ tool 错误吞 | core.py |
③ | Progress Tracking | ⑤ 状态丢失 | progress.py |
④ | Context Management | ② context 溢出 / ③ cache miss | context.py |
⑤ | Feature List | ② context 溢出(源头防控) | planner.py |
⑥ | Verification Loop | ④ tool 错误吞(下游验证) | verifier.py |
⑦ | Subagents | ② context 溢出 / ⑧ 成本失控 | subagent.py |
⑧ | Generator-Evaluator | ⑦ 缺自动化评审 | evaluator.py |
⑨ | Permission Gate | ⑥ 缺权限闸 | permission.py |
⑩ | Hooks | 贯穿所有机制的事件挂钩基础设施 | hooks.py |
⑪ | Token Budget | ⑧ 成本失控 | budget.py |
本文将逐一拆解这 11 个机制的核心实现,并在最后用一组真实的 E2E 对比数据来回答那个核心问题。
二、项目骨架:11 个文件 = 1 个配置中心 + 10 个机制模块
整个 Mini Harness 刻意不使用任何 Agent 框架——目的不是省事,而是看清裸骨架:每一块肌肉是什么、做什么、怎么连接。框架会帮你隐藏复杂度,但代价是你不知道出了问题该去哪里找。
配置中心:HarnessConfig
所有 11 个机制共享一个配置对象,避免参数散落各处:
注意
max_steps=50——它是机制①防止循环失控的硬刹车。三、核心机制详解
机制①②:Agent Loop + Tool Use(core.py)
这是整个 Mini Harness 的心脏。Agent Loop 的本质是一个
while 循环,Tool Use 是循环体内的工具调度器。Agent Loop 核心结构
关键设计点:
max_steps硬刹车:while steps < config.max_steps确保循环不会无限执行
BudgetExceeded优雅终止:token 超限时抛异常,由外层 try/except 捕获
- Permission Gate 挂载点:
trigger_gate("pre_tool_use")在工具执行前拦截危险命令
Tool Use:自动反射 + 结构化错误回传
传统做法需要开发者手工维护一份 JSON Schema 配置文件,极易与代码脱节。Harness 使用 Python 的
inspect.signature 做运行时反射,自动从函数签名生成 tool schema:核心收益:业务源码与调用契约 100% 自动同源同步。你在 Python 里增删一个参数,给大模型的 JSON 契约瞬间自适应改变。
工具执行层的
dispatch_tool 是另一个关键设计——绝不吞报错:传统做法要么让程序崩溃(Agent 死机),要么
try...except: pass 吞掉异常(LLM 产生幻觉)。dispatch_tool 走第三条路:将错误包裹成结构化 JSON 回传给 LLM,让 LLM 自己读错误信息、修正参数、重新调用。这是 Agent 自我纠偏的核心枢纽。机制③:Progress Tracking(progress.py)
故障模式⑤(状态丢失)的解药。
ProgressTracker 通过 HookManager 的三个事件点把会话过程记录到 progress.md:核心 API 是一行
tracker.register_to(agent.hooks)——零侵入接入,不需要改动 run_agent 内部任何代码。机制④:Context Management(context.py)
故障模式②(context 溢出)和③(cache miss)的解药。核心策略:不改 toolset、不改 memory、不改 system prompt(三铁律),只对 messages 做结构化压缩。
三铁律的出处是 AGENTS.md 规范——压缩时绝不能改变 agent 的能力边界(toolset)、已有知识(memory)和行为规范(system prompt)。
机制⑤:Feature List(planner.py)
故障模式②(context 溢出)的源头防控。核心思想:用一个外部数据结构承载任务状态,把"全局规划的复杂性"从 LLM 的 context 里剥离出去。
三种模式对应任务生命周期的三个阶段:
- 替换模式(
merge=False):任务开始时创建清单
- 合并模式(
merge=True):执行过程中更新状态(pending → in_progress → completed)
- 查询模式(
todos=None):任务完成前检查是否全部完成
在 E2E demo 的 7 步任务中,有 5 步是 todo 操作。这不是低效,而是刻意设计:每步只做一件事的纪律,是防止 context 溢出的源头防控。
机制⑥:Verification Loop(verifier.py)
故障模式④(tool 错误吞)的下游验证。核心原则:验证必须由工具完成,而不是由 LLM 完成。 LLM 的自我确认没有验证效力——它倾向于说"我检查过了",但无法真正运行自己生成的代码。
两层验证架构:
第一层(引导层):通过 system prompt 植入验证思维:
第二层(执行层):用真实工具验证——例如通过
subprocess 调用 pytest 验证生成的代码是否真的能跑通。工具返回的确定性结果(pass/fail)比 LLM 的自我确认可靠得多。与第二章错误回传的本质区别:
机制 | 触发时机 | 验证主体 | 作用 |
结构化错误回传 | 工具调用本身出错时 | 工具执行层 | 确保错误不被吞掉 |
Verification Loop | 工具调用成功后 | 独立验证工具 | 确保结果本身是正确的 |
机制⑦:Subagents(subagent.py)
故障模式②(context 溢出)和⑧(成本失控)的解药。核心设计:子 agent 拥有完全独立的 messages 列表,父 agent 的对话历史对子 agent 不可见。
父子迭代预算不是加法,是乘法。 假设父 agent
max_steps=50,每步都 spawn 一个子 agent(max_steps=50),最坏情况是 50 × 50 = 2500 步。这是 Manus 早期版本的真实教训。三条子 agent 设计铁律:
- 独立迭代上限:子 agent 步数上限必须比父更小(推荐父 50 / 子 10)
- 结果长度上限:子任务返回内容必须截断,防止撑爆父 context
- 成本上限:子任务必须设置 Token Budget,达到阈值强制终止
机制⑧:Generator-Evaluator(evaluator.py)
故障模式⑦(缺自动化评审)的解药。核心思想:生成和评估分离,用独立 context 的另一个 LLM 做客观审查。
为什么 LLM 自审不可靠?LLM 在生成内容时,注意力已被当前推理路径"锚定"。当被要求"检查自己的输出"时,它倾向于沿着相同的推理路径再走一遍,而不是真正以批判视角重新审视。生成者和审查者读的是同一份 messages 历史,思维起点相同,盲点也相同。
两个关键设计:
temperature=0.3:评审需要稳定性和一致性,低温度保证同样的候选方案每次评审得分接近
- Evaluator 的 system prompt 完全独立:它不知道 Generator 的内部推理过程,只看最终输出
与 Verification Loop 的关系:两者可以组合使用——先用 Verification Loop 做客观验证(pytest),再用 Generator-Evaluator 做主观质量评审,构成双重质量保障。
四、三个生产级扩展机制
机制⑩:Hooks 事件总线(hooks.py)
Hooks 本身不直接救任何一条故障模式,而是为 Permission Gate、Progress Tracker 和 Budget Guard 提供挂载基础设施。它是整个 Harness 的"神经系统"。
六大标准事件:
HookManager 提供两类接口:trigger(event):普通事件,顺序调用所有 handler,单个失败不影响其他
trigger_gate(event):门控事件,任一 handler 返回(False, reason)则立即 veto
关键安全策略:普通事件 handler 失败只记录不中断;门控事件 handler 失败视为拦截——因为允许一个"门坏了"的危险命令执行比多记录一条日志严重得多。
机制⑨:Permission Gate(permission.py)
故障模式⑥(缺权限闸)的解药。挂在
pre_tool_use gate 事件上,在执行前拦截危险命令。核心实现是一个正则黑名单,包含 14 条危险模式(如
rm -rf、sudo、chmod 777、curl | bash 等)。任何匹配的工具调用参数都会被 veto,返回 (False, reason) 阻止执行。机制⑪:Token Budget(budget.py)
故障模式⑧(成本失控)的解药。
BudgetGuard 在每次 LLM 调用后累计 token 消耗,超限时抛出 BudgetExceeded 异常,由 run_agent 的 try/except 捕获后优雅终止。五、E2E 真实数据:Harness 到底值不值?
以下是 2026-04-22 真实跑通的数据(模型:
deepseek-chat,任务:分析 main.py 的重复代码并给出重构建议):维度 | Baseline(单轮调用) | Full Harness(8 机制) | 倍率 |
步骤数 | 1 | 7 | 7× |
耗时 | 35.45 s | 94.02 s | 2.65× |
总 tokens | 1,104 | 15,053 | 13.6× |
答案字符数 | 2,498 | 2,819 | +13% |
成本 (USD) | — | $0.0697 | — |
预算上限 | — | $0.50 | — |
Permission 拦截 | 0 | 0(本次无危险命令) | — |
无 | 已落盘(7 条记录) | — |
13.6× tokens,2.65× 耗时。 这不是 Harness 效率低,而是它的成本结构。你用 13 倍的 tokens 换来了三个用单轮调用永远买不到的属性:
- 可观察性:
progress.md落盘了 7 条记录,每一步做了什么、调用了哪个工具、结果是什么,全程可追溯。Baseline 跑完了,你只能看到最终答案。
- 可干预性:Permission Gate 就绪,任何危险命令都会被在执行前拦截。Baseline 里 agent 直接执行任何工具,包括
rm -rf——你没有机会干预。
- 可控性:Token Budget 守住了整个任务,$0.0697 < $0.50 上限。如果任务出现异常循环,Budget 会触发优雅终止而不是无限烧钱。
六、三条核心结论
结论一:Harness 的 13× tokens 换的是"三性",不是低效
成本直觉建立后,你才能判断"这个任务值不值得上 Harness"——不是所有任务都需要,但凡是你需要追溯、拦截、兜底的任务,这个成本就是必要的。
结论二:Harness 与底层模型解耦
Mini Harness 基于 OpenAI Python SDK 写成,但每个机制都能在 Claude Code、Codex 里找到对应实现。如果把
core.py 的主循环换到 Anthropic SDK,只需要动 API 调用、循环结束判断、tool call 位置、结果回写格式、tool schema 字段这 5 处——Context Management、Progress Tracking、Permission Gate 等深层机制一行代码都不需要动。Harness 的架构逻辑与模型提供商是完全解耦的。结论三:Harness 会 go stale,它是工具不是信仰
Anthropic 在 2026-03-24 的博客中坦率承认:"Every component in a harness encodes an assumption about what the model can't do on its own"。今天你为 agent 加 Permission Gate,是因为模型可能误执行危险命令;如果未来模型默认就能做到"不执行危险命令",这个组件就可以从 Harness 里移除。随着模型能力提升,Harness 的组件会慢慢过时——这不是劝退,是让你建立正确的成本直觉。
七、Mini Harness vs 生产级工具对照
机制 | Mini Harness | Claude Code 生产版 | OpenAI Codex 生产版 |
Agent Loop | while + max_steps=50 | 多层事件驱动 | App Server JSON-RPC |
Context | head(2)+tail(6)+middle summary | 5 层 compaction pipeline | AGENTS.md 渐进披露 |
Progress | progress.md 追加写 | claude-progress.txt + git | 待补充 |
Feature List | todo_tool JSON 状态机 | 200+ 项结构化清单 | PLANS.md 持久化 |
Verification | pytest subprocess | Puppeteer MCP 真机 | structural test |
Subagents | delegate 递归隔离 | /agent + 独立 workflow | 待补充 |
Permission | 正则黑名单 14 条 | 27 个 hook + 规则矩阵 | sandbox policy |
Hooks | HookManager 6 事件 | Claude Code 27 事件 | middleware 3 hook |
Budget | BudgetGuard + BudgetExceeded | token budget + iteration cap | per-model quota |
Mini Harness 是"裸骨架"——功能极简,但结构透明;生产工具是成熟系统——功能丰富,但内部封装。学完骨架,以后读生产工具的源码时,你会认出每一块肌肉。
附录:关键术语快速检索
术语 / 机制 | 核心文件 | 关键函数 / 类 |
Agent Loop | core.py | run_agent, while steps < config.max_steps |
Tool Use | core.py | dispatch_tool, _build_tool_schemas |
Progress Tracking | progress.py | ProgressTracker.register_to |
Context Management | context.py | compress_if_needed, estimate_tokens |
Feature List | planner.py | todo_tool(替换/合并/查询三模式) |
Verification Loop | verifier.py | verify_by_pytest |
Subagents | subagent.py | delegate |
Generator-Evaluator | evaluator.py | evaluate, temperature=0.3 |
Hooks | hooks.py | HookManager, trigger_gate |
Permission Gate | permission.py | PermissionGate.check, 14 条黑名单 |
Token Budget | budget.py | BudgetGuard.add, BudgetExceeded |
参考引用
来源 | 日期 | URL |
Anthropic · Effective Harnesses for Long-Running Agents | 2025-11-26 | |
Anthropic · Harness Design for Long-Running Apps | 2026-03-24 | |
OpenAI · Unlocking the Codex Harness | 2026-02-04 | |
Phil Schmid · The Importance of Agent Harness in 2026 | 2026-01-05 | |
AGENTS.md 规范 | — |
本文基于 2026 年 4 月技术状态编写,使用
deepseek-chat 模型验证 E2E demo。依赖版本:openai==2.26.0、python-dotenv==1.2.2、pytest==9.0.3、httpx==0.28.1。📎 参考文章
欢迎您在底部评论区留言,一起交流~
Loading...
