核心问题:有没有一种办法,让 RAG 系统既不用把整篇文档塞进 prompt,又能把“搜什么”和“怎么答”放在同一张梯度图里一起训练?
答案:CLaRa 用“压缩向量 + 可微 Top-k”把检索与生成一次性对齐,上下文长度缩短 4×–128×,效果反而更好。


本文核心速览

维度 传统 RAG CLaRa
上下文长度 原始文本 128× 压缩向量
检索-生成优化 割裂、无梯度 同一 LM loss 端到端
监督信号 人工标注相关句 仅答案文本(NTP)
推理延迟 随文档线性增长 离线压缩,常数时间

目录

  1. 背景:RAG 的两只“拦路虎”
  2. 关键洞察:共享连续空间
  3. SCP 预训练:先让压缩向量“看得懂”文档
  4. CLaRa 联合训练:可微 Top-k 打通梯度
  5. 实验结果:更短上下文,更高指标
  6. 场景化示例:HotpotQA 多跳问答一条流
  7. 作者反思:我们踩过的三个坑
  8. 实用摘要 / 一页速览
  9. FAQ

1. 背景:RAG 的两只“拦路虎”

核心问题:为什么传统 RAG 总是“搜得挺准,答得一般”?

  1. 优化墙
    检索器用相似度排序,生成器用交叉熵训练,两者目标函数不互通,梯度流被离散 top-k 截断。
  2. 效率墙
    检索阶段把文档压成 512 d 向量,生成阶段又把原文 2 k token 塞进 prompt——同一篇文档被重复编码,上下文爆炸,推理昂贵。

CLaRa 把“墙”拆掉的办法:
① 把文档先离线压成 32~256 个“记忆 token”向量;② 让查询向量与文档向量在同一连续空间里做可微 top-k;③ 用生成器的 next-token prediction 作为唯一损失,反向传播到查询编码器。


2. 关键洞察:共享连续空间

模块 输入 输出 作用
SCP Compressor 原始文档 记忆向量 M_i 语义骨架,长度固定
Query Reasoner 问题 Q 查询向量 q 与 M_i 同维度
Generator [q; M_{1:k}] 答案文本 直接生成,无需原文

因为三者共用同一套词表与 Transformer 权重,梯度可以一路从答案 token 回流到查询向量,再回流到文档压缩器——检索与生成第一次在同一张图里联合更新


3. SCP 预训练:先让压缩向量“看得懂”文档

核心问题:压缩向量那么短,怎么保证它不掉信息?

SCP(Salient Compressor Pre-training)用三把“筛子”把文档精华逼出来:

  1. Simple QA
    一条文档只问一个原子事实,例如
    Q: Trichocladus crinitus 属于哪个科?
    A: Hamamelidaceae
    → 压缩器必须保留“科名”实体。

  2. Complex QA
    把多条事实串成多跳问题,例如
    Q: 哪位球员 2014-10-02 加盟 Newport County 并在 4 日替补登场?
    A: James Loveridge
    → 压缩器得同时保留“日期 + 俱乐部 + 人名”。

  3. Paraphrase
    让模型自己把文档换一种说法,但语义不变。
    → 压缩向量被迫丢弃表层词序,只留语义骨架。

训练套路

  • 数据:200 万条 Wikipedia 2021 文档,本地 Qwen-32B 自动生成 QA 与改写。
  • 结构:共享底座 + 两套 LoRA(compressor / generator)。
  • 损失:
    ℒ_total = ℒ_CE(生成) + λ·ℒ_MSE(记忆向量 vs 平均词向量)
    λ=0.1 时,压缩向量与原文空间重合度最高(t-SNE 可视化见原文附录)。

场景示例
假设你要把 50 页技术手册塞进手机端聊天助手。SCP 阶段把每页压成 64 个记忆 token(约 0.5 kB),离线存进向量库。用户提问时,只需把 64×50=3200 个浮点数读入 GPU,无需再把 50 页原文送进 LLM,上下文长度瞬间从 >16 k token 降到 320 token。


4. CLaRa 联合训练:可微 Top-k 打通梯度

核心问题:top-k 是离散操作,怎么让梯度“溜”过去?

CLaRa 用 Straight-Through (ST) Gumbel-Softmax 思路:

前向:hard top-k(真的只取 k 个向量)
反向:soft top-k(用 softmax 权重近似)

算法伪代码(PyTorch 风格)

scores = cosine(q, M)          # [batch, D]
soft = softmax(scores / tau)   # 用于反向
hard = one_hot(argmax(scores)) # 用于前向
Z = hard + (soft - soft.detach())  # ST 估计
M_topk = einsum("bkd,bdv->bkv", Z, M)  # 选 Top-k 向量

损失只有一项:

ℒ_CLaRa = −Σ_t log p(a_t^* | Q, M_{1:k}, a_{<t}^*)

没有“相关/不相关”人工标签,全靠答案文本驱动。
实验发现:当温度 τ=0.3,k=5 时,Recall@5 在 HotpotQA 上比全监督 BGE-Reranker 还高 10.28%。


5. 实验结果:更短上下文,更高指标

5.1 压缩有效性(Oracle 设定:保证正例在候选池)

方法 压缩比 NQ HotpotQA Musique 2Wiki 平均
PISCO 16× 73.44 66.53 33.80 60.45 58.55
SCP-Mistral-7B 16× 75.48 70.79 43.15 66.16 63.90
SCP-Mistral-7B 128× 69.96 62.09 30.86 59.08 55.50

结论:

  • 128× 极限压缩下,SCP 仍比同为 128× 的 xrag 高 27.8%。
  • 16× 压缩的 SCP 向量直接替代原文,指标反超未压缩的 BGE 检索(+2.5%),说明压缩过程滤掉了噪声。

5.2 端到端问答(Normal 设定:从 Wikipedia-2021 Top-20 里现搜)

方法 上下文长度 NQ F1 2Wiki F1
DRO-Mistral-7B 51.01 43.65
CLaRa-Mistral-7B 16× 51.41 47.18

反思 / 学到的教训

  1. 压缩不是“偷工减料”,而是显式去噪:SCP 预训练让模型学会丢弃与问答无关的修饰语,留下实体、关系、数字。
  2. 联合优化比“先训检索、再冻住训生成”更稳:训练曲线显示,CLaRa 的验证集 F1 在 3 个 epoch 后就超过两阶段方案,且方差更小。
  3. 温度 τ 是隐形“学习率”:τ 太大,soft 权重太平,梯度信号被稀释;τ 太小,近似 argmax 导致梯度方差大。经验上 τ=0.3–0.5 最稳。

6. 场景化示例:HotpotQA 多跳问答一条流

问题
“How many yards did the nephew of Ivory Lee Brown get during his 2004 true freshman season?”

传统 RAG 痛点

  • 需先搜“Ivory Lee Brown nephew”→得“Adrian Peterson”
  • 再搜“Adrian Peterson 2004 freshman yards”→得“1,925”
    两次检索、两次重排,延迟翻倍。

CLaRa 单步流程

  1. Query Reasoner 把问题压成 32 个记忆 token;
  2. 与离线压缩的维基百科向量做 cosine,Top-5 已包含“Peterson 2004 season”片段;
  3. 生成器直接读 [q; M_1:5] 输出“1,925 yards”。

Logit-Lens 可视化
把查询向量过 LM 头,Top-50 token 出现“NFL”“Oklahoma”——这些词原问题里根本没有,说明联合训练把“隐含实体”也压进了查询向量,从而一步召回关键文档。


7. 作者反思:我们踩过的三个坑

  1. MSE 对齐损失不能省
    早期尝试只靠生成损失,记忆向量很快“飘”到与原文不同的区域,检索召回掉 8%。加上 λ=0.1 的 MSE 后,t-SNE 显示两组向量基本重合,指标回升。

  2. 指令微调初始化 ≠ 万能
    直觉上“先指令微调再联合训练”应该更强,结果发现指令微调会让查询向量过于聚焦“答案句”局部语义,反而丢失全局检索能力。最终方案:SCP 预训练 → 直接联合训练,只在下游 QA 数据上做 early stopping。

  3. 压缩比不是越高越好
    128× 以后继续压到 256×,指标开始下滑;但延迟不再线性下降(向量 IO 成为瓶颈)。产品落地时,16×–32× 是延迟-质量甜点。


8. 实用摘要 / 一页速览

适用场景

  • 长文档问答:技术手册、法律条文、医疗指南
  • 端侧部署:手机、车载、嵌入式 GPU
  • 多跳知识库:Wiki、企业知识图谱

落地步骤

  1. 用 SCP 脚本把知识库所有文档压成记忆向量(一次性,离线)。
  2. 把 Query Reasoner LoRA 插到现有 LLM,训练数据只需“问题-答案”对。
  3. 推理时:
    a. 问题 → 查询向量(32 token)
    b. FAISS 搜 Top-5 文档向量(共 160 token)
    c. 拼接后送进生成器,答案即出。

硬件收益

  • 原文 16 k token → 192 token,显存占用降到 1/80
  • 100 k 文档库,向量总大小 < 20 GB,一张 A100 可全放显存。

9. FAQ

  1. CLaRa 与 Retrofit 类“先检索再精排”方案有何不同?
    传统方案检索、精排、生成三阶段目标不一致;CLaRa 用同一套 LM loss 端到端训练,梯度直达查询编码器,无需人工标注相关句。

  2. 记忆 token 数量如何选?
    经验:每 100 字用 1 个记忆 token;新闻/百科 16 足矣,科技论文建议 32–64。

  3. 压缩向量会“遗忘”表格或数字吗?
    SCP 预训练用 Simple QA 显式保留数字、实体,实验表明在需要数值回答的 2Wiki 数据集上,CLaRa 仍比原文 BGE 基线高 2-4%。

  4. 温度 τ 需要调吗?
    0.3–0.5 区间对结果不敏感;若候选池 >10 k,可适当升至 0.7 防止 softmax 太平。

  5. 能否直接用在中文?
    输入文件实验仅覆盖英文维基,但框架与语种无关。只需用中文语料重新走 SCP 预训练即可。

  6. 离线压缩多久?
    单卡 A100,7B 模型,200 万篇维基约 18 小时;一次完成,后续无需再动。

  7. 向量库更新怎么办?
    新增文档只需单独压向量并追加到 FAISS,无需重训模型;删除文档则做软删除标记即可。