Files
SuperBizAgent-java/mvp/issues/archived/ISS-009-negative-observation-no-evidence-reference.md
T

240 lines
5.7 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# ISS-009 negative_observation 精确引用 no-evidence 结果
**严重程度**:中
**状态**:已修复
**发现时间**:2026-07-08
**关联**:
- `ISS-007-verifier-evidence-summary-fidelity`
- `ISS-008-executor-narrow-scope-overreach`
- `executor-structured-output-v2`
---
## 背景
ISS-007 已经把正向证据引用收敛为:
```text
source_invocation_id + raw_path + evidence_excerpt
```
Gatekeeper 通过 `tool_invocation.retrieval_details.evidence_refs` 校验 Executor 引用是否真实存在。
但负向观察存在一个缺口:当工具明确返回“没查到”时,结果通常是空数组:
```json
{
"logs": [],
"total": 0,
"message": "未找到匹配的日志"
}
```
这时没有 `$.logs[0]`、`$.alerts[0]` 或 `$.evidence_blocks[0]` 可以引用。Executor 如果输出 `negative_observation`,Gatekeeper 无法稳定验证它引用的“无证据结果”,容易降级为 `LOW_CONFID` 或 `REJECT`。
---
## 问题
用户问:
```text
只确认 inventory-service 是否存在 HikariCP 连接池耗尽日志。
```
工具返回:
```json
{
"success": false,
"logs": [],
"total": 0,
"message": "未找到匹配的日志"
}
```
合理 claim 是:
```json
{
"claim_type": "negative_observation",
"claim_text": "未检索到 inventory-service 的 HikariCP 连接池耗尽日志。"
}
```
但旧设计只支持正向数组项:
```text
$.alerts[i]
$.logs[i]
$.evidence_blocks[i]
```
因此负向观察缺少可回溯的精确引用点。
---
## 修复决策
给 no-hit / no-evidence 结果增加一等证据引用:
```json
{
"raw_path": "$.no_evidence",
"text": "query_logs returned no evidence; evidence_status=no_evidence; query=inventory-service HikariCP; topic=application-logs; total=0; message=未找到匹配的日志"
}
```
Executor 可以引用:
```json
{
"tool_name": "query_logs",
"source_invocation_id": 123,
"raw_path": "$.no_evidence",
"evidence_excerpt": "query_logs returned no evidence; query=inventory-service HikariCP; total=0; evidence_status=no_evidence"
}
```
### 语义边界
`$.no_evidence` 只表示:
```text
该工具对当前查询返回无匹配证据。
```
它不表示:
- 问题绝对不存在。
- 根因被排除。
- 系统已经健康。
- 没有必要继续排查。
---
## 实施范围
### 已修改
- `ToolInvocationRecorder`
- `query_logs` no-hit 时生成 `evidence_refs[0].raw_path="$.no_evidence"`。
- `query_metrics` no-hit 时生成 `evidence_refs[0].raw_path="$.no_evidence"`。
- `lookup_knowledge` no-hit 且无 evidence blocks 时生成 `evidence_refs[0].raw_path="$.no_evidence"`。
- `ExecutorGatekeeperService`
- 复用既有 `evidence_refs` 校验逻辑,无需新增特殊分支。
- `$.no_evidence` 和普通 raw_path 一样必须存在于 `retrieval_details.evidence_refs`。
- `chat-executor-prompt.md`
- 明确 `negative_observation` 必须引用 `$.no_evidence`。
- 明确没有实际工具调用时禁止使用 `$.no_evidence`。
### 未修改
- 不新增数据库表。
- 不新增复杂 metadata。
- 不改变 Planner。
- 不改变 Agent 编排。
---
## 验收标准
1. `query_logs` 返回 `logs=[] / total=0 / evidence_status=no_evidence` 时,`tool_invocation.retrieval_details.evidence_refs` 包含:
```json
{
"raw_path": "$.no_evidence"
}
```
2. Executor 输出 `negative_observation` 并引用 `$.no_evidence` 时,Gatekeeper 可以校验通过。
3. Executor 如果用 `$.no_evidence` 搭配正向证据文本,例如 `HikariCP active=50/50`,Gatekeeper 必须拒绝。
4. `$.no_evidence` 不得被解释为“问题绝对不存在”,只能表达“当前查询未检索到匹配证据”。
5. HikariCP negative E2E:
```text
只确认 inventory-service 是否存在 HikariCP 连接池耗尽日志。
```
期望:
- 工具返回 no-hit。
- 不返回 `generic-service`。
- Executor 输出 `negative_observation`。
- `raw_path="$.no_evidence"`。
- Gatekeeper `pass/none`。
- Verifier 不误判为正向 HikariCP 证据。
---
## 验证记录
### 2026-07-08 单元测试
命令:
```text
mvn '-Dtest=ToolInvocationRecorderTest,ExecutorGatekeeperServiceTest,QueryLogsToolsTest' test
```
结果:
```text
Tests run: 23, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS
```
覆盖点:
- `query_logs` no-hit 生成 `$.no_evidence`。
- `query_metrics` no-hit 生成 `$.no_evidence`。
- `lookup_knowledge` no-hit 生成 `$.no_evidence`。
- Gatekeeper 可以校验 `$.no_evidence`。
- 多个 no-evidence 调用存在时,Gatekeeper 可按 `tool_name + raw_path + evidence_excerpt` 唯一回填 `source_invocation_id`。
- `negative_observation` 混绑正向 `$.logs[i]` 会被拒绝。
- HikariCP negative mock 不返回 `generic-service`。
### 2026-07-08 E2E 验证
输入:
```text
只确认 inventory-service 是否存在 HikariCP 连接池耗尽日志。
```
最终通过 session:
```text
sessionId: iss009-hikari-negative-latest-20260708-232428
verdict: PASS
groundedness_score: 1.0
gatekeeper_result.status: pass
gatekeeper_result.severity: none
claim_count: 1
claim_type: negative_observation
raw_path: $.no_evidence
generic_service_hit: false
overstate_hit: false
```
Executor claim:
```text
当前查询未检索到 inventory-service 的 HikariCP 连接池耗尽日志。
```
最终答案:
```text
本次查询在 inventory-service 中未发现 HikariCP 连接池耗尽的日志记录,检索结果未匹配到相关证据。
```
说明:
- Executor 仍可能输出多个 `$.no_evidence` binding。
- 如果 `source_invocation_id` 缺失,Gatekeeper 会按 `tool_name + raw_path + evidence_excerpt` 唯一匹配真实 invocation 并写入 warning。
- 最终答案不使用“排除”“确认没有”“不存在该问题”等过度表达。