助手-RAG 答案准不准,是谁的责任?
日期: 2026-08-20 | 作者: sunxin(+ Cursor AI) | 关联: 智能助手专题 · ADR-044 ·
AssistantApplicationService.knowledgeQa·OpenAiCompatibleKnowledgeAnswerAdapter· 前置阅读 助手-大模型幻觉与grounding / 助手-RAG向量检索新手科普
TL;DR
- 「模型答得准不准」其实是两件事:事实准(说的对不对)和忠实/通顺(有没有照资料说、话说得清不清楚),在 RAG 里由不同的人负责。
- RAG 系统里,"标准答案"由你的知识库定义,不是模型定义。你写 md 那一刻,事实的对错就定了;模型只负责"忠实复述 + 不编造"。
- 「准不准跟 LLM 训练有关,还是跟我写的 RAG 编排有关?」——都有关,分工不同:编排/知识库决定"模型手上有没有对的资料 + 会不会拒答";LLM 训练程度决定"拿到资料后能不能忠实用好"。
- 真实实拍(2026-08-20 首次联调):问"冰岛要注意什么",检索过了阈值(
grounded:true),但模型照 grounding 提示词软拒答"资料里没有冰岛,只有青海湖/新疆/赛里木湖"——两层拒答(Java 硬拒 + 模型软拒)双保险被验证生效。
目录
- 场景:一个让人卡住的问题
- 原理一:先把"准"拆成两件事
- 原理二:RAG 下责任是分层的
- 原理三:训练 vs 编排,到底谁决定
- 原理四:不开 RAG 会怎样(对比才看得清)
- 项目落地:两层拒答(含冰岛实拍)
- 怎么验收"准不准"
- 教学收获
场景:一个让人卡住的问题
"我要让模型回答'赛里木湖最佳旅游季节是什么时候',可我自己都不知道是几月。那这个答案是从我定的知识库来的,还是模型自己推测的?模型答得准,到底是它训练得好,还是我 RAG 编排写得好?"
这个困惑几乎每个做 AI 应用的人都会遇到。根因是:把"事实对不对"和"模型忠不忠实"当成了一件事。拆开就通了。
原理一:先把"准"拆成两件事
| 维度 | 问的是 | 例子 |
|---|---|---|
| 事实准(factual) | 说的内容对不对 | 赛里木湖到底 6-9 月还是 1 月最佳 |
| 忠实/通顺(faithful / fluent) | 有没有照资料说、有没有瞎编、话顺不顺 | 有没有编出资料里没有的"景点门票 200 元" |
在 RAG 里,这两件事是不同的人负责的——这就是解开困惑的钥匙。
原理二:RAG 下责任是分层的
| 环节 | 谁负责 | 负责哪种"准" |
|---|---|---|
| 知识库(你写的 md) | 你 | 事实的标准答案——"6-9 月"这个事实来自你库里的攻略 |
| 检索(embedding + RAG 编排) | 你的代码 | 把"对的那段"捞出来喂给模型(召回 / recall) |
| 生成(LLM / DeepSeek) | 模型训练程度 | 拿到那段后忠实、通顺地作答,不加戏(faithfulness) |
核心结论:RAG 里"标准答案"是你的知识库定义的,不是模型。
所以"我自己都不知道几月"恰恰点破了 RAG 的前提——你需要的不是"自己成为专家",而是"有一份你信得过的资料"。你只需在写库那一刻,从官方/马蜂窝/靠谱攻略确认一次"6-9 月",写进 md。之后系统的职责就只是"忠实检索 + 复述"。事实对错,在你写库那一刻就定了。
原理三:训练 vs 编排,到底谁决定
都有关,但分工完全不同:
- 你的 RAG 编排 + 知识库 → 决定 "模型手上有没有对的资料" + "没资料时会不会拒答"(覆盖面 / 召回 / 防幻觉的第一道闸)。
- LLM 的训练程度 → 决定 "拿到资料后,能不能读懂、忠实按它作答、不自己加戏"(faithfulness)。
一个类比最好记:
- 知识库 = 教科书(你编的,事实以它为准)
- RAG 检索 = 帮学生翻到正确那一页
- LLM = 学生,照着那页用自己的话答题
- 考"学生准不准" = 看他有没有照书答(不是看书本身对不对)
- 书本身对不对 = 你(编书人)的责任
原理四:不开 RAG 会怎样(对比才看得清)
同样问"赛里木湖最佳季节":
| 纯 LLM(不开 RAG) | 开 RAG | |
|---|---|---|
| 答案来源 | 模型训练时"背下来的世界知识",回忆/推测 | 你库里检索出的攻略片段 |
| 可控性 | 不可控、不可溯源、不可更新 | 改 md 就能改答案,末尾标 来源: |
| 风险 | 可能过时 / 可能编造(幻觉),你还不知道它为啥错 | 检索不到就拒答,不硬编 |
在本项目里,生成那一步的系统提示词是强制 grounding 的("只能用我给的片段作答,没有就说没有"),再加相似度阈值拒答——所以模型本来就不该"自己推测",要么照库答、要么拒答。这正是"真 RAG"与"让模型自由发挥"的分水岭。
项目落地:两层拒答(含冰岛实拍)
拒答(防幻觉)在本项目有两层,任一层生效都不会编造:
| 层 | 触发条件 | 话术来源 | 谁拦的 | 代码位置 |
|---|---|---|---|---|
| 硬拒答(Java) | top1 相似度 < score-threshold(默认 0.2) | knowledgeRefuse():"资料库暂时没有…我不敢瞎编" | 你的编排(省钱,压根不调模型) | AssistantApplicationService.knowledgeQa |
| 软拒答(模型) | 过了阈值、检索到片段,但片段答非所问 | 模型自己生成:"资料里没有 X,只有 A/B/C" | LLM 忠实度 | OpenAiCompatibleKnowledgeAnswerAdapter 的 grounding 提示词 |
三条真实联调日志(2026-08-20 首次接通义 v4 + DeepSeek)
# ① 直接命中
助手意图 - intent:KNOWLEDGE_QA, keywords:[赛里木湖]
助手知识问答 - 检索:3 条, top1:0.944, 阈值:0.2, grounded:true
→ 答:"赛里木湖最佳旅游季节是每年 6 月到 9 月……" + 来源:赛里木湖
# ② 换个说法(语义召回:关键词不同、意思相同,仍命中同一篇——关键词版做不到)
助手意图 - intent:KNOWLEDGE_QA, keywords:[赛里木湖] (问的是"几月去赛里木湖比较合适")
助手知识问答 - 检索:3 条, grounded:true
→ 答:"6 月到 9 月都挺合适……" + 来源:赛里木湖
# ③ 库外问题(冰岛):检索"过了"阈值,但模型软拒答
助手意图 - intent:KNOWLEDGE_QA, keywords:[冰岛]
助手知识问答 - 检索:3 条, 阈值:0.2, grounded:true ← 注意:grounded=true,Java 没硬拒
→ 答:"资料里暂时没有冰岛旅游的相关信息,只有青海湖、新疆和赛里木湖的注意事项……"冰岛为什么走软拒答? 因为"冰岛旅游注意事项"和库里"XX 旅游注意事项"语义沾边,相似度过了 0.2,Java 硬拒没触发;但模型读完片段发现讲的是别的地方,照 grounding 提示词老实说"没有"。
这就是"责任分层"的活教材:检索这层把它放进来了(语义确实沾边,这是召回的正常行为),模型这层兜住了(忠实度好,没拿着青海湖的资料硬答冰岛)。两层双保险,任一层生效都不幻觉。
运行时还有 W5(生成后 Java 再对一次数字/月/地名)。检索过了、模型也答了,仍可能被降级摘录——有时是真胡编,有时是正则误杀。怎么读 rag_grounded / rag_degraded、对照哪些测试:手册 · W5 事实校验与审计怎么读。
⚠️ 一个观测坑(心里有数)
冰岛这条审计记的是 outcome:HIT, hitCount:3——因为审计的 HIT/REFUSE 只看"Java 硬拒答"那条线(snippets≥1 且 score≥阈值 → HIT),看不出"模型软拒答"。所以统计"拒答率"时,模型软拒的部分现在会被算进 HIT。要精确统计需在生成后加一层"模型是否软拒"的判定(未来项,见迭代主线技术债),当前不影响功能与防幻觉。
怎么验收"准不准"
分两层,标准不一样:
① 检索层(能自动化,客观) —— RagEvalRunner 问某地问题,有没有把该篇捞到 top-K?→ Recall@K。不需要标准文字答案,只需要你知道"这题该命中哪篇"。
② 生成层(较主观,抽检 / LLM-as-judge) 判断标准是——
"模型有没有照资料说话",而不是"6-9 月是不是宇宙真理"。
因为"6-9 月对不对"是知识库的责任。你验模型时只看它有没有超出片段范围乱说(faithfulness)。
出问题时"该怪谁"排错表:
| 现象 | 怪谁 | 怎么修 |
|---|---|---|
| 编了库里没有的内容 | LLM 忠实度差 / grounding 没生效 | 换更强模型、强化 prompt |
| 该命中却说"资料未提及" | 检索没捞到(embedding / 切块 / 阈值) | 调编排、降阈值、改切块粒度 |
| 照库答但内容本身错 | 你的知识库写错了 | 改 md |
| 该拒答却硬答 | 阈值太低 / grounding 不够硬 | 调高 score-threshold、强化提示词 |
教学收获
- RAG 的"准"不是"符合客观真理",而是"忠于你给的资料"。 事实对错是写库人的责任,模型只负责"别漏检、别瞎编"。
- 写 RAG 编排的本质,是把"答案的话语权"从模型的黑箱记忆,夺回到你可控、可溯源、可更新的知识库手里。
- 拒答要有两层:Java 阈值硬拒(省钱、快、确定)+ 模型 grounding 软拒(兜语义沾边但答非所问的漏网之鱼)。两层都留着,防幻觉才稳。
- 验收要分层:检索层用 Recall@K 自动化;生成层看忠实度、别用"客观真理"当标尺。
- 遇到"我自己都不知道标准答案"——那是提醒你该先建一份信得过的知识库,而不是指望模型替你当专家。
附录
- 前置:助手-大模型幻觉与 grounding(模型为什么编、三层防治)· 助手-RAG 向量检索新手科普(embedding/向量/切块/惰性索引)
- 总目录:助手-AI 应用工程心智地图与验收标尺
- 决策:ADR-044
- 验证:本地验证手册 §场景 7 · 配置开关速查