Skip to content

高频面试题

当对话历史超出上下文窗口时,有哪些上下文压缩策略?各自的优缺点是什么?

这道题看起来在问“怎么缩短聊天记录”,实际在考你能否把 Agent 长任务里的历史、工具结果、状态、记忆和证据分层治理。

适合阶段:Agent 工程 / Context Engineering 面核心能力:Context Compression · State Management · Memory Retrieval · Reliability

面试官角度分析,想考什么

  • 上下文超窗时你会怎么处理?
    考策略意识:不是只删最早消息,而是摘要、结构化 state、检索召回和工具结果蒸馏。

  • 不同压缩策略的取舍是什么?
    考优缺点:截断便宜但丢约束,摘要压缩率高但失真,检索省窗口但有召回风险。

  • 压缩会丢关键信息怎么办?
    考治理:保留目标、约束和证据 id,关键细节能回看,并用评估检查压缩后有没有掉质量。

可直接抄走的 30 秒参考答案

text
对话历史超出上下文窗口时,我不会只删最早消息。常用策略有几类:滑动窗口保留最近对话;滚动摘要把早期历史压成任务摘要;把目标、约束、计划、证据 id 抽成结构化 state;把完整历史放外部 store,需要时检索召回;工具结果做蒸馏和落盘;长任务按阶段做 checkpoint;复杂子任务用上下文隔离。它们的取舍是:截断和滑窗便宜但容易丢早期约束,摘要压缩率高但会失真,检索省窗口但有召回风险,结构化 state 稳定但需要 schema 和冲突治理。

面试回答详解,知其所以然

这道题的核心不是“怎么把 token 变少”,而是“怎么在变少以后仍然让 Agent 做对事”。上下文压缩本质上是有损信息管理:要明确保留什么、压缩什么、丢弃什么,以及丢了以后有没有回看原文的路径。

1. 为什么不能只靠更大的上下文窗口

长上下文模型能缓解容量问题,但不能消除上下文治理。

  • 成本更高:同一段历史如果每轮都带上,Agent 多轮循环会重复付费。
  • 延迟更高:长 prompt 会增加 prefill 时间,用户体感变慢。
  • 噪声更多:旧工具结果、过期计划、错误尝试会干扰当前决策。
  • 位置偏置:Lost in the Middle 研究表明,长上下文中间的信息更容易被模型忽略。
  • 隐私风险:把所有历史长期留在 prompt 里,会扩大敏感信息暴露面。

所以压缩的目标不是把窗口塞满,而是提高当前这一轮的信噪比。

2. 策略一:硬截断

硬截断就是超过阈值后直接删除一部分历史,常见做法是保留最近 N 轮。

text
messages = system + recent_messages[-N:]

优点:

  • 实现最简单,稳定可控。
  • 延迟低,不需要额外 LLM 调用。
  • 适合闲聊、一次性任务、低风险客服问答。

缺点:

  • 很容易删掉早期用户约束、验收条件和关键决策。
  • 不知道被删内容是否重要,失败时也难以定位。
  • 对长任务、代码修改、合同审阅、数据分析这类任务风险很高。

面试里要补一句:硬截断只能做最后兜底,不应该是唯一策略。即使要截断,也要先抽取关键状态。

3. 策略二:滑动窗口

滑动窗口比硬截断稍好:系统提示词和当前任务状态常驻,只滚动保留最近对话。

text
system prompt + current state + last K turns -> model

优点:

  • 对最近上下文连贯性很好。
  • 实现成本低,适合绝大多数普通多轮对话。
  • 容易和 token budget 结合。

缺点:

  • 早期目标仍然会自然丢失。
  • 如果用户一开始给了长约束,后面只靠滑窗会忘。
  • 对跨阶段任务不够,比如“先调研、再设计、再实现、再验证”。

工程上常见做法是滑动窗口配合结构化 state:最近消息保留原文,早期重要事实进入 task_state

4. 策略三:滚动摘要

滚动摘要是在历史变长时,把较早对话压缩成一段 summary,再和最近消息一起放进上下文。

text
旧 summary + 新一批历史 -> 新 summary
新 summary + 最近 K 轮 -> model

优点:

  • 压缩率高,能支撑很长的单 session。
  • 比直接截断更能保留任务背景、决策和未完成事项。
  • 适合长客服会话、长代码任务、研究型 Agent。

缺点:

  • 摘要是有损的,可能漏掉否定约束、数值、异常和边界条件。
  • 摘要会累积错误,早期误解会被固化到后续所有轮次。
  • 需要额外模型调用,增加成本和延迟。

高质量摘要应该有固定 schema,而不是一段散文:

text
目标:
用户硬约束:
已完成:
关键决策:
工具证据:
未完成事项:
风险和待确认:

5. 策略四:结构化状态外置

很多信息不应该靠聊天原文保存,而应该抽成结构化 state。

适合外置的内容:

  • 用户目标和验收条件。
  • 当前计划、已完成步骤、待办项。
  • 工具调用得到的关键结论和证据 id。
  • 文件路径、资源 id、版本号、错误码。
  • 需要严格保真的数字、枚举、权限和审批状态。

优点:

  • 信息更稳定、更可验证,不容易被自然语言摘要改写。
  • 便于恢复、审计、回放和 UI 展示。
  • 可以跨模型、跨进程、跨任务阶段复用。

缺点:

  • 需要设计 schema、更新规则和冲突策略。
  • 对开放式任务不一定容易抽取完整。
  • 如果 state 写错,会比普通摘要更“像事实”,污染更强。

成熟回答要强调:结构化 state 不替代对话历史,它保存的是任务骨架;最近原文仍然要保留,避免丢失语气、上下文和用户刚刚表达的变化。

6. 策略五:检索式历史

检索式历史是把完整历史或压缩片段存到外部 store,需要时根据当前 query 召回相关片段。

text
历史片段 -> embedding / keyword index / metadata index
当前任务 -> retrieve + rerank -> 注入少量相关历史

优点:

  • 不必每轮携带全部历史。
  • 对“很久以前提过的细节”更友好。
  • 可以结合时间、重要性、来源和权限过滤。

缺点:

  • 检索可能召回不到关键片段,也可能召回旧片段。
  • 只靠向量相似度容易漏掉数字、否定、罕见实体。
  • 检索结果仍然占上下文,需要 rerank 和压缩。

工程上通常用混合检索:关键词保证精确实体,向量召回语义相关,metadata 过滤用户、项目、时间、权限,再用 reranker 或规则挑最终片段。

7. 策略六:工具结果清理和蒸馏

Agent 的上下文膨胀常常不是用户聊天造成的,而是工具结果造成的。工具输出进入上下文后,应该定期蒸馏。

  • 大文件读取:保留文件路径、行号范围、关键结论,不长期保留全文。
  • 测试日志:保留失败测试名、错误类型、关键 stack frame、修复结果。
  • 搜索结果:保留采用的证据链接和结论,清理未采用候选。
  • 数据查询:保留聚合指标、筛选条件、版本,不保留上千行原始记录。

优点:

  • 压缩收益大,通常比压用户消息更有效。
  • 保留证据 id 后仍可回看原始结果。
  • 能显著降低噪声和 Lost in the Middle 风险。

缺点:

  • 需要工具协议支持分页、句柄、行号和 artifact。
  • 蒸馏错误会导致 Agent 基于错误结论继续走。
  • 不同工具需要不同策略,不能只用一个通用 summarizer。

8. 策略七:分阶段 checkpoint

对长任务,可以在阶段结束时生成 checkpoint,然后开启新的上下文。

text
阶段一:调研 -> checkpoint
阶段二:方案 -> checkpoint
阶段三:实现 -> checkpoint
阶段四:验证 -> checkpoint

优点:

  • 让上下文按任务阶段重置,避免历史无限增长。
  • checkpoint 可用于恢复、审计和人工 review。
  • 对复杂 Agent workflow 很自然。

缺点:

  • 阶段切分不准会丢掉跨阶段依赖。
  • checkpoint 质量决定后续质量。
  • 需要 runtime 支持任务状态、artifact 和 trace。

面试里可以说:checkpoint 不是单纯摘要,而是“可以接着干”的任务快照,至少包含目标、约束、决策、证据、当前状态和下一步。

9. 策略八:上下文隔离

上下文隔离是把子任务放到单独上下文里执行,只把结果带回主上下文。LangChain 把这类策略称为 isolate,Anthropic 也强调 subagent 需要自包含 prompt。

适合场景:

  • 让一个子 Agent 阅读长文档,只返回结构化结论。
  • 让代码分析子任务在独立上下文里跑,不污染主决策历史。
  • 对多个候选方案并行分析,主 Agent 只看比较结果。

优点:

  • 主上下文更干净。
  • 子任务可以使用专门工具和专门提示词。
  • 失败可以局部隔离,不一定污染全局历史。

缺点:

  • 子任务如果 prompt 不完整,会因为缺背景而答偏。
  • 汇总结果可能丢细节,需要保留证据引用。
  • 编排复杂度、成本和延迟都会上升。

10. 怎么选择策略

可以按任务风险和信息形态选:

  • 低风险闲聊:滑动窗口 + 简单摘要。
  • 客服与业务流程:滑动窗口 + 结构化工单状态 + 用户偏好记忆。
  • 代码 Agent:文件引用 + 工具结果蒸馏 + checkpoint + 最近操作窗口。
  • 研究与写作 Agent:检索式历史 + 证据链接 + 分阶段 checkpoint。
  • 高风险决策:结构化 state + 原始证据可回放 + 压缩后校验 + 人工确认。

一个可靠的压缩流程通常是:

text
token 计数 -> 判断触发阈值 -> 抽取关键 state
  -> 压缩旧历史和工具结果 -> 保留最近原文
  -> 校验摘要是否覆盖硬约束和未完成事项
  -> 写入 trace,继续下一轮

面试官追问3个问题

追问一:滑动窗口和滚动摘要怎么配合?

  • 考察点:是否知道近期连贯和长期状态要分开。
  • 回答方向:最近 K 轮保留原文,保证模型理解刚发生的交互;更早历史压成结构化摘要,保留目标、约束、决策、证据和待办。每次摘要更新都基于旧摘要加新历史,而不是每次重读全部历史。

追问二:摘要压缩会丢信息,怎么降低风险?

  • 考察点:是否把压缩当成有损操作。
  • 回答方向:用固定摘要 schema;把用户硬约束、数字、否定、未完成事项和证据 id 设为必保字段;压缩后做 verifier 检查;关键证据保留原文引用;高风险变更需要人工确认后再丢弃原文。

追问三:检索式历史为什么不能只用向量库?

  • 考察点:是否理解 memory retrieval 的召回风险。
  • 回答方向:向量检索擅长语义相似,但容易漏数字、版本、实体和否定。生产里要混合检索:关键词、metadata、时间、权限和向量一起用,再 rerank。召回结果还要去重、处理过期和冲突,不能直接塞进 prompt。

扩展知识

压缩策略可以分成四类动作

LangChain 在 context engineering 里把策略概括成 write、select、compress、isolate,这个分类很适合面试表达。

  • Write:把信息写到上下文之外,比如 scratchpad、checkpoint、memory store、artifact。
  • Select:从外部信息里选当前相关的少量内容,比如检索历史、动态工具加载。
  • Compress:把长历史、长文档、长工具结果压短,比如摘要、抽取、token 级压缩。
  • Isolate:把子任务放到独立上下文,避免主上下文被污染。

这比“总结一下历史”更像工程答案,因为它覆盖了上下文进入模型前后的完整链路。

摘要压缩和 prompt compression 不完全一样

  • 历史摘要:面向多轮任务,把过去发生了什么压成“可继续执行”的状态。
  • 工具结果蒸馏:面向 observation,把长输出压成结论和证据引用。
  • 文档压缩:面向资料,把长文档压成相关片段或摘要。
  • Prompt compression:更偏 token 级删除或重写,例如 LLMLingua 类方法。

面试里不要把所有压缩都说成 summarization。生产系统里通常是多种压缩混用。

压缩摘要最容易丢什么

  • 否定约束:例如“不要发邮件”“不要改配置”。
  • 数字和阈值:例如金额、日期、版本号、limit。
  • 异常和失败:例如某工具调用失败、某方案已被否决。
  • 用户偏好变化:例如用户从“要 PDF”改成“只要 Markdown”。
  • 证据来源:例如哪个链接、哪个文件、哪一行支持这个结论。

所以摘要 prompt 要显式要求保留这些字段,压缩后还要做检查。

压缩也可能制造上下文污染

压缩不是纯优化,它也可能把错误固化下来。比如模型误把“候选方案 A 已被否决”摘要成“当前采用方案 A”,后续所有轮次都会被带偏。

缓解方式:

  • 摘要里保留 confidencesourcetimestampstatus
  • 冲突信息不要合并成一句,要并列保留并标记待确认。
  • 关键事实用结构化 state,不只靠自然语言。
  • 高风险任务保留原始证据引用,必要时二次验证。

基于 MIT 协议开源