WeLM 喂长文为什么越到后面越糊——是截断还是提示没收敛?

文章导读
长文越到后面越糊,通常不是单一原因:一类是输入侧被截断,模型根本没看到后面的原文;另一类是提示没收敛,前面的原文把指令冲淡了,后半段开始自由发挥。这两类问题现象很像,但处理方式完全不同。可以先做两件事:把长文按段落切开逐段单独跑一遍,再在同一段上做整篇与分段的对照,用返回长度、结束原因和内容完整性来判断卡在哪一环。
📋 目录
  1. A 把长文按段落切开,逐段单独跑一遍
  2. B 在返回内容里找被截断的位置
  3. C 把提示里的关键要求挪到最前面再跑同一段长文
  4. D 对比分段处理和整篇处理的输出差异
  5. E 定下长文任务的分段策略和长度上限
A A

长文越到后面越糊,通常不是单一原因:一类是输入侧被截断,模型根本没看到后面的原文;另一类是提示没收敛,前面的原文把指令冲淡了,后半段开始自由发挥。这两类问题现象很像,但处理方式完全不同。可以先做两件事:把长文按段落切开逐段单独跑一遍,再在同一段上做整篇与分段的对照,用返回长度、结束原因和内容完整性来判断卡在哪一环。

判断顺序建议固定为:先分段单测排除段落本身的问题,再看返回内容里有没有被截断,最后把关键要求前置、用同一段长文重跑。三步做完仍然糊,通常要把长文切短,而不是继续改提示措辞。这套做法适用于能通过配置、日志或返回字段观察的常规调用;如果接口不返回结束原因、也不暴露输入长度上限,只能靠复述测试和输出长度间接推断,结论需要留有余地。

把长文按段落切开,逐段单独跑一遍

切分方式不用复杂:先按空行、标题层级或列表项切成块,每块单独送一次,不让模型看到其他段落。这一步的目的只有一个——确认单段本身能不能被正常处理,把长文长度这个变量先摘出去。

记录位置要具体到段号、起始字符偏移、输入长度、输出长度和偏差描述。段号从 1 开始编号,字符偏移用整篇原文中的下标,方便回溯到具体位置。

段号起始偏移输入长度输出长度是否完整偏差描述
1<填写><填写><填写><填写><填写>
2<填写><填写><填写><填写><填写>
………………

判断标准是“从哪一段开始出现明显偏差”。事实编造、丢掉关键信息、答非所问、不遵守输出格式,都算偏差。如果第 1 段就不正常,问题一般在提示写法或单段长度,不在长文;如果前面若干段都稳定、到中段往后才崩,多半与长度或截断有关。每段建议重跑两次,看偏差是否稳定复现,波动大的段单独标注,别急着下结论。

# 通用分段骨架:先按自然边界切块,再按长度兜底合并

def split_long(text, max_chars):
    blocks = [b.strip() for b in text.split('\n\n') if b.strip()]
    segs, cur = [], ''
    for b in blocks:
        if len(cur) + len(b) + 2 <= max_chars:
            cur = (cur + '\n\n' + b) if cur else b
        else:
            if cur:
                segs.append(cur)
            cur = b
    if cur:
        segs.append(cur)
    return segs

在返回内容里找被截断的位置

看整篇调用的返回内容,先分清是内容被砍掉了,还是模型自己写不下去了。截断的典型表现通常有这几种:句尾突然中断、没有收尾标点、最后一句语义不完整;后半段与原文无关,像换了话题;重复开头的语句或重复同一段结构;输出长度贴着已知上限。

resp = call_model(prompt)
print(resp.get('finish_reason') or resp.get('stop_reason'))  # 字段名以自己接入为准
print(len(resp['text']))                                      # 输出长度
print(repr(resp['text'][-40:]))                               # 末尾 40 字,看是否断句

如果返回结构里带结束原因字段(不同接口叫法可能是 finish_reason、stop_reason 之类,需要结合自己的接入方式确认),取值与长度上限相关时,一般是输出侧被截断。如果字段显示正常结束但内容仍然糊,更可能是提示没收敛,或者输入侧被截掉了一段。

输入侧截断不容易直接看见,可以用复述测试兜底:只让模型复述该段材料的第一句和最后一句,不复述出来或明显改写,通常说明尾部没进模型。

请只做一件事:原样复述下面材料的第一句和最后一句,不要总结,不要改写。
<材料>
{seg_text}
</材料>

把提示里的关键要求挪到最前面再跑同一段长文

这是对照实验里改动最小的一次:同一段输入、同一组要求,只调顺序。

<材料>{long_text}</材料>
请基于材料回答:{question}
要求:只依据材料;不确定就写无法确定;输出不超过 200 字。
要求(必须遵守):只依据下面材料作答;不确定就写无法确定;
输出不超过 200 字;先给结论再给依据。
<材料>{long_text}</材料>
再次确认:只依据材料,不要引入外部知识。

对比时只盯三件事:约束是否被遵守(长度、格式、只依据材料)、结论是否与原文一致、后半段是否还跟着要求走。如果前置后明显变好,说明原提示里的关键要求被前面的原文冲淡了,后续固定用“要求前置 + 材料后置”的写法。如果前置后依然糊,更可能是这一段本身超长或输入被截断,应该回到分段和长度上限,而不是继续改措辞。

对比分段处理和整篇处理的输出差异

把两组输出放在一起,重点看完整性和一致性,以及衔接处是否出现断裂。

对比项分段处理整篇处理
完整性单段内通常更完整,尾段不再丢信息后段容易少句、少要点
一致性跨段人称、术语可能不统一一次成文,风格更连贯但可能整体跑偏
衔接处需要合并,接口处方易出现指代不清不存在拼接问题,但中后段可能脱离原文
排错难度出错能定位到具体段只能整体重跑,定位靠猜
调用成本调用次数和总耗时增加单次调用,成本低但结果不稳定

说分段“换回稳定性”要谨慎:它主要换回的是可定位性,代价是跨段一致性变差、需要额外做衔接,调用次数也更多。是否值得,取决于任务对完整性的要求,需要结合自己的场景确认。

定下长文任务的分段策略和长度上限

把上面的定位结果落成规则,下次直接套用,不再重新试错。

  • 分段粒度:优先按原文的自然边界(标题、空行、列表项)切;单个块仍超长时再按字符数兜底切,不要在一个语义单元中间硬切。
  • 段间衔接:每段带上上一段结尾的少量句子作上下文,并附一份统一的术语和人称约定;对全局一致性要求高的任务,先跑一次全局摘要,再把摘要随每段下发。
  • 单段长度上限:不要照抄模型标称上限,用复述测试逐步加长——从较短的一段开始,持续加长直到模型无法完整复述该段最后一句,取失败前一次的长度作为上限。

这些值建议写进配置文件或调用封装里,而不是留在提示文本中,方便下次复用;换模型或换接入方式后,长度上限需要重新测一遍再定。