Milvus 稀疏/稠密向量检索及混合检索

17次阅读
没有评论

共计 16015 个字符,预计需要花费 41 分钟才能阅读完成。

内容目录

当前大模型落地应用的主要技术是RAG(检索增强生成),它是一种结合知识检索生成模型的架构,其核心思想是:在AI生成回答前,先检索相关知识文档,再结合这些文档生成高质量答案。其流程如下:

  • 用户输入问题query;
  • 系统先根据query从知识库中检索相关语料片段documents;
  • 再通过prompt将检索到的语料片段documents与query结合起来一起丢给大模型;
  • 大模型基于提供的语料片段进行回复。

通俗理解就是:传统的大模型在回复时,是基于自己老旧的训练数据进行回复的(自身记忆),有了RAG后,大模型在回复时,会基于我们提供的参考答案进行回复。这样就能保证回复的数据准确性,随时能更新数据。

Milvus 稀疏/稠密向量检索及混合检索

RAG技术中,一个非常核心的技术点就是检索,与传统数据检索不同的是,RAG检索一般基于向量数据库实现相似度检索,而非传统数据库那样通过规则匹配进行检索。向量数据库检索主要分为稀疏检索(关键字检索)稠密检索(相关性检索)

  • 稀疏检索:依赖传统的倒排索引(如BM25),对关键字匹配敏感,擅长精确匹配,但对同义词和上下文理解能力较弱
  • 稠密检索:依赖向量表示,通过向量计算得到语义相似度,擅长语义匹配,但容易召回不相干的文档,特别是长尾或精确匹配的信息。

混合检索顾名思义就是同时结合稀疏检索稠密检索,基于两部分的检索结果通过权重融合得到最终排名,使得检索同时具有两者优势,既能保证关键字匹配,又能捕获语义相关性。

准备工作

首先要实现混合检索,需要拥有将文本转换为稠密向量和稀疏向量的方法。阿里百炼提供的向量模型text-embedding-v4就支持将文本向量化为稀疏向量稠密向量(默认)。通过官方SDK调用时,只需控制参数:**output_type**来确定接口返回稀疏向量还是稠密向量。文档:https://bailian.console.aliyun.com/?tab=doc#/doc/?type=model&url=2842587

Milvus 稀疏/稠密向量检索及混合检索

引入Java版SDK后,可以通过下面的方法同时得到稀疏向量和稠密向量。

    public record EmbeddingResult(List<Float> denseEmbedding,SortedMap<Long, Float> sparseEmbedding, List<String> sparseWords){}

    private EmbeddingResult embedding(String text) throws NoApiKeyException {
        // 向量化
        TextEmbeddingParam textEmbeddingParam = TextEmbeddingParam.builder()
                .model("text-embedding-v4")
                .text(text)
                .outputType(TextEmbeddingParam.OutputType.DENSE_AND_SPARSE)
                .dimension(2048)
                // 替换为自己的KEY
                .apiKey("sk-0dexxxxxxxxxxxdb7db30cefe90")
                .build();

        TextEmbedding textEmbedding = new TextEmbedding();
        TextEmbeddingResult result = textEmbedding.call(textEmbeddingParam);

        List<TextEmbeddingResultItem> embeddings = result.getOutput().getEmbeddings();
        TextEmbeddingResultItem textEmbeddingResultItem = embeddings.get(0);

        // Double转Float
        List<Float> denseEmbedding = textEmbeddingResultItem.getEmbedding().stream()
                .map(Double::floatValue)
                .toList();
        List<TextEmbeddingSparseEmbedding> sparseEmbedding = textEmbeddingResultItem.getSparseEmbedding();
        SortedMap<Long, Float> sortedMap = new TreeMap<>();
        ArrayList<String> sparseWords = new ArrayList<>();
        sparseEmbedding.forEach(item -> {
            sortedMap.put(Long.valueOf(item.getIndex()), item.getValue().floatValue());
            sparseWords.add(item.getToken());
        });
        // softmax归一化处理
        Map<Long, Float> softmaxSortedMap = SparseSoftmaxNormalizer.softmax(sortedMap);
        System.out.println(softmaxSortedMap);
        return new EmbeddingResult(denseEmbedding,new TreeMap<>(softmaxSortedMap),sparseWords);
    }
因为通过百炼调用稀疏向量得到的value没有做归一化处理,因此我们在得到稀疏向量后,需要再调用**softmax**归一化函数对得分进行归一化处理。softmax归一化类如下:
import org.apache.commons.math3.util.FastMath;

import java.util.*;

/**
 * @author Zhang De Ning
 * @email zhangdening@huice.com
 * @time 2025-10-09 15:22
 * @description 稀疏权重 Softmax 归一化工具
 */
public class SparseSoftmaxNormalizer {

    /**
     * 对稀疏向量的权重进行 Softmax 归一化。
     *
     * @param sparseMap 稀疏向量,key 为 token index,value 为原始权重
     * @param alpha 温度系数(控制压缩强度),默认 1.0f
     *              - α > 1:放大差异
     *              - α < 1:压缩差异
     * @return 归一化后 Map,value 在 (0,1),且总和为 1
     */
    public static Map<Long, Float> softmax(Map<Long, Float> sparseMap, float alpha) {
        if (sparseMap == null || sparseMap.isEmpty()) {
            return Collections.emptyMap();
        }

        List<Float> values = new ArrayList<>(sparseMap.values());

        // 防止数值溢出(Softmax trick:减去最大值)
        float max = Collections.max(values);

        // 计算 e^(α * (v - max))
        List<Double> expValues = new ArrayList<>(values.size());
        for (Float v : values) {
            expValues.add(FastMath.exp(alpha * (v - max)));
        }

        // 求和
        double sum = expValues.stream().mapToDouble(Double::doubleValue).sum();

        // 计算 softmax = e^v / sum(e^v)
        Map<Long, Float> normalized = new LinkedHashMap<>();
        int i = 0;
        for (Long key : sparseMap.keySet()) {
            normalized.put(key, (float) (expValues.get(i++) / (sum + 1e-8)));
        }

        return normalized;
    }

    /**
     * 默认 α = 1.0 的 Softmax
     */
    public static Map<Long, Float> softmax(Map<Long, Float> sparseMap) {
        return softmax(sparseMap, 1.0f);
    }
}

调用embedding后得到的结果如下:

EmbeddingResult[
  denseEmbedding=[-0.018853987, -0.012462231,....,  0.027241051], 
  sparseEmbedding={100017=0.67896074, 108770=0.32103923}, 
  sparseWords=[标杆, 客户]
]

其中sparseWords是稀疏向量得到的关键词元(token),sparseEmbedding中,key是该token的id号或索引号,value表示这个token在这句话中的权重占比。

混合检索流程

Milvus内置了一些得分融合重排器,并且原生就支持混合检索。Milvus使用SPARSE_INVERTED_INDEX索引来存储稀疏向量,该索引利用了倒排索引的原理,为稀疏数据创建了一种高效的搜索结构。在实际使用中,我们会利用加权重排器对稀疏检索和稠密检索得到的结果进行重新排序,然后再调用专门的重排序模型进行重新排序。检索流程如下:

  • 设置稠密检索参数,检索50条相关语料片段;
  • 设置稀疏检索参数,检索30条相关语料片段;
  • 设置加权重排器,设置稠密检索权重为0.6,稀疏检索权重为0.4;
  • 执行混合检索,在检索20条的基础上,过滤掉低于阈值的语料片段;
  • 再调用重排序模型,保留10条语料片段(实际可能因为片段低于阈值 只有几个甚至没有);
    // 混合检索
    public SearchResult hybridSearch(String text) throws NoApiKeyException, ClassNotFoundException, NoSuchMethodException, InputRequiredException {
        ConnectConfig connectConfig = ConnectConfig.builder()
                .uri("http://localhost:19530")
                .dbName("default")
                .build();
        MilvusClientV2 milvusClientV2 = new MilvusClientV2(connectConfig);

        EmbeddingResult embeddingResult = embedding(text);

        // 设置稠密向量检索参数
        AnnSearchReq denseReq = AnnSearchReq.builder()
                .vectors(List.of(new FloatVec(embeddingResult.denseEmbedding)))
                .vectorFieldName("dense_embedding")
                .metricType(IndexParam.MetricType.IP)
                .topK(50)
                .build();
        // 设置稀疏向量检索参数
        AnnSearchReq sparseReq = AnnSearchReq.builder()
                .vectors(List.of(new SparseFloatVec(embeddingResult.sparseEmbedding)))
                .vectorFieldName("sparse_embedding")
                .metricType(IndexParam.MetricType.IP)
                .topK(30)
                .build();
        // 设置加权重排器
        WeightedRanker weightedRanker = new WeightedRanker(List.of(0.6F, 0.4F));

        // 混合检索20条
        HybridSearchReq hybridSearchReq = HybridSearchReq.builder()
                .collectionName("hybrid_collection")
                .searchRequests(List.of(denseReq, sparseReq))
                .ranker(weightedRanker)
                .outFields(List.of("metadata", "content"))
                .topK(20)
                .build();
        SearchResp searchResp = milvusClientV2.hybridSearch(hybridSearchReq);
        List<SearchResp.SearchResult> searchResults = searchResp.getSearchResults().get(0);

        // TODO:这里可以把得分低于阈值的过滤掉
        List<SearchResultItem> resultItems = searchResults.stream().map(item -> {
            String content = item.getEntity().get("content").toString();
            String metadata = item.getEntity().get("metadata").toString();
            return new SearchResultItem(content, item.getScore(), metadata);
        }).toList();
        // 调用重排序模型 保留10条
        List<SearchResultItem> rerankedItems = rerank(text, resultItems);
        return new SearchResult(rerankedItems, embeddingResult.sparseWords);
    }

其中rerank方法如下:

    private List<SearchResultItem> rerank(String query, 
                                          List<SearchResultItem> resultItems) throws NoApiKeyException, InputRequiredException {
        TextReRankParam textReRankParam = TextReRankParam.builder()
                .apiKey("sk-0xxxxxxxe90")
                .model("gte-rerank-v2")
                .query(query)
                // 从20条里面保留10条
                .topN(10) 
                .documents(resultItems.stream().map(SearchResultItem::text).toList())
                .build();

        TextReRank textReRank = new TextReRank();
        TextReRankResult results = textReRank.call(textReRankParam);
        List<TextReRankOutput.Result> rerankResults = results.getOutput().getResults();
        return rerankResults.stream().map(item->{
            Integer index = item.getIndex();
            SearchResultItem searchResultItem = resultItems.get(index);
            return new SearchResultItem(searchResultItem.text,item.getRelevanceScore().floatValue(),searchResultItem.metadata);
        }).toList();
    }

为了方便对比,我们再实现传统的稠密检索和稀疏检索。

    // 稠密检索
    public SearchResult denseSearch(String text) throws NoApiKeyException, ClassNotFoundException, NoSuchMethodException, InputRequiredException {
        ConnectConfig connectConfig = ConnectConfig.builder()
                .uri("http://localhost:19530")
                .dbName("default")
                .build();
        MilvusClientV2 milvusClientV2 = new MilvusClientV2(connectConfig);

        EmbeddingResult embeddingResult = embedding(text);

        SearchReq searchReq = SearchReq.builder()
            .data(List.of(new FloatVec(embeddingResult.denseEmbedding)))
            .outputFields(List.of("metadata", "content"))
            .collectionName("hybrid_collection")
            .annsField("dense_embedding")
            .metricType(IndexParam.MetricType.IP)
            .topK(10)
            .build();
        SearchResp searchResp = milvusClientV2.search(searchReq);
        List<SearchResp.SearchResult> searchResults = searchResp.getSearchResults().get(0);
        List<SearchResultItem> resultItems = searchResults.stream().map(item -> {
            String content = item.getEntity().get("content").toString();
            String metadata = item.getEntity().get("metadata").toString();
            return new SearchResultItem(content, item.getScore(), metadata);
        }).toList();
        List<SearchResultItem> rerankedItems = rerank(text, resultItems);
        return new SearchResult(rerankedItems, embeddingResult.sparseWords);
    }

    // 稀疏检索
    public SearchResult sparseSearch(String text) throws NoApiKeyException, ClassNotFoundException, NoSuchMethodException, InputRequiredException {
        ConnectConfig connectConfig = ConnectConfig.builder()
                .uri("http://43.138.67.57:19530")
                .dbName("default")
                .build();
        MilvusClientV2 milvusClientV2 = new MilvusClientV2(connectConfig);

        EmbeddingResult embeddingResult = embedding(text);

        SearchReq searchReq = SearchReq.builder()
            .data(List.of(new SparseFloatVec(embeddingResult.sparseEmbedding)))
            .outputFields(List.of("metadata", "content"))
            .collectionName("hybrid_collection")
            .annsField("sparse_embedding")
            .metricType(IndexParam.MetricType.IP)
            .topK(10)
            .build();
        SearchResp searchResp = milvusClientV2.search(searchReq);
        List<SearchResp.SearchResult> searchResults = searchResp.getSearchResults().get(0);
        List<SearchResultItem> resultItems = searchResults.stream().map(item -> {
            String content = item.getEntity().get("content").toString();
            String metadata = item.getEntity().get("metadata").toString();
            return new SearchResultItem(content, item.getScore(), metadata);
        }).toList();

        return new SearchResult(rerank(text,resultItems), embeddingResult.sparseWords);
    }

以检索爆款打单为例,取检索到的前6条。

稠密检索结果:

[
    {
      "text": "Q8:极速版3.0爆款打单功能如何提升发货效率?\\*\\* A8: + \\*\\*适用客户\\*\\*:爆款多或需要管库存的客户 + \\*\\*核心优势\\*\\*: - 自动汇总爆款商品,一次性打印5万+单,打单效率提升3倍 - 支持杂单批量处理,一键打印多件订单 \\*\\*\\*\\* \\*\\*\n",
      "score": 0.6127913,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163304964107\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    },
    {
      "text": "Q2:在爆款打单功能方面,极速版3.0和打单软件有什么区别? A2: + 打单软件:需要手动搜索包含某货品的订单来打印,若同一商品对应多个名称,就需要多次搜索,操作耗时费力;而且在订单量大时会出现卡顿情况,一批订单往往需要分多次才能打印完。 + 极速版3.0:能够自动汇总相同商品的订单,实现一键打印,支持快捷分单,同时可降低拣货错误率;还支持筛选汇总、自动剔除退款订单、订单排序,以及秒拼、闪电购、叫号模式等功能。一次性可打印5万单以上,不会出现卡顿现象,相比之下能提升打单效率3倍以上。\n",
      "score": 0.5868525,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163288186888\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    },
    {
      "text": "Q4:极速版3.0的爆款聚合打单功能有什么优势?\\*\\* A4:可自动汇总爆款订单,多维度打单不混乱,一次性打印万单,打单效率提升300% ,适配秒拼、闪电购等模式,还能自动剔除退款订单 。 \\*\\*\n",
      "score": 0.4440746,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163267215362\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    },
    {
      "text": "Q4:极速版3.0的爆款订单处理方面有什么特色功能?\\*\\* A4:具备爆款聚合打单功能,可快速合并爆款订单,支持筛选汇总、异常订单剔除及排序,将打单时间从每天6小时降至0.5小时。 \\*\\*\n",
      "score": 0.4352119,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163317547013\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    },
    {
      "text": "Q10:Y企业版3.0的爆款订单处理有哪些效率提升?\\*\\* A:自动汇总同结构订单(如一单多货、爆款组合),支持一次性打印1万+单,分拣页自动分隔避免错单,打单时间从4小时压缩至1.5小时。 \\*\\*\n",
      "score": 0.3792385,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752663520,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1945437923439439875\",\"attachId\":\"1945437923280056322\",\"categoryId\":\"1\"}"
    },
    {
      "text": "Q:新人怎么快速开单/新人如何快速开单\nA:1:得找到合适的客户(招聘网站,线上店铺)\n2:要能和客户聊(聊我们软件的优势:爆款打单,快递智能拦截,采购智能预警,智能退货入库,异常预警,财务对账,自动审核,智能分单)\n3:了解客户需求,然后售前,跟进,逼单,开单(核心是找好客户)",
      "score": 0.3446634,
      "metadata": "{\"fragmentId\":\"1970105510861131777\",\"creator\":\"1952912432057802754\",\"category\":\"1\",\"attachId\":\"1970103395409383426\",\"createTime\":\"1758544731\",\"kId\":\"1944992792110387201\"}"
    }
]

稀疏检索结果:

[
    {
      "text": "Q8:极速版3.0爆款打单功能如何提升发货效率?\\*\\* A8: + \\*\\*适用客户\\*\\*:爆款多或需要管库存的客户 + \\*\\*核心优势\\*\\*: - 自动汇总爆款商品,一次性打印5万+单,打单效率提升3倍 - 支持杂单批量处理,一键打印多件订单 \\*\\*\\*\\* \\*\\*\n",
      "score": 0.6127913,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163304964107\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    },
    {
      "text": "Q2:在爆款打单功能方面,极速版3.0和打单软件有什么区别? A2: + 打单软件:需要手动搜索包含某货品的订单来打印,若同一商品对应多个名称,就需要多次搜索,操作耗时费力;而且在订单量大时会出现卡顿情况,一批订单往往需要分多次才能打印完。 + 极速版3.0:能够自动汇总相同商品的订单,实现一键打印,支持快捷分单,同时可降低拣货错误率;还支持筛选汇总、自动剔除退款订单、订单排序,以及秒拼、闪电购、叫号模式等功能。一次性可打印5万单以上,不会出现卡顿现象,相比之下能提升打单效率3倍以上。\n",
      "score": 0.5868525,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163288186888\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    },
    {
      "text": "Q4:极速版3.0的爆款聚合打单功能有什么优势?\\*\\* A4:可自动汇总爆款订单,多维度打单不混乱,一次性打印万单,打单效率提升300% ,适配秒拼、闪电购等模式,还能自动剔除退款订单 。 \\*\\*\n",
      "score": 0.4440746,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163267215362\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    },
    {
      "text": "Q4:极速版3.0的爆款订单处理方面有什么特色功能?\\*\\* A4:具备爆款聚合打单功能,可快速合并爆款订单,支持筛选汇总、异常订单剔除及排序,将打单时间从每天6小时降至0.5小时。 \\*\\*\n",
      "score": 0.4352119,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163317547013\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    },
    {
      "text": "Q:新人怎么快速开单/新人如何快速开单\nA:1:得找到合适的客户(招聘网站,线上店铺)\n2:要能和客户聊(聊我们软件的优势:爆款打单,快递智能拦截,采购智能预警,智能退货入库,异常预警,财务对账,自动审核,智能分单)\n3:了解客户需求,然后售前,跟进,逼单,开单(核心是找好客户)",
      "score": 0.3446634,
      "metadata": "{\"fragmentId\":\"1970105510861131777\",\"creator\":\"1952912432057802754\",\"category\":\"1\",\"attachId\":\"1970103395409383426\",\"createTime\":\"1758544731\",\"kId\":\"1944992792110387201\"}"
    },
    {
      "text": "Q3:对比打单软件,极速版3.0档口模式的核心差异是什么?\\*\\* A3: + \\*\\*独家功能\\*\\*:平台铺货快速上新、万能链接防错发、组合装自动解析、缺货处理、录入登记发货、报表可视化、物流预警、退款重发、极速管理库存 + \\*\\*优化升级\\*\\*:备货单分享报货、爆款打单、不限制数据时效\n",
      "score": 0.19641457,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163304964102\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    }
]

混合检索结果:

[
    {
      "text": "Q8:极速版3.0爆款打单功能如何提升发货效率?\\*\\* A8: + \\*\\*适用客户\\*\\*:爆款多或需要管库存的客户 + \\*\\*核心优势\\*\\*: - 自动汇总爆款商品,一次性打印5万+单,打单效率提升3倍 - 支持杂单批量处理,一键打印多件订单 \\*\\*\\*\\* \\*\\*\n",
      "score": 0.6127913,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163304964107\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    },
    {
      "text": "Q2:在爆款打单功能方面,极速版3.0和打单软件有什么区别? A2: + 打单软件:需要手动搜索包含某货品的订单来打印,若同一商品对应多个名称,就需要多次搜索,操作耗时费力;而且在订单量大时会出现卡顿情况,一批订单往往需要分多次才能打印完。 + 极速版3.0:能够自动汇总相同商品的订单,实现一键打印,支持快捷分单,同时可降低拣货错误率;还支持筛选汇总、自动剔除退款订单、订单排序,以及秒拼、闪电购、叫号模式等功能。一次性可打印5万单以上,不会出现卡顿现象,相比之下能提升打单效率3倍以上。\n",
      "score": 0.5868525,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163288186888\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    },
    {
      "text": "Q4:极速版3.0的爆款聚合打单功能有什么优势?\\*\\* A4:可自动汇总爆款订单,多维度打单不混乱,一次性打印万单,打单效率提升300% ,适配秒拼、闪电购等模式,还能自动剔除退款订单 。 \\*\\*\n",
      "score": 0.4440746,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163267215362\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    },
    {
      "text": "Q4:极速版3.0的爆款订单处理方面有什么特色功能?\\*\\* A4:具备爆款聚合打单功能,可快速合并爆款订单,支持筛选汇总、异常订单剔除及排序,将打单时间从每天6小时降至0.5小时。 \\*\\*\n",
      "score": 0.4352119,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163317547013\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    },
    {
      "text": "Q:新人怎么快速开单/新人如何快速开单\nA:1:得找到合适的客户(招聘网站,线上店铺)\n2:要能和客户聊(聊我们软件的优势:爆款打单,快递智能拦截,采购智能预警,智能退货入库,异常预警,财务对账,自动审核,智能分单)\n3:了解客户需求,然后售前,跟进,逼单,开单(核心是找好客户)",
      "score": 0.3446634,
      "metadata": "{\"fragmentId\":\"1970105510861131777\",\"creator\":\"1952912432057802754\",\"category\":\"1\",\"attachId\":\"1970103395409383426\",\"createTime\":\"1758544731\",\"kId\":\"1944992792110387201\"}"
    },
    {
      "text": "Q3:极速版3.0有哪些核心亮点功能?\\*\\* A3:有六大核心亮点:爆款聚合打单(自动汇总爆款订单,提升打单效率)、PDA智能仓储(PDA全流程作业,提效降错)、员工绩效管理(PDA数据化记录,支持绩效统计)、经营决策报表(多维数据看板,辅助决策)、采购智能预警(系统实时生成需求,智能测算)、售后解决方案(多平台售后自动化处理) 。 \\*\\*\n",
      "score": 0.30448285,
      "metadata": "{\"creator\":\"1\",\"createTime\":1752558435,\"kId\":\"1944992792110387201\",\"fragmentId\":\"1944997163263021059\",\"attachId\":\"1944997163091054593\",\"categoryId\":\"1\"}"
    }
]

稠密检索结果分析

特征:

  • 主要依赖语义相似度(embedding 向量)。
  • 检索结果语义高度相关,内容集中在“爆款打单功能”“发货效率”“极速版3.0 优势”等描述上。
  • 前 4 条均与 “爆款聚合打单” 直接相关,语义覆盖较完整。
  • 排名靠后的结果(第5条、第6条)开始出现语义漂移(涉及“Y企业版3.0”、“新人开单”),但仍包含“爆款打单”等关键词。

结论:
✅ 稠密检索能够较好捕捉语义相似内容。
⚠️ 但对“爆款打单”关键词的精确匹配不敏感,可能混入主题相近但场景不同的内容。


稀疏检索结果分析

特征:

  • 结果与稠密检索几乎一致,说明稀疏检索的 BM25 权重在本场景中与语义高度一致。
  • 第 6 条新增了“极速版3.0档口模式的核心差异”,属于主题边缘内容。
  • 稀疏得分范围集中在 0.6~0.2,梯度更明显,说明匹配程度区分度较强。

结论:
✅ 稀疏检索对关键词(如“爆款打单”、“极速版3.0”)的覆盖能力强。
⚠️ 但纯稀疏检索对上下文语义理解较弱,对问答型内容(Q/A)缺乏深层语义匹配。


混合检索结果分析

配置:

  • 稠密检索权重:0.6
  • 稀疏检索权重:0.4
  • 使用 WeightedRanker 融合后取前 6 条。

结果表现:

  • 前 4 条与稠密、稀疏均一致(说明两个检索结果在高相关区域重叠)。
  • 第 5 条为“新人开单”,可能来自稀疏召回部分。
  • 第 6 条为“极速版3.0核心亮点功能”,包含“爆款聚合打单”等核心描述,是语义增强带来的有效补充。

结论:
✅ 混合检索在保持稠密检索语义精度的同时,增强了稀疏检索的关键词召回能力。
✅ 最终结果兼顾语义与关键词匹配,整体相关性最优。

混合检索优化

  • 检索动态加权
    • 针对短句和特定名词,提高稀疏权重;
    • 针对长句和问句,提高稠密权重;
正文完
 0
PG Thinker
版权声明:本站原创文章,由 PG Thinker 于2025-11-12发表,共计16015字。
转载说明:除特殊说明外本站文章皆由CC-4.0协议发布,转载请注明出处。
评论(没有评论)
热评文章
Milvus 稀疏/稠密向量检索及混合检索

Milvus 稀疏/稠密向量检索及混合检索

内容目录 当前大模型落地应用的主要技术是RAG(检索增强生成),它是一种结合知识检索和生成模型的架构,其核心思...