首先,为什么非得进行Query改写?
答案其实有以下三个维度:
1、弥补语言风格的断层
比如有这么一个场景,用户随口问了一句,那个东西咋操作呢?这是一种日常聊天的语气,但知识库存的通常是详实且专业的书面语,如果直接用原始提问去做向量检索,搜出来的结果基本都是虽然相关但不太对的垃圾内容。
而改写做的就是把口语化表达转换成书面语,让两个世界在向量空间里靠近,这样检索召回率就能显著提升。
2、补齐缺失的上下文信息
用户很多时候提问都不完整,比如有人直接问:应该怎么处理?
那具体处理什么呢?处理代码bug,处理模型精度问题,还是处理业务流程。。。
对于这种提问,模型也是一脸懵,因为就这几个字根本没办法精准检索。
改写器的职责就是把这种模糊提问,通过挖掘隐含的背景信息转化成一个具体且可检索的声明式描述。
3、解决多轮对话的连贯性问题
在多轮对话场景下,用户经常会使用代词(比如它,那个)来指代他前面提到的某件事,但是检索模块根本就听不懂这种表述,接下来对话进行到第四轮,第五轮,系统就开始出现记忆断裂,回复的内容就开始莫名其妙,导致的结果就是用户体验感直线下降。
改写这一环要做的就是执行“指代还原”,把所有的代词、模糊指示语都替换成明确的实体名称,这样即使用户只说:再谈谈刚才那个人的问题,系统也能自动理解那个人具体指的是谁,保证每一轮检索都逻辑清晰。
所以,改写根本不是简单的把话说一遍,它是连接用户表达和向量检索的一座桥梁。
接下来再看具体怎么做
业界验证过的方案有三种,每一种策略都有各自的适用场景。
策略一,反向生成法,学名叫HyDE
这个方法有点反向思维,核心是不直接拿用户提问去搜索库,而是让大模型先生成一个假设的符合用户需求的答案,然后用这个中间产物去做向量检索。
为什么这样效率更高?
因为用户的提问可能表述各异,风格多变,但知识库里的文档都是某种统一的风格,两者直接对比,在向量空间里可能相距甚远。
但如果你先生成一个假答案,这个假答案的语言风格往往会更接近真实的库文档。
假答案和真答案都是答案体,它们在向量空间里自然就靠得更近,这就是用相似的东西搜相似的东西的逻辑,由此一来,召回率能够明显提升。
策略二,任务拆解法
针对复杂综合性的问题,比如用户问:对比分析a公司和b公司过去三年的财务状况,如果你的系统尝试一次性搜索,结果会是什么?
可能会拿到一堆混乱的交叉的信息,最后汇总出来的对比分析就很别扭,聪明的做法是把这个大问题分解成多个子问题,分别执行搜索,最后再做整合。
流程大概是这样,独立搜索a公司财务数据,独立搜索b公司财务数据,提取关键指标,进行纵向对比,生成最终的对比报告。
这种分而治之的方法在复杂问题面前往往效果更好。
策略三,历史融合法
这个方法是专门针对多轮对话而设计的。
逻辑很直白,就是从对话历史自动提取有价值的信息,融合到当前的查询中,比如对话进行到第三轮,用户说:能说的更具体些吗?
系统不是直接拿这句话去搜,而是先回头看看前两轮的关键内容,然后把当前提问补充完整,变成关于之前讨论的推荐算法优化话题,能详细解释一下具体的实现细节吗?
这样每一次检索请求都变成了独立完整的句子,不需要依赖外部上下文。
实战难点与解决方案
响应延迟
改写意味着额外调用一次大模型,这直接导致响应延迟增加,用户可能就得多等上两三秒钟。
这听起来不多,但在互联网产品的世界里,两秒钟就可能造成用户流失,怎么破解?
有两条路线:
1.轻量化模型
别用GPT4这样的大模型来改写,用一个经过专项微调的小模型,速度更快,成本更低。
2.流水线并行
让改写和初步检索同时进行,不要串联执行,用异步处理把总时间压到最低。
查询漂移
语义偏移的风险模型有时候会过度创意,改着改着就把原意改变了。
比如,用户问:苹果怎么选购?
模型可能给你改成了iphone手机的性能对比,意思完全反了,这叫查询漂移,是Rag系统的大忌。
解决办法是设置相似度检测阈值,改写完成后,系统自动计算改写内容和原始提问的语义相似度,如果低于某个值,比如0.75,就放弃改写版本,直接用原始问题去检索,宁可保守一点,也不能让模型乱改。
成本开销
如果每一个用户请求都去改写,Token消耗就会直线上升。
解决办法是建立一个智能路由机制,设定规则。
比如:
简单直接的提问、打招呼、闲聊这些就直接跳过改写;
复杂冗长、表述模糊的提问,这时候才启动改写;
把有限的计算资源用在最需要的地方。