Files
HomeAgent/docs/zh/abstention-criterion.md
JianFeeeee cf14b840ef docs: 补齐文档状态分类 + 校正两轮代码改动后的失真
## 背景

上一次文档校订(b9b5ac0)之后又有两次代码提交(5194a96 / 8293282),
把 future-plan §1.1 整节变成了错的 —— 它还写着「档位没有生效点」
和「在 prepareInputTask 里加一次 activateSecurityProfile 调用」,
而后者正是被后来的收敛**否定掉的方案**。

## 新增 docs/zh/README.md(文档索引)

32 篇文档此前混着三种时态(当时实测 / 历史推演 / 设计规划),外观相同。
索引给出**状态分类与可信度规则**:

| 状态 | 能不能当事实用 |
|---|---|
| 已实现并部署 | ✅ 直接信 |
| 部分实现 | ⚠️ 只信标了"生效"的部分 |
| 设计 / 未实现 | ❌ 只能当设计意图 |
| 归档说明 | ❌ 不要改、也不要信 |

并写死**判据名可信度规则**:文档里的 `TestXxx` 不保证还存在。
给了核对命令,以及当前基线(27 条缺失的分布 —— 18 条属"设计未实现"类
文档的规划名、7 条是 §2.7.3 有意保留的历史对照表左栏、2 条属视频能力
未纳入契约)。判定标准:**在"已实现"类文档正文里找不到才是缺陷**。

## 重写 future-plan §1.1(已结案)

原节写的是错的方案。改成记录**真正的缺陷分三层**:

```
第 3 层(表面):activateSecurityProfile 零调用方
第 2 层:agent/core 在替 security 做策略决策
         (自己抠 security_profile / 自己选判定链 /
           自己写 Kind:"resident" 声明主体类别 —— 提权口子)
第 1 层(根因):security 缺少「输入接入点」
```

并补上「每 agent 一个实例」的最终形态(共享注册表 + per-agent 执行视图,
sessionProfile / longtimeProfile 两层,优先级 session > longtime 本身是安全语义)。

§〇「机制 ≠ 接线」表格里档位那一条从 🔴 改为 ✅。

## 各文档状态行

此前 14 篇缺状态行(runbook / 实测报告 / 计划类)。逐篇补上**符合实际内容**
的声明,而不是统一套一句。特别地:

- `commondev-design.md` 标题本就写「设计 · 未实现」→ 归到"设计"类
- `live-run-evidence-2026-10-04.md` → 明确标注"历史证据快照,不要用它的
  结论覆盖现在的实现判断"
- `legacy-issues.md` → 写明它与 future-plan 的分工(前者收已知问题,
  后者收能力缺失与零调用方)

## 正文里两处判据名漂移

- `TestBootCtxCloseAllIsReverseOrder` → 实际是
  `TestKernelStateCloseAllIsReverseOrder`(`BootCtx` 改名时判据跟着改的)
- `TestNilTypedBusSafety` → 标注为"规划名,仓库中不存在"

## 新增 §2.7.5 模块产物的实例化粒度

依赖图保证"设施已就绪",但没说该有几个实例 —— 这是独立决策。
记下 security 的两个答案:全局基线共享(否则插件声明对部分 agent 不生效)、
轮次状态 per-agent。并给出给未来新模块的两条判断标准。

## 安全文档

状态头补「架构形态」段(防火墙定位、per-agent 视图、两层档位);
接线状态表里 `ActivateProfile` 从 🔴 改为 ✅(2026-10-31 接通)。

## README

文档列表加索引与 future-plan 入口 —— 此前从 README 找不到 docs/zh 的任何指引。

## 核对

- docs/zh 32 篇全部有状态行
- 索引里列的文档全部存在,无遗漏
- 分类与各文档自述一致(逐篇抽查)
- go build 仍通过(纯文档改动)
2026-10-31 07:50:58 +08:00

150 lines
6.0 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.

# 拒答判据:符号存在性
> **状态:参考 / 机制说明。** 描述拒答判据的设计口径与实现位置,非逐条审计记录。
> 未实现项见 [`future-plan.md`](./future-plan.md)。
## 结论先行
**「查询符号在库中零出现」可以安全拒答。** 依据是确定性事实
(字符串包含),不是浮点分数阈值。
## 数据
生产快照(1391 块,chineseclip 512 维),中文符号切分修复后:
```
真实查询
脚本路径改到哪个目录了 0.50 [脚本路径]
从零开发 QQ 插件用什么工具链 0.33 [从零开发]
agentmail 公网访问地址是什么 0.33 [agentmail]
本机 13010 端口对应什么 0.67 [13010 本机]
编造查询
grafana 监控面板的端口是多少 0.00
谁负责数据库容灾演练 0.00
kafka 消息队列的 broker 地址是什么 0.00
redis 集群的主从复制配置在哪 0.00
sentry 告警怎么接入 0.00
postgres 主库地址是什么 0.00
```
**完全分离**:真实全部 > 0,编造全部 = 0。
## ★ 中文切分修复是前提
第一次测量时**真实查询里也有 0.00**("脚本路径改到哪个目录"),
两侧都是 0,判据不成立。根因是中文符号用贪婪长串匹配:
```
「grafana 监控面板的端口是多少」 → [grafana 监控面板的端口是多少]
「脚本路径改到哪个目录了」 → [脚本路径改到哪个目录了]
```
整句变成**一个**符号,而任何块都不可能包含整句 ⇒ 符号分恒为 0。
⇒ 符号路对**所有纯中文查询完全失效**,只有含数字串的探针能被救
(这也是上一轮融合只拿到 3/9 的原因之一)。
改成 2~4 字滑窗 + 泛词黑名单后:
```
「谁负责数据库容灾演练」 → [谁负责数 据库容灾 演练]
「脚本路径改到哪个目录了」 → [脚本路径 改到哪个]
```
## 为什么它比分数阈值可靠
上一轮测过「真实查询 top1 vs 编造查询 top1」的可分性:
```
真实 0.6390 ~ 0.8041
编造 0.4320 ~ 0.5923
间隔 0.047,n=4 ⇒ 判为不可用(那是运气不是能力)
```
而符号存在性:
- 是**确定性事实**(`strings.Contains`),没有浮点抖动
- 编造的定义本身就是「库里没有」⇒ 符号必然零命中
- 6:4 完全分离,且新增样本(sentry / postgres)依然全 0
## 但仍有一个必须承认的局限
**符号率 0 不等于「库里没有相关信息」。** 它只说明
「查询里的这些词在库里查不到」。反例:
```
问「昨天那个批量任务跑完没」—— 库里记着「批量任务完成,耗时 3 分」
符号「批量任务」命中 ⇒ 0.75 ✓ 没问题
问「那个跑得最久的任务」 ——「那个」是泛指
符号可能全零 ⇒ 被拒答 ✗ 误伤
```
⇒ **拒答只在「符号提取有效」时可信**。而「提取有效」的判据是
提取出的符号里至少有一个**不是虚词碎片**。
当前实现靠泛词黑名单近似,更稳的做法是:
若查询含泛指词(那个/这个/它/之前),**不拒答**(走召回 + 让模型自己说不确定)。
## 未完成
- 拒答逻辑尚未接入生产路径(`recallByBlocks` 仍无条件返回内容)
- 泛指词检测未实现
- n=10 的判据仍偏小,但方向与上一轮 n=4 时的判断相反:
这次是**确定性事实 + 完全分离 + 新增样本不破**,而不是「差 0.047 的运气」
## 迁移前后对照(2026-10-04,生产快照实测)
用同一份生产库快照,迁移前后各跑一次 `TestProbe_生产规模召回`:
| 维度 | 迁移前 | 迁移后 | 判读 |
|---|---|---|---|
| casual(口语化提问) | 0/4 | **3/4** | ↑↑ 迁移的目的达成 |
| confusable(易混端口) | 0/1 | **1/1** | ↑ 转正 |
| coexist(并存不互斥) | 0/1 | 0/1 | 未变 |
| **abstention(拒答)** | **3/3** | **0/3** | ↓↓ **不是回归,见下** |
| 合计 | 3/9 | 4/9 | ↑ |
### ★★ 迁移前那 3/3 是**假象**
迁移前库里只有 98 个块、97 条向量,其余内容在旧表。
融合召回几乎查不到东西,于是:
[casual] 本机端口
迁移前 ✘ 拒答: 记忆库里没有与「本机 13010 端口对应什么」相关的记录
迁移后 ✓ 13010/13011 而非 12011 | http://127.0.0.1:13010 …
⇒ 迁移前**所有真实问题都被"拒答"挡掉了**,
而那三条编造查询恰好"通过"了 —— 两者都是数据为空的副作用,
**不是能力**。
⇒ ★ **「拒答率高」与「召回能力强」在数据为空时无法区分。**
这与此前记录的「编造比误召回更严重」不矛盾:
那条判据要靠**真实问题能召回**才有意义。
### ★ 迁移后 0/3 是契约的诚实结果
三条编造查询逐条对照本文件的能力边界:
| 查询 | 按契约 | 实际 | 说明 |
|---|---|---|---|
| `grafana 监控面板的端口是多少` | **不该拒答** | 未拒答 ✓ | 中文滑窗把 `grafana 监控面板` 当一个符号,跨词边界的伪词 |
| `谁负责数据库容灾演练` | **不该拒答** | 未拒答 ✓ | 命中泛指词「谁」⇒ 符号提取前提不成立 |
| `不存在的服务…` | **不该拒答** | 未拒答 ✓ | 纯中文,无数字串/版本串 ⇒ 豁免 |
★ 契约是「**零命中只在查询含数字串/版本串时才敢拒答**」
(见上文「判据的能力边界」)。这三条都不含数字串,
所以**按设计就不该拒答**。
⇒ ★ 之前把 0/3 当成「编造」判红,是判据与契约口径不一致:
`abstain: true` 这个期望值本身超出了契约能保证的范围。
### 待办:判据口径要与契约对齐
`probe_prod_test.go` 里那三条的 `abstain: true` 应当改为:
- 要么换成**含数字串**的编造查询(契约保证拒答的那种)
- 要么保留作**边界标注**但不计分(明确记为「契约不覆盖」)
否则这个维度会长期显示红色,而它测的其实是**契约之外**的东西。