滑窗切分必须基于tokenizer真实编码结果而非字符数,预留prompt空间、归一化空白、设置合理重叠步长(128~256),禁用自动截断,输出需后处理融合而非直接拼接。

滑窗切分前必须明确 token 长度和模型限制
直接按字符或字数切分长文本,大概率导致 tokenizer.encode() 后实际 token 数超标,尤其遇到中文、标点、特殊符号时。不同模型的上下文上限(如 gpt-2 是 1024,Llama-3-8b 是 8192)是硬边界,超出会触发 IndexError: index out of range in self 或静默截断——后者更危险,因为没报错但丢数据。
正确做法是:先用目标模型的 tokenizer 对原始文本做 encode(),拿到真实 token ID 列表,再基于该列表滑动切片。不要依赖 len(text) 或 text.split()。
- 用
tokenizer.is_fast判断是否支持快速 token 计数,True 时可用tokenizer(text, return_length=True) - 预留至少 50 token 给 prompt 模板(如 “请总结以下内容:”),别把全部长度都分配给文档
- 若原文含大量换行/空格,先用
re.sub(r'\s+', ' ', text).strip()归一化,避免 tokenizer 为冗余空白生成额外 subword
滑窗步长不能简单设为窗口大小
纯等长切片(如窗口 512、步长 512)会导致段落断裂在句子中间,丢失上下文连贯性。例如“该公司成立于2015年,总部位于上海——”被截成两半,后半句无主语。
滑窗步长应小于窗口大小,形成重叠。典型配置是:窗口 max_length=512,步长 stride=128,即每次向前滑动 128 个 token,保留前 384 个作为重叠上下文。
- 重叠部分不是简单复制,而是用
tokenizer.convert_ids_to_tokens()检查边界是否落在词内(如▁in、##tion),避免切开 subword - 若使用 Hugging Face 的
BatchEncoding,可传return_offsets_mapping=True获取每个 token 对应的原文字符位置,便于后续对齐原文标注 - 步长太小(如 16)会导致重复计算爆炸;太大(如 400)则重叠不足,上下文断裂风险上升——128~256 是较稳妥区间
如何安全拼接多个片段的输出结果
模型对每个片段独立生成响应后,直接拼字符串大概率产生重复、矛盾或逻辑断层。比如两个相邻片段都生成了“综上所述”,或对同一事件给出不同时间描述。
真正可行的策略是:只让模型处理片段,**不生成总结性语句**,而是在后处理阶段由规则或轻量模型做融合。例如:
- 对所有片段输出做
set()去重(适用于关键词抽取类任务) - 用
spaCy提取各片段的命名实体,再按出现频次 + 位置加权合并 - 若需生成连贯摘要,把所有片段的 embedding(用
sentence-transformers)聚类,选每类中心句 + 首尾片段的开头结尾句拼接,再喂给一次小模型润色
跳过这步直接 concat,等于把问题甩给下游,多数情况下比不处理还糟。
注意 tokenizer 的 truncation 参数陷阱
tokenizer(..., truncation=True, max_length=512) 看似省事,但它默认从开头或结尾硬截,不保证语义完整。更糟的是,它不返回被截掉的部分,你根本不知道丢了什么。
滑窗机制本质是手动实现可控截断,因此必须关掉自动 truncation:
- 显式设
truncation=False,否则encode()可能静默生效,干扰滑窗逻辑 - 若用
pipeline(如pipeline("summarization")),它内部可能自带 truncation,得传tokenizer_kwargs={"truncation": False} - 调试时打印
len(tokenizer.encode(text))和len(tokenizer.encode(text[:1000]))对比,确认没有隐式截断发生
滑窗不是万能解法——它增加计算量、引入重叠噪声、且无法解决长程依赖(如跨 20 段的指代消解)。真要处理万字文档,优先考虑检索增强(RAG)或分块后建向量索引,而不是堆滑窗。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











