展开菜单
首页 精品内容 本月促销 装机必备 Windows PDF教程 macOS软件 IOS软件 Android AI 专题
全部分类

当前位置:

首页 > 编程开发 > 基于SpringAI+Milvus的RAG混合检索的实战指南

基于SpringAI+Milvus的RAG混合检索的实战指南

Air Explorer Pro
Air Explorer Pro

Air Explorer Pro是一款跨平台多网盘管理工具,可实现一站式完成不同网盘间文件的互传、搜索和同步等操作。任务管理和过程控制会更完整,持续下载、批量同步或需要稳定传输流程的场景会更适合它。

¥99
Windows/macOS 2026-08-22
正版软件 Windows macOS软件 Pro 文件搜索工具 Pro下载 Pro正版软件 Pro购买
立即下载

1. 背景与动机 1.1 业务场景 这次要解决的问题很明确:给一个垂直业务平台搭建智能客服助手。用户会直接描述问题,比如“产品A启动不了该怎么办”,或者“产品B的保养周期是多久”,系统需要给出准确、可操作的解决方案。 数据方面已经有了大量按产品线(A、B、C、D、E)分类的技术文档,主要是PDF和D

1. 背景与动机

1.1 业务场景

这次要解决的问题很明确:给一个垂直业务平台搭建智能客服助手。用户会直接描述问题,比如“产品A启动不了该怎么办”,或者“产品B的保养周期是多久”,系统需要给出准确、可操作的解决方案。

基于SpringAI+Milvus的RAG混合检索的实战指南

数据方面已经有了大量按产品线(A、B、C、D、E)分类的技术文档,主要是PDF和DOCX格式。现在要做的是搭一套检索增强生成(RAG)系统,把这些文档“喂”给大模型,让它能输出结构化的解决方案,而不是天马行空地乱说。

1.2 核心挑战

如果只是做一个“用户提问 → 向量检索 → LLM回答”的常规RAG,数据能洗干净吗?坦白讲,不够。

实际落地会碰到几个硬骨头:

  1. 意图太杂:用户不是说每句话都需要翻文档的。像“你好”这种打招呼,或者“我上次的工单怎么样了”这种查记录,直接走LLM或者查数据库就行。每次无差别触发全套检索,完全是浪费资源。
  2. 精准召回是个老大难:纯向量检索对专业术语的理解能力有限。Most of the time,用户说“产品C运行异常”和文档里的“产品C系统故障”,在语义空间里可能很近,但纯向量一搜,关键信息可能就漏掉了。
  3. 检索噪声大:一次召回40条候选,里面可能超过一半是与问题不相关的。把这些噪音一股脑塞给大模型,不但费钱(token消耗),还容易把大模型带偏。
  4. 用户和文档说话的方式不一样:用户嘴里说“设备发热”,但写文档的人用的是“机身温度过高”;用户说“接口松动”,文档写的是“连接端口接触不良”。不做点query扩展,根本检索不到目标内容。

1.3 选型

组件选型理由
框架Spring Boot 3.4.5 + Spring AI 1.1.2Ja va生态成熟,Spring AI对向量存储和LLM调用有很好的封装
向量数据库Milvus 2.5.6原生支持BM25内置函数,省去了额外维护一个ES
嵌入模型DashScope text-embedding-v21536维,中文效果不错
LLMDashScope Qwen两阶段调用,意图分类和答案生成用同一模型,切换system prompt就行
RerankDashScope Rerank跟LLM同一家供应商,延迟比较可控

2. 整体架构概览

整个问答系统的主流程分两大阶段:

┌─────────────────────────────────────────────────────────┐
│                    用户输入(问题文本)                    │
└─────────────────────┬───────────────────────────────────┘
                      ▼
┌─────────────────────────────────────────────────────────┐
│              Phase 1: 意图分类(轻量 LLM 调用)           │
│                                                         │
│  ┌─────────────┐  ┌──────────────────┐  ┌────────────┐ │
│  │GENERAL      │  │VIEW_RECENT       │  │FIND        │ │
│  │_CONSULT     │  │_FOLLOWUP_TASKS   │  │_COMPONENT  │ │
│  │一般咨询      │  │查看历史记录       │  │查找解决方案  │ │
│  └──────┬──────┘  └────────┬─────────┘  └─────┬──────┘ │
└─────────┼──────────────────┼──────────────────┼────────┘
          │                  │                  │
          ▼                  ▼                  ▼
   LLM 直接回复      查数据库返回         触发 Phase 2
   (可选同步 QA 库)   历史记录             RAG 检索链路
                                             │
                                             ▼
                          ┌─────────────────────────────────┐
                          │    Phase 2: RAG 混合检索         │
                          │                                 │
                          │  Query 改写 → 向量检索 + BM25    │
                          │     → RRF 融合 → Rerank          │
                          │     → 后处理门控 → LLM 生成      │
                          └─────────────────────────────────┘

核心设计思路是:意图优先,RAG按需触发。只有判断为FIND_COMPONENT意图时,才会走完整的混合检索链路。这带来了几个好处:

  • 不必要的LLM调用次数大幅减少(Phase 1和Phase 2各自只调一次LLM)
  • 平均延迟显著降低(大部分请求根本不需要走RAG)
  • 两个阶段的LLM调用可以针对各自的轻量分类和重量生成分别调参

核心服务类的职责分工:

层级关键类职责
Web 层AssistantController, RagControllerREST 接口
核心 pipelineDoctorAssistantService两阶段 LLM pipeline
RAG 检索RagQueryService混合检索编排
Query 改写RagQueryRewriteService同义扩展 + 领域词映射
文档摄入DocumentIngestService文档上传、文本提取、切片
Milvus BM25MilvusBuiltInBm25KeywordSearchMilvus 内置 BM25 全文检索
Milvus 建表MilvusBm25CollectionProvisionerBM25 集合 schema 自动创建
Milvus v2 写入MilvusBm25V2DocumentWriter适配 BM25 函数字段的数据写入

3. 意图路由:轻量分类 + RAG 按需触发

3.1 方案选型

要不要在入口处先做意图分类?这个问题的权衡其实很直接:

  • 不做分类,直接RAG:简单是真简单,但每一个“你好”都要跑一遍检索,不仅浪费算力,延迟也上去了。
  • 两阶段LLM:Phase 1用轻量prompt做分类,Phase 2只在确认需要时触发。

我们选了后者。Phase 1的意图分类prompt强制LLM返回严格的JSON格式:

你是产品技术支持领域的意图识别专家。根据用户问题,识别意图类型。
必须严格返回JSON格式:
{"intentType": "GENERAL_CONSULT"|"FIND_COMPONENT"|"VIEW_RECENT_FOLLOWUP_TASKS"}

这个阶段的推理负担极轻——不需要理解全文,不需要检索上下文,只需要判断用户到底想干什么。

3.2 三种意图的处理路径

意图处理方式延迟
GENERAL_CONSULTLLM 直接回答,可选同步到 QA 库低
VIEW_RECENT_FOLLOWUP_TASKS调用外部用户服务查历史数据低
FIND_COMPONENT触发完整 RAG pipeline → LLM 生成解决方案高

只有FIND_COMPONENT这一个意图会触发RAG。这里还有一道前置校验——通过外部服务确认用户确实关联了某种产品配置。如果用户没有相关产品却来问“产品A故障怎么办”,系统压根不会浪费时间去检索文档。

3.3 后处理门控

即使RAG召回了文档,LLM生成了回答,最后还有一关要过:

  1. LLM返回的答案中必须包含componentCode(产品类型编码)
  2. 系统检查这个编码是否与用户实际关联的产品类型一致
  3. 如果不一致——比如用户用的是产品B,但RAG召回了产品A的文档——系统会将回答降级为GENERAL_CONSULT,也就是只给一般性建议,绝不给具体操作指引

这个门控很关键,因为在业务场景下,给错产品线的操作建议,比不给建议更危险。

4. 混合检索 pipeline:向量 + BM25 + RRF 融合

混合检索是整个RAG系统的核心,我们来逐个步骤拆解。

4.1 为什么要混合检索

纯向量检索(dense retrieval)的问题在于:

  • 向量相似 ≠ 关键词匹配。 “产品C故障”和“产品C运行异常”语义相近,但用户搜“产品C”这个词时,向量检索不一定能准确把“产品C”和“产品A系列”的文档区分开。
  • 对稀有词、专业名词的召回容易跑偏。向量模型在训练时很可能没见过足够多的该领域语料。

纯关键词检索(BM25 sparse retrieval)的问题在于:

  • 词汇不匹配就没结果。用户说“设备发热”,BM25搜不到写了“机身温度过高”的文档。
  • 无法理解语义。“产品A卡顿”和“设备无响应”没有共同词,BM25得分直接是0。

两者结合,才能优势互补。

4.2 技术选型:Milvus 2.5 内置 BM25

市面上的混合检索方案,通常需要两个引擎:Milvus/Qdrant做向量 + Elasticsearch做BM25。维护两套索引,还要在两个结果集之间做融合,架构复杂度不小。

Milvus 2.5开始支持内置BM25——通过FunctionType.BM25在schema中定义一个函数,将文本字段自动转换为稀疏向量。检索时用EmbeddedText将查询文本发给Milvus,服务端自动分词并计算BM25分数。

好处很明显:

  • 单一数据库,不需要维护ES集群
  • 向量检索和BM25检索可以复用同一套过滤条件(documentId、documentSource)
  • 部署简单,运维成本低

当然也有代价:

  • BM25参数调优受限于Milvus的暴露程度(可以在建索引时配置k1、b,但运行时不可动态调整)
  • 分词依赖Milvus内置的analyzer(我们用的是Chinese analyzer)

4.3 检索 pipeline 代码拆解

核心入口在RagQueryService.retrieveForRag():

                     用户问题
                        │
                        ▼
              queryRewriteService
                .rewriteForRetrieval()     ← 领域改写(见第5节)
                        │
                        ▼
          ┌─────────────┴─────────────┐
          │      hybrid enabled?       │
          └─────────────┬─────────────┘
                  Yes   │   No
          ┌─────────────┴─────────────┐
          ▼                           ▼
   ┌──────────────┐           ┌──────────────┐
   │ 并行双路检索   │           │ 纯向量检索     │
   │              │           │ topK=N       │
   │ 向量池: 40条 │           │ minSim=0.15  │
   │ BM25池: 24条 │           └──────────────┘
   └──────┬───────┘
          ▼
     RRF 融合 (k=60)
          │
          ▼
    截断到 max(topK, 48)
          │
          ▼
    DashScope Rerank
          │
          ▼
    多重过滤 → 返回 topK

如果hybrid.enabled=false,整个链路会退化为纯向量检索,方便做对照实验。

4.4 向量检索

使用Spring AI封装的Milvus向量存储,配置IVF_FLAT索引 + COSINE相似度:

MilvusSearchRequest request = MilvusSearchRequest.milvusBuilder()
    .query(retrievalQuery)
    .topK(topK)
    .searchParamsJson("{"nprobe":128}")
    .similarityThreshold(0.15)  // 过滤低分噪声
    .build();
return milvusVectorStore.similaritySearch(request);

几个要点:

  • nprobe=128:IVF_FLAT索引搜索时扫描128个最近的聚类中心,在召回率和速度之间取平衡
  • similarityThreshold=0.15:COSINE相似度低于0.15的文档直接丢弃,从源头减少噪声
  • 向量池取max(topK, 40)条——即使请求只需要5条,也要多召回一些,给后续融合留出空间

4.5 Milvus BM25 检索

BM25检索通过MilvusBuiltInBm25KeywordSearch实现,直接调用Milvus v2 gRPC API:

SearchReq.builder()
    .collectionName(collectionName)
    .annsField("sparse_bm25")           // 稀疏向量字段名
    .data(List.of(new EmbeddedText(query)))  // 服务端自动分词
    .topK(topK)
    .metricType(IndexMetricType.BM25)
    .outputFields(List.of("id", "content", "metadata"))
    .filter(filter)                      // 与向量检索一致的过滤条件
    .build();

关键设计点:

  1. 使用EmbeddedText而非手动BM25向量化:把原始查询文本发给Milvus,让服务端用建库时相同的Chinese analyzer分词后做BM25匹配。这保证了词法对齐——入库分析和查询分析用的是同一套tokenizer。
  2. 词法池取max(topK, 24)条:比向量池的40小,因为实际场景中查询词一般较短(一两句话),BM25能有效匹配的文档数本就有限。
  3. BM25绝对分过滤:加了minBm25AbsoluteScore=1.0的阈值。BM25分数低于1.0的文档基本没有有意义的词法匹配,属于噪声。
  4. BM25相对分过滤:同一批次内,BM25_score / max(BM25_score)低于0.8的丢弃。这个阈值可以按需配置。

4.6 RRF 融合

Reciprocal Rank Fusion(RRF)是一种简洁有效的分数融合方法:

// 伪代码
Map scores = new HashMap<>();

int rank = 1;
for (doc : vectorRankedList) {
    scores.merge(doc.getId(), 1.0 / (rrfK + rank), Double::sum);
    rank++;
}

rank = 1;
for (doc : keywordRankedList) {
    scores.merge(doc.getId(), 1.0 / (rrfK + rank), Double::sum);
    rank++;
}

return scores.entrySet().stream()
    .sorted(Map.Entry.comparingByValue().reversed())
    .limit(rerankCandidateMax)
    .toList();

RRF公式:RRF_score(d) = Σ 1 / (k + rank_i(d)),其中 k 是阻尼常数。

为什么用RRF,而不是简单的分数归一化?

传统分数融合需要做score normalization——比如min-max归一化。但问题是:

  • 向量相似度和BM25分数的分布完全不同,线性归一化的假设不成立
  • BM25分数理论上无上限,向量COSINE相似度在 -1 到 1 之间,归一化后的“权重”很难解释

RRF不关心原始分数的绝对值,只关心相对排名,天然适合异构检索结果的融合。

k值的选择:我们设rrfK=60。k越大,排名差异的影响越小,更偏向于“同时出现在两个列表中的文档得分高”。k=60意味着:

  • 只在向量列表中排第1名的文档:1/(60+1) = 0.0164
  • 在向量列表排第10、BM25列表排第5的文档:1/(60+10) + 1/(60+5) = 0.0143 + 0.0154 = 0.0297
  • 同时在两个列表排第1的文档:1/61 + 1/61 = 0.0328

可以看到,出现在两个列表中的文档RRF分明显更高——这正是我们想要的:两个检索器“共识”的文档排前面。

5. Query 改写:领域词扩展与同义映射

5.1 为什么需要改写

前面提到,用户的自然语言和专业文档的书面表述之间存在gap。一个典型的例子:

用户问题文档表述
“设备发热”“机身温度过高”
“接口松动”“连接端口接触不良”
“多久换一次”“配件更换周期/更换频率”

如果不做改写,无论是向量检索还是BM25检索,都可能漏掉真正相关的文档。

5.2 改写策略

RagQueryRewriteService.rewriteForRetrieval()执行三步处理:

Step 1: 文本归一化(Normalize)

String normalized = original.trim().replaceAll("\s+", " ");

最简单的清洗:去首尾空白、合并多余空格。

Step 2: 规则驱动的词扩展

维护了一个包含27条规则的映射表,每条规则定义了一组触发词和对应的扩展词:

rule(
    new String[] {"保养周期", "保养频率", "多久保养", "检查周期",
                  "多长时间检测", "维护频率", "多久检查"},
    new String[] {"常规保养间隔", "使用期间检查频率", "保养周期",
                  "安装后维护", "常规保养"}
)

匹配逻辑是:如果用户问题中间出现任意一个触发词,就将所有扩展词(未在问题原文中间出现的)追加到检索query后面。

为什么用规则而不是LLM做改写?

  • 确定性:规则扩写的结果是可预测、可调试的。LLM改写可能引入不确定的语义漂移。
  • 低延迟:规则匹配是O(n)字符串查找,毫秒级完成。LLM改写需要一次完整的推理,延迟1-3秒。
  • 可维护性:新增一个领域词映射只需要加一条规则,不需要重新训练或调prompt。
  • 够用:该业务领域的同义词汇是有限的、可枚举的。花里胡哨的LLM改写是overkill。

当一个领域的同义词是可枚举且有限的,规则引擎就是最好的选择。

Step 3: 产品上下文扩展

如果检测到问题涉及特定产品线,自动追加对应术语:

if (question.contains("产品A") || question.contains("A系列")) {
    expansionTerms.add("产品A");
    expansionTerms.add("产品A系列(企业级高性能型号)");
    // 追加产品A相关的故障关键词
    expansionTerms.addAll(getKeywordsForProduct(PRODUCT_A));
}

最终,改写后的检索query是:

原始问题 + 扩展词1 扩展词2 扩展词3 ...

改写后的query只用于检索,不用于LLM生成。生成阶段的prompt仍然使用用户原始的提问文本。

6. DashScope Rerank 精排与多重过滤

6.1 为什么需要 Rerank

RRF融合的结果是基于两个检索器各自排名的折中,但它不知道哪个文档真正回答了用户的问题。

Rerank模型把每个候选文档和用户问题做一对一的语义相关性打分,比向量相似度的rank更精细。DashScope的Rerank模型(gte-rerank)专门为这个任务优化过。

6.2 Rerank 调用

RRF融合后,候选列表先截断到max(topK, 48)条,然后调用DashScope Rerank:

RerankResponse response = rerankModel.call(new RerankRequest(
    retrievalQuery,
    fusedDocs,  // candidate documents
    DashScopeRerankOptions.builder()
        .withTopN(topK)
        .build()
));

注意这里的retrievalQuery是改写后的query(包含扩展词),不是原始问题。因为Rerank阶段希望获得更多的检索信号来排序。

6.3 双重过滤

Rerank返回的结果还要经过两层过滤,而且是AND关系:

相对分过滤(batch-normalized):

double maxScore = results.stream()
    .mapToDouble(RerankResult.Result::getRelevanceScore)
    .max().orElse(1.0);

results.stream()
    .filter(r -> r.getRelevanceScore() / maxScore >= 0.8)
    .toList();

以同一批次中最高分为基准,相对分低于0.8的丢弃。这保证了返回的文档相关性不低于“最佳匹配文档”的80%。

绝对分过滤:

results.stream()
    .filter(r -> r.getRelevanceScore() >= 0.3)
    .toList();

Rerank分数低于0.3的文档基本与问题无关,直接扔掉。

两重过滤的关系是AND:一个文档必须同时满足相对分 >= 0.8×max 和绝对分 >= 0.3 才会被保留。

6.4 热切换与降级

Rerank是可热切换的:

RerankModel rerank = hybridProperties.isUseRerankWhenA vailable()
    ? rerankModel.getIfA vailable() : null;

if (rerank == null) {
    // 无 rerank,直接用 RRF 结果截断返回
    return fused.stream().limit(topK).toList();
}

use-rerank-when-a vailable配置项设为false即可跳过rerank,这对于压测和故障降级很有用。

降级策略:如果rerank调用返回空结果,系统回退到RRF融合列表截断topK输出。但如果rerank返回了结果但全被过滤掉了(双重过滤导致),则不降级——返回空结果,不兜底。因为“找到但全不相关”比“假装找到了”更诚实,也避免LLM拿到无关上下文后胡编乱造。

7. 文档摄入:分词策略与 Milvus BM25 自动入库

7.1 上传与文本提取

文档上传通过REST接口:

POST /api/rag/documents
Content-Type: multipart/form-data

file: 产品手册.pdf
documentId: product_manual_v2
documentSource: product_kb

后端使用Apache Tika做文本提取,支持PDF、DOCX、XLSX、HTML等常见格式:

String rawText = TikaTextExtractor.extract(inputStream, filename);

7.2 两种切片策略

DocumentIngestService提供两种切片策略,通过jmyzt.rag.ingest.strategy配置:

FIXED_LENGTH(固定长度滑动窗口):

int maxSize = 1200;   // 每块最多 1200 字符
int overlap = 150;    // 块间重叠 150 字符

int start = 0;
while (start < text.length()) {
    int end = Math.min(text.length(), start + maxSize);
    String chunk = text.substring(start, end).strip();
    start = Math.max(end - overlap, start + 1);  // 避免死循环
}

适合结构规整的文档。1200字符大约400-600个中文字,是一个比较适中的上下文窗口。

PARAGRAPH_THEN_FIXED(先按段落切,长段落再固定切):

// 先按空行切段落
String[] paragraphs = text.split("\n\s*\n+");
for (String para : paragraphs) {
    if (para.length() <= maxChunkChars) {
        chunks.add(para);  // 短段落直接作为一个 chunk
    } else {
        // 长段落递归按固定长度切
        splitLongParagraphFixedRecursive(para, chunks);
    }
}

适合有明确段落结构的产品技术文档。保留了文档的自然段落边界,检索时上下文的连贯性更好。

7.3 解决 Spring AI v1 InsertParam 与 BM25 函数字段的兼容问题

这是整个项目中最“工程化”的一个坑。

Milvus的BM25函数字段(FunctionType.BM25)是由服务端从content字段自动生成的。在插入数据时,不应该手动给这个字段赋值。

但Spring AI 1.x的MilvusVectorStore使用的是Milvus v1 gRPC客户端(InsertParam),它会尝试给schema中定义的所有字段赋值。当遇到sparse_bm25字段时,Spring AI没有对应的数据,直接就报错了:

The field: sparse_bm25 is not provided

解决方案:绕过Spring AI,直接使用MilvusClientV2.insert(),在构建插入请求时故意不包含sparse_bm25字段:

// MilvusBm25V2DocumentWriter.insertDocuments()
for (Document doc : documents) {
    JsonObject row = new JsonObject();
    row.addProperty("id", doc.getId());
    row.addProperty("content", doc.getText());
    row.addProperty("metadata", metadataJson);
    row.add("embedding", embeddingArray);  // 手动嵌入
    // 注意:不添加 sparse_bm25 字段!
    // Milvus 服务端 BM25 函数会自动填充
    data.add(row);
}

InsertReq insertReq = InsertReq.builder()
    .collectionName(collectionName)
    .data(data)
    .build();

milvusClientV2.insert(insertReq);

嵌入向量的生成也是手动调EmbeddingModel.embed()完成的,绕开了Spring AI的自动嵌入流程。

7.4 Collection Schema 自动建表

MilvusBm25CollectionProvisioner在应用启动时自动执行,支持三种模式(milvus-bm25-collection-bootstrap配置):

模式行为
none不做任何操作,假设集合已存在
create-if-missing如果集合不存在则创建(生产推荐)
recreate删除已有集合并重建(数据丢失! 仅开发用)

创建的集合schema包含:

字段名类型说明
idVarChar(36)主键
contentVarChar(65535)文本内容,Chinese analyzer 分词
metadataJSON文档元信息(documentId, documentName 等)
embeddingFloatVector(1536)文本嵌入向量
sparse_bm25SparseFloatVectorBM25 函数输出字段

BM25函数定义:

schema.addFunction(CreateCollectionReq.Function.builder()
    .name("content_bm25")
    .functionType(FunctionType.BM25)
    .inputFieldNames(List.of("content"))       // 输入:文本字段
    .outputFieldNames(List.of("sparse_bm25"))  // 输出:稀疏向量字段
    .build());

BM25索引参数:

Map sparseParams = new HashMap<>();
sparseParams.put("inverted_index_algo", "DAAT_MAXSCORE");
sparseParams.put("bm25_k1", 1.2);    // 词频饱和度参数
sparseParams.put("bm25_b", 0.75);    // 文档长度归一化参数

k1=1.2和b=0.75是Okapi BM25的标准默认值。在这个中文长文档场景中没有做特别调整,因为标准参数对于中文长文档通常表现不错。

索引就绪等待:创建集合后,启动时会轮询describeIndex等待索引构建完成(最多120次 × 500ms = 60秒),避免索引未就绪时查询返回空结果。

8. 踩过的坑与调参经验

8.1 向量池和 BM25 池不宜过大

最开始设向量池100、BM25池100,觉得“多召回一些,反正后续有rerank筛选”。结果:

  • Milvus检索时间从几十毫秒飙到几百毫秒
  • Rerank阶段需要处理近200条候选,单次rerank调用耗时3-5秒
  • 大部分候选文档的分数很低,徒增延迟

现在稳定在向量池40、BM25池24、rerank候选上限48。实测延迟降到1.2秒以内(全链路)。

原则:多路检索的池大小是“够用就好”,不要贪多。

8.2 Rerank 后的绝对分过滤比相对分过滤更重要

一开始只设置了相对分过滤(minRelativeRetrievalScore=0.8),没有绝对分过滤。发现在某些边缘query上——用户问“今天天气怎么样”——Rerank返回的所有文档分数都很低(~0.1),归一化后最高分也只有0.1,相对分过滤形同虚设(0.1/0.1=1.0,全通过)。

加上minRerankAbsoluteScore=0.3后,这种情况会被正确拦截——所有rerank分低于0.3的文档直接丢弃,返回空列表,LLM至少知道“没有找到相关文档”而不是对着无关内容瞎编。

8.3 Spring AI 版本不匹配问题

Spring AI 1.1.2的Milvus集成基于v1 gRPC客户端,而Milvus 2.5的部分功能(EmbeddedText、BM25函数)只在v2 gRPC中可用。这导致了两个API路径共存:

  • 向量检索:走Spring AI(v1)
  • BM25检索:直接调MilvusClientV2(v2)
  • 文档写入:绕开Spring AI,用自定义的v2 writer

教训:框架的封装层不一定总是够用。对于前沿功能(如Milvus 2.5内置BM25),要做好绕过框架直接调底层SDK的准备。 我们做了封装隔离——只在底层交互类中依赖v2 SDK,上层业务逻辑仍然通过统一接口调用。

8.4 Query 改写的扩展词要有“节制”

最开始给每条规则加了很多扩展词,比如“故障”触发词映射到十几个扩展词。结果某些query改写得非常长(几百字),反而稀释了核心关键词的信号。

现在的策略是每条规则3-5个精准的扩展词。宁可少写,不要多写。

8.5 RRF 的 k 值调优

k=60不是拍脑袋定的。在开发环境做了小规模对比:

k 值效果
k=0极端重视高 rank,排第一的文档权重极大。结果:几乎退化为“取两个列表的交集排序”,单路表现差的 query 全挂
k=60当前的平衡点,共识文档有优势,但单路高排名的文档也不会被完全埋没
k=∞所有 rank 权重相同,退化为“在两个列表中都出现的排前面,都没出现的随机排”

k=60在开发和测试阶段的表现稳定,所以沿用到了生产。

8.6 中文分词的 BM25 分析器选择

Milvus的Chinese analyzer对中文文本的处理包括分词和停用词过滤。我们发现通用Chinese analyzer对垂直领域的专业术语分词效果有一些偏差——例如“产品A系列”可能被切为“产品” + “A” + “系列”,“部件故障”可能被切为“部件” + “故障”。

目前通过在query改写阶段追加完整的专业词汇作为缓解手段(即使分析器误切,也能通过扩展后的完整词匹配到),后续考虑使用自定义词典来进一步优化。

9. 总结与下一步

9.1 这套方案的核心价值

  1. 意图优先,RAG按需触发:不是所有请求都需要全套检索,两阶段pipeline在延迟和效果之间取得了好的平衡。
  2. 向量 + BM25混合检索:单一数据库(Milvus 2.5内置BM25)搞定,不需要维护多个存储引擎。
  3. 规则驱动的query改写:领域知识显式编码,可调试、可维护,延迟为零。
  4. 多层过滤漏斗:从向量相似度阈值 → BM25分过滤 → RRF融合 → Rerank双重过滤,每层砍掉一部分噪声,最终喂给LLM的是高度相关的上下文。
  5. 后处理门控:答案与用户实际情况交叉校验,降低风险。

9.2 当前局限与改进方向

  • Query改写依赖规则维护:新增产品线时需要手动加规则。未来可以考虑用LLM生成候选扩展词 + 人工审核的半自动化流程。
  • BM25分词精度:通用Chinese analyzer对领域专业术语的分词有偏差,可以引入自定义词典。
  • Rerank是唯一的外部依赖:如果DashScope Rerank服务不可用,系统虽有降级策略但排序质量会下降。考虑评估本地Cross-Encoder模型作为备选。
  • 评估体系缺失:目前靠人工抽样评估检索质量。下一步需要构建标注数据集和自动化评估。

9.3 关键配置速查

配置项值用途
hybrid.vector-pool-top-k40向量召回候选数
hybrid.keyword-pool-top-k24BM25 召回候选数
hybrid.rrf-k60RRF 阻尼常数
hybrid.rerank-candidate-max48Rerank 输入上限
hybrid.min-vector-similarity0.15向量相似度阈值
hybrid.min-bm25-absolute-score1.0BM25 绝对分阈值
hybrid.min-relative-retrieval-score0.8Rerank 相对分阈值
hybrid.min-rerank-absolute-score0.3Rerank 绝对分阈值
rag.ingest.max-chunk-chars1200切片大小
rag.ingest.overlap-chars150切片重叠量
本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系bd@zhengruan.com
作者最新文章
编程开发 AI
相关文章 更多
精品专题 更多
装机必备

正软商城装机必备专区,精选办公、浏览器、安全防护、影音播放、压缩解压、设计创作和系统工具等电脑常用正版软件,帮助用户快速完成新电脑软件配置。

Windows

正软商城Windows软件专区,汇集适用于Windows电脑的办公、设计、安全防护、影音播放、开发工具和系统优化软件,提供软件介绍、系统要求、正版授权及购买下载服务。

PDF教程

正软商城PDF教程频道提供PDF编辑、转换、合并、拆分、压缩及格式处理方法,同时介绍常用PDF软件和工具的使用技巧。

macOS软件

正软商城macOS软件专区,精选适用于Mac电脑的办公、设计、影音、效率、开发和系统工具,提供软件功能介绍、macOS兼容版本、正版授权及购买下载服务。

IOS软件

正软商城iOS软件专区,精选适用于iPhone和iPad的办公、学习、影音、设计、效率及AI应用,提供功能介绍、适用设备、系统要求和正版获取方式等信息。

AI

正软商城AI软件专区,汇集AI写作、AI绘画、AI视频、AI办公、AI编程、AI翻译、智能客服和数据分析等人工智能工具,提供功能介绍、适用平台、收费方式及正版购买信息。

Mac软件 更多
WPS Office macOS版
WPS Office macOS版

WPS Office是一款面向macOS用户的综合办公套件,将文字处理、电子表格、演示文稿、PDF工具、模板与云协作整合在同一应用中。它兼容常见Microsoft Office格式,支持Intel及Apple芯片Mac,基础功能可免费使用,

Shapr3D macOS版
Shapr3D macOS版

Shapr3D是一款面向工业设计、机械工程、建筑概念和三维打印工作流的CAD软件。Mac版采用Parasolid建模内核,支持草图约束、实体建模、工程图、可视化渲染及常见CAD格式交换,并可通过账户在多台设备之间同步项目。

REAPER macOS版
REAPER macOS版

REAPER是Cockos开发的数字音频工作站,提供多轨音频与MIDI录制、剪辑、处理、混音和母带制作工具。Mac版兼容Intel与Apple芯片,支持AU、VST、VST3、CLAP等插件格式,并提供高度可定制的工作流程。

Ableton Live macOS版
Ableton Live macOS版

Ableton Live 是面向音乐制作人与现场表演者的数字音频工作站,提供编曲视图、独具特色的现场视图、音频录制、MIDI创作、实时变速、乐器及效果器。Mac版原生支持Apple芯片,并可连接音频接口、MIDI控制器和第三方插件。

Adobe After Effects macOS版
Adobe After Effects macOS版

Adobe After Effects 是面向动态图形、影视特效与视频合成的专业创作软件。它提供关键帧动画、遮罩抠像、运动跟踪、三维空间、文字动画和表达式等工具,并可与 Premiere Pro、Photoshop、Illustrator

Adobe Audition macOS版
Adobe Audition macOS版

Adobe Audition 是面向播客、影视后期、音乐制作及内容创作者的专业音频工作站,提供波形精修、多轨录制与混音、频谱编辑、降噪修复、响度匹配和效果处理工具,并可与 Adobe Premiere 协同完成视频声音制作。

Adobe Bridge macOS版
Adobe Bridge macOS版

Adobe Bridge 是面向摄影师、设计师及内容团队的免费数字资产管理工具,可集中预览照片、视频和 Adobe 项目文件,并利用评级、标签、关键词、元数据、筛选与收藏集完成分类检索。它还支持批量重命名、格式导出、相机导入及 Camera

Adobe Illustrator macOS版
Adobe Illustrator macOS版

Adobe Illustrator 是 Adobe 推出的专业矢量图形设计软件,适合在 Mac 上制作标志、图标、插画、包装、信息图及印刷版面。它以路径和锚点构建可无损缩放的图形,并提供钢笔、形状、文字、图像描摹、渐变、画板及生成式功能。

Adobe InDesign macOS版
Adobe InDesign macOS版

Adobe InDesign 是面向印刷品与数字出版物的专业版面设计软件,可在 Mac 上制作书籍、杂志、宣传册、海报、报告及交互式文档。它提供精细的文字样式、网格、母版、长文档管理和印前输出能力。

Adobe Lightroom Classic macOS版
Adobe Lightroom Classic macOS版

Adobe Lightroom Classic 是面向桌面摄影工作流的照片管理与后期处理软件,可将原始照片保存在本地硬盘,通过目录、关键词、评分和收藏夹高效整理图库,并提供 RAW 冲印、蒙版、镜头校正、批量同步及多格式导出等功能。

Adobe Media Encoder macOS版
Adobe Media Encoder macOS版

Adobe Media Encoder 是 Adobe 推出的专业音视频编码与转码工具,可通过队列、预设和监视文件夹批量完成格式转换、代理文件创建及多平台成片输出,并与 Premiere Pro、After Effects 等软件紧密协作。

Adobe Photoshop macOS版
Adobe Photoshop macOS版

Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理软件,提供图层、蒙版、选区、修复、调色、文字排版、智能对象及生成式编辑等能力。Mac 版支持 Intel 与 Apple Silicon 处理器。

WINDOWS 更多
Adobe Photoshop Windows版
Adobe Photoshop Windows版

Adobe Photoshop 是面向摄影师、设计师和内容创作者的专业图像处理工具,可在 Windows 上完成照片修饰、选区抠图、图层合成、文字排版、绘画及生成式编辑。软件采用订阅授权,由 Creative Cloud 管理安装、更新与许

Adobe InDesign Windows版
Adobe InDesign Windows版

Adobe InDesign 是面向印刷与数字出版的专业页面排版工具,可制作书籍、杂志、宣传册、海报、交互式 PDF 和电子书。它提供精细的文字样式、多页面管理、印前检查及多格式输出能力,并能与 Photoshop、Illustrator

Adobe Illustrator Windows版
Adobe Illustrator Windows版

Adobe Illustrator 是用于绘制矢量图形、插画、图标、徽标和版式的专业设计工具。它以路径和锚点为核心,作品放大后仍能保持清晰,并提供画板、文字、渐变、图像描摹及精确变换等功能,适合品牌视觉、印刷物料、数字界面和商业插画创作。

Adobe Bridge Windows版
Adobe Bridge Windows版

Adobe Bridge 是 Adobe 推出的创意资产管理工具,可集中预览、分类和查找照片、视频、PDF及多种设计文件,并支持元数据、关键词、评级、批量重命名和格式导出。它可与 Photoshop、Illustrator 等应用衔接,

Affinity Photo Windows版
Affinity Photo Windows版

Affinity Photo 是一款面向摄影师、修图师和视觉设计人员的桌面图像编辑工具,提供 RAW 显影、多图层合成、蒙版、实时滤镜、批处理和色彩管理等功能。原独立产品已停止销售,其照片编辑能力已延续至免费的新 Affinity 应用;

Adobe Lightroom Classic Windows版
Adobe Lightroom Classic Windows版

Adobe Lightroom Classic 是面向 Windows 桌面摄影工作流的照片管理与无损编辑工具,可通过目录集中整理大型图库,并完成 RAW 显影、局部蒙版、批量调整、打印和多格式导出。它强调本地文件管理与精细控制,

Figma Windows版
Figma Windows版

Figma 是面向产品设计与开发团队的云端协作平台,可在 Windows 桌面客户端中完成界面绘制、组件管理、交互原型、评论评审和开发交付。文件保存在云端,多名成员能够同步编辑并共享设计系统;官方同时提供免费 Starter 方案及按席位计

Affinity Designer Windows版
Affinity Designer Windows版

Affinity Designer 是面向矢量图形、数字插画和界面设计的专业创作工具,可在矢量、像素与导出工作区之间快速切换。它提供曲线编辑、形状构建、画板、排版、图层和专业色彩管理,并支持常见设计文件的导入及多种印刷、网页格式输出。

Capture One Pro Windows版
Capture One Pro Windows版

Capture One Pro 是面向摄影师和影像团队的专业桌面照片处理工具,提供相机定制色彩配置、RAW转换、图层与蒙版、联机拍摄、目录及会话管理等功能。它适合棚拍、人像、商业产品、婚礼和风光摄影,

Adobe Acrobat Pro Windows版
Adobe Acrobat Pro Windows版

Adobe Acrobat Pro 是面向专业 PDF 工作的综合解决方案,可在 Windows 中创建、编辑、转换、比较、整理和保护文档,并支持表单、电子签名、扫描件文字识别及敏感信息永久遮盖。订阅还包含网页、移动服务和云端协作能力,

Adobe After Effects Windows版
Adobe After Effects Windows版

Adobe After Effects 是面向动态图形、动画与影视视觉特效制作的专业工具,可完成关键帧动画、图层合成、遮罩跟踪、抠像、文字动画和二维三维元素整合。Windows 版通过 Adobe Creative Cloud 安装及更新,

DaVinci Resolve Windows版
DaVinci Resolve Windows版

DaVinci Resolve是Blackmagic Design推出的一体化影视后期工具,将素材管理、非线性剪辑、专业调色、Fusion视觉特效、Fairlight音频处理和成片交付整合在统一工程中。免费版已覆盖多数个人创作需求,

即将离开本站
您即将前往第三方网站,请确认是否继续?