8 条带引用的回答里,脚本抓出 2 条格式错(编号越界、该引用却没有); 另外 2 条格式完全合法但内容错——引用编号在范围内,可原文说的是「由买家承担」, 回答写成「由商家承担」。引用核对必须分两层:格式层自动查,内容层抽检。
上一节把检索调好了。这一节是最后一环:让答案带上出处,并且能核对。
一、引用有哪几种形态
① 编号式:答案里写 [1]、[2],下面列出对应片段。最常见,也最好自动检查。
② 行内式:把出处直接写进句子(「根据《退换货总则》第三条」)。读起来自然,但机器不好解析。
③ 整段附加:答案后面挂一段「参考材料」。信息最全,但用户要自己去找对应关系。
做产品建议用①,因为它是唯一能被脚本逐条校验的形态。②③ 更好读,但出问题时你只能人工比对。
📋 实操清单:Cherry Studio 的知识库对话里可以打开「显示引用来源」,
它会把你上传的片段附在回答下面。
但这不等于模型在答案里标了 [1]——前者是界面拼的,后者要提示词里明确要求。
二、格式层:两条规则就够
规则一:编号不能越界。 答案里出现 [4],但只给了 3 段材料——这个引用是假的,模型在编。
规则二:有结论就必须有引用。 一个陈述事实的句子后面没有任何编号,
它是从哪来的?要么是模型自己知道的(那就该标注),要么是它编的。
Demo 里 8 条回答,这两条规则抓出 2 条问题:一条越界、一条完全没引用。
两条规则十行代码,跑一次不到一秒。
还可以加第三条:编号重复率。如果 8 条回答里 7 条都只引 [1],
说明检索把同一个片段反复排在第一位——库里的内容分布可能有问题。
三、内容层:脚本查不到的那一半
Demo 里还有 2 条,格式完全合法,内容是错的:
「退货免费,运费由商家承担 [1]」——[1] 的原文写的是「退货运费由买家承担」。
编号对、范围对,就是反了。
「审核要一周 [2]」——[2] 的原文是「四十八小时内审核」。数字错了。
这两条脚本抓不到,因为脚本不知道「商家」和「买家」哪个对。
但有一条规则能抓住大部分这类错:答案里的每个数字,都应该能在它引用的片段里找到。
「一周」在 [2] 里找不到,「四十八小时」找得到;「商家」也在 [1] 里找不到(原文是「买家」)。
这条规则能拦住编造的数字和掉包的主体。代价是要先把数字和名词抽出来——不难,
但比前两条规则贵得多。
四、引用到底是给谁看的
给用户看:他不信这个答案时,能点开原文核对。 这是让业务方敢用它的唯一理由。不能核对的答案,出了问题只能整体下线。 给我们自己看:用户反馈「答得不对」时, 看一眼引用就知道是「检索拿错了材料」还是「材料对但答歪了」。 这两种问题的修法完全不同(一个改切块,一个改提示词)。 所以引用不是「好看的功能」,它是这套系统的可观测性。没有引用,你就只有「对/不对」两个信号; 有了引用,你能定位到具体哪一环坏了。 最后一条工程纪律:把每次检索的片段和分数存下来。日志里存了片段,事后才能复盘; 只存最终答案,等于把所有证据都扔了。
五、动手 Demo:引用核对:格式错的 2 条脚本抓到了,内容错的 2 条抓不到
造 8 条带 [n] 引用的回答,3 段材料,其中混入 4 类问题:引用越界、该引用却没有、
引用对但主体掉包、引用对但数字错。跑两条格式规则,看能抓出哪几条、漏掉哪几条。
for text, refs, _ in ANS:
prob = []
for r in refs:
if r < 1 or r > len(SEG):
prob.append(u'越界') # 规则一
if not refs:
prob.append(u'无引用') # 规则二
print(text[:14], refs, prob or u'—')
实跑输出:
--------------------------------------------------------------------
引用核对:格式错的 2 条脚本抓到了,内容错的 2 条抓不到
--------------------------------------------------------------------
回答(截断) 引用 脚本发现
--------------------------------------------------
退货运费由买家承担 [1]。… [1] —
商家四十八小时内审核 [2]… [2] —
退款一到三个工作日到账 [3… [3] —
运费买家承担,三个工作日到账… [1]、[3] —
退货免费,运费由商家承担 [… [1] —
审核要一周 [2]。… [2] —
到账时间以银行为准 [4]。… [4] 越界
具体可以咨询客服。… — 无引用
这一屏是「格式层」能查出来的:**越界、缺引用,两条规则就够。**8 条里抓出 2 条。
但另外 2 条格式完全合法、内容错的,脚本抓不到:
「退货免费,运费由商家承担 [1]」——引用编号对,**但 [1] 的原文说的是「由买家承担」。**
「审核要一周 [2]」——[2] 在范围内,**但原文是四十八小时。**
所以引用核对一定要分两层:**格式层自动查,内容层抽检。**
想全自动,就得让模型输出结构化的引用,再逐句比对原文。
最后一层最省事:**回答里的每个数字,都该能在引用片段里找到。**
「一周」找不到,「四十八小时」找得到——一条规则拦住大部分编造。
done -> _out_39i.txt
表里 8 行,脚本只标了 2 行:[4] 越界、最后一条完全没引用。这两条是「格式层」能抓的全部。
第 5 行「退货免费,运费由商家承担 [1]」——脚本什么都没标。因为 [1] 在 1 到 3 之间,格式完全合法。
可原文写的是「由买家承担」。
第 6 行「审核要一周 [2]」同理:[2] 合法,
但原文是「四十八小时内审核」,一周和四十八小时差了三倍多。
所以引用核对一定是两层:
格式层自动查(快、便宜、抓一半),内容层抽检或加规则(慢、贵、抓另一半)。只做一层,
等于只装了一半的门。
最省事的内容层规则是「数字必须在片段里」:「一周」找不到、「四十八小时」找得到。
这一条能拦住大部分编造的数字,而数字恰恰是业务最不能错的部分。
30 秒实验
- 加一条规则:答案里的「买家/商家」这类主体词,必须在引用片段里出现。 第 5 行会被抓出来——这就是「主体掉包」的检查。
- 加一条规则:统计每个
[n]被引用的次数,看有没有某个片段被反复引用。 这能发现「检索老是返回同一段」的问题。 - 把 3 段材料扩到 10 段,看「越界」这条规则还灵不灵。 材料越多,模型编造编号的概率反而越高——因为没有约束它会顺着往下数。
常见误区
- 「界面上显示了来源就等于有引用」。界面附的来源是拼上去的,答案里标
[n]才需要提示词明确要求。 - 「引用编号在范围内就没问题」。Demo 里两条内容错的,编号全在范围内。格式对不等于内容对。
- 「引用只是给用户看的装饰」。它同时是排查工具——没它你分不清是检索坏了还是生成坏了。
自测三问(点开对答案)
1. 为什么建议用编号式引用? —— 因为它是唯一能被脚本逐条校验的形态。行内式和整段附加更好读,但出问题只能人工比对。 2. 格式层能查什么、不能查什么? —— 能查编号越界、该引用却没有、编号重复; 不能查「引用对但内容错」,因为脚本不知道哪个说法是对的。 3. 最省事的内容层规则是什么? —— 答案里的每个数字都要能在它引用的片段里找到。数字错了是最不能接受的错,也是最好查的。第六章到这里结束:两个客户端、九个环节,从配嵌入模型到引用核对,一条完整的知识库链路走完了。 第七章换一个完全不同的模态——让模型学画画。
- ☐ (本章完,下一节 7.1.1 LoRA模型简介)