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,使得:
- S 中的块均与 q 的话题相关
- Σ|b| (b ∈ S) ≤ C
- 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
评论 (0)
发表评论
请先登录后发表评论