长文本与上下文管理
问题
AI 应用中如何处理超长文本?对话历史越来越长导致超出上下文窗口怎么办?
答案
一、上下文管理策略
二、对话历史管理
策略对比
| 策略 | 做法 | 优点 | 缺点 |
|---|---|---|---|
| 滑动窗口 | 只保留最近 K 轮 | 简单 | 丢失早期上下文 |
| 摘要压缩 | 旧对话→LLM 生成摘要 | 保留关键信息 | 摘要可能丢失细节 |
| 混合方案 | 摘要 + 最近 K 轮 | 兼顾 | 实现稍复杂 |
// 混合方案:摘要 + 最近 N 轮
async function buildContext(
history: Message[],
maxTokens: number = 4000
) {
const recentN = 5 // 保留最近 5 轮
const recent = history.slice(-recentN * 2) // user + assistant
if (history.length <= recentN * 2) {
return recent // 历史不长,全部保留
}
// 旧对话压缩为摘要
const oldMessages = history.slice(0, -recentN * 2)
const summary = await llm.generate(`
请用 2-3 句话总结以下对话的关键信息:
${formatMessages(oldMessages)}
`)
return [
{ role: 'system', content: `之前的对话摘要:${summary}` },
...recent,
]
}
三、长文档处理
Map-Reduce 模式
适用于:文档总结、报告分析、合同审查等需要处理全文的场景。
Refine 模式
Chunk 1 → 初始摘要
Chunk 2 + 初始摘要 → 更新摘要
Chunk 3 + 更新摘要 → 再次更新
...
最终摘要
适用于:需要连续性的场景(如小说梗概)。
常见面试问题
Q1: 128K 上下文窗口够用了为什么还需要 RAG?
答案:
| 维度 | 长上下文 | RAG |
|---|---|---|
| 成本 | 128K Token 很贵 | 只取相关片段,省 Token |
| 延迟 | Prefill 长文本很慢 | 检索快,输入短 |
| 精度 | Lost in the Middle 问题 | 只提供相关内容 |
| 更新 | 每次传全文 | 知识库独立更新 |
结论:长上下文和 RAG 不是替代关系。RAG 在成本、延迟、精度上仍有优势。
Q2: "Lost in the Middle" 是什么?
答案:
研究发现,LLM 对上下文开头和结尾的信息关注度高,中间部分的信息容易被忽略。
应对策略:
- 重要信息放在开头或结尾
- 减少上下文长度,只保留相关内容
- 使用多次短上下文调用替代一次长上下文
Q3: 如何处理超长会议记录的总结需求?
答案:
- 按发言人/时间段分块
- 每块生成局部摘要(要点、决策、行动项)
- 合并局部摘要生成最终总结
- 输出结构化格式:会议主题、关键决策、行动项、待跟进