Files
SuperBizAgent-java/mvp/engineering/harness/Harness progress 代码学习笔记-从拦截器五道门到唯一发布点.md
zhuyongxin 7844bcea40 docs(harness): annotate progress core classes and add code-level learning notes
- Annotate DiagnosisProgressTracker, HarnessToolInterceptor, DiagnosisProgressProjector,
  DiagnosisReleaseUseCase, ToolBoundary, ToolBoundaryResult, CanonicalToolInvocation
- Add progress code learning note: interceptor gates, tracker state machine,
  canonical lifecycle, execution gate, projection/release pipeline
- Update learning roadmap: progress marked as deeply learned, next is tool domain
2026-08-03 18:37:23 +08:00

24 KiB
Raw Permalink Blame History

Harness progress 代码学习笔记:从拦截器五道门到唯一发布点

更新日期:2026-08-03 主题:Progress 子系统的代码落地——拦截器五道门、Tracker 状态机、canonical 生命周期、执行门禁、投影与发布闭环 术语与状态:CONTEXT.md · Harness生命周期与状态.md 设计视角:Harness 信息增益停止-让无证据诊断正常收敛(讲「为什么这样设计」) 本文视角:代码里怎么落地(类地图、调用链、生命周期、状态机、门禁、易错点、面试话术)

1. 定位:双停止机制与三方判断权

1.1 双停止机制(progress 存在的根本理由)

预算管「能不能花」,progress 管「值不值得继续查」。让预算充当正常停止策略,会把「当前证据不足」错误表达成「系统执行失败」——这是语义错误,不是资源问题。

机制 问的问题 归属
RunBudget 这次 Run 最多允许消耗多少? core 域
Progress 继续查询是否仍可能推进当前诊断? progress 域

1.2 三方判断权(信任边界)

flowchart LR
    T["Tool / Projector<br/>客观结果"] -->|"evidence_status:空不空(代码判)"| H
    M["Diagnosis Agent<br/>语义价值"] -->|"information_gain:有没有用(模型判)"| H
    H["Harness<br/>最终停止权"] -->|"scope 重复 / 连续 NO_GAIN / 协议合规"| R["停止裁决"]
  • 谁判空:EVIDENCE_FOUND / NO_EVIDENCE 是 Harness 代码判(证据数组空不空),Projector 投影时客观计算,不需要模型。
  • 谁判价值:GAINED / NO_GAIN 的语义价值是模型判——非空结果「有没有用」只有结合诊断上下文才能判断。
  • 谁决定停止:Harness。模型可以主动结束(输出 Draft),但不能用继续发 Tool Call 绕过 Harness 已定的饱和状态。

两层信任边界分开:模型输出乱来(瞎报增益)时,Harness 手里仍有 evidenceStatus 这个与模型无关的事实层(canonical 记录、审计、验真都建立在它之上)。

2. 类地图与调用链

2.1 14 个文件分类

类别 类 作用
状态机核心 DiagnosisProgressTracker 记账(双计数/pending/identity)+ 停止裁决
判重 ToolScopeNormalizer + ToolScopeIdentity 业务输入 → 稳定 scope 指纹
投影 DiagnosisProgressProjector + DiagnosisProgressProjection identity → 回读 canonical → 有界快照
枚举 InformationGain / DiagnosisCollectionState / DiagnosisStopReason / ProgressProtocolViolationType GAINED·NO_GAIN / COLLECTING·SATURATED / 三种停止原因 / 五类违规
record PreviousObservation / CompletedToolCall / DiagnosisProgressSnapshot / DiagnosisProgressSnapshotState 协议字段 / 完成 identity / 对外快照 / 内部快照
异常 ProgressProtocolViolationException 受控协议违规

2.2 一次 Tool Call 的完整链路

sequenceDiagram
    participant I as HarnessToolInterceptor(per-Run)
    participant ET as HarnessEvidenceTools(注册表)
    participant AD as Adapter(接线员)
    participant TB as ToolBoundary(门禁)
    participant S as CanonicalInvocationStore(真相)
    participant P as Projector(投影)

    I->>ET: invoke(context, toolName, toolCallId, args)
    ET->>AD: bridge 包装的 invoker
    AD->>TB: boundary.execute(context, envelope, executor, projector)
    TB->>S: begin(PROJECTING)
    TB->>TB: executor.execute(requestJson)(backend raw)
    TB->>P: projector.project(raw) → agent_result + evidenceStatus
    TB->>S: markReady(READY) 或 markError(ERROR)
    TB-->>AD: ToolBoundaryResult(READY/ERROR)
    AD-->>I: 一路 return
    I->>I: 双源交叉验证 → recordCompleted → 返回有界 observation

2.3 三层关系

持有关系:

HarnessToolInterceptor ──持有──▶ RunContext(含 Tracker)/ HarnessEvidenceTools
HarnessEvidenceTools ──持有──▶ Map<toolName, EvidenceToolInvoker>(bridge 注册表)
Adapter ──持有──▶ ToolBoundary + 具体 backend + 具体 Projector
ToolBoundary ──持有──▶ DiagnosisHarnessCore / CanonicalInvocationStore / ToolCallKeyFactory

接口-实现关系:

接口 实现
EvidenceToolInvoker(@FunctionalInterface) HarnessEvidenceTools.fromAdapters 的 bridge
AdapterCall(内部 @FunctionalInterface) 三个 Adapter 的 execute 方法
ToolExecutor(@FunctionalInterface) Adapter 里 ignored -> legacyExecutor.execute(query)
ToolResultProjector RagResultProjector / QueryLogsResultProjector / MysqlResultProjector
CanonicalInvocationStore JpaCanonicalInvocationStore 等

3. 生命周期:单例 vs per-Run

flowchart TD
    subgraph 应用启动(一次)
        A["Spring 容器装配单例 bean"]
        A --> B["DiagnosisHarnessCore / ToolBoundary / Adapter / HarnessEvidenceTools / DiagnosisAgentFactory"]
    end
    subgraph 每次请求(多次)
        C["core.startRun() → RunContext(含 new DiagnosisProgressTracker)"]
        C --> D["DiagnosisAgentFactory.create(context)"]
        D --> E["new HarnessModelInterceptor / HarnessToolInterceptor(绑定本 Run context)"]
        E --> F["ReactAgent.call() → ReAct loop"]
        F --> G["Run 结束:拦截器/ReactAgent 变成垃圾"]
    end
对象 生命周期 原因
core / ToolBoundary / Adapter / EvidenceTools / AgentFactory 单例 无状态,只存依赖与规则
RunContext per-Run 状态容器(Tracker/Budget/Lifecycle)
两个 Interceptor per-Run 持有本 Run 的 RunContext
ReactAgent per-Run 框架有状态对象(loop/memory)

无状态体现:单例 bean 的字段全是构造注入的依赖/配置(创建后不变);可变状态全部外置到 RunContext 和持久化存储。方法一律以 context 参数显式传入——同一个 ToolBoundary 实例可并发服务多个 Run,各算各的账,状态外置是并发正确性的硬要求(若在 bean 里存「当前预算计数」,并发 Run 会互相覆盖)。

4. 拦截器五道门(代码核心)

4.1 门卫 + 执行者合一

证据工具的 ToolCallback 被故意定义为直接抛异常("Harness evidence Tools require the framework Tool interceptor")——如果框架绕过拦截器执行 handler.call(),直接爆炸。这从结构上保证:执行不可绕过门禁,校验+执行是原子操作。

flowchart LR
    REQ["Tool Call 到达"] --> CHK{"evidenceTools.supports?"}
    CHK -->|"非证据工具"| HANDLER["handler.call() 透传"]
    CHK -->|"证据工具"| GATES["五道门(校验+执行+记账)"]

为什么不在 definition 里写(四个原因):

  1. 拦截器接管执行时根本不经过 ToolCallback——写在 definition 里永远不会执行;
  2. ToolCallback 是纯函数(input→output),拿不到 RunContext,调不了 context.progress();
  3. ToolCallback 本身就是执行,没有「执行前」时机——判重必须在 backend 前,只有拦截器同时拥有执行前/后两个观察点;
  4. progress 逻辑横跨所有证据工具,写在每工具 callback 会复制漂移。

4.2 五道门流程

flowchart TD
    A["① 已停止检查"] -->|"SATURATED && stopInstructionDelivered"| B["抛 DiagnosisCollectionStoppedException(硬停止)"]
    A --> C["② 解析 + 协议校验"]
    C -->|"违规"| D["recordProgressProtocolViolation → 可修复反馈 / 达阈值饱和"]
    C -->|"评价导致饱和"| E["stopRequired(软停止)"]
    C --> F["③ 判重:isDuplicate(toolName, normalizedScope)"]
    F -->|"重复"| G["recordDuplicateScope(直接 NO_GAIN)→ 饱和? stopRequired : 返回 DUPLICATE_SCOPE 观察"]
    F --> H["④ ToolBoundary 执行(预算/canonical/审计/checkActive)"]
    H -->|"READY"| I["双源交叉验证 → recordCompleted → ⑤ 收尾(NO_EVIDENCE 立即 NO_GAIN / FOUND 挂 pending / 饱和交付 stop_required)"]
    H -->|"非 READY"| J["error observation(BUDGET_EXHAUSTED 额外 markBudgetLimitReached)"]

4.3 协议三类违规(第二道门)

校验的是 Envelope 与 Tracker pending 状态的协议关系(不是 JSON 结构——JSON 结构在 parse 用严格反序列化做了):

违规 含义 判定条件
UNEXPECTED_PREVIOUS_OBSERVATION 没欠账却带评价 pending == null 且 observation != null
MISSING_PREVIOUS_OBSERVATION 欠账不还 pending != null 且 observation == null
OUT_OF_ORDER_PREVIOUS_OBSERVATION 还错账 observation.toolCallId() != pendingToolCallId

另两类(parse 阶段):MISSING_INPUT(缺业务输入)、INVALID_ENVELOPE(JSON/字段非法)。

可修复反馈:首次违规(未达阈值)返回 repair_required:true 观察——带 violation_type / missing_field / expected_previous_tool_call_id / allowed_information_gain / instruction,让模型下一轮自愈;连续违规达独立阈值才饱和(PROGRESS_PROTOCOL_VIOLATED)。

4.4 双源交叉验证(第四道门,READY 后)

源1:result.evidenceStatus()               ← Projector 投影时计算并携带的声明值
源2:controlView.evidenceStatus()          ← 从 agent_result 内容里解析 "evidence_status" 字段
比较:一致 ? 通过 : OBSERVATION_CONTRACT_MISMATCH 拒绝

本质是「自洽性防线」:同一状态被两处描述(结果对象字段 vs 内容 JSON 字段),必须一致——防止投影 bug / 数据损坏 / 构造不一致导致 progress 基于错误状态决策(如声明 FOUND 但内容空 → 挂 pending 等评价不存在的证据;声明 NO_EVIDENCE 但内容有证据 → 误记 NO_GAIN)。

4.5 三副 observation 面孔

面孔 触发 关键字段
正常执行结果 READY 且未饱和 有界观察 + 可选 stop_required
STOP_REQUIRED 饱和后交付一次 stop_required:true + reason
可修复协议错误 协议违规未达阈值 repair_required:true + violation_type/missing_field/expected id/instruction

5. Tracker 状态机

5.1 11 个字段

字段 含义
stopAfterConsecutiveNoGain 连续 NO_GAIN 阈值(默认 2,yml 可配)
stopAfterConsecutiveProgressProtocolViolations 连续协议违规阈值(默认 2)
completedScopes toolName + normalizedScope 去重集合
completedToolCalls 已完成调用 identity 列表(无 payload)
consecutiveNoGain 连续无增益计数(GAINED 清零)
consecutiveProgressProtocolViolations 连续协议违规计数(合法评价清零)
collectionState COLLECTING / SATURATED
stopReason INFORMATION_SATURATED / BUDGET_LIMIT_REACHED / PROGRESS_PROTOCOL_VIOLATED
pendingToolCallId 待评价调用 ID(同一时刻最多一个)
stopInstructionDelivered STOP_REQUIRED 是否已交付(只一次)

5.2 两条独立计数(重点:协议违规 ≠ NO_GAIN)

NO_GAIN 路径(applyGain)—— backend 执行了但没增益:
  入口:applyPreviousObservation(NO_GAIN) / recordDuplicateScope() / recordCompleted(NO_EVIDENCE)
  阈值:stopAfterConsecutiveNoGain(2) → SATURATED + INFORMATION_SATURATED
  GAINED 清零连续计数

协议违规路径(recordProgressProtocolViolation)—— backend 根本没执行:
  入口:拦截器 catch 分支
  阈值:stopAfterConsecutiveProgressProtocolViolations(2) → SATURATED + PROGRESS_PROTOCOL_VIOLATED
  一次合法评价(applyPreviousObservation 通过)清零

为什么分开:NO_GAIN 表示「Tool 执行了但没推进诊断」;协议错误表示「模型没守契约,Tool 根本没执行」。混淆会让真实空转无法归因(真实 E2E:9 次协议拒绝 + 13 轮模型调用空转)。

5.3 pending 协议(锚点)

flowchart LR
    A["recordCompleted(EVIDENCE_FOUND)"] --> B["pendingToolCallId = toolCallId(挂账)"]
    B --> C["模型下一轮回带 previous_observation"]
    C --> D{"ID == pending ?"}
    D -->|"是"| E["清 pending → applyGain"]
    D -->|"否"| F["OUT_OF_ORDER 违规"]
  • 只对非空成功结果设 pending;NO_EVIDENCE 不设(Harness 已自己判 NO_GAIN)。
  • pending 是「唯一欠账」——保证协议逐轮、不乱序、不重评。
  • 模型读完 observation 直接输出 Draft → pending 不消费也合法(不需要评价最后一轮)。

5.4 收集状态机

stateDiagram-v2
    [*] --> COLLECTING
    COLLECTING --> COLLECTING: GAINED / consecutiveNoGain=0
    COLLECTING --> COLLECTING: NO_GAIN 未达阈值
    COLLECTING --> SATURATED: NO_GAIN 达阈值 / 协议违规达阈值
    SATURATED --> SATURATED: claimStopInstruction 交付一次(软停止)
    SATURATED --> [*]: 模型再请求 Tool → DiagnosisCollectionStoppedException(硬停止)

软/硬停止两段式(易错点:stopReason 设置 ≠ 软停止):

饱和瞬间 → stopReason 已设置(状态事实)
软停止 = 第一次交付 stop_required 观察(claimStopInstruction 返回 true,流程不中断)
        → 给模型合法输出 Draft 的机会
硬停止 = 模型无视指令再次请求 Tool → 入口检查 SATURATED && delivered
        → 抛 DiagnosisCollectionStoppedException 穿出框架 loop

5.5 为什么需要 Tracker(三层)

  1. progress 本身需要:预算只止损,不能当正常停止策略;
  2. 必须单一所有者:「连续无增益」是跨轮次、跨入口(模型评价/代码判空/重复检测)的全局判断,分散记账会状态漂移;
  3. 最小状态:不存 payload(真相在 Canonical Store),避免第二份真相。

6. canonical 生命周期(tool 域衔接)

6.1 状态机

stateDiagram-v2
    [不存在] --> PROJECTING: store.begin(preflight+预算通过后)
    PROJECTING --> READY: store.markReady(backend 成功+投影成功)
    PROJECTING --> ERROR: store.markError(任何异常)
    note right of PROJECTING: 仅身份+request+startedAt
    note right of READY: raw + agent_result + evidence + completedAt
    note right of ERROR: raw + error_code + completedAt(禁 agent_result)

6.2 为什么分 begin/markReady/markError 三段

动机 说明
崩溃恢复 backend 执行可能耗时数秒,一次写入会丢「已开始」的事实;begin 先留痕(PROJECTING = WAL)
审计耗时 需要 startedAt(begin 记)和 completedAt(迁移记)算调用耗时
状态合法 每种状态只允许合法字段组合,由构造校验兜底
防篡改 record 不可变,迁移生成新实例——READY 一旦写入不可改(证据可验真的前提)
幂等 begin 抛 DuplicateInvocationException(同 key 重复 begin 拒绝)→ DUPLICATE_TOOL_CALL

两类失败不落库:requestBytes 超限、preflight 非法、重复 begin——都发生在 begin 之前,canonical 里无记录。

6.3 Store vs Tracker 分层

Store(事实层):request / raw_response / agent_result / 状态 / 时间戳 —— 完整真相
Tracker(判断层):identity(引用)+ 双计数 + pending + 状态 —— 决策状态

NO_GAIN 计数不是「第二份真相」:它无法从 Store 重建
(模型评价是瞬时的、不落 Store),是独立增量状态

7. ToolBoundary 执行门禁

7.1 executeCanonical 五阶段

flowchart TD
    A["阶段一:preflight + Tool 预算 + request bytes 预留 → begin(PROJECTING)"]
    B["阶段二:executor.execute(requestJson)(backend raw)"]
    C["阶段三:raw 大小校验 + Run bytes 预留"]
    D["阶段四:projector.project(raw) → 有界 agent_result + evidenceStatus"]
    E["阶段五:agent_result 校验 + Run bytes 预留 → markReady(READY)"]
    A --> B --> C --> D --> E

三笔 bytes 预留:request(阶段一)/ raw(阶段三)/ agent_result(阶段五)——Run 的 bytes 预算分三个时间点消耗,任何一笔超限触发对应错误码。

7.2 失败路径错误码

失败点 是否已 begin canonical 错误码
requestBytes 超限 / preflight 非法 / 重复 begin / Run 终态 否 无记录 RESULT_TOO_LARGE / 分类错误码 / DUPLICATE_TOOL_CALL / BUDGET_EXHAUSTED·RUN_INACTIVE
executor 抛错 是 ERROR TOOL_EXECUTION_ERROR
raw 过大 / 预算 / 取消 是 ERROR RESULT_TOO_LARGE / BUDGET_EXHAUSTED / RUN_INACTIVE
投影失败 是 ERROR PROJECTION_ERROR
agent_result 过大 / store 失败 是 ERROR RESULT_TOO_LARGE / PROJECTION_ERROR / STORE_ERROR

7.3 checkActive 在哪

progress 拦截器流程里看不到显式 checkActive——它在 ToolBoundary/core 层隐式执行:core.beforeToolCall / core.reserveRunBytes 内部若 Run 已终态,抛 RunAbortedException → 映射为 RUN_INACTIVE 错误码。

8. 投影与发布闭环

8.1 停止后的数据流

flowchart LR
    T["Tracker(identity 列表)"] --> P["DiagnosisProgressProjector"]
    P --> S["CanonicalInvocationStore(回读 READY)"]
    S --> P
    P --> SN["ProgressSnapshot(verifiedSources + observedFacts + limitations + stopReason)"]
    SN --> R["DiagnosisReleaseUseCase"]
    R --> O["SUCCESS / FALLBACK(INSUFFICIENT_EVIDENCE 等)"]

8.2 Projector 有界投影

  • 三重校验(isReferencableBy / toolCallId / toolName)通过才发布;无法验真/不可读/格式非法 → limitation,绝不输出 raw;
  • 空结果也投影为有界事实(「该范围内未发现」)——限定范围的空查询是「已检查」的证明;
  • 硬截断:MAX_FACTS=12、summary/scope 320 字符、source 160 字符;
  • 去重:sourceKey = type + source + scope,factKey = sourceKey + summary(LinkedHashMap 保序)。

8.3 Release 决策树

flowchart TD
    EX["execute(execution)"] --> D1{"draft == null?"}
    D1 -->|"是"| CS["releaseControlledStop<br/>需 hasObservedFacts → INSUFFICIENT_EVIDENCE"]
    D1 -->|"否"| D2{"conclusion == null?"}
    D2 -->|"是"| NC["releaseNoConclusion<br/>有事实 → INSUFFICIENT_EVIDENCE<br/>missing_info → MISSING_REQUIRED_CONTEXT<br/>都没有 → fail closed"]
    D2 -->|"否"| C["releaseConclusion<br/>EvidenceGuard 验引用 → repair → SemanticGuard 裁决<br/>SUPPORTED ? SUCCESS : FALLBACK"]

9. 易错点清单

易错 正确
EVIDENCE_FOUND 累计 NO_GAIN NO_EVIDENCE(空结果)才立即累计;FOUND 挂 pending 等模型评价
重复调用计入协议违规 重复走 NO_GAIN 路径(recordDuplicateScope),不是违规
软停止 = 设置 stopReason stopReason 饱和时就设了;软停止是交付 stop_required 观察
checkActive 应该在拦截器 在 ToolBoundary/core 层,RUN_INACTIVE 错误码
拦截器直接 invoke = 绕过设计 是唯一执行通道(证据工具 handler 必炸)
数据都在 Tracker 判断层在 Tracker,事实层在 Canonical Store
判重对比裸入参 对比的是规范化指纹(字段顺序/格式/缺省值统一后)
首次协议违规直接终止 首次返回可修复反馈,连续违规才饱和

10. 面试话术合集(30 秒)

10.1 双停止机制

"Harness 有两套停止机制。预算是资源门禁,管『能不能花』;Progress 是收敛门禁,管『继续查有没有价值』。核心设计是:Tool 只提供客观结果,模型负责判断语义增益,但停止权归 Harness。信息增益故意只保留 GAINED/NO_GAIN 两值,靠模型在下次 Tool Call 里用 previous_observation 回传评价;连续两次 NO_GAIN 就进入饱和,交付一次 STOP_REQUIRED 给模型合法收尾的机会,再纠缠就抛受控异常穿出框架。"

10.2 为什么需要 Tracker(单一所有者)

"ProgressTracker 是 Run 内收敛控制的单一决策者:它不存证据内容,只保存最小账——已完成调用的 identity、连续 NO_GAIN 和协议违规两条计数、一个待评价的 pending ID、以及 COLLECTING/SATURATED 状态。三路输入(模型评价、代码判空、重复检测)汇入计数,GAINED 清零、NO_GAIN 累加,达阈值进入饱和,交付一次停止指令。所有方法 synchronized,是并发安全的单一所有者。"

10.3 拦截器为什么自己执行(必炸路径)

"Harness 的证据工具不是『拦截后放行』——拦截器对它们既是门卫又是执行者。证据工具的 ToolCallback 被故意定义为直接抛异常,使 handler 路径成为必炸路径,从结构上保证执行不可绕过门禁;校验(判重/协议/预算)和执行(ToolBoundary/canonical)内联在同一个流程里,保证『执行前判重、执行后记录』的时机原子性,且模型拿到的永远是有界观察而不是 raw。"

10.4 为什么 begin/markReady/markError 三段式

"Tool 执行是跨门禁、backend IO、校验、投影多个不可靠阶段的流程,所以 canonical 记录用 begin → markReady/markError 的追加式状态机:begin 先落 PROJECTING 保证已开始的调用必有痕迹,backend 成功且投影成功才 markReady 定案为 READY,任何异常 markError 收尾;三个状态各校验合法字段组合,record 不可变保证一旦写入不可篡改——这样崩溃可恢复、审计可对账(startedAt/completedAt 算耗时)、证据可验真(READY 不可造假),重复 begin 还能幂等拦截。"

10.5 谁判空谁判价值

"空不空是客观事实,代码可判,所以 evidenceStatus 归 Harness 的 Projector;有没有用是语义判断,代码判不了(一段通用知识可能看似相关实则无用),所以 information_gain 归模型。Harness 绝不把客观状态交给模型声明,模型也绝不替 Harness 做停止裁决——两层的信任边界是分开的。"

10.6 无状态 bean

"Harness 的单例 bean(core/ToolBoundary/Adapter)全部无状态:字段只有构造注入的依赖和配置,创建后不变;所有可变状态外置到每个 Run 的 RunContext(预算计数、进度 Tracker、生命周期)和持久化存储里。方法一律以 context 参数显式传入,所以同一个 bean 实例能并发服务多个 Run 而不串账——状态在参数里,不在实例里。"

11. 代码位置索引

类 文件
DiagnosisProgressTracker src/main/java/com/superbiz/agent/harness/progress/DiagnosisProgressTracker.java
ToolScopeNormalizer src/main/java/com/superbiz/agent/harness/progress/ToolScopeNormalizer.java
DiagnosisProgressProjector src/main/java/com/superbiz/agent/harness/progress/DiagnosisProgressProjector.java
DiagnosisProgressProjection src/main/java/com/superbiz/agent/harness/progress/DiagnosisProgressProjection.java
progress 枚举/record/异常 src/main/java/com/superbiz/agent/harness/progress/(其余 9 个文件)
HarnessToolInterceptor src/main/java/com/superbiz/agent/harness/agent/HarnessToolInterceptor.java
HarnessEvidenceTools src/main/java/com/superbiz/agent/harness/agent/HarnessEvidenceTools.java
DiagnosisAgentFactory src/main/java/com/superbiz/agent/harness/agent/DiagnosisAgentFactory.java
RagToolAdapter src/main/java/com/superbiz/agent/harness/tool/adapter/RagToolAdapter.java
ToolBoundary src/main/java/com/superbiz/agent/harness/tool/boundary/ToolBoundary.java
ToolBoundaryResult src/main/java/com/superbiz/agent/harness/tool/boundary/ToolBoundaryResult.java
CanonicalToolInvocation src/main/java/com/superbiz/agent/harness/tool/store/CanonicalToolInvocation.java
CanonicalInvocationStore src/main/java/com/superbiz/agent/harness/tool/store/CanonicalInvocationStore.java
DiagnosisReleaseUseCase src/main/java/com/superbiz/agent/harness/release/DiagnosisReleaseUseCase.java
装配 src/main/java/com/superbiz/agent/config/HarnessChatConfiguration.java