简介:面向开发者与技术负责人,系统梳理长上下文大模型的选型维度、上下文长度换算、文档分段与装配策略、提示词设计、任务编排与异常处理。读者可按步骤搭建一套可验证的长文档解析与摘要服务,并掌握输入截断、关键信息遗漏、输出幻觉与成本延迟等常见问题的排查思路。
本教程要解决一个很具体的工程问题:如何把”能处理超长上下文”的大模型能力,真正接入到业务系统里,稳定地完成长文档的解析、归纳与问答。
完成本教程后,你应该能够独立做到以下几点:
本教程不涉及模型训练与微调,聚焦”调用侧”的工程实现。
长上下文能力的典型受益场景包括:
反过来说,如果你的任务只是”在几千字里找一句话”,那么向量检索加短上下文通常更快更便宜,没有必要上长上下文方案。
大模型计费与长度限制的单位是 token,不是字数。中文与 token 的换算比例随分词器实现不同而变化,业界常见的经验区间是 1 个汉字约等于 1~2 个 token。行业内的一个常见对照是:某类长文本模型对外宣称支持约 200 万字中文输入,按上述比例折算约为 400 万 token 量级。
结论很明确:不要凭感觉估算,要用实际分词器统计。在方案评估阶段,就应该拿 50~100 份真实业务文档跑一遍统计,得出长度分布的 P50、P95、P99 值。
一次调用的 token 消耗 = 输入 prompt + 参考文档 + 系统指令 + 模型输出。也就是说,输入与输出通常共享同一个窗口额度。这意味着:
价值方面,长上下文带来的不只是”塞得下”,更关键是:
局限同样需要提前认知:
| 类别 | 具体准备项 | 说明 |
|---|---|---|
| 开发环境 | 支持 HTTP/JSON 的开发语言运行时、文件解析库、可选 OCR 能力 | 通用技术栈即可,无需特定工具 |
| 权限凭据 | 大模型服务的访问密钥、对应配额 | 密钥必须走环境变量或密钥管理服务,禁止硬编码入库 |
| 存储组件 | 对象存储、可选的向量检索能力 | 用于存放原始文档、切分结果与向量索引 |
| 网络条件 | 服务端可访问模型服务的网络出口、超时策略 | 生产环境建议走专线或 VPC 内网通道 |
| 数据合规 | 脱敏规则、数据留存策略、审计要求 | 涉及个人信息、商业秘密的文档需先评估 |
| 基础知识 | 提示词工程、JSON 结构约定、重试与幂等概念 | — |
如果业务系统本身运行在百度智能云上,可以直接复用其对象存储、身份认证、日志与监控、消息队列等通用云能力来承载流水线中的存储、鉴权与可观测环节,无需额外引入组件。
做什么:统计文档的格式分布、平均与 P95 长度、是否含大量表格与扫描件、是否需要引用溯源。
为什么:路线选择完全由数据驱动。若 95% 文档在窗口的 60% 以内,直接长上下文直传最简单可靠;若存在大量超出窗口的文档,必须设计分段汇总。
注意:不要只用”平均长度”决策,长尾的超长文档往往是故障来源。
原始问题中”哪个模型最有前途”本质上是个选型问题,但正确做法是用自有数据评测,而不是看参数榜单。建议的评估维度:
评测方法:准备一个 50~100 份的评测集,标注”标准答案要点”,让候选方案各跑一遍,记录要点召回率、格式合规率、平均延迟、单次成本四项指标。这比任何排行榜都可靠。
做什么:把所有模型调用收敛到一个客户端类里,屏蔽 endpoint、模型标识、鉴权方式等差异。
为什么:一是便于后期换模型而不动业务代码;二是集中实现超时、重试、日志、token 计量,避免每个业务分支各写一套。
注意:客户端层必须记录每次调用的 prompt_tokens、completion_tokens 与耗时,这是后续成本优化的唯一可靠依据。
class LLMEndpoint:"""通用模型调用封装(字段名以实际服务文档为准)"""def __init__(self, endpoint: str, model: str, credential: str,timeout_s: int = 120, max_retry: int = 3):self.endpoint = endpointself.model = modelself.credential = credential # 从密钥管理服务注入self.timeout_s = timeout_sself.max_retry = max_retrydef complete(self, messages, temperature=0.2,max_output_tokens=4096, stream=False):# 1) 组装请求体 2) 发送并处理响应# 3) 记录 usage 与耗时 4) 异常按可重试/不可重试分类...return {"text": "...", "usage": {"prompt_tokens": 0,"completion_tokens": 0}}
做什么:
为什么:预处理质量决定输出质量上限。 garbage in, garbage out 在长文本场景尤其明显——页眉页脚反复出现会挤占窗口并干扰模型判断文档边界。
注意:不要在预处理阶段做”摘要式压缩”,那会丢失后续推理所需的细节。
根据文档长度选择不同策略:
策略 A:整篇直传(长度 ≤ 窗口的 70%~80%)
最简单可靠,保留全局视野。适合单篇长文档理解。
策略 B:结构提纲先行 + 分章处理
先让模型基于目录或首轮扫描输出文档提纲,再按提纲逐章节处理并回填结果,最后做一次全局一致性合并。适合超长书籍、规范类文档。
策略 C:分段 + 层次摘要(Map-Reduce)
第一段映射:把文档切成带重叠的块,逐块抽取要点,输出结构化要点列表;
第二段归约:把要点列表合并去重,生成全局摘要;
第三段细化(Refine,可选):针对全局摘要发现的可疑点,回原文对应块重新核对。
策略 D:检索增强 + 局部长上下文
先用向量检索召回与问题最相关的 N 个片段,再把这些片段(而非全文)拼成上下文。适合”问答式”而非”总结式”任务,成本与延迟最优。
关键工程细节:
推荐的提示词骨架(按顺序):
[角色] 你是一名严谨的文档分析助手。[任务] 对输入文档生成结构化归纳。[输入] 文档标题、章节路径、正文内容(用明确分隔符包裹)[输出格式] 严格输出 JSON,字段为:summary(≤300字)、key_points(数组,每点≤50字)、risk_items(数组)、citations(数组,每项含 section 与 quote)[约束] 只允许基于文档内容作答;无法确认的内容写入 unknown 列表;引用必须是原文连续片段,禁止改写后当作引用。[禁止] 不得推测文档中不存在的条款编号、金额、日期。
要点说明:
做什么:
为什么:批量文档处理是典型 IO 密集型任务,串行执行会让吞吐被单次延迟锁死;但并发过高会触发限流,需要在吞吐与稳定性之间取平衡点。
注意:所有写操作要设计幂等键(如”文档指纹 + 块序号”),否则重试会导致重复计费和重复数据。
| 异常类型 | 典型表现 | 处理策略 |
|---|---|---|
| 输入超长 | 请求被拒绝或参数校验失败 | 按预算动态截断/降级到分段模式 |
| 限流 | 状态码与频率限制提示 | 指数退避 + 抖动,控制并发上限 |
| 超时 | 长输入下响应耗时过长 | 提高超时阈值、启用流式、缩小单次输入 |
| 输出格式不合规 | JSON 解析失败 | 校验失败后携带错误说明重试,最多 N 次 |
| 服务不可用 | 5xx 类错误 | 熔断 + 队列缓冲,避免雪崩 |
区分可重试与不可重试错误是重点:鉴权失败重试毫无意义,只会浪费时间和日志。
建立三层验证机制:
注意:长文档任务中”摘要看起来通顺”和”摘要准确”经常不一致,必须依靠可量化的召回率而不是主观阅读判断。
需要采集的核心指标:单次调用的输入/输出 token 数、P50/P95 延迟、错误率与错误类型分布、平均单次成本、缓存命中率、格式校验失败率。
日志必须脱敏:不要将完整文档内容写入普通日志,只记录文档指纹、长度、token 用量与耗时。
以下是长文本场景的通用配置项及其取值逻辑(具体字段名与上限以所选用模型服务的文档为准):
| 配置项 | 含义 | 取值建议 | 配置风险 |
|---|---|---|---|
| 输入长度预算 | 单次输入 token 上限 | 窗口 × 70%~80%,预留输出与系统提示空间 | 设满会频繁触发超长错误 |
| 最大输出长度 | 单次生成 token 上限 | 按业务输出篇幅设定 | 过小导致摘要被截断 |
| 分段大小 chunk size | 单块字符/token 数 | 800~2000 token 起调 | 过大丢细节,过小增调用次数 |
| 重叠长度 overlap | 块间重叠 | 分段大小的 10%~15% | 为 0 时易在边界丢信息 |
| 温度 temperature | 随机性 | 抽取/总结 0~0.3;创意类可放宽 | 过高导致结果不可复现 |
| 超时时间 | 单次请求等待上限 | 长文本建议 120s 以上,配合流式 | 过短导致大量误判超时 |
| 重试次数 | 失败重试上限 | 2~3 次,配合退避 | 过多放大故障与费用 |
| 并发度 | 同时进行的请求数 | 按配额上限的 70%~80% | 过高触发限流与雪崩 |
def summarize_long_document(doc, endpoint, budget_tokens):blocks = split_by_semantic_boundary(clean_document(parse_document(doc)),chunk_tokens=1200,overlap_tokens=180,)# 为每个块注入全局定位信息blocks = [with_locator(b, doc.title, i, len(blocks))for i, b in enumerate(blocks)]# 场景一:整篇直传if estimate_tokens(blocks) <= budget_tokens * 0.75:return endpoint.complete(build_prompt(SYSTEM_EXTRACT, join_blocks(blocks)),temperature=0.1,)["text"]# 场景二:Map 阶段,带并发上限与重试partials = run_with_concurrency(fn=lambda b: endpoint.complete(build_prompt(SYSTEM_EXTRACT, b), temperature=0.1)["text"],items=blocks,max_concurrency=8,retry=2,)# 场景三:Reduce 阶段,要点过长时递归归约merged = merge_points(partials)while estimate_tokens(merged) > budget_tokens * 0.5:merged = merge_points(chunk_text(merged, chunk_tokens=8000))result = endpoint.complete(build_prompt(SYSTEM_MERGE, merged), temperature=0.1)["text"]# 结果验证:引用溯源 + 格式校验assert_json_schema(result, SCHEMA)assert_citations_in_source(result, doc)return result
问题 1:请求直接被拒绝,提示输入过长
原因:预算计算只算了文档,没算系统提示与预期输出。
排查:打印实际输入 token 数,按”文档 + 提示词 + 输出预留”重新核算,并降级为分段模式。
问题 2:摘要遗漏了文档中后段的关键条款
原因:中间信息衰减 + 块级要点在归约阶段被合并丢弃。
排查思路:检查归约阶段的输入是否保留了块序号;对高风险条目(金额、期限、责任主体)采用”全量保留、不合并”规则;必要时对文档尾部单独追加一次显式提问。
问题 3:输出出现原文不存在的条款编号或金额
原因:模型对上下文的推断性补全。
应对:强制要求引用原文片段并在代码侧做子串校验,校验不通过的条目直接进入人工复核队列;提示词中明确禁止推测编号类信息。
问题 4:输出 JSON 格式不稳定
原因:仅靠提示词约束格式,长输入下约束被稀释。
应对:优先使用服务提供的结构化输出能力;否则加入格式校验 + 带错误反馈的重试,并把失败率纳入监控。
问题 5:处理一篇超长文档耗时数分钟
原因:分段串行调用 + 单次输入过大。
应对:Map 阶段并行化、启用流式输出降低首字延迟、对高频重复文档做结果缓存、把”粗筛”任务交给更轻量的模型。
问题 6:费用远超预期
原因:一是同一文档被重复解析(无缓存);二是归约阶段输入过长导致输出 token 暴涨;三是把长上下文用于本可检索解决的任务。
应对:按文档指纹缓存;归约前压缩要点冗余;按任务类型分流——总结走长上下文,问答走检索增强。
问题 7:长文档跨章节结论自相矛盾
原因:分段处理时各段独立判断,缺少全局一致性校验。
应对:增加一次 Refine 轮次,把全局摘要与冲突章节一起回灌核对;或在提示词中要求显式列出冲突项而非强行统一。
回到最初的问题——“长文本能力最有前途吗?”从工程角度看,正确的答案不是比较谁的窗口数字更大,而是:先用自己的文档评测集测出各方案在长文本上的真实衰减曲线与成本,再决定技术路线。
本教程的核心结论可以归纳为四点:
后续可以继续深入的方向包括:长上下文场景下的检索与生成融合排序、多文档对比的结构化抽取、以及基于评测集持续迭代提示词版本的工程化机制。