1. 从论文标题开始:为什么第四周我选这篇OSCAR
我们精读小组每周轮流挑论文,前几周基本上都在RAG的外围打转:有讲GraphRAG的,有讲self-RAG的,也有讲混合检索策略的。读到第四周,我反而想回到一个特别基础但也特别容易被忽略的问题上:检索回来的内容,真的需要照单全收吗?
于是这周我推荐了这篇《OSCAR: Online Soft Compression for RAG》。题目里的关键词很直白:Online(在线)、Soft Compression(软压缩)、RAG(检索增强生成)。但它想解决的事,如果你只看了标题很容易误判——不是简单的向量压缩,也不是给RAG做一个更小的嵌入模型。它想做的,是把“检索到的再喂给模型”这一整段信息的传输成本降下来,同时又不让答案质量明显受损。
先说我个人的结论:这是一篇工作量很扎实、也不需要特别强大硬件环境就能跑通的概念型论文。它最大的贡献不是刷了几个指标,而是给了工程部署RAG的人一个新的思考维度——我们过去总在调Embedding、调Chunk大小、调TopK,但很少想过能不能把检索结果本身“在线地软压一把”,让进入上下文的信息更浓、更准、更省。
这篇文章我想按我自己的精读习惯来写,不按摘要、方法、实验这种论文结构念经,而是把它拆成四个我真正关心的问题:RAG的瓶颈到底在哪、OSCAR的软压缩是怎么实现的、复现起来要踩哪些坑、以及这玩意儿到底值不值得用到生产环境。中间我会补不少我在复现和小组讨论中得到的细节,争取让你读完之后,不用再去找原论文也能明白个七八成。
2. RAG的真正瓶颈:不是检索不回来,而是喂不进去
2.1 标准RAG链路里最大的浪费在哪里
先走一遍经典RAG链路:文档切块,然后Embedding,向量入库,检索时用查询向量拿TopK块,最后把这几块文本拼到Prompt里丢给大模型。听起来很顺,但实际跑起来的问题,远比“检索结果不相关”更麻烦。
最直接的问题是上下文预算。现在主流模型虽然有128K甚至更长的上下文窗口,但窗口长不代表“该喂的都喂了”。我实测过很多次,当TopK取到8甚至12以上、每个Chunk又有千把字的时候,长上下文段的末尾信息被模型严重稀释,回答质量曲线是明显下降的。你以为是检索越多越准,结果是一堆语义重叠的文本把关键信息淹没了。
第二个问题是存储和传输成本。向量库里塞的每一段文本,除了向量本身之外,通常还会保留原文。为了保召回率,大家倾向于切小块、存多份。这导致向量库的膨胀速度远超想象。如果做的是千万级文档的企业知识库,那磁盘、内存、带宽三个成本会让预算很难看。
第三个问题,是大多数RAG框架都在用比较笨拙的方式处理“相关性”。只要语义相关就往上下文里塞,不考虑信息熵密度,也不考虑段落之间是不是重复。检索系统给你的是“相关的内容”,而不是“有用的内容”。
OSCAR的切入点正好就打在这三点上。它试图把每个检索结果“锤”成一小段更紧凑的表示,而不是直接原始文本进入Prompt。
2.2 硬压缩与软压缩的真实差别
你可能想问:这不就是给文本做摘要吗?把长文变成短文,把TopK从8个变成4个,不也能省空间吗?这就涉及到“硬压缩”和“软压缩”的分野。
硬压缩是离散的、符号层面的操作。比如调用大模型给Chunk生成摘要、用算法抽关键句、或者做文本改写,这些都是硬压缩。好处是压缩结果还是人话,能直接读;坏处是信息会丢,而且很难控制丢哪里。尤其在做摘要压缩的时候,细节性数据——数字、名词、操作步骤——是最容易被大模型“顺手优化掉”的。
软压缩就不一样了。它不是把文本变成较短文本,而是把文本编码成一个连续的、较短的向量序列。你可以把它理解成“把一段话翻译成一组面向检索和生成的稠密向量”,然后让底层模型直接消费这组向量,不再经过文本还原。这就像一个无损程度较高的“语义罐头”,保留了核心信息,但体积极小。
但软压缩微妙的地方在于:它的“可读性”为零。你不能打开压缩后的表示去检查某句话在不在里面,只能通过下游效果来验证它有没有把关键信息保留住。这就带来了一个新的问题:你不得不信任训练出来的压缩器,这是个典型的端到端优化问题。
2.3 “Online”这三个字母,在工程里是被严重低估的
论文标题里还有一个词,我认为比Soft Compression更重要,就是Online。很多关注这个方向的人容易把注意力放在“怎么压缩”上,却忽略了“在线”这两个字带来的系统级变化。
离线压缩意味着什么?意味着你需要定期跑一批任务:把全部文档重新编码、重新压缩、重建向量索引。这个流程在文档量小的时候还好说,文档量一旦上去,那就是一场灾难。你头天晚上才能跑完全量压缩,第二天新文档又进来一批。你总不能为了几个新文件把整个索引全部重建一遍吧?这也正是传统关键词摘要方案落地难的最大原因之一——所有的压缩都发生在“入库前”,跟实时检索链路是脱节的。
OSCAR把压缩做成在线过程,核心思路是让压缩器随着新数据不断增量介入:新文档一进来,立刻做Embedding,再立刻做软压缩,接着更新到向量库里。相当于交付了一套实时增量管道,而不是定时的批处理任务。这个思路对RAG工程化太重要了,因为真实场景的用户永远在问“刚上传的文档什么时候能被检索到”,而答案最好是“几乎立刻”。
3. OSCAR的核心设计:把一个长文本块变成一小段稠密浓缩序列
3.1 两级编码,中间夹着一层瓶颈
按我的理解,OSCAR的整体结构可以用“两级编码加一个瓶颈”来概括。第一级是常规的文本编码器,负责把文本变成上下文向量;第二级是一个专门训练好的软压缩器,把上下文向量进一步浓缩成一组数量很少的“软表示”。这个软表示的序列长度,由你设置的压缩预算决定。
举个例子,假设一个Chunk原始长度是512个Token,编码器出来的表示可能是512个向量;经过软压缩器之后,得到的可能只有32个向量,甚至更少。这32个向量不是原始向量里随便挑的32个,而是通过可微的注意力聚合把整段文本的核心语义揉进去之后的浓缩产物。下游无论是检索还是生成,消费这32个向量就够了。
这种设计最讨巧的地方在于:它没有改变原有Embedding链路。你不用推翻已经跑得好好的向量检索流程,只需要在Embedding之后、写库之前加一道压缩模块。整个系统是渐进式的,对存量系统的侵入非常小。
我在和小组讨论时提出的一个类比是:这相当于把所有正文内容做成了一堆高度浓缩的“记忆胶囊”,检索时先看胶囊上的标签够不够匹配,匹配之后再打开胶囊把营养输送给模型。跟以前直接把整袋食材扛进Prompt里相比,效率高了不少。
3.2 训练目标:三重约束同时发力
OSCAR如果要作为一个端到端可训练的模块,就必须同时优化几个目标。这一点,我判断论文里的训练构造大体上是围绕“语义保真、检索对齐、压缩约束”三个方向来设计的,这也是我认为它方法论最稳的部分。
语义保真,是指压缩后的表示不能“忘了”原文语义。常见做法是加一个重建目标,要求从压缩表示尽可能还原出原始表示,或者要求压缩表示和原始表示之间的语义差异尽量小。这保证压缩不是随机的“乱浓缩”。
检索对齐,是指压缩表示要跟Query保持正确的相关性顺序。如果原始检索排序是A比B更相关,那压缩之后也应该保持A比B更相关。只有这样,压缩后的向量才能在向量库里扛起召回任务,而不是让系统为了压缩牺牲掉检索性能。
压缩约束,是指要给压缩预算设置上限。压缩得越多,表示越短,存储越省,但信息损失也越大。这个上限必须是个可配置的超参,用户可以根据自己的硬件和效果需求来调。
这三个目标本质上是互相制衡的。压缩太狠,保真会崩;保真第一,压缩率就上不去。读者在读论文时最该关注的,不是模型用了什么花哨的注意力结构,而是它怎么平衡这三个方向的关系。
3.3 生成端怎么消费软表示
关于软表示怎么送到大模型里,这一点值得单独拿出来说,因为实际操作中不给出文本,很多人第一步就卡住了。
常规思路是直接拼接。把压缩后的软向量当作文本Embedding的替身,直接接到Prompt的上下文向量之后。对Transformer模型来说,它反正吃的是Token Embedding序列,你把文本换成软表示生成的Embedding序列,本质上没有区别。这个手法在Soft Prompt、Prefix Tuning这类工作里已经很成熟。
更稳妥的方案是加一个轻量解码头,先把软表示“翻译”回近似文本,或者生成一组摘要Token,再接LLM。这类设计的缺点是多了额外模块,优点是可以继续跑现有的文本链路,兼容性最好。
我的建议是:如果你只是做实验验证,直接用软表示接后续模型即可;如果要往生产系统里放,尽量用轻量解码方案,因为纯向量级别的交互对框架屏蔽太深,出了问题你很难定位是哪一层的锅。
4. 复现OSCAR的几个关键步骤和参数设计
4.1 第一步:实验环境怎么搭
复现工作不需要顶级硬件。我是在一张24G显存的卡上完成的整个流程,用的模型是Mistral系列的中小尺寸版本,编码器用的是一套开源的通用Embedding模型。关键不是模型大,而是你得准备好一份结构相对完整的问答/检索数据集。数据最好长这样:一个Query对应一批正相关文档和一批负相关文档。
环境依赖其实很常规,无非是PyTorch、Transformers、向量数据库客户端这几个。如果你本地内存紧,把向量库换成轻量的也行,因为实验阶段的检索量通常不大。
4.2 第二步:压缩预算和隐藏维度的选择
压缩预算是影响实验效果的头号超参。同一个小范围的实验,我试过把512个Token的块压到32个Token、64个Token和128个Token,效果差距非常明显。压到32时检索指标掉得比较厉害,但生成质量掉得没那么快;压到128时检索指标基本能持平原始文本,但省空间的效果就弱了。
隐藏维度方面,要和Embedding维度对齐。常见的底座Embedding是1024维或者768维,压缩表示也建议保持同样的维度,这样检索的时候可以直接用余弦相似度,不必做额外映射。如果你想进一步压存储,可以在投影之后把维度变成256甚至128,但要接受检索精度下降。
下面这张表是我在复现中比较推荐的一组参数:
| 参数项 | 建议范围 | 说明 |
|---|---|---|
| 压缩后Token数 | 32到128 | 越小越省,32是效果下降临界点 |
| 隐藏维度 | 与底座Embedding一致 | 通常768或1024 |
| 训练批次 | 16到32 | 太小不稳定,太大显存吃紧 |
| 学习率 | 1e-5到5e-5 | 低于1e-6几乎训不动 |
| 训练Epoch | 3到5 | 多了会过拟合检索排序 |
| 温度参数 | 0.05到0.1 | 影响对比学习时的分布平滑度 |
4.3 第三步:在线更新管道怎么接
在线更新对我来说是全文落地最需要提前设计的部分。你不能训练完压缩器就完事,还得在业务管道里塞一个实时处理环节。
我的做法是:文档上传后进入消息队列,消费端先做解析,再调编码器得到原始向量,紧接着调压缩器得到软表示,最后把软表示和原始向量都做UPSERT进向量库。查询阶段只回调TopK软表示,然后走解码模块。整体延迟增加不多,主要代价是消息队列到消费端的处理时间,实测增量文档从上传到可检索大约只多了不到一秒钟。
这里有个很重要的经验:新文档处理不能直接复用离线训练时的批量压缩策略,要封装成一个纯推理接口,并且在接口层做幂等处理,防止消息重复消费导致同一个文档被压两次进库。
5. 评估视角:检索、生成、成本三条线分开看
5.1 检索侧关注什么
评估OSCAR的第一条线,是看压缩后的表示还能不能扛住召回。最常用的指标是召回率、MRR和NDCG。我的建议是不要只看一个指标,因为它们反映的问题不同。
Recall@K说明的是“该有的有没有被找回来”,MRR说明的是“正确结果是排在第几位”,NDCG则要看排序的全面质量。实测下来,压缩率在64/512附近时,Recall@10基本能保持住,MRR有小幅下降,NDCG也还算稳定。这说明OSCAR的压缩表示对“找回相关文档”这件事是够用的,但在“精排”层面有点损失。
检索侧还有一个容易忽略的问题:压缩后的向量在索引结构里的分布变化。原始向量往往分布比较分散,压缩后向量会变得相对聚拢。这会导致IVF这类聚类索引的召回波动,所以我建议评估的时候,检索距离度量最好同时看余弦相似度和内积结果,再做一次阈值校准。
5.2 生成侧关注什么
生成侧不只要看回答对不对,还要看是否忠实于检索内容。RAG有一个典型痛点是:即使检索到了正确答案,模型也可能不按检索内容回答。OSCAR经过软压缩之后,检索信息变成了连续向量,模型没有机会“照着原话抄”,反而必须依赖压缩表示里的信息来组织语言。
从我的实验来看,生成结果在事实一致性上略好于直接拼原文,原因可能是压缩后的表示去掉了文本里的干扰噪声和重复信息,模型更容易抓到核心内容。但这依赖压缩器训练得够好,如果压缩器训练不足,生成端会明显出现“言之无物”“泛泛而谈”的问题。
因此复现评估时,我强烈建议同时用生成准确率、忠实度、回答完整度这类指标,而不是只看检索指标。很多论文在压缩率上做得很好看,但生成质量一塌糊涂,这就是评估设计偏科了。
5.3 成本侧怎么算
OSCAR的成本收益要从三笔账来算:存储账、延迟账、训练账。
存储方面,如果只存压缩表示而不存全文向量,能省多少取决于压缩率。512压到64,存储理论下降八倍;如果再算上全文缓存的历史包袱,整体收益更显著。
延迟方面,在线压缩推理本身会增加一点入库时间,但查询阶段因为返回的向量更短,Prompt缩短了,大模型的首Token时间会变快。这里有个很妙的取舍:你是多花一点入库时间,去换每次查询的响应速度,还是反过来?对企业级高频调用场景,前者显然是更划算的。
训练成本则是一次性投入。小规模数据集半天能训完,中等规模大概要两到三天。相比它为整个查询链路节省出的长期成本,这笔训练开销完全值得投入。
6. 复现过程中遇到的高频问题与排查思路
6.1 压缩后召回率突然崩了
这是最常见的问题,我身边好几个做复现的朋友都遇到过。表现是原始文本的检索效果不错,但压缩表示的Recall掉了一截。
排查思路首先看压缩率是不是压得太狠了。把32的预算改成64或128,试一下曲线是否恢复。其次是看训练数据里Query和正负样本的比例,如果负样本太难区分,模型会倾向于把所有压缩表示都锚定到模糊的语义中心,导致检索区隔性变差。
还可以排查训练温度。温度太高,对比学习的对比度过低,正负样本被拉得太近;温度太低,模型又只关注难负例,忽略全局结构。我最后一版复现是把温度从0.1调到0.07,召回指标就回升了三个点。
6.2 生成模型“无视”压缩表示怎么办
如果压缩表示已经被拼进Prompt,但模型生成的回答索然无味,大概率是拼接方式的问题。压缩表示的维度和原始Token Embedding维度不一致,或者拼接时没有做LayerNorm规范化,都会让模型无法有效读取这部分信息。
我的建议是,先在拼接处加一个可学习的投影层,让压缩表示先对齐到文本Embedding的分布空间。其次,可以在训练压缩器时加入一个辅助生成损失,让模型在训练阶段就学会“读压缩表示”。很多RAG压缩类工作都会加这种联合训练,我个人实践经验是它很有效。
6.3 在线增量更新的数据漂移问题
在线更新的一个隐患,是随着新的领域文档不断流入,压缩器训练时的数据分布和线上数据分布逐渐偏离。我遇到过真实案例:某业务的文档库里混进了一批风格差异很大的内容,检索结果在整体Recall上看着还行,但个别重要板块的相关性有明显退化。
应对办法有两个方向:要么定期用滑窗方式拿最近的数据做增量微调;要么干脆把线上压缩器做成A/B双版本,跑一段时间对比看效果再切换。后者的工程成本高一些,但风险最小。我个人更建议先用滑窗增量,观察指标衰减情况后再决定要不要做双版本。
6.4 评估结果与论文报告对不上
这也是复现中非常容易心态崩的时刻。论文里报告的收益很美好,自己复现却差一口气。大概率不是模型代码写错,而是数据集的差异。论文用的检索数据集通常是带人工标注的问答对,而你如果拿通用语料做实验,检索难度和相关性分布完全不同。
我的建议是:先找一份与论文同源或同类型的数据集复现,确认代码链路没问题后,再换自己的行业数据做迁移测试。否则你很难判断效果差异是来自方法本身,还是来自数据分布错位。
7. 关于这篇论文,我的几条实操心得
如果只让我提炼这篇OSCAR论文最有价值的地方,我会说:它把RAG的优化视角,从“怎么更准地找回来”延伸到了“怎么更省地送进去”。检索召回率已经卷到头的今天,上下文的运输成本才是真正值得动刀的地方。
第一条心得是:压缩效果好不好,不取决于模型结构多高级,而取决于你愿不愿意花时间调那个压缩预算和训练温度。这两个参数是全场性价比最高的旋钮,比疯狂加训练数据管用得多。
第二条心得是:软压缩和硬摘要并不互斥。现实中合理的方式是协同工作——先用轻量的硬抽句把明显无关的内容过滤掉,再对保留内容做软压缩。两道工序叠加,效果比任何一道单打独斗都好。这也是我在线上系统里尝试过的最稳的组合方案。
第三条心得,也是我最想提醒后来者的:不要急着在生产环境全量替换。先在一条链路上做影子模式,同时跑旧链路和OSCAR链路,收集一段时间的真实查询和人工评估结果再切换。这一步投入不大,但能让你避开很多“实验效果很好、线上翻车”的尴尬。
好了,这周的精读笔记就到这里。如果你手头也正在搞RAG相关的项目,尤其被长上下文和向量库存储成本折磨得不行,这篇OSCAR值得你花一个晚上细读。下一周的小组讨论,我们准备把视角移到训练数据的质量治理上——那也是个看着基础、实际深不见底的方向。