28 KiB
Diagnosis Agent 信息增益与停止控制架构
更新日期:2026-07-27 状态:已实施,待归档 关联 Issue:ISS-016
1. 背景
当前 Diagnosis ReAct Agent 在知识库没有直接答案、日志持续为空或查询条件不足时,可能继续改写查询并反复调用 Tool,直到资源预算耗尽。此时 Run 被发布为技术失败,用户只能看到通用错误,而不是“已完成有限排查,但证据不足”。
本设计解决两个不同问题:
- 查询何时已经不再产生有效信息,必须停止继续调用 Tool。
- 停止后如何避免模型在证据不足时生成无依据结论。
2. 核心原则
Tool:返回客观数据
Harness:判断查询过程是否还允许继续
Model:判断数据是否推进了当前诊断,并通过实际 Tool Call 或 Draft 表达行为
SemanticGuard:判断最终结论是否有证据支撑
Release:统一把 Draft 或 Harness 停止投影为安全的 SUCCESS / FALLBACK
停止权属于 Harness。模型可以建议继续,但不能绕过 Harness 的饱和状态和硬资源边界。
“没有找到根因”是合法业务结果,不等于执行失败。模型被允许输出 conclusion=null 的 DiagnosisDraft;最终仍只使用 SUCCESS / FALLBACK / FAILED / CANCELLED,不增加第二套诊断终态。
3. 总体架构
flowchart TD
U["用户提出诊断问题"] --> M["Diagnosis Agent"]
P["ReAct Prompt<br/>允许合法放弃"] -.-> M
C["会话上下文<br/>有界历史和已检查范围"] -.-> M
M -->|"Tool Call Envelope"| B["Harness 调用门禁"]
B --> A["应用 previous_observation<br/>更新连续 NO_GAIN"]
A --> GATE{"是否允许继续"}
GATE -->|"INFORMATION_SATURATED"| STOP["拒绝调用<br/>注入 STOP_REQUIRED"]
GATE -->|"BUDGET_LIMIT_REACHED"| BSTOP["停止调用<br/>记录资源保护原因"]
GATE -->|"允许调用"| T["剥离控制字段<br/>执行业务 Tool"]
T -->|"执行失败"| ERR["Tool 状态:FAILED"]
ERR --> EP["技术故障策略<br/>有限重试或 FAILED 结束"]
T -->|"执行成功"| CR["Canonical Tool Result<br/>完整内部结果"]
CR --> CV["Harness Control View"]
CR --> AP["Agent Observation Projector"]
CR --> STORE["Canonical Store"]
AP --> MO["Model Observation<br/>白名单有界结果"]
MO --> SM["模型阅读返回内容"]
CV --> O{"Harness 客观判断"}
O -->|"evidence_status=NO_EVIDENCE"| NG1["Harness 标记 NO_GAIN"]
O -->|"重复 Tool + 相同 scope"| NG1
O -->|"其他成功非空结果<br/>包括 REFERENCE"| SM
SM --> SD{"语义信息增益"}
SD -->|"推进或排除诊断假设"| G["GAINED"]
SD -->|"没有可验证的新事实"| NG2["NO_GAIN"]
G --> M
NG1 --> M
NG2 --> M
M -->|"DiagnosisDraft"| SNAP["结束时投影 ProgressSnapshot"]
M -->|"空或非法 Draft"| DRAFTERR["丢弃非法内容<br/>投影当前进展"]
DRAFTERR -->|"有已验真 observed facts"| SNAP
DRAFTERR -->|"无安全进展"| EP
STOP -->|"给模型一次合法完成机会"| M
STOP -->|"仍无合法 Draft"| SNAP
BSTOP --> SNAP
STORE --> SNAP
SNAP --> RELEASE["DiagnosisReleaseUseCase"]
RELEASE -->|"conclusion 非空"| GUARD["EvidenceGuard / Repair / SemanticGuard"]
RELEASE -->|"conclusion 为空或无 Draft"| SAFE["确定性 SafeFallback<br/>不修复结论"]
GUARD -->|"证据支持"| SUCCESS["SUCCESS"]
GUARD -->|"无证据推断"| SAFE
SAFE --> FALLBACK["FALLBACK"]
EP --> FAILED["FAILED"]
SUCCESS --> APP["ChatApplicationUseCase<br/>持久化"]
FALLBACK --> APP
FAILED --> APP
APP --> SSE["ChatSseSession<br/>发送 content/failure + done"]
4. 状态模型
状态按职责分开,不使用一个枚举表达整个生命周期。
| 维度 | 状态 | 负责人 | 含义 |
|---|---|---|---|
| Tool 执行 | SUCCEEDED / FAILED |
ToolBoundary | Tool 是否完成技术执行 |
| 信息增益 | GAINED / NO_GAIN |
Harness 或模型 | 本次结果是否推进当前诊断 |
| 收集生命周期 | COLLECTING / SATURATED |
Harness | 是否允许继续调用 Tool |
| 内部停止原因 | INFORMATION_SATURATED / BUDGET_LIMIT_REACHED |
Harness | 为什么停止继续调用 Tool |
| Fallback 原因 | SafeFallback.type |
DiagnosisReleaseUseCase | 为什么没有发布诊断结论 |
| 最终发布 | SUCCESS / FALLBACK / FAILED / CANCELLED |
Release | 对外发布结果 |
错误码、停止原因、Fallback 原因和 RAG 相关度是附带字段,不提升为全局生命周期状态。CONFIRMED / INSUFFICIENT_EVIDENCE / NEED_MORE_INFO 不作为第二套诊断状态;其中后两种语义由 SafeFallback.type 表达。
当前实现中的兼容映射是:内部 PROJECTING 不对外暴露,READY 对应目标语义 SUCCEEDED,ERROR 对应目标语义 FAILED。
不定义独立的模型行动状态。模型发起 Tool Call 表示继续收集,输出正常 DiagnosisDraft 表示完成诊断,输出证据不足 Draft 表示主动停止;Harness 直接从实际输出推导行为。
5. Tool 结果与上下文边界
Tool 不判断业务结论,只提供事实和可机械计算的元信息。
tool_call_id 本次调用的唯一标识
execution_status SUCCEEDED | FAILED
returned_count 本次实际返回的记录数量
scope 本次查询实际覆盖的结构化范围
metadata Tool 特有的有限元信息
result 提供给模型的有界结果
字段说明:
returned_count只表达“返回了多少条”,不表示这些内容有诊断价值。scope用于识别相同 Tool、相同查询范围的重复调用,例如企业、时间窗、服务和过滤条件。metadata保存 Tool 特有信息,例如 RAG 的relevance_level、是否截断和分页信息。- 第一版不引入
new_count。它要求为不同 Tool 建立稳定的结果指纹,而且“新数据”也不等于“有效数据”。
5.1 客观信号来源
这些信号不是模型推导的:
| 信号 | 来源 | 含义 |
|---|---|---|
PROJECTING / READY / ERROR |
ToolBoundary | 当前实现的调用生命周期;目标外部语义映射为 SUCCEEDED / FAILED |
EVIDENCE_FOUND / NO_EVIDENCE / ERROR |
Tool Result Projector / ToolBoundary | 是否存在候选结果或发生技术错误 |
PRECISE / HIGHLY_RELEVANT / REFERENCE / null |
RAG 后处理规则 | RAG 候选内容的相关度 |
重复 tool + scope |
Harness | 本次查询范围是否与历史调用等价 |
NO_EVIDENCE 由各 Projector 根据结果集合是否为空确定。REFERENCE 由 RAG 根据归一化相似度及查询提示命中情况计算。两者都不是 LLM 生成的状态,但职责不同:NO_EVIDENCE 可由 Harness 机械判定为 NO_GAIN;REFERENCE 只表示候选内容相关度一般,仍由模型判断是否推进当前诊断。
改造前 RagResultProjector 只根据 evidence 是否为空生成 EVIDENCE_FOUND / NO_EVIDENCE,没有保留上游 relevanceLevel,因此会出现:
relevanceLevel = REFERENCE
evidenceBlocks 非空
-> RagResultProjector
-> evidence_status = EVIDENCE_FOUND
这不是两个判断冲突,而是 Projector 丢失了相关度维度。当前实现已兼容读取上游 relevanceLevel 或 relevance_level,并统一保留为 relevance_level。
5.2 Tool 双视图架构
内部控制信息和模型观察不能继续共用一个无差别 JSON。标准化结果产生两个明确视图:
flowchart TD
A["Tool 原始返回"] --> B["结果标准化"]
B --> C["Canonical Tool Result<br/>完整内部结果"]
C --> D["Harness Control View"]
C --> E["Agent Observation Projector"]
D --> F["Harness<br/>重复检测、低收益计数、预算、饱和状态"]
D --> G["Canonical Store"]
E --> H["Model Observation<br/>最小必要字段"]
H --> I["ToolCallResponse.content"]
I --> J["模型上下文"]
改造前会把完整 agent_result 作为 ToolCallResponse.content 交给模型。当前实现已改为白名单投影,Harness 控制字段默认不进入模型上下文。
字段边界:
| 字段 | Harness | 模型 | 说明 |
|---|---|---|---|
tool_call_id |
是 | 是 | 引用与归属校验 |
实际查询 scope |
是 | 是 | 重复检测与有界负向观察 |
有界 evidence |
是 | 是 | 模型语义判断所需内容 |
evidence_status |
是 | 是 | 候选结果是否为空或失败 |
relevance_level |
是 | 是 | 只暴露粗粒度标签,不暴露原始分数 |
truncated |
是 | 是 | 提醒模型结果并不完整 |
returned_count |
是 | 否 | Harness 客观统计 |
| 原始相似度和检索轨迹 | 是 | 否 | 内部质量与审计信息 |
| 规范化 scope、重复指纹 | 是 | 否 | Harness 控制信息 |
| 低收益计数、阈值、预算 | 是 | 否 | Run 内部状态 |
| 原始 Tool Response | 是 | 否 | 不进入模型上下文 |
只有当 Harness 必须改变模型行为时,才注入有界控制指令,例如:
{
"stop_required": true,
"reason": "INFORMATION_SATURATED",
"checked_scopes": ["本 Run 已检查范围的有界摘要"]
}
计数器、阈值和剩余预算不随控制指令进入模型上下文。
5.3 Tool 调用与投影流程
sequenceDiagram
participant Model as Diagnosis Agent
participant Interceptor as Harness Tool Interceptor
participant Gate as Harness Gate
participant Adapter as Tool Adapter
participant Backend as Tool Backend
participant Projector as Result Normalizer / Projector
participant Progress as Progress Tracker
participant Store as Canonical Store
Model->>Interceptor: Tool Call Envelope
Interceptor->>Progress: 校验并应用 previous_observation(如有)
Progress-->>Interceptor: 更新后的收集状态
Interceptor->>Gate: 校验 Run、授权、预算和饱和状态
alt 已经 SATURATED
Gate-->>Interceptor: STOP_REQUIRED
Interceptor-->>Model: 有界停止指令
else 达到硬预算
Gate-->>Interceptor: BUDGET_LIMIT_REACHED
else 允许调用
Gate-->>Interceptor: ALLOW
Interceptor->>Interceptor: 剥离 previous_observation
Interceptor->>Adapter: input 中的 typed request
Adapter->>Backend: 执行只读查询
Backend-->>Adapter: raw response
Adapter->>Projector: 标准化原始结果
Projector-->>Progress: Harness Control View
Projector-->>Store: Canonical Tool Result
Projector-->>Interceptor: Model Observation
Interceptor-->>Model: 有界 Tool Observation
end
重复查询由 Harness 根据 tool_name + normalized_scope 判断,不属于 Tool 返回状态。规范化只处理确定性的业务参数,例如时间格式、无序数组和非业务字段;第一版不判断自然语言改写是否语义等价。
5.4 结束时进展投影
每次 Tool 调用完成后只追加 Canonical Tool Result,不在每轮维护另一份用户可见摘要。Tool Loop 因 Agent 输出 Draft、信息饱和或预算限制结束时,一次性生成内部 ProgressSnapshot:
flowchart LR
T["每次 Tool 完成"] --> C["Canonical Tool Result"]
C --> S["Canonical Store"]
S -->|"Tool Loop 结束时只读投影"| P["ProgressSnapshot"]
P --> R["DiagnosisReleaseUseCase"]
R --> O["SafeFallback.observed_facts"]
ProgressSnapshot 不是新的真理源,也不进入模型上下文。它只包含来源、实际 scope、客观结果摘要、截断标记和 Harness stop_reason;原始 Tool Response、Prompt、内部 thought、计数器和剩余预算不进入发布内容。
现有 SafeFallback 和前端已经支持 observed_facts / verified_sources / limitations / next_steps,因此不新增前端协议。FallbackType 增加 INSUFFICIENT_EVIDENCE / MISSING_REQUIRED_CONTEXT,分别表达有限排查后证据不足和缺少有效查询条件。
6. 信息增益契约
信息增益只保留两个值:
information_gain = GAINED | NO_GAIN
6.1 GAINED
满足以下任一条件:
- 返回了与当前问题直接相关、可验证的新事实。
- 新事实确认了一个当前诊断假设。
- 新事实排除了一个当前诊断假设。
- 新事实实质性缩小了故障范围。
“排除假设”也是信息增益。信息增益不要求得到最终根因。
6.2 NO_GAIN
满足以下任一条件:
- 内容为空、重复或只有通用参考资料。
- 数据虽然非空,但与当前问题没有直接关系。
- 没有新增可验证事实,也没有改变任何诊断假设。
- 只是建议继续查询另一个位置,没有提供新的诊断事实。
- 模型无法判断结果是否推进诊断。
不增加 UNKNOWN。无法判断时归入 NO_GAIN,避免它成为无限继续查询的出口。
6.3 谁负责赋值
FAILED
-> 不产生 information_gain,进入技术故障流程
SUCCEEDED + evidence_status=NO_EVIDENCE
或重复的 tool_name + normalized_scope
-> Harness 直接赋 NO_GAIN
其他 SUCCEEDED 非空结果,包括 relevance_level=REFERENCE
-> 模型必须赋 GAINED 或 NO_GAIN
模型只判断“本次结果是否推进当前诊断”,不评价 Tool 产品质量,也不输出 0 到 100 的主观分数。
7. 模型步骤契约
模型收到未被 Harness 客观标记为 NO_GAIN 的成功非空结果后,如果要继续调用 Tool,必须在下一次 Tool Call 中给出上一调用的信息增益。该设计不要求模型显式声明下一步行动。
{
"previous_observation": {
"tool_call_id": "call-123",
"information_gain": "NO_GAIN"
},
"input": {
"query": "下一次查询参数"
}
}
约束:
previous_observation只在上一轮存在待模型评价的 Tool Observation 时必填;首次调用以及上一轮已由 Harness 客观赋值时省略。tool_call_id必须指向当前 Run 中最后一个尚未评价的成功 Tool 调用。- Harness 必须先校验并应用
information_gain,再判断是否允许执行本次 Tool 调用。 - Harness 消费并剥离
previous_observation,业务 Tool 只接收input中的原有业务参数。 - 上一个待语义评价的结果未被评价时,Harness 不接受新的 Tool 调用。
- Harness 已经进入
SATURATED时,新的 Tool Call 被拒绝,并向模型注入STOP_REQUIRED。 - 模型主动判断没有合理查询方向时,应直接输出证据不足 Draft,不必等待 Harness 强制停止,也无需为放行下一次调用而回传最后一轮评价。
模型行为直接从实际输出推导:
Tool Call -> 继续收集
正常 DiagnosisDraft -> 完成诊断
证据不足 DiagnosisDraft -> 主动停止
该 Envelope 是模型侧 Tool 调用协议。服务端为动态注册的 Tool Schema 统一增加 Envelope,Harness 在边界处消费控制字段,业务 Tool 的入参协议保持不变。这是一项有意的协议变更,影响模型 Tool Schema 生成、Tool Call 解析、Harness 拦截和相关测试,不影响 Tool Backend。
8. Harness 饱和规则
第一版使用连续低收益计数,不维护复杂进展账本。硬调用上限是独立资源保护,不作为信息饱和条件。
evidence_status=NO_EVIDENCE -> consecutiveLowYield + 1
重复 Tool + 相同 scope -> consecutiveLowYield + 1
成功非空结果(包括 REFERENCE)+ 模型 NO_GAIN
-> consecutiveLowYield + 1
其他成功非空结果 + 模型 GAINED -> consecutiveLowYield = 0
FAILED -> 技术故障流程,不计入低收益
consecutiveLowYield >= stopAfterConsecutiveNoGain
-> SATURATED
-> stop_reason=INFORMATION_SATURATED
达到单 Tool 或 Run 硬调用上限 -> stop_reason=BUDGET_LIMIT_REACHED
配置项 stop-after-consecutive-no-gain 默认值为 2、必须大于等于 1,只在 Run 启动时读取并固定,不进入模型上下文。默认值需要通过固定 E2E 和评测集校准,不作为不可调整的业务真理。
伪代码:
onToolResult(result):
if result.execution_status == FAILED:
handleTechnicalFailure(result)
return
if isEmpty(result) or isRepeatedScope(result):
applyInformationGain(NO_GAIN)
return
requireModelAssessment(result.tool_call_id)
applyInformationGain(gain):
if gain == GAINED:
consecutiveLowYield = 0
else:
consecutiveLowYield += 1
if consecutiveLowYield >= stopAfterConsecutiveNoGain:
collectionState = SATURATED
stopReason = INFORMATION_SATURATED
onHardLimitReached():
stopReason = BUDGET_LIMIT_REACHED
stopToolCollection()
SATURATED 是当前 Run 的 Tool 收集终态。模型不能在同一 Run 中把它恢复为 COLLECTING。用户补充新范围或新事实后,应开启新的诊断 Run。
9. 控制与发布边界
9.1 Harness 层:物理停止
Harness 使用 NO_EVIDENCE、重复的 tool_name + normalized_scope 和连续 NO_GAIN 检测信息饱和。RAG REFERENCE 与其他成功非空结果一样,由 Diagnosis Agent 通过下一次 Tool Call Envelope 回传语义评价。硬调用上限只产生 BUDGET_LIMIT_REACHED,不伪装成信息饱和。
9.2 SemanticGuard 层:无证据推断兜底
只有 DiagnosisDraft.conclusion 非空时才进入完整 EvidenceGuard、EvidenceRepair 和 SemanticGuard 链路。SemanticGuard 在最终发布前检查:
- 正常诊断中的关键结论是否绑定已验证证据。
REFERENCE和通用资料是否被错误当作当前故障事实。- scoped
NO_EVIDENCE是否被错误解释为“故障不存在”。 - 证据不足时是否生成了确定性根因。
发现无证据推断时,不继续 Tool Loop,而是转换为有界的证据不足结果。
conclusion=null 是合法业务结果,不触发 EvidenceRepair,也不要求额外调用 SemanticGuard 来证明“没有结论”。已有 analysis 时只校验其 Tool 引用真实性;Release 从 ProgressSnapshot 和 limitations 生成安全 Fallback。零次 Tool 调用且 limitations.missing_info 非空时,直接生成 MISSING_REQUIRED_CONTEXT Fallback。
9.3 ReAct Prompt 层:合法放弃许可证
Prompt 必须明确:
- 不要求模型必须得出诊断结论或根因,但必须输出一个诚实、有界的完整 Draft。
- 无法得到足够证据时,
conclusion=null是成功完成,不是失败。 - Tool 调用次数可以为零。缺少企业、时间范围、服务或错误信息,且不存在预期能产生新诊断信息的明确查询时,直接在
limitations.missing_info中列出缺口。 - 不得为了表现“已经排查”而调用没有明确目标的 Tool。
- Tool 返回内容事实正确、表述完整或结果非空,不代表它对当前诊断有信息增益。
- 通用知识、背景说明、重复内容或不能改变当前判断的内容属于
NO_GAIN。 NO_GAIN后不得通过改写相似关键词或重复相同 scope 继续尝试。- 如果仍存在范围明确、可能产生新诊断信息的不同查询,可以继续;否则应主动停止。
- 不得为了表现“尽力”而重复或扩大无明确目标的查询。
- 收到
STOP_REQUIRED后不得继续调用 Tool。
Prompt 不包含 Tool 名称、Tool Schema 或需要展开 Schema 的文本占位符。Tool 只通过服务端的模型原生 Tool Calling 通道注册;通用 Envelope 由服务端包装动态 Tool Schema。
9.4 会话上下文层:历史边界认知
每条 Tool 结果只以白名单 Model Observation 进入模型上下文一次。Harness 不在后续步骤中重复注入完整 Tool 结果、原始响应或内部进展账本。
只有 Harness 必须改变模型行为时,才注入有界停止指令:
stop_required
stop_reason
已检查 Tool 和 scope 的有界摘要
不向模型注入 consecutiveLowYield、阈值、剩余预算、重复指纹、原始相似度、完整 Tool 原始载荷或内部 thought。
9.5 Release 层:统一安全发布
DiagnosisReleaseUseCase 是诊断业务发布的唯一决策入口:
DiagnosisDraft.conclusion 非空
-> EvidenceGuard
-> 必要时 EvidenceRepair
-> SemanticGuard
-> SUCCESS 或 FALLBACK
DiagnosisDraft.conclusion 为空
-> 不执行 EvidenceRepair
-> 校验已有 Tool 引用(如有)
-> ProgressSnapshot + limitations
-> FALLBACK
Harness 已停止且没有 DiagnosisDraft
-> stop_reason + ProgressSnapshot
-> 确定性 FALLBACK
最终 Draft 为空或违反严格 JSON/Schema 合同
-> 丢弃非法 Draft,不做宽松提取或模型修复
-> ProgressSnapshot 有已验真 observed facts:INSUFFICIENT_EVIDENCE
-> 无安全进展:FAILED
Draft 合同失败不是新的 stop_reason。Trace 只记录固定失败类别、输出字节数和是否存在可发布进展,不记录模型原文、字段值或解析异常文本。
ChatApplicationUseCase 只负责编排、持久化,以及把无法形成安全业务内容的不可恢复故障映射为 FAILED / CANCELLED。预算 Fallback 不再由它单独构造。ChatSseSession 只发送 content|failure + done,不判断诊断语义。
10. 生命周期
stateDiagram-v2
[*] --> COLLECTING
COLLECTING --> COLLECTING: GAINED / 低收益清零
COLLECTING --> COLLECTING: NO_GAIN / 未达到阈值
COLLECTING --> SATURATED: 连续 NO_GAIN 达到阈值
COLLECTING --> BUDGET_STOP: 达到硬调用上限
COLLECTING --> TECHNICAL_FAILURE: 不可恢复的 Tool 或基础设施故障
COLLECTING --> DRAFT_READY: 模型输出 DiagnosisDraft
COLLECTING --> DRAFT_INVALID: 最终 Draft 为空或违反合同
COLLECTING --> CANCELLED: 用户取消
SATURATED --> RELEASE_INPUT: INFORMATION_SATURATED + ProgressSnapshot
BUDGET_STOP --> RELEASE_INPUT: BUDGET_LIMIT_REACHED + ProgressSnapshot
DRAFT_READY --> RELEASE_INPUT: Draft + ProgressSnapshot
DRAFT_INVALID --> RELEASE_INPUT: 有已验真 observed facts
DRAFT_INVALID --> FAILED: 无安全进展
RELEASE_INPUT --> EVIDENCE_GUARD: conclusion 非空
RELEASE_INPUT --> FALLBACK: conclusion 为空或无 Draft
EVIDENCE_GUARD --> SEMANTIC_GUARD: 引用有效或修复成功
EVIDENCE_GUARD --> FALLBACK: 引用无法安全验证
SEMANTIC_GUARD --> SUCCESS: 证据支持最终结论
SEMANTIC_GUARD --> FALLBACK: 无证据推断
TECHNICAL_FAILURE --> FAILED
SUCCESS --> [*]
FALLBACK --> [*]
FAILED --> [*]
CANCELLED --> [*]
11. 示例
查询:诊断切换企业失败的问题
第 1 次 lookup_knowledge
execution_status = SUCCEEDED
returned_count = 5
relevance_level = REFERENCE
information_gain = NO_GAIN(模型)
consecutiveLowYield = 1
第 2 次 query_logs
execution_status = SUCCEEDED
returned_count = 0
information_gain = NO_GAIN(Harness)
consecutiveLowYield = 2
Harness
collectionState = SATURATED
拒绝新的 Tool 调用
注入 STOP_REQUIRED
最终结果
stop_reason = INFORMATION_SATURATED
release_outcome = FALLBACK
SafeFallback.type = INSUFFICIENT_EVIDENCE
展示已检查范围、客观结果、限制和需要补充的信息
不发布 INTERNAL_FAILURE
如果第二次查询返回了能够排除某个假设的日志,模型应标记 GAINED,低收益计数清零,允许继续进行有目标的诊断。
如果用户首次请求即缺少企业、时间范围等有效查询条件,模型可以零次 Tool 调用直接输出 conclusion=null,把缺口写入 limitations.missing_info。Release 将其发布为 FALLBACK + MISSING_REQUIRED_CONTEXT,不执行 EvidenceRepair 或 SemanticGuard。
12. 非目标
- 不通过简单增加 Tool、Token 或超时预算解决空转。
- 不让 Tool 或 Harness 判断业务根因。
- 不增加多级质量分数、
UNKNOWN或复杂状态矩阵。 - 不引入
new_count和跨 Tool 通用内容指纹。 - 不新增独立 Progress Judge 模型调用。
- 不重新引入 Planner/Executor/Verifier/Composer 多角色 Graph。
13. 模型 Token 与 Tool 拒绝审计
Run 使用 RunBudget 作为 Token 总账,diagnosis_trace_event 作为模型调用明细账,AgentStep.token_count 只作为 Diagnosis Agent 轮次摘要,不新增独立 Token 表。
flowchart LR
R["Router / System / Knowledge / Repair / Semantic"] --> G["GuardModelCall"]
A["Diagnosis ReAct round"] --> I["HarnessModelInterceptor"]
G --> U["Provider Usage"]
I --> U
U --> L["Run ModelCallLedger"]
U --> B["RunBudget Token 总账"]
U --> T["MODEL_TOKEN_USAGE Trace"]
I --> S["AgentStep.token_count"]
L --> F["RUN_FINISHED 对账摘要"]
B --> F
每个 MODEL_TOKEN_USAGE 只记录:
component与component_round;usage_available;- Usage 可用时的
input_tokens / output_tokens / total_tokens。
Usage 不可用时不写 Token 字段,不把未知值记成零;Run 结束以 usage_unavailable_count 和 tokens_reconciled=false 暴露缺口。RUN_FINISHED 同时记录预算总量与审计明细合计,便于 exact Run 对账。
Tool 请求进入 HarnessToolInterceptor 后若被进展协议、重复 scope、信息饱和或观察合同门禁拒绝,写入 TOOL_REQUEST_REJECTED。事件只含安全 Tool Call ID、Tool name 和稳定错误码,不含业务参数、normalized scope 正文、原始响应或内部异常。实际执行仍只由 TOOL_INVOCATION 表达,因此两类数量不能混用。
真实审计发现:INVALID_PROGRESS_PROTOCOL 已可完整观察,但当前不会增加 NO_GAIN 或触发信息饱和。连续协议拒绝可能产生高 Token 空转,这属于待确认的停止行为改造,不属于 Token 审计本身。
14. 验收标准
- Tool 执行状态、信息增益、收集状态和发布状态职责分离。
- RAG
REFERENCE不再自动等同于诊断证据。 NO_EVIDENCE和重复的tool_name + normalized_scope被 Harness 确定性标记为NO_GAIN;REFERENCE由模型评价。- 模型继续调用 Tool 前,对上一轮待评价结果给出
GAINED或NO_GAIN。 - 下一次 Tool Call Envelope 能回传上一轮语义评价;Harness 应用评价后才决定是否放行,并在调用业务 Tool 前剥离控制字段。
- 不引入独立
next_action;Harness 从 Tool Call 或 Draft 等实际输出推导模型行为。 stop-after-consecutive-no-gain可配置且默认值为2;连续低收益达到阈值后 Harness 阻止新的 Tool 调用。- 只对
tool_name + normalized_scope做确定性去重,第一版不承诺自然语言语义去重。 INFORMATION_SATURATED与BUDGET_LIMIT_REACHED分开,硬预算不进入SATURATED。FAILED不被统计为NO_GAIN,技术故障与证据不足保持区分。- 模型可以零次 Tool 调用输出
conclusion=null + limitations.missing_info,收到STOP_REQUIRED后必须停止。 conclusion=null不触发 EvidenceRepair;只有存在结论时才执行完整 EvidenceGuard、EvidenceRepair 和 SemanticGuard 链路。- SemanticGuard 能把无证据确定性结论转换为安全的证据不足结果。
DiagnosisReleaseUseCase统一处理 Draft、信息饱和和预算终止,并复用SafeFallback.observed_facts展示ProgressSnapshot。- 空或非法 Draft 仅在有已验真进展时降级为
INSUFFICIENT_EVIDENCE,无安全进展继续 fail closed。 - 不引入
CONFIRMED / INSUFFICIENT_EVIDENCE / NEED_MORE_INFO第二套生命周期状态;后两种语义由SafeFallback.type表达。 - Tool Schema 只通过模型原生 Tool Calling 通道注册,不拼接进 Prompt。
- 原始复现 Query 在预算耗尽前正常收敛,不再发布通用
INTERNAL_FAILURE。 - Trace 能解释每轮信息增益和停止原因,但不保存原始 Tool 载荷或内部 thought。
- 模型调用 Token 可按组件和轮次对账,Run 总账与明细账差异显式可见。
- Tool 请求拒绝与实际 Tool invocation 分开审计,且拒绝事件不泄露 payload。