事实边界:检索、引用、拒答与人工兜底

把回答分成有据可答、无据低风险、澄清拒答与转人工四种模式,给出检索白名单、片段身份与不可变版本、逐句引用和每周审计的做法;区分检索分数与正确概率,复算引用覆盖率、拒答召回率、拒答精确率和人工兜底率,避免把有引文当作结论必然正确。

模型最危险的时候不是答错,而是答错时语气和答对时一模一样。

一、一句「应该可以」让用户错过了申报期

沈瑜给一个产业园区做政策问答助手,知识库是园区整理的补贴文件:一次性创业补贴、场地租金减免、社保补贴,按年度和主体类型分册。上线第一个月,回答看起来都很像回事。

以下情境为教学假设,人物、引语和数字不代表经核实的真实案例。

六月,一位个体户问:「我这种个体工商户能不能领一次性创业补贴?」助手答:「应该可以,建议尽快准备材料申请。」还顺手给了一个截止日期。用户照着准备了半个月,到窗口才被告知:当年的细则已经把个体工商户排除在外,那个日期来自两年前的一份通知。

复盘时发现三件事。知识库里同时存在 2024 年与 2026 年两份文件,检索把旧的那份排在了前面;提示词只写了「尽量给出处」,模型于是自由发挥;系统里根本没有「没有依据就不许下结论」这条硬规则,也没有任何转人工的出口。

这不是一次孤立的幻觉,而是一套边界设计的缺失:没有白名单,过期的文档照样能被召回;没有逐句引用,用户无法核验;没有阈值,低置信度的答案照样被当成结论输出。

事实边界要解决的不是「让模型更聪明」,而是「让它在没有依据时闭嘴,并且在闭嘴时把人送到能解决问题的地方」。前者靠模型,后者只能靠你自己的路由与流程。

二、四种回答模式:按风险与置信度路由

所有回答先落到四种模式之一,再决定要不要生成。路由同时考虑错误后果、问题范围、来源适用条件和经校准的检索分数。相似度或重排分数只是路由信号,不是答案正确的概率;最高分过线也不能代替地区、年度及主体条件检查。

模式触发条件输出要求失败后果
有据可答命中白名单文档,最高分过阈值,问题在可答范围每条事实句带可点击来源,无来源的句子删掉引用错位,用户按错误条款办事
无据但低风险检索为空或低于阈值,但答错只造成困惑首句声明「文档中未找到依据」,禁止出现数字、日期、金额用户误以为是官方口径
澄清或拒答问题缺关键要素,或要求预测审批结果、绕过条件固定话术 + 需要补充的信息清单 + 可自查的入口用户反复追问,或转向别处被骗
转人工高风险且低置信度,或同一问题连续两轮未解决带原问题、命中文档 ID、已生成草稿用户流失,且没人知道发生过

有据可答的第一条规则是「句子级引用」。 不是文末挂三个链接,而是每一句包含事实的陈述后面跟一个来源编号,点开能定位到文档的具体段落。做不到句子级,至少要做到段落级;做不到段落级,就别声称这是「有据」。

无据但低风险是一个窄口子,不能当成默认出口。 它只适用于「解释一个通用概念」这类答错也不造成实际损失的问题,并且必须在首句声明没有找到依据。一旦问题涉及金额、期限、资格、责任,无论检索结果如何,都不许走这条路径。

澄清优先于拒答。 「我能领吗」这类问题缺三个要素:注册地、主体类型、成立时间。直接拒答会让用户觉得系统没用,先问清要素往往就能变成有据可答。澄清话术要写成清单,不要每次都让模型重新组织语言。

拒答必须是产品行为,不是模型即兴发挥。 固定话术里写清三件事:为什么不能答(超出可答范围 / 文档未覆盖)、用户可以去哪里查、能不能转人工。让模型自由生成拒答理由,拒答本身就会变成新的幻觉来源。

转人工要带三样东西:原问题、命中的文档 ID、已生成的草稿。 少了草稿,人工要从零开始;少了文档 ID,人工不知道机器看过什么;少了原问题,用户得重述一遍。这三样东西决定兜底是「接手」还是「重来」。

路由要写成代码里的一个函数,不要写在提示词里。 提示词里的规则会被模型的措辞偏好稀释,而函数里的阈值不会。风险等级来自功能配置,置信度来自检索分数,两者都不该由模型自己判断。

三、检索白名单、稳定 chunk ID 与逐句引用

检索质量决定事实边界能不能成立。检索召回了一份过期文件,后面所有的引用、校验、拒答都是在给错误做包装。

规则具体做法可验收的信号
白名单只检索审核过的文档集合,按地区、年度、主体类型打标签每次检索都能打印命中的文档 ID 与标签
过期处理旧文件不删除,标 deprecated 并在检索时过滤抽查 20 条查询,无过期文档进入上下文
片段身份与版本chunk_id 为持久分配的逻辑 ID;另存完整 version_sha256 与源文档快照改标题不改逻辑 ID;改正文或来源元数据生成新版本,旧版仍可查
切分方式按标题层级切,单块不超过 800 字,保留父标题每个块能独立读通,且能回溯到章节
引用校验source_id 必须在白名单内,quote 必须是块内容的子串校验失败时整条回答重写或拒答

身份、位置与版本分开保存。 chunk_id 存在持久映射表里,标题路径只是可变的定位信息;version_sha256 对规范化正文及来源元数据计算完整摘要,并绑定不可变快照。审计记录引用 (chunk_id, version_sha256),重建索引复用映射,标题修改不会改变逻辑 ID。拆分或合并片段时分配新 ID、记录前后映射,保留被历史答案引用的版本;不能只留八位摘要或覆盖旧正文。

白名单不是一次配置,而是一份要维护的清单。 新文件进来要有人签字,旧文件过期要有人标 deprecated。一个人做的话,把它做成每周一次十分钟的例行检查:看新增文件、看失效日期、看有没有被误标的年度。

没有超过阈值的来源,就不生成事实断言。 阈值用重排分数或相似度都可以,具体数值必须在自己的语料上校准:拿 30 条已知能答的问题看分数分布,再拿 30 条已知答不了的问题看分布,阈值取在两者之间的低谷。不要照抄别人的 0.8。

机器校验只能先保证引用存在。 输出结构使用 facts: [{text, chunk_id, version_sha256, quote}],服务端检查该版本确实在本次授权检索的上下文中,且 quote 是对应快照的子串。子串匹配并不证明引文支持结论,还要审查否定词、例外和适用条件;高风险结论交给领域人员复核。失败时重写或拒答,不能删掉限定句后留下更强的错误结论。

引用覆盖率只统计事实句,不统计寒暄。 分子是带有通过存在性校验引用的事实句,分母是全部事实句;把寒暄只加进分母会压低比率,不能与其他口径混用。另行抽检“引文是否支持结论”,不要把引用覆盖率称作事实准确率。

上下文拼装要带生效日期,并按时序排。 每个块除了正文还要带 effective_from 与 effective_to,拼装时把过期块排除,剩下的按年度倒序放。这样即使白名单里同时存在新旧两份文件,模型看到的也是当前有效的那份,而不是先看到谁就信谁。

四、拒答、转人工与每周审计

拒答做得好不好,取决于你敢不敢承认「应拒答」这个集合是人工标出来的,而不是模型算出来的。

审计字段记录什么用来回答什么问题
问题原文脱敏后的用户输入这类问题该不该由系统接
来源 ID命中的文档与 chunk 列表答错时它看了什么
答案与引用最终输出、逐句来源引用是否真的支撑结论
拒答原因越界、无依据、要素缺失、低置信度拒答是在拦风险还是在偷懒
人工结论人工是否认同、正确口径是什么该拒不拒与误拒各占多少
成本与延迟token 数、耗时兜底是否被滥用

越界检测分三层,按成本从低到高排。 第一层是规则:正则命中「保证」「一定能批」「包过」这类词,直接拦截。第二层是分类器:判断意图是否落在可答范围内。第三层是模型自检:生成前先回答「现有证据是否足以支持结论」。规则快、分类器稳、自检便宜,三层都过才放行。

置信度阈值要按风险分档,而不是全局一个数。 涉及钱和期限的问题,阈值调高,宁可拒答;通用概念解释,阈值可以低。分档的依据写进配置,和功能开关放在一起,改的时候走同一条变更流程。

拒答话术要固定,并且给出去处。 一句「抱歉,我无法回答」等于把用户推走。合格的话术包含:说明限制、给出可自查的官方入口、提供转人工按钮。这三样每次都由模板渲染,不让模型改写。

转人工队列要有上限和优先级。 一个人一天能处理的人工请求是有限的,队列满了就要降低转人工的触发面,只保留高风险场景。否则兜底会变成第二份全职工作,而且没有人会为它排期。

每周抽 20 条复核,重点看两类错误。 「该拒不拒」会造成实际损失,「不该拒却拒了」只会损失体验,两者成本不对称,所以抽样要刻意多抽高风险场景。复核结论写回审计表,成为下周的对照。

误拒也要有申诉入口。 用户点「这个回答有帮助」或「我被拒绝得不合理」,这条记录就是最好的误杀样本。一个月能收到十条左右,比你自己构造的对抗集更真实。

人工结论要回流成知识,否则兜底永远在兜同一件事。 每周把人工回复整理成一条 FAQ 或一份补充文档,走白名单审核后入库,下一周观察同类问题的转人工量有没有下降。这个数字不降,说明回流做成了摆设:要么文档没进白名单,要么检索阈值把新文档挡在外面。

五、行动清单与复算验收

先把四种模式的路由写成函数,再补检索白名单,最后才调提示词。顺序反了,你会用提示词去弥补结构问题,越补越脆。

下面 8 条按一周节奏排,做完就能跑出第一版审计指标。

  • 列出功能的可答范围与三类越界情形,写成路由函数的输入
  • 打标签:给知识库文档补地区、年度、主体类型,并标出已过期文件
  • 建立持久 chunk_id 映射、完整版本摘要与不可变快照;重建索引后仍能打开旧答案引用
  • 校准检索阈值:用 60 条已知可答与不可答的问题记录分数分布
  • 改输出结构为逐句 facts 数组,服务端校验来源与引文子串
  • 写四种模式的固定话术,禁止模型自由生成拒答理由
  • 接通人工队列,转人工时自动带上原问题、文档 ID 与草稿
  • 建审计表并抽最近 20 条会话复核,标注该拒不拒与误拒

验收标准:随便抽一条回答,都能在不问工程师的情况下指出每个事实句的来源,或指出它为什么被拒答。

教学假设:一周 1200 次会话,4200 个事实句,转人工 96 次
人工标注应拒答处置 150 次:正确拦下 138,漏拒 12
其余 1050 次中误拒 18,正常放行 1032;实际拒答处置 156 次
这里“拒答处置”包含停止自动回答并转人工,96 次属于该处置集合
引用覆盖率 = 3860 ÷ 4200 = 91.9%
拒答召回率 = 138 ÷ (138 + 12) = 92.0%
拒答精确率 = 138 ÷ (138 + 18) = 88.5%
正常问题误拒率 = 18 ÷ (18 + 1032) = 1.7%
人工兜底率 = 96 ÷ 1200 = 8.0%
结论:召回率过 90% 内部线,但精确率未过;引用覆盖率不是事实准确率
优先复核 12 条跨年度漏拒与 18 条误拒,再决定文档、规则或路由怎么改

使用边界与实操验收

这套路由适用于「答案有明确出处、错误可被追溯」的场景:政策、产品文档、内部制度、合同条款。它不适用于需要价值判断的问题,也不适用于出处本身就有争议的领域。

实操验收可以这样跑:从最近 100 条会话里随机抽 10 条,让一个不了解系统的人只看回答,判断每句话有没有来源、该不该被拒答。他判断不出来的地方,就是你的边界没写清楚的地方。

不适用情形要提前说清。知识库本身错误或过期时,引用做得再好也只是把错误包装得更可信,这类问题要先解决文档治理。另一个不适用之处是多跳推理:答案需要合并三份文件才能得出时,逐句引用会退化成「每句都有出处,合起来是错的」,需要额外的推理链校验。

关键参考与核验范围

核对日期:2026-10-25。下列来源仅支持明确标注的机制或原则。

使用边界。 chunk_id、完整版本摘要和不可变快照是本文的工程约定,不声称为 W3C 指定的 ID 格式。会话量、引用数量、拒答与转人工数字均为教学假设,未核验任何地区政策资格。

如何自行复核。 用旧答案中的 ID 与版本取回当时原文;分别标注应拒、实拒和正确拒答,重算召回率与精确率,再人工核对引文是否支持结论。

系列导航

继续阅读

探索更多技术文章

浏览归档,发现更多关于系统设计、工具链和工程实践的内容。

全部文章 返回首页

「Indie」更多文章

  1. 开源项目验收:十项能力、四维评分与三种不该开源的项目
  2. 治理、fork 与退出:17 位贡献者、82% 的提交与一次改协议的代价
  3. 双许可与企业版:九家询价、两家成交与 4,800 美元