受监管行业的 DocQA 系统要求每个答案必须有机械验证过的原文引用,详解提示词 + 引用验证三层规则实现。
答案下方的引用,其可信度取决于撰写它的人。如果引用出自模型之手,那它的可靠程度就和模型说的其他所有话一样。
当我们为受监管团队构建 yOGI Neural Grid DocQA 时,简报归结为一句话:答案要么附带一条经过机械校验(对照其引用的文档)的引文,要么就不显示。下面是它的工作原理,以及我们一路走来的教训。
提示词确实要求模型引用来源,并在段落无法回答问题时加以说明。模型大多会照做。"大多"就是问题所在——当读者是一位正在核对剂量的药剂师时。所以提示词被视为一种请求,而真正的保证在于模型回复后运行的验证步骤。
模型返回 JSON:答案、它所依赖的引文(每段都有标记),以及一个标志位(表示它认为这些段落是否充分)。然后应用三条规则。
每条引文必须出现在它所归属的段落中。
答案中的一个句子只有在携带了通过规则 1 的段落的标记时,才算有依据。
文档名、章节和页码通过段落 ID 从我们自己的索引中查询,模型无权自行写入。
如果答案中通过验证的部分太少,就予以隐藏,并告知用户原因,而不是展示一个更弱的答案。
我们第一个匹配器是对引文和段落逐字符比较的。看起来没问题,直到我们喂给它故意编造的引文——结果发现它给那些只是碰巧共享了一些字母的引文打了过高的分。改写(paraphrase)和真实复制的得分过于接近。
逐 token 比较解决了这个问题。漏掉一个"the"或订正一个拼写错误仍然能通过,但改写不行。在我们的测试用例中,真实复制和改写现在得分差距足够大,两者的阈值不再像走钢丝一样敏感。
为了正确测试这个,我们需要一个能按需编造引文的模型,而真实模型只是偶尔这样做。所以测试套件中有一个替代模型,它的工作就是产生坏输出:编造的引文、附在错误段落上的引文、没有标记的句子。
检索是混合式的(稠密向量和稀疏向量,经排名融合后,再由 cross-encoder 对前几十条重新排序)。如果最相关段落的得分仍低于阈值,DocQA 直接拒绝,根本不调用模型。让模型从一个不包含答案的段落中回答,是一种制造流畅虚构内容的做法。
我们的评估集特意包含了语料库中无答案的问题,对于这些问题,唯一的通过响应就是拒绝回答。
如果用户没有某份文档的访问权限,过滤器就应用在向量搜索内部。我们考虑过之后再过滤,但拒绝了:因为那时段落已经在模型的上下文中了,即使 UI 隐藏了来源,其中的片段也可能泄露到答案文本中。
每个问题、答案和管理操作都写入一个只追加的日志,其中每行的哈希覆盖自身内容和上一行的哈希。编辑或删除一行,链就会从该点断裂;验证端点会指明第一个坏掉的行。有一点坑过我们:时间戳必须显式设置并在哈希前规范化为 UTC,否则链就无法自我验证。
把来源元数据放到模型够不着的地方。从第一天就在测试集中加入无答案的问题。还要记录你失败的测试。我们的系统需要 GPU 才能达到对话式的响应时间,我们在自己最后的验收测试中发现了这一点。
更详细、非技术性更强的版本在我们的网站上:https://www.2sdtechnologies.com/insights/private-document-qa-2026/