1 引言

大语言模型在多轮对话中面临两个核心问题:

上下文污染:随着对话进行,历史内容容易混入当前回答。例如前 50 轮讨论 Redis,第 51 轮突然问 Git,模型的回答仍可能受到 Redis 上下文的影响。

上下文膨胀:对话一长,token 快速增长,context window 极易触发上限,费用随之增加。

现有方案包括:最近窗口截断、稀疏检索(BM25 等)、向量检索(embedding + FAISS)、摘要压缩等。其中向量检索依赖额外模型,最近窗口截断无法处理话题切换。

本文关注的是其中最轻量的一类:纯规则方法,不依赖任何神经网络模块。在构造的测试集上能过滤掉其他话题的干扰,同时比 Last-5 节省约 38% 的 token。

2 问题形式化

对话历史是一串块 B = (b₁, b₂, ..., bₙ),bᵢ 为一对问答 (uᵢ, aᵢ)。当前查询为 q,上下文预算为 C。

目标:从 B 中选取一个子集 S,使得:

  1. S 中的块均与 q 的话题相关
  2. Σ|b| (b ∈ S) ≤ C
  3. S 覆盖 q 的关键锚点,覆盖度 ≥ η

硬约束:不使用任何神经网络模块(embedding、reranker、分类器等)。

3 方法

3.1 锚点提取

从文本中提取有检索价值的词,记为锚点集合 A(t)。

规则:

  • 中文 2-gram / 3-gram(过滤掉"有什么""什么""怎么"等通用疑问词)
  • 英文单词(长度 ≥ 2)
  • 代码标识符(长度 ≥ 2)
  • 版本号(v\d+(.\d+)*)
  • 引号内的完整短语

无需分词库,规则实现。

工程判断:为何过滤"有什么区别""怎么"等?因为所有查询结尾均有此类表达,它们在不同话题中反复出现,无区分度,不排除会导致 gate 和召回失效。

3.2 话题门控

当前活跃话题的锚点集合为 T,当前查询的锚点为 A(q),锚点 t 的 IDF 为 idf(t)。

定义 1(加权重叠率)

overlap(q, T) = Σ idf(t) for t ∈ (A(q) ∩ T) / Σ idf(t) for t ∈ A(q)

定义 2(新锚点比例)

new_ratio(q, T) = Σ idf(t) for t ∈ (A(q) \ T) / Σ idf(t) for t ∈ A(q)

门控规则

条件 判断
overlap < 0.20 且 new_ratio > 0.70 切换话题
overlap > 0.45 继续当前话题
q 中含指代词("这个""它""上面"等) 继续当前话题
中间地带 默认继续

指代词集合:{这个, 那个, 它, 上面, 刚才, 继续, 展开, 为什么, 怎么改, 然后, 还有}

3.3 稀疏召回

话题切换时,通过内容词过滤无关旧话题块,其余块按 BM25/IDF 评分排序。

内容词过滤(仅话题切换时):从 query 中抽取英文术语、代码标识符、2 字以上中文词(停用词除外)、版本号,构成 Wq。不含 Wq 词的候选块直接排除。

此过滤为防污染的关键——旧话题块不含新话题关键词,表明其与当前问题无关。

定义 3(块相关度评分)

score(b, q) = 1.5 × lex(user, q) + 0.7 × lex(assistant, q) + 1.0 × exact(q) + 0.2 × recency(b)

各项含义:

  • lex(x, q) = Σ idf(t) × min(tf(t, x), 3)
  • exact(b, q):英文术语 / 代码标识符 / 版本号精确命中,命中一个 +1 分
  • recency(b) = (index(b) + 1) / |B|(新鲜度)
  • 用户侧权重 1.5,助手侧 0.7。助手回答的信息密度通常更低。

取 top-20 候选进入下一阶段。

3.4 最小覆盖选择

将上下文选择建模为带约束的加权集合覆盖问题。

定义 4(贪心增益)

gain(b | S) = Σ idf(t) for t ∈ (cov(b) \ covered(S)) / |b|^α

α = 0.8。每次选择增益最高的块,直到覆盖率达到 η = 0.85 或 token 预算耗尽。

覆盖度 η:

η = Σ idf(t) for t ∈ covered(S) / Σ idf(t) for t ∈ A(q)

3.5 句级裁剪

块选中后,块内再做句子级裁剪:仅保留包含 query 锚点的句子,最多 3 句。助手侧即使不含锚点,也保留第一句,保证上下文衔接。

4 实验

4.1 设置

测试集:4 个话题(Redis、asyncio、PostgreSQL、Git),每话题 5 轮交替,共 20 轮。预算 C = 4000 tokens。

对比方法:Last-3/5/10、BM25-5、Full CGK。

Ablation 变体:Gate-only、Coverage-only、-Recency、-IDF、-Deictic、-Exact Match、-Trim。

评价指标说明:本方法以"块纯度"和"污染率"为主要指标,但这是一种以话题隔离为核心的评价视角。Last-N 系列方法的设计目标是以简单性换取鲁棒性,并非以话题隔离为目标;BM25 以语义相关度排序,也不显式处理话题切换。因此本对比更多展示的是"在话题隔离这一特定需求上,有设计的方法优于无设计的方法",而非全面评价各方法的优劣。

统计口径:token 数包含完整 prompt——历史上下文 + 格式化标签(约 8% overhead)+ 当前 query,非仅统计"选中的块"。

4.2 基线对比

方法 平均 Prompt Tokens 污染率
Last-3 43.6 100%
Last-5 67.6 100%
Last-10 137.6 100%
BM25-5 70.6 60%
Full CGK 42.6 0%

在构造的测试集上,CGK 实现了最少 token 消耗且零污染。Last-N 均 100% 污染——无话题过滤,必然混入其他话题。BM25 污染率较低(60%),但 token 消耗更大,且仍无法完全避免污染。

本方法比 Last-5 节省约 37% token。

关于"污染率"指标的说明:本指标的定义是"检索到的上下文中是否混入了其他话题的块"。Last-N 在交替话题场景下必然产生此类混入,因为其设计不包含话题过滤维度。以此指标评价 Last-N 不完全公平,但其结果仍具有参考价值——它反映了在话题频繁切换场景下,不同策略在上下文纯净度上的实际差异。

4.3 上下文构造质量

上下文质量不仅体现在"无其他话题混入",还体现在关键信息的覆盖程度。本节通过规则估算指标评估上下文构造的质量。

指标 CGK Last-5 说明
平均 Prompt Tokens 42.2 67.6 CGK 省 38%
块纯度 1.000 0.280 CGK 上下文几乎全属目标话题
锚点召回率 0.638 0.066 CGK 上下文覆盖 64% query 锚点,Last-5 仅 7%
术语覆盖率 0.380 0.080 CGK 上下文包含更多专业术语
污染发作次数 0 5 Last-5 每次查询均混入其他话题

无真实 LLM 调用,此处质量指标为规则估算,非实际模型答案。实际表现可能不同。

4.4 Ablation Study

变体 平均 Token 污染率 与 Full CGK 差异
Full CGK 42.2 0%
Coverage-only(无门控) 42.6 20% 污染率大幅上升
Gate-only(无覆盖优化) 47.4 0% 多 5.2 tokens
-Recency 42.2 0% 无显著差异
-IDF 42.2 0% 无显著差异
-Deictic 42.2 0% 无显著差异
-Exact Match 42.2 0% 无显著差异
-Trim 42.2 0% 无显著差异

话题门控(Gate)为防污染的核心——移除后污染率从 0% 升至 20%,是唯一带来显著差异的模块。

其余模块的说明:在当前干净测试集上,最小覆盖选择、精确匹配、Recency、IDF 加权、指代词规则、句级裁剪均未产生显著差异。这并不意味着这些模块无用——它们是针对真实对话中的复杂场景(短 query、术语拼写错误、口语化追问等)设计的稳健性机制,其价值需在真实数据上才能验证。

4.5 参数敏感性

参数 测试范围 结论
OVERLAP_CONTINUE_THRESHOLD 0.30 ~ 0.60 干净数据上无显著差异
NEW_RATIO_SWITCH_THRESHOLD 0.50 ~ 0.90 干净数据上无显著差异
RECENT_WINDOW 5 ~ 30 窗口越小,token 越少(主要杠杆)

OVERLAP 和 NEW_RATIO 在干净数据上无显著差异,原因在于锚点停用词过滤已使话题切换边界变得清晰——query 的锚点要么全属新话题,要么全属旧话题,无需精细的阈值判断。RECENT_WINDOW 是唯一有清晰量效的参数:窗口从 15 缩减至 5,token 从 42.2 降至 21.6。

这些参数的敏感性分析需在真实对话数据上进一步验证,当前结论的泛化性有限。

5 适用与不适用场景

适用

  • 资源受限的环境(边缘设备、私有化部署)
  • 对延迟敏感的实时对话
  • 话题边界清晰的技术问答

不适用

  • 需要精确语义匹配的场景:规则无法理解同义词,语义相近但措辞不同的相关内容会遗漏,建议使用向量检索
  • 超过 100 轮的极长对话:IDF 分布已过时,历史锚点集合失效
  • 真实对话未经验证:用户可能半句中文半句英文,可能输入错误术语,可能仅发送"那这个呢"——这些情况均未测试
  • 部分场景下前面的知识对当前回答有帮助(如类比解释),严格隔离可能损失有用的跨话题迁移

6 结论

上下文门控器,基于纯规则的轻量级多轮对话上下文压缩方法。先通过话题门控判断是否切换话题,再在候选块中以 IDF/BM25 评分召回,最后在 token 预算约束下做最小覆盖选择。

定位说明:这不是向量检索的替代品,而是一个适合低成本、话题边界清晰场景的前置过滤器。在话题切换频繁且边界清晰的场景中有效,但在需要精确语义理解的场景中,建议与向量检索配合使用。

实验结论

  • 4 话题交替测试集上,比 Last-5 节省约 38% token,污染率为 0%
  • 话题门控是防污染的核心模块,其余模块在干净数据上暂无显著收益
  • RECENT_WINDOW 是主要的 token 控制杠杆

局限说明

  • 仅在构造的干净测试集上进行了实验,未在真实对话日志上验证
  • 未与向量检索等强基线做端到端对比(仅测了检索块质量)
  • "污染"定义为"检索块中混入其他话题内容",不等同于"模型回答被污染"
  • 测试查询仅有 5 个,样本量较小,结论的可复现性还需进一步验证
  • 无真实 LLM 调用,质量评估为规则模拟,真实模型行为未知
  • OVERLAP / NEW_RATIO 参数敏感性在真实数据上的表现尚不明确

代码仓库:https://gitea.ephron.ren/elaina/context-gatekeeper