Skip to content

助手 · 观测 / 审计 / 评测怎么分工 ​

日期: 2026-08-28 | 作者: sunxin(+ Cursor AI 结对讲解)
你问:「assistant_audit 是专门用来检测回答对不对的吗?第一组有问题但答对了,单测测不出来,是不是只能自己看指标改代码?」
姊妹篇:W5 事实校验与审计怎么读 · 评测集两轨 · 心智地图 §3 · 幻觉与 grounding

TL;DR ​

AI 应用的难点不是「写完能答」,而是 「答对了但链路不健康」这种隐性问题怎么被发现。

  • RAG 指标不替代用户判断对错。 它把一次回答拆开:检索有没有命中、阈值过没过闸、生成是否忠实、有没有降级、错因在哪一层。
  • 听感答对 ≠ 健康地直接答对。 第 1 句海拔数字对,但 rag_degraded=1:系统靠 W5 丢掉模型原答、摘录兜底才答对,不是两道闸都过。不看指标会当成「全对」,误杀会一直在。
  • assistant_audit + rag_* + assistant_feedback + rag-cases.json 是同一类东西的轻量自建版。 大厂用 LangSmith / Phoenix / OpenAI Tracing+Evals:记 trace、建 dataset、跑 eval、做人审、做实验对比。我们刻意不做 W7 大盘,一行 SQL 就是看板。
  • 单测锁已知规则,发现未知靠线上 trace。 Mock 测不到 DeepSeek 把「那边」抽成目的地、写成「的湖面」。闭环:手测 → 看审计 → 收成夹具 → 改那一层 → 回归。

1. 「审计」在这里是什么意思 ​

软件里 audit / 审计 = 把一次请求发生了什么记下来,事后能复盘。航班黑匣子、支付对账、权限操作日志,都是同一类东西。

它回答的是:

这一轮走了哪条路?检索 query 是什么?top1 哪一篇、几分?W5 有没有把模型答案丢掉?花了多少 token?

它不回答:

海拔 2073 在现实里对不对?(那是知识库作者的责任)
这句话好不好听?(那是产品/人工抽检)
用户满不满意?(那是 assistant_feedback 点赞)

所以:审计 = 可观测性(observability),不是金标准(golden answer)。

东西表 / 文件干什么不干什么
运行时审计assistant_audit每轮一行,含 RAG 闸门字段;Web「对话审计」Tab不判「标准答案」
用户反馈assistant_feedback点了有用/没用才有行;Web「用户反馈」Tab没点赞的对话不出现在这个 Tab
分诊评测eval-cases.json这句话该判成哪个意图不管攻略正文漂不漂亮
检索评测rag-cases.jsontop-1 是不是那一篇、数字能否对回夹具不管 DeepSeek 会不会写成「的湖面」
编排单测*ToolTeststub 检索/生成,锁「过闸后代码怎么走」stub 不到真模型临场发挥

Web 助手质量是 两个 Tab、同一条 trace:对话审计 = 全量 Runs;用户反馈 = 人审队列。手测不必点赞就能在审计 Tab 看到闸门。


2. 为什么「答对了」审计里仍可能是红的 ​

知识问答有 两道闸(详见 W5 手册):

  1. 检索闸:top1 分数 ≥ 阈值 → rag_grounded=1,否则拒答。
  2. 生成闸(W5):答案里的数字 / 月份 / 地名必须能在 本轮 topK 片段 里对回原文 → 对不上就丢掉模型答案,改摘片段。

用户看见的是最终气泡。降级摘录往往仍含正确数字(「根据资料,湖面海拔约 2073 米」),所以 听感上答对了。审计记的是第二道闸有没有开火:rag_degraded=1 + rag_verify_fail_reason=places=…。

这不是「指标造假」,是两套尺子:

尺子问的是谁用
用户听感最后这句话能不能用你手测、用户点赞
闸门模型有没有说出片段对不回的事实;正则有没有误杀你查审计、改代码

第一组「赛里木湖海拔」:检索对、数字对,但旧正则把「赛里木湖的湖面」当成新地名 → 降级。结果可用,过程误杀。 不看审计就当「全对」了,误杀会一直在。

两种「答对」不要混:

用户看到审计含义
健康地答对模型组织的话 + 来源grounded=1 degraded=0检索对、生成也对回片段
兜底答对「根据资料,」+ 摘录,数字往往仍对grounded=1 degraded=1生成闸开火(真幻觉或正则误杀),靠摘录才没把错的给用户

指标的价值正在这里:把第二种从「感觉还行」里捞出来,告诉你该修校验规则,而不是去改知识库或换模型。


3. 单测为什么测不出来(以及不该指望它测出来) ​

单测要 可重复:输入固定,输出断言固定。所以检索/生成在测试里是 stub(你写死「模型会回这句」)。

线上 DeepSeek 每次措辞不同:

线上真实发生默认 Mock / 单测
「赛里木湖的湖面海拔…」夹具写的是「赛里木湖海拔是 2073 米」,旧正则不炸
「去青海湖…正规观景区…环湖」没人预先把「观景区」写进断言
把「那边」抽成 destinationKeywords=["那边"] 盖掉会话里的赛里木湖Mock 把「那边」当停用词丢掉,会话槽还在,W4 单测一直绿

不是单测没用,是单测锁的是「已知规则」。 未知措辞只能:线上打到审计 → 把这一次收成新夹具 → 下次回归才红。

行业里这叫 eval(评测集)+ observability(线上观测) 两手。没有谁靠「把模型所有说法写进 JUnit」过关。


4. 和大厂那套是同一件事(只是轻量) ​

大厂不靠「相信模型」,也不靠人工看每条答案。共同做法是:

记录 trace(这一轮内部每一步)
  → 建 dataset(固定问法 / badcase)
  → 跑 eval(回归:改完有没有把别的搞坏)
  → 抽检标注(人审:听感 + 错因)
  → 实验对比(换 Prompt / 阈值 / 模型,看指标)

产品形态是 LangSmith、Arize Phoenix、OpenAI Tracing / Evals、Langfuse 一类。共同点都是 trace + 指标看板 + 抽检 + badcase 集 + 回归实验。

本项目对应关系(ADR-054:加厚现有审计行,不新建 rag_trace、不上 W7 大盘):

大厂能力本项目现在还没做(有意)
Trace / spanassistant_audit 一行 = 一轮;rag_query / rag_top1_* / rag_grounded / rag_degraded / rag_verify_fail_reason独立 rag_trace 表、逐步 span 瀑布图
Online 看板助手质量「对话审计」Tab 读 RAG 列(不做按天折线)Grafana / W7 大盘
Dataseteval-cases.json(分诊)· rag-cases.json(检索)自动从线上灌 badcase
Evals / 回归AssistantEvalRunner · RagEvalRunner · Checker 单测托管实验、A/B
人审assistant_feedback + 你自己看审计标注平台、抽检队列

补 rag_* 的目的,就是从「感觉回答还行」推进到:知道它为什么行、哪里不健康、该修哪一层(检索 / 阈值 / W5 正则 / 会话改写 / 知识库)。

B 端怎么摆这两路数据:列表分 Tab(对话审计 / 用户反馈),点开后是同一条 trace。不是合成一个命中率,也不是两个互不认识的页面。见 ADR-056。


5. 「看指标再改代码」是不是很大一摊 ​

大厂会做仪表盘、周报、自动 badcase 池。我们现在 刻意不做 W7 大盘。

维护者一周够用的闭环:

手测 6 句(或用户反馈一条)
    → SELECT id, message_preview, rag_query, rag_grounded, rag_degraded, rag_verify_fail_reason
      FROM assistant_audit ORDER BY id DESC LIMIT 20;
    → 分清:检索失败 / W5 真拦幻觉 / W5 误杀 / 会话槽被覆盖
    → 误杀或覆盖:加 1 条 Checker 或 ToolTest,改正则 / strip 指代词
    → 重启后再问同一句,看新行 rag_degraded=0

你不需要先上「全命中率」「忠实度均值」才能开工。那些是量变之后的统计。现在每一行审计已经带齐闸门字段,一行 SQL 就是指标。

工作量大的部分其实是:正则误杀会随模型措辞冒出来,要一次收一条。这是概率系统的常态(心智地图 §1),不是你漏做了某张表。


6. 和「全命中」相关的词,别混 ​

你可能听到的在本项目里实际指
Recall@1 / 命中正确篇检索 top-1 是不是评测里标注的那篇(rag-cases.json)
grounded检索闸:分数过阈值,不是「答案客观正确」
degraded生成闸开火,模型原答被丢掉
HIT(outcome)这轮给了用户一份非拒答回复(含降级摘录)
忠实(faithfulness)答案事实能否对回给定片段(W5 / 评测 check)
有用/没用用户点的,跟闸门无关

所以:不要用 outcome=HIT 当「模型全对」。 HIT + rag_degraded=1 恰恰是「给了可用回复,但生成没过闸」。


7. 手测 6 句时建议盯的列 ​

重启后端(新正则 + 新 strip 才生效;第一次攻略问答仍可能慢,那是建索引)。

#问期望审计(过程)用户听感
1赛里木湖海拔多少米?grounded=1 degraded=0,reason 空可保留模型原句,不必再套「根据资料」
2青海湖有什么注意事项?同上;若仍 places=黑马河 可能是 该 chunk 没写黑马河(真缺实体,不是「去青海湖」误杀)注意点来自青海湖篇
3赛里木湖攻略degraded=0(环湖/观景区不再误杀)攻略长文 + 来源
4同一 session:那边怎么去rag_query 含「赛里木湖」,不要 top1 北京 / 拒答交通类攻略
5迪拜购物中心有哪些品牌?grounded=0 拒答明说没有
6赛里木湖有什么活动?RAG 列空,SEARCH_ACTIVITIES活动卡不是攻略

查法:message_preview 对上问句,看同 session_id 的第 4 句 rag_query。


8. 要测多少条?160 个新疆景点要不要全测? ​

不要。 自动评测按 失败模式 / 问法类型 / 易混对 覆盖,不按「库里有 N 篇就写 N 套题」。160 篇全测一遍,测的是内容运营(这篇攻略写没写错),不是助手链路。

大厂也不会对知识库每条文档做完整问答回归。他们分三层:

层覆盖什么规模感本项目现在
黄金集(手写,进 CI)问法类型 + 硬负例 + 易混地名大约 20~50 条 RAG 就够用很久;意图集可以到几十条rag-cases 16 条(5 个种子目的地 + 冰岛/迪拜拒答);eval-cases 68 条
参数化冒烟(可扫 160 篇)只用标题/地名当 query,看 top-1 是不是自己这篇。不调 DeepSeek1 个测试 × N 篇,不是 N×6 道问答题还没有;库涨到上百篇时再加最划算
线上全量(用户问到才测)降级率、拒答、易混检索160 篇都会「被测到」,靠 assistant_audit 按 rag_top1_source 聚合rag_degraded / rag_verify_fail_reason 已有

第 1 句那种「数字对但 degraded=1」,不是再给赛里木湖加 159 条同类海拔题能发现的。它是一种失败模式(「的湖面」误杀),黄金集里锁 1 条措辞 + 1 条 Checker 即可;160 个湖都会受益。

8.1 黄金集里该有什么(不是 160 个「海拔多少」) ​

每种问法 1~2 个代表目的地就够:

  • 事实:海拔 / 季节 / 距离
  • 攻略口吻:注意事项、怎么去、住哪、适不适合第一次
  • 分诊边界:「有什么活动」走找局,「XX攻略」走知识,「N 日游」走计划
  • 硬负例:库外(冰岛、迪拜)必须拒
  • 易混对(新疆库越大越重要):赛里木湖 vs 青海湖、喀纳斯 vs 禾木、天山天池 vs 赛里木湖——问 A 不能 top-1 成 B

你现在缺的主要是 易混对,不是「每个景点一条」。库从 5 篇涨到 160 篇,检索串篇风险上升,黄金集加 5~10 条易混 比加 160 条海拔题有用得多。

8.2 160 篇真正该做的两件事 ​

  1. 内容对不对:写库的人抽检正文(数字、季节、注意事项)。W5 不负责这个。
  2. 检索会不会捞错篇:标题冒烟(上面那一层)+ 易混对黄金集 + 线上看 rag_query/rag_top1_source。

大厂的日常是:黄金集保持小而稳(改切块/阈值必跑)→ 线上 100% 记 trace → 按 degraded、点踩、串篇 挖 badcase 再灌回黄金集。所以你会觉得「永远测不完」:不是 160 没测完,而是模型措辞会冒出新失败模式,一次收一条。

一个人维护时,够用的目标不是「160 全覆盖」,而是:

  • CI:现有 16 条 RAG + 68 条意图 不退步;易混对随新疆热点补几条。
  • 线上:每周扫一眼 rag_degraded=1 的 reason,重复的收成单测。
  • 不要为每个新景点写 6 句自动问答。

Powered by VitePress