返回文章列表
RAGSummarization上下文工程Agent成本优化

上下文窗口不够怎么办:RAG 与摘要链路的工程对比

上下文窗口不够时,常见解法是“加检索”(RAG) 或“做摘要”(Summarization),也有人直接截断/滑窗硬扛。本文用工程视角对比三条链路的准确率、成本、时延与可观测性,并给出可落地的选型与混合架构建议。

2026年3月4日
Synthly 团队
预计阅读 12 分钟
将“检索增强”和“摘要压缩”两条上下文链路并排对比的架构示意图

📷 Photo by Nikolaos Dimou via Pexels

你遇到的不是“窗口不够”,而是“信息预算不够”

当对话变长、任务变复杂,你会看到这些现象:

  • 模型开始忘记早先约束(例如“不要改动第 3 步”)
  • 细节被覆盖(例如“客户 A 和客户 B 的 SLA 不同”)
  • 召回变随机:有时能答对,有时像没看过一样

这不是单纯的“上下文窗口太小”。更准确的说法是:你有一个固定 token 预算,要在“保留多少信息”和“保持多少信噪比”之间做取舍

在工程上,常见的三种办法是:

  1. 截断/滑窗:只保留最近的对话
  2. 摘要链路:把历史压缩成更短的表示
  3. RAG 链路:把历史或外部知识放到可检索存储里,按需取回

下面用“链路视角”把它们讲清楚。


一、三条链路的最小实现长什么样

1)截断/滑窗:最低成本,但最容易“忘规矩”

适用场景:短对话、弱约束、信息主要集中在最近几轮。

最小实现(伪代码):

function buildPromptWithWindow(messages: Message[], maxTurns = 12) {
  return messages.slice(-maxTurns);
}

它的优点是简单、便宜、可预测;缺点是:

  • 忘掉早期约束与关键事实
  • 长任务阶段切换时容易跑偏

如果你只能做一件事来提升它:把“不可丢的约束”单独提取为系统约束(System/Policy),不要和对话混在一起

2)摘要链路:把“对话历史”变成“可续写的状态”

适用场景:对话连续性很重要;你需要把长会话压缩成“当前状态”。

最小实现:

  • 把对话分段(例如每 20 轮或每 8k tokens)
  • 对每段做摘要
  • 用“摘要 + 最近滑窗”拼出下一次 prompt
type SummaryChunk = {
  fromTurn: number;
  toTurn: number;
  summary: string;
  createdAt: string;
};

function buildPromptWithSummary(recent: Message[], summaries: SummaryChunk[]) {
  const longTerm = summaries
    .map((s) => `【阶段摘要 ${s.fromTurn}-${s.toTurn}】\n${s.summary}`)
    .join('\n\n');
  return [
    { role: 'system', content: '你是一个严格遵循约束的助手。' },
    { role: 'system', content: longTerm },
    ...recent,
  ];
}

摘要链路的本质是把历史“压缩成状态”。它的最大风险是信息损失:一旦摘要把关键约束写错/写丢,后续会持续偏离。

3)RAG 链路:把“信息”从对话里搬到索引里

适用场景:问题需要引用事实、文档、代码、规范;或历史信息量巨大但只需按需召回。

最小实现:

  • 把对话片段、文档片段做 chunk
  • 生成向量 + 元数据
  • 查询时检索 top-k,再把片段塞回 prompt

RAG 的典型 prompt 结构:

  • 系统约束
  • 用户问题
  • 检索到的证据片段(带来源)
  • 生成要求(格式/字段)

RAG 的最大风险不是“不会检索”,而是:

  • 检索不到(召回率低)
  • 检索到不该要的(误召回污染)
  • 检索到但不会用(生成阶段忽略证据)

二、工程对比:准确率、成本、时延、可观测性

下面这张表给你一个直觉(不是绝对结论,目的是帮助选型):

方案质量上限质量下限成本时延主要风险最需要的“治理组件”
截断/滑窗忘约束、丢事实约束抽取 + 关键事实卡片
摘要链路中-高信息损失、偏置累积分段策略 + 摘要评测 + 可回溯
RAG 链路中-高中-高误召回、证据缺失召回评测 + 重排 + 引用约束

1)准确率:你到底是在解决“记忆”还是“知识”?

  • 知识型问题(政策条款、产品手册、代码库):RAG 通常更合适
  • 状态型问题(任务进行到哪、用户偏好、约束列表):摘要更合适
  • 短期局部问题(只看最近几轮就够):滑窗就够

一句话:RAG 擅长“找对东西”,摘要擅长“把事情说清楚”,滑窗擅长“省钱”

2)成本:别只看 embedding,真正贵的是“无效 token”

很多团队算成本只算 embedding / 向量库。

但线上最常见的浪费是:

  • 把一堆“可能有用”的历史塞回 prompt
  • 每轮都带上同一坨背景(重复 token)
  • 误召回把无关 chunk 塞进去,既贵又降质

建议你按三类 token 记账:

  • 必要约束 token(必须带)
  • 证据 token(按需带)
  • 噪声 token(应该尽量为 0)

目标不是“带更多”,而是“带对 + 带少”。

3)时延:摘要是“前置时延”,RAG 是“查询时延”

  • 摘要:你把成本/时延提前支付(写摘要时慢一点,生成时更稳)
  • RAG:你在每次请求时支付检索开销(向量检索 + 重排 + 拼接)

长任务里通常会出现一个拐点:

  • 对话短时,滑窗最快
  • 对话长后,滑窗因为“不断失败重试/反复澄清”反而更慢

所以时延评估不要只看一次请求的 p95,要看“完成任务的总轮次”。

4)可观测性:没有指标就没有优化

三条链路分别该观测什么:

  • 滑窗:约束命中率、关键事实遗漏率、返工轮次
  • 摘要:摘要长度、摘要一致性(同输入多次摘要差异)、摘要回退次数
  • RAG:召回率(是否命中正确文档)、误召回率、引用覆盖率(回答中使用了多少证据)

如果你只做一个最小指标:“任务完成率 + 失败原因分类”,并把失败映射回链路(忘了/丢了/没检索到/检索错了)。


三、怎么选:一个可落地的决策树

你可以用下面的顺序做最小选型:

  1. 问题是否依赖外部事实/文档?
    • 是:先做 RAG(哪怕是最简 top-k)
    • 否:进入下一步
  2. 任务是否跨多个阶段、需要保持连续状态?
    • 是:做分段摘要(阶段总结 + 最近滑窗)
    • 否:先用滑窗
  3. 失败主要是“忘规矩/忘约束”还是“缺知识”?
    • 忘规矩:抽取约束到系统层 + 摘要
    • 缺知识:RAG + 引用约束

很多团队一上来就“全都做”,结果链路复杂、调不动。更稳妥的是:先用失败驱动迭代


四、推荐的混合架构:短期摘要 + 长期 RAG

在生产里,一个常见且好调的组合是:

  • 短期:最近 8-12 轮对话(滑窗)
  • 中期:阶段摘要(每个阶段 1-3 条)
  • 长期:可检索存储(RAG),只在需要时取

你可以把它理解为三层缓存:

  • L1:滑窗(便宜、命中快)
  • L2:摘要(压缩状态)
  • L3:RAG(按需召回证据)

一个简化的拼接顺序:

  1. System:全局约束与安全边界
  2. System:当前任务目标(从用户输入/状态机得出)
  3. System:阶段摘要(只放“状态/约束/待办”,不要放长证据)
  4. Tool/RAG:检索证据片段(带来源)
  5. Recent:最近对话
  6. User:当前请求

想继续完善的话,可以在回答里要求“引用证据”,并在 UI 上把引用做成可点击(文章列表见 /articles)。


五、落地清单:把“链路”做成“可控系统”

你可以按这个 checklist 做到可上线:

  • 约束抽取:把不可丢规则提升到 system
  • 分段策略:什么时候写摘要(按轮次/按 token/按阶段)
  • 摘要评测:抽样人工评审 + 自动一致性检查
  • RAG 评测:召回率/误召回率/引用覆盖率
  • 回退机制:摘要不足时,回退到原始片段或触发检索
  • 成本看板:按“必要/证据/噪声 token”记账

如果你正在做 Agent 产品,建议把“任务阶段”显式化:阶段切换时强制写一次总结,这能显著降低长任务的漂移。


常见问题

RAG 的 chunk 要多大?

没有万能答案,但建议从“能被引用的最小语义单元”开始:一段话或一个小节,而不是一整页。更重要的是配合元数据过滤(时间、产品版本、权限)减少误召回。

摘要要不要每轮都写?

通常不要。每轮写摘要成本高且容易引入偏置。更常见的是“阶段总结”或“超过阈值再总结”,并保留可回溯索引。

滑窗真的有用吗?

有用,而且几乎总是混合架构的一部分。它提供了最稳定的短期上下文与语气延续,但不应该承担长期知识与约束的存储职责。

想看更多 Agent 工程化文章,可以从 /articles 开始,或直接在 /apps/new 体验产品。