Appearance
Harness 设计思想
来自
idea-business多模块实践的抽象经验。这里记录的是初始化新项目时可复用的思考方式,而不是某个项目的目录结构。
核心观点
Harness 不是一套文件夹,也不是一组 prompt。它是围绕 agent 工作方式设计的工程环境。
好的 harness 会持续回答五个问题:
- 谁拥有边界?
- 什么算完成?
- 下游凭什么相信上游?
- 失败后系统如何变聪明?
- 哪些信息应该进入 context,哪些应该留在文件系统?
只要这些问题没有被设计清楚,项目越自动化,问题传播越快。
1. 先设计所有权,再设计目录
目录结构只是所有权的投影。真正重要的是回答:
- 哪些知识是全局的?
- 哪些能力必须独立进化?
- 哪些代码只是基础设施?
- 哪些产物属于具体产品或任务?
- 哪些状态只是 pipeline 过程记录?
idea-business 的重要经验不是“hub + 多 repo”这个形状本身,而是这个原则:
知识可以集中,业务闭环要独立,基础设施只共享确定性部分。
如果把业务逻辑过早共享,会切断每个场景自己的进化循环。如果完全不共享基础设施,日志、gate、schema、修复经验又会漂移。
初始化项目时先画“所有权地图”,再决定 monorepo、multi-repo、packages、modules、projects 怎么摆。
2. 把 Agent 输出当作声明,不当作事实
Agent 说“完成了”,只是一个声明。Harness 要求系统回答:
- 产物在哪里?
- 它是否非空?
- 它是否符合下游契约?
- 它是否真的改变了 workspace?
- 它的质量判断来自谁?
这就是 phase success contract 的抽象形式:
phase 成功不是由执行者自报,而是由可验证证据证明。
这个思想适用于所有自动化边界,不限于 LLM:
- CLI 成功返回不等于 artifact 可用。
- judge 给分不等于 gate 通过,blocker 也必须被理解。
- review-only agent 不等于没有改动,仍要检查 workspace。
- markdown、HTML、图片、代码都可以是证据,但要有验证方式。
初始化新项目时,每个硬 handoff 都要写清楚“下游凭什么相信它”。
3. 把概率能力包在确定性壳里
LLM、外部 agent、生成式工具都是概率系统。不要把它们直接接到下游。
好的 harness 会在概率系统外面加确定性壳:
- 输入边界明确:传什么文件、什么 prompt、什么上下文。
- 调用方式明确:workspace、参数、权限、超时、输出路径。
- 输出边界明确:必须写什么 artifact,怎么验证。
- 失败语义明确:缺文件、空文件、schema 错、gate fail、工具不可用要能区分。
抽象原则:
让模型负责判断和生成,让代码负责边界、证据、状态和失败分类。
这条原则能防止 harness 变成“prompt 里祈祷模型守规矩”。规则越关键,越应该被确定性代码或结构化契约承载。
4. Context 是预算,不是仓库
很多 harness 问题不是信息不够,而是无关信息太多。
CLAUDE.md、AGENTS.md、skill、ADR、历史产物、产品档案都在争夺同一个稀缺资源:agent 的注意力。
实践经验:
- always-on 文件只放每次都会影响行为的规则。
- 场景知识按需加载,不要常驻。
- 历史 raw JSON 容易造成 schema contagion。
- 给 agent 精炼事实,比让它自己读一堆旧产物更稳定。
- 负面清单经常激活错误模板,隔离输入更有效。
抽象原则:
不要问“这条信息有没有用”,要问“它是否值得每次都占用注意力”。
初始化新项目时,要设计 context 分层:哪些是 L1 always-on,哪些是 L2 入口,哪些是 L3 按任务读取。
5. 可观测性必须独立于业务流程
如果日志依赖每个模块自觉上报,迟早会漏。
好的 harness 会把运行事实作为独立系统:
- event log 是 source of truth。
- dashboard 只读,不参与修复。
- run、phase、gate、tool、heartbeat 是观察维度,不是业务语义。
- metrics 是长期趋势,不是一次报告。
- failure reason 要稳定,方便聚合和复盘。
抽象原则:
业务 pipeline 可以变化,但观测模型要稳定。
当观测系统独立,项目才能回答更高级的问题:哪个阶段退化了,哪个 judge 漂了,哪个外部工具最常失败,哪个修复方案反复被用到。
6. 知识沉淀要按生命周期分层
不是所有经验都应该写进同一个文档。
有效的 harness 会区分:
| 知识类型 | 回答的问题 | 典型生命周期 |
|---|---|---|
| Decision | 为什么这样设计 | 长期,可被替代 |
| Solution | 这个故障怎么修 | 长期,随重复故障增强 |
| Plan | 当前任务如何完成 | 短期,完成后归档 |
| Playbook | 重复流程怎么执行 | 中期,随流程成熟更新 |
| Reference | 外部世界有什么变化 | 持续巡查,定期提炼 |
抽象原则:
经验不是越集中越好,而是要放到符合它生命周期的位置。
Bug fix 不应该伪装成 ADR。长期架构边界也不应该埋在一次 plan 里。外部调研不能只停留在 briefing,要能转化为 ADR、playbook 或 solution。
7. Gate 要保护边界,不要替代思考
Gate 的价值不是“打分”,而是阻止错误状态进入下游。
一个好的 gate 应该具备:
- 明确的所有权:谁有资格判断这个边界?
- 明确的输入:它读哪些 artifact?
- 明确的输出:下游只看哪个 verdict、score 或 blocker?
- 明确的失败动作:halt、retry、prototype、manual review 还是 force override?
实践里的关键教训:
Gate 不应该扩大自己的权力范围。
例如实现前的 evidence gate 可以检查“是否满足已声明的 stop/go 条件”,但不应该重新发明产品验证。边界越清晰,agent 越不容易在相邻职责之间漂移。
8. 抽象要等重复真实出现
Harness 很容易过早架构化。看到两个相似 phase,就想做通用 DSL;看到两个类似 skill,就想合并成库。
更稳的做法:
- 先让两个真实流程独立跑通。
- 观察重复发生在哪里:日志、gate、artifact、session、错误处理,还是业务判断。
- 只抽确定性边界,不抽业务语义。
- 抽完后做诚实度检查:代码更少了吗?上下文更少了吗?失败更清楚了吗?
抽象原则:
共享基础设施,保留进化闭环。
如果抽象让每个场景更难自我改进,它就是错误抽象。
9. 外部 Agent 是协作者,不是可信子程序
当 harness 调用另一个 agent、plugin 或 CLI 时,要把它视为外部协作者:
- 它可能误解 cwd。
- 它可能无法读需要的文件。
- 它可能返回一段解释而不是写 artifact。
- 它可能因权限、sandbox、quoting、上下文丢失而静默失败。
- 它可能“看起来完成了”,但没有产生下游需要的证据。
抽象原则:
外部 agent 的自然语言响应不能直接成为 pipeline 状态。
自动化链路应该拥有调用、输出路径、artifact 验证和失败分类。plugin 或人工交互可以用于探索,但不能直接作为无人值守 pipeline 的成功依据。
初始化时的 12 个问题
新项目开始前,先回答这些问题,比先搭目录更重要:
- 这个项目有哪些独立进化闭环?
- 哪些规则每次都必须加载,哪些只在特定任务加载?
- 哪些知识是全局原则,哪些是产品或模块事实?
- 每个 phase 的下游是谁?
- 每个 hard handoff 的成功证据是什么?
- 哪些产物给机器读,哪些只给人看?
- 失败原因要如何分类,才能未来自动聚合?
- Judge 的权力边界在哪里?
- Fix 是否可能影响 Judge 的独立性?
- 外部工具或 agent 的输出如何被验证?
- 日志系统是否能在业务流程变化时保持稳定?
- 哪些重复已经真实出现,值得抽象成基础设施?
这些问题回答清楚后,再选择具体实现:单 repo 还是多 repo、目录怎么命名、是否需要 dashboard、是否需要 shared libs、是否需要 pipeline executor。
最小可复用理念
如果只能带走五句话:
- 先定所有权,再定结构。
- Agent 自报完成不算完成,证据才算。
- 概率能力负责生成,确定性壳负责边界。
- Context 是预算,文件系统才是仓库。
- 共享基础设施,保留业务闭环。