🧠 第六章 语言模型训练:高效赋能业务场景
📄 一句话概括

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 秒实验

  1. 加一条规则:答案里的「买家/商家」这类主体词,必须在引用片段里出现。 第 5 行会被抓出来——这就是「主体掉包」的检查。
  2. 加一条规则:统计每个 [n] 被引用的次数,看有没有某个片段被反复引用。 这能发现「检索老是返回同一段」的问题。
  3. 把 3 段材料扩到 10 段,看「越界」这条规则还灵不灵。 材料越多,模型编造编号的概率反而越高——因为没有约束它会顺着往下数。

常见误区

  1. 「界面上显示了来源就等于有引用」。界面附的来源是拼上去的,答案里标 [n] 才需要提示词明确要求。
  2. 「引用编号在范围内就没问题」。Demo 里两条内容错的,编号全在范围内。格式对不等于内容对。
  3. 「引用只是给用户看的装饰」。它同时是排查工具——没它你分不清是检索坏了还是生成坏了。
自测三问(点开对答案) 1. 为什么建议用编号式引用? —— 因为它是唯一能被脚本逐条校验的形态。行内式和整段附加更好读,但出问题只能人工比对。 2. 格式层能查什么、不能查什么? —— 能查编号越界、该引用却没有、编号重复; 不能查「引用对但内容错」,因为脚本不知道哪个说法是对的。 3. 最省事的内容层规则是什么? —— 答案里的每个数字都要能在它引用的片段里找到。数字错了是最不能接受的错,也是最好查的。

第六章到这里结束:两个客户端、九个环节,从配嵌入模型到引用核对,一条完整的知识库链路走完了。 第七章换一个完全不同的模态——让模型学画画。

相关笔记