向量检索优化

之前我们讲过,文本转为向量后,如何与其他的向量进行比较相似度,也讲过一个向量如何在大批量向量中找出最相近的几个向量的索引策略。

但是这样就足够了吗,我们仅仅依靠语义的匹配就可以做到内容匹配几乎没问题吗?其实不行的,举个例子,如果我们的某个新品女装,是不允许进行7天无理由退货的,但是如果用户来问,问是否可以退货,那通过语义识别,是有可能将其识别为允许7天无理由退货的。所以这种误导就可能让用户做出错误的行为,语义的识别也是有可能出问题的,所以我们需要在语义识别的基础上,再加上关键词检索,对一个chunk进行两种评分的计算,然后选择。

BM25

BM25算法是一种基于词频(TF)和逆文档频率(IDF)的统计检索算法,简单说就是通过计算查询词与chunk内容的相关性进行打分。优势在于:

  1. 考虑词频饱和性:避免单个词重复出现导致得分过高。
  2. 引入文档长度归一化:有些文档可能长度很长,那词频出现的概率也高,所以BM25会对文档的长度进行归一化处理,文档的长度不会过多的影响打分。
    在RAG中的使用通常和语义相似度一起使用,可以额外引入es,在es里做关键词的检索。milvus也支持关键词的检索,提供一段关键词检索的代码,支持向量检索和BM25关键词检索。
import io.milvus.v2.service.vector.request.AnnSearchRequest;
import io.milvus.v2.service.vector.request.HybridSearchReq;
import io.milvus.v2.service.vector.response.HybridSearchResp;
import io.milvus.v2.service.vector.ranker.RRFRanker;

// 1. 准备稠密向量查询
float[] denseQueryVector = getEmbedding("人工智能应用");  // 假设的嵌入函数
Map<String, Object> denseParams = new HashMap<>();
denseParams.put("metric_type", "IP");
denseParams.put("params", Collections.singletonMap("nprobe", 10));

AnnSearchRequest denseRequest = AnnSearchRequest.builder()
    .vectors(Collections.singletonList(denseQueryVector))
    .annsField("dense_vector")  // 假设有稠密向量字段
    .searchParams(denseParams)
    .limit(10)
    .build();

// 2. 准备BM25查询
Map<String, Object> bm25SearchParams = new HashMap<>();
bm25SearchParams.put("metric_type", "BM25");

AnnSearchRequest bm25Request = AnnSearchRequest.builder()
    .data(Collections.singletonList("人工智能应用"))  // 查询文本
    .annsField("sparse_vector")
    .searchParams(bm25SearchParams)
    .limit(10)
    .build();

// 3. 执行混合搜索
List<AnnSearchRequest> reqs = Arrays.asList(denseRequest, bm25Request);
RRFRanker ranker = new RRFRanker(60);  // RRF融合算法

HybridSearchReq hybridReq = HybridSearchReq.builder()
    .collectionName("hybrid_collection")
    .reqs(reqs)
    .ranker(ranker)
    .limit(10)
    .outputFields(Arrays.asList("text"))
    .build();

HybridSearchResp hybridResp = client.hybridSearch(hybridReq);

RRF

OK,即使向量相似度匹配和BM25关键词匹配后,其实也有个问题,那就是这两种检索方式是不同的检索方式,得到的chunk是根据自己检索体系的打分,那我们怎么知道该用哪种检索算法得到的高分chunk呢?

看上面的代码,有个RRF融合算法。

RRF叫做倒数排名融合。是一种用于融合多个检索系统结果的算法,在混合检索中广泛用于合并稠密向量检索和稀疏向量检索的结果。

假设我们有这么几个doc
向量相似度排名:

doc1: rank=1, doc3: rank=2, doc5: rank=3, doc7: rank=4

关键词检索排名:
doc2: rank=1, doc1: rank=2, doc4: rank=3, doc3: rank=4
然后对这些文档进行RFF最终计算。
假设k=60
doc1: RRF = 1/(60+1) + 1/(60+2) = 0.0164 + 0.0161 = 0.0325
doc3: RRF = 1/(60+2) + 1/(60+4) = 0.0161 + 0.0156 = 0.0317
等等...
就可以得到最终的doc排名。

RRF算法因其简单、高效、鲁棒的特性,成为混合检索中最常用的融合算法。在Milvus等向量数据库中,RRF是默认的混合检索融合策略。

reRank:重排序

上文我们通过混搜检索得到了top-n个与问题直接相关的chunk,那为什么还需要重排序呢?

首先一个要明确的点,向量+关键词的最高评分,不代表真的是最合适的答案,可以理解为是返回了多个高评分的答案,但是是不是最合适的,还需要大模型去判断。也就是让大模型去做一次精排。
在能力上来说,我们在工程里进行的向量化使用的都是参数量较小的专用嵌入模型,比如BGE、text-embedding模型等。最擅长将文本转换为向量,衡量整体的语义,速度快、成本低。

但是rerank的模型,是参数量巨大的用模型。具备深度的语言理解、逻辑推理和知识关联能力,能进行复杂的判断和关联上下文。

所以正常我们在混搜检索后还会使用专用的比如Qwen3-Reranker重排序模型进行重排序,因为耗时比较慢,但精细度高,所以需要前面的混搜搜索出最相关的一些答案。

内容生成策略

在我们得到reRank的后的chunk内容,就可以拿着内容去和大模型交互,得到我们想要的结果了。

但是和大模型交互也有点说法,prompt的设计决定了最终产出的质量。

比如:

以偏概全,过度概括
用户问:你们支持信用卡分期付款吗?

chunk 内容:在“黑色星期五”大促期间,部分指定商品支持与某银行合作的3期、6期免息分期。

模型回答:是的,我们支持信用卡分期付款,您可以在结算时选择分期选项,通常享有免息优惠。

问题分析:chunk明确限定了条件(特定活动期间、部分商品、特定银行),但prompt没有强制模型严格遵守原文的限定范围。模型自行将“部分、特定”概括为“普遍支持”,并补充了不存在的“结算选项”,属于严重的过度推断。

以及

无视优先级,错误综合
用户问:这个会员的免运费门槛是多少?

检索返回了两个chunk:chunk 1(普通规则):所有用户享受购物满99元包邮。chunk 2(特殊公告):【重要通知】即日起至年底,为庆祝公司成立,所有订单免运费,无门槛。

模型回答:您的免运费门槛是99元。如果满足条件,系统会自动减免运费。

问题分析:prompt缺乏信息优先级和时效性判断的指令。模型没有理解chunk 2是一个更高优先级、临时的特殊规则,它覆盖了chunk 1的常规规则。模型可能简单地选择了它认为“更通用”或更早出现的规则,给出了一个在当前时段完全错误的答案。

等等很多的问题,其实都是我们prompt没有输入好。

我们些提示词有几个要点:

  1. 告诉大模型自己的角色,是一个什么类型的模型。
  2. 告诉大模型要回答的任务,需要回答什么东西。
  3. 告诉大模型一些约束,比如必须从知识库chunk提供的内容去回答,不允许从预训练的产物中去使用,如果不知道就说不知道。
  4. 输入的内容需要拆分开,比如用户的问题,mcp的结果,知识库的内容等等。
  5. 输出,告诉大模型输出以什么样的格式返回。

举例prompt构造

【System】
你是一名专业的法律咨询助手。你的任务是根据【参考资料】中的法律条文、司法解释或案例摘要,准确、严谨地回答用户的法律问题。
请严格遵守以下规则:
严格依据原文:你的回答必须完全基于【参考资料】中的内容。不得引入任何外部法律知识、个人理解或常识性推断来补充、解释或延伸参考资料。
禁止演绎与创造:严禁对参考资料中的信息进行组合、关联、推测以创造新的结论。例如,不能将A条文中的条件与B案例中的结果自行结合,得出一个参考资料中未明确陈述的结论。
直接回应,禁止发散:用户问什么,就只回答什么。如果参考资料中有直接答案,请直接给出。不要主动补充操作建议、流程步骤、或无关的法律概念,除非它们明确包含在参考资料中。
处理信息不足:如果【参考资料】中没有任何信息能够直接或间接回答用户的问题,请明确回答:“根据提供的资料,无法对您的问题作出判断。建议您咨询专业律师以获取正式法律意见。”
处理规范冲突:如果多条参考资料(如新旧法律、不同司法解释)对同一问题有不同规定,请首先指出存在规范冲突,然后说明应以生效日期最新或效力层级更高的规范为准(具体规则见参考资料标注),并据此给出答案。
精确引用:回答中的每一句法律判断或事实陈述,只要来源于参考资料,都必须标注出处,格式为 [编号]。确保引用编号准确无误。
语气与免责:使用清晰、审慎、中立的语气。必须在回答开头或结尾加入标准免责声明:“请注意,以下分析仅基于提供的有限资料,不构成正式法律意见。具体案件请以有权机关的认定为准。”
【参考资料】
[1] 来源:《民法典》第563条 | 生效日期:2021-01-01
有下列情形之一的,当事人可以解除合同:(一)因不可抗力致使不能实现合同目的;(二)在履行期限届满前,当事人一方明确表示或者以自己的行为表明不履行主要债务;(三)当事人一方迟延履行主要债务,经催告后在合理期限内仍未履行;(四)当事人一方迟延履行债务或者有其他违约行为致使不能实现合同目的;(五)法律规定的其他情形。
[2] 来源:最高人民法院第67号指导案例摘要 | 发布日期:2023-08-10
在房屋买卖合同中,卖方迟延交房超过60日,经买方书面催告后仍未履行,买方主张解除合同的,人民法院应予支持。该“60日”期限被视为《民法典》第563条第(三)项中的“合理期限”的一种具体情形。
[3] 来源:《某市商品房销售管理办法》第12条 | 施行日期:2025-03-01
本市范围内,商品房出卖人迟延交付房屋,买受人催告后,出卖人自约定交付之日起90日内仍未交付的,买受人有权解除合同。
【用户问题】
我买的房子,开发商已经延迟交房75天了,我发过书面催告函,但开发商还没交房。我能据此解除购房合同吗?
Logo

AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。

更多推荐