一个"合同审阅"功能要处理 200 页的合同,而模型的上下文只有几万 token——于是系统"截断"了后 80 页,模型自信地审完了前 20 页,并在结论里写"未发现风险"。
"超长输入"不是"能不能塞进去"的问题,而是"塞不进去的那部分,怎么保证不被忽略"。而三种处理方式(截断/分块/检索)对"漏看"的处理完全不同。
1. 三种处理的"漏看"形态
| 方式 | 漏看形态 |
|---|---|
| 硬截断(保留前 N) | 后面完全没看,但结论像"全看过" |
| 分块 + 汇总 | 每块都看了,但"跨块的关联"丢了 |
| 检索后喂片段 | 只看了"像相关"的部分 |
第一种最危险:它不报错,只给"局部结论"——这个"以为"是产品层面的错:输出里没有"我只看了 20%"这句话,于是"结论的范围"被隐含成"全文"——而这不是模型的问题,是"上下文工程"的问题。
而用户以为"这是全文结论"。
第二种的漏看"更隐蔽":"第 3 页提到 X,第 150 页提到 Y,X 与 Y 冲突"第二种的"漏看"还有一个变体:"每块单独看都没问题,合起来互相矛盾"——如"付款期限 30 天"与"付款期限 60 天"(不同章节)。
——单块看不出冲突。
2. "分块"的三种切法
| 切法 | 问题 |
|---|---|
| 按字数切(每 4000 字) | 切断句子/条款 |
| 按结构切(标题/条款) | 依赖"结构清晰" |
| 按语义切(模型判断) | 成本高、不稳定 |
第二项的"前提"是"结构清晰":扫描件 OCR 后"编号可能错乱",而"错乱的结构"比"按字数切"更糟——所以要先"校验结构"再切。
第二项是"最适合合同/报告"的:它们有"条款编号"这种天然边界——于是"每块 = 一个条款"最自然。
第一项的"切断"在合同上会致命:"除下列情形外,本条不适用:" 被切到下一块第一项的"通用表述"是"切点落在"条件与结果之间"":"如果…"被切到上一块,"则…"在下一块——而这两块单独看都"通顺"。
,于是"第一款的意思完全相反"。
// 三种切法的效果(同一份合同)
按字数:块 3 结尾"除下列情形外",块 4 开头"1) 逾期..."→ 语义断裂
按条款:块 3 = "第三条 付款"(完整)→ 语义完整
按语义:模型判断"这条属于付款"→ 成本高,且"判断错就切错"
3. "分块 + 汇总"的三种做法
| 做法 | 效果 |
|---|---|
| 逐块摘要 + 汇总摘要 | 快,但"丢失细节" |
| Map-Reduce(每块抽要点,再合并) | 主流 |
| 逐块"问答"(针对问题抽答案) | 最准(问题明确时) |
第三项的"代价"是"必须知道问题":"开放式审阅"("找出所有风险")没有具体问题——此时只能"每块抽风险清单"再合并去重。
第三项是"最实用"的:当"用户的问题是具体的"("有没有自动续约条款"),让每块只回答"这一块里有没有"——于是"不相关的块"不会污染结论。
第一项的"丢细节"很具体:摘要会"抹平数字与例外",而合同的关键恰恰在"例外"。
// 两种"汇总"的差别(同一份 200 页合同)
摘要式:块 1 摘要"付款条款…",块 2 摘要"违约条款…" → 汇总"合同整体规范"
问答式:逐块问"有无自动续约?" → 块 12 命中"本合同自动续约一年" → 结论具体
// 判据:用户要"整体印象"还是"具体事实"
"块"要能"独立阅读",否则"单块结论"会被误读——而它靠"块首尾的上下文提示":
// 一个"可独立阅读"的块(三段式包装)
[所属] 合同第 3 条(共 48 条)· 付款条款
[正文] 甲方应在验收后 30 日内付清全款;逾期按日 0.05% 计违约金。
[边界] 本条不含"预付款"(见第 2 条);本条不设例外情形。
// 判据:单看这一段,能否回答"它在说哪件事、有没有例外"
4. "跨块关联"的三种补救
| 补救 | 说明 |
|---|---|
| 全局索引(实体→块号) | 先建"谁在哪出现" |
| 二次检索(按第一轮结果找关联) | 两轮 |
| 人工指定(用户给关键词) | 最简单 |
第一项是"工程上最稳"的:先跑一遍"抽取实体/条款号",建"实体 → 块号"的索引第一项的"成本"是"多一遍抽取":200 页抽取要几十秒——但它只做一次,而"问答"要做几十次,所以账是划算的。
——于是"跨块关联"变成"按索引取两块"。
第二项的成本是"两轮调用",而它比"一次全塞"便宜得多。
5. "必须告知"的三件事
| 告知 | 为什么 |
|---|---|
| 覆盖了哪些部分 | 用户要判断"够不够" |
| 哪些部分没看 | 否则"未发现风险"是误导 |
| 结论的置信来源 | "基于第 3、12 条" |
第二项的"写法"要"具体到范围":"本次覆盖第 1–20 页(条款 1–48),第 21–200 页未处理"——比"部分内容未覆盖"有用得多。
第二项是"底线":"我只审了前 20 页"必须在输出里出现——而它常被"产品文案"抹掉,因为"看起来不专业"。
"覆盖范围"要能"算出来",而不是"凭感觉写":
// 三个数(每次输出都带)
total_blocks = 48
processed = 12 # 实际送进模型的块数
coverage = 25% # processed / total_blocks
// 输出模板:"本次覆盖 12/48 块(25%),未处理 36 块"
// 判据:coverage < 100% 时,结论必须带"范围限定词"
6. 排错:五种"超长输入问题"
| 现象 | 成因 | 处理方向 |
|---|---|---|
| 结论像"全看过" | 截断未标注 | 标注覆盖范围 |
| 漏掉末尾的关键条款 | 硬截断 | 改分块/检索 |
| 条款语义相反 | 按字数切断 | 按结构切 |
| 跨块冲突没发现 | 无全局索引 | 建实体索引 |
| 成本爆炸 | 逐块全量调用 | 先检索再精读 |
第五项在"200 页 × 每块一次调用"时很明显:"逐块全量"可能几十次调用第五项的"优化顺序"是"先检索、再精读、最后回溯":检索把 200 页缩到 5 块,精读只读那 5 块,回溯按实体索引找关联——于是调用数从几十降到个位数。
——而"先检索出 5 块"只要 5 次。
"检索"这条路要防"只检索到"看起来相关"的块",否则"漏看"变成"漏得更有理由":
// 三层召回(对"事实类问题"够用)
1 关键词/BM25:条款号、专有名词(准确)
2 向量:语义相近(覆盖改写)
3 结构:按"条款引用关系"扩展(3.1 → 3.2)
// 判据:召回块数 ≥ 5 且覆盖"问题涉及的全部主体"
7. 边界:什么情况不必处理超长
| 场景 | 为什么 | 做法 |
|---|---|---|
| 输入本来就短(< 上下文一半) | 无"塞不进"问题 | 直塞 |
| 只需"整体印象"(如情绪) | 截断影响小 | 可截断 |
| 用户能自己指定范围("看第 3 条") | 范围已收敛 | 按范围取 |
| 有"结构化输入"(已提取字段) | 不需要全文 | 用字段 |
最后一条与"合规"有关的边界:"未处理的部分"要能被"复查":日志里记"读了哪些块",于是"事后追查'为什么漏了第 150 页'"有依据。
判断口径一句话:"漏掉的那部分,会不会改变结论"。会(合同、财报、病历),必须"分块 + 覆盖标注 + 跨块关联";不会(摘要、情绪、概述),截断可接受。
8. 自测
- 三种处理的"漏看"形态分别是什么?为什么"硬截断"最危险?
- "按字数切"为什么在合同上会致命?举一个"语义反转"的例子。
- "逐块问答"为什么比"逐块摘要"更准?它适合什么样的用户问题?
- "跨块关联"的三种补救里,哪一种"工程上最稳"?它把关联变成了什么?
- "必须告知的三件事"里,哪一件是底线?为什么它常被产品文案抹掉?
- 判断"是否需要处理超长"的那个问题是什么?