ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

Spring-ai-Rag 检索与 Rerank 重排序

Spring-ai-Rag 检索与 Rerank 重排序 文章目录RAG 检索与 Rerank 重排序为什么需要、两种写法有何不同一、RAG 检索在链路中的位置二、为什么需要 Rerank三、Maven 依赖四、方法一search() 纯向量检索1 SearchRequest 参数表2 适用场景五、方法二reRank() 检索 重排 生成1 RetrievalRerankAdvisor 构造参数表六、两种方法的区别七、RetrievalRerankAdvisor 核心源码1 整体流程2 before()检索 → 重排 → 拼 Prompt3 doRerank()调用 RerankModel 打分、过滤、排序4 after()回写检索结果八、DashScopeRerankModel 调用链九、小结RAG 检索与 Rerank 重排序为什么需要、两种写法有何不同本文基于技术栈Java 21 / Spring Boot 4.1 / Spring AI 2.0.0-M1 / spring-ai-alibaba 2.0.0-M1.1。官方参考Spring AI Vector Databases · Spring AI Alibaba一、RAG 检索在链路中的位置入库完成后RAG检索Retrieve阶段负责从 VectorStore 找出与用户问题相关的文档片段否是用户问题EmbeddingModelVectorStore 初检 topKRerank?上下文RerankModel 精排ChatModel 生成二、为什么需要 Rerank向量检索Bi-Encoder快但粗RerankCross-Encoder / 专用重排模型慢但准。对比项向量相似度检索Rerank 重排序原理问题向量 vs 文档向量算余弦/内积距离把「问题 每条文档」成对送入重排模型打分速度快适合从百万级索引里捞 topK慢通常只对 topK如 520 条做精排语义理解双塔各自编码没有交叉注意力易「形似神不似」联合编码更懂 query 与 passage 的细粒度相关性典型问题关键词重叠高但答非所问短 query 对长 chunk 不敏感能剔除初检里的噪声片段把真正相关的排到前面三、Maven 依赖Rerank 能力来自spring-ai-alibaba-starter-dashscope与 Embedding / Chat 同一个 StarterdependencygroupIdcom.alibaba.cloud.ai/groupIdartifactIdspring-ai-alibaba-starter-dashscope/artifactIdversion2.0.0-M1.1/version/dependency!-- Redis VectorStore --dependencygroupIdorg.springframework.ai/groupIdartifactIdspring-ai-starter-vector-store-redis/artifactId/dependencydependencygroupIdorg.springframework.boot/groupIdartifactIdspring-boot-starter-data-redis/artifactId/dependency四、方法一search()纯向量检索只做Retrieve不涉及 Rerank 和 Generate。Testvoidsearch(){SearchRequestrequestSearchRequest.builder().query(机器学习)// 检索问题会先向量化再查相似文档.topK(5)// 最多返回 5 条.similarityThreshold(0.45)// 相似度下限低于此值的结果会被过滤.build();ListDocumentdocumentsvectorStore.similaritySearch(request);// 向量相似度检索documents.forEach(System.out::println);assertThat(documents).isNotEmpty();// 至少命中一条}1 SearchRequest 参数表参数说明query检索文本内部会先 Embedding 再查 VectorStoretopK最多返回几条 DocumentsimilarityThreshold相似度下限低于阈值的结果被丢弃2 适用场景验证文档是否成功入库、向量维度是否正确调topK/similarityThreshold观察召回质量只要文档列表、不需要 LLM 回答五、方法二reRank()检索 重排 生成完整 RAG 链路由RetrievalRerankAdvisor封装三步。TestvoidreRank(AutowiredDashScopeRerankModelrerankModel,// 阿里云重排序模型AutowiredChatModelchatModel){// 大语言模型// 1. 检索参数topK / 相似度下限// query 只是占位运行时会被用户问题覆盖SearchRequestsearchRequestSearchRequest.builder().query(机器学习)// 占位 query实际以 user 消息为准.topK(5)// 初检最多返回 5 条.similarityThreshold(0.45)// 相似度下限.build();// 2. 构造 AdvisorVectorStore RerankModel 检索参数RetrievalRerankAdvisorreRankAdvisornewRetrievalRerankAdvisor(vectorStore,// 检索来源rerankModel,// 重排序模型searchRequest);// 检索参数// 3. 挂载到 ChatClientChatClientchatClientChatClient.builder(chatModel).defaultAdvisors(reRankAdvisor).build();// 4. 提问内部 检索 → 重排 → 拼 Prompt → 生成StringanswerchatClient.prompt().user(什么是机器学习).call().content();System.out.println(RAG 重排回答: answer);assertThat(answer).isNotBlank();}1 RetrievalRerankAdvisor 构造参数表构造方法参数(VectorStore, RerankModel)最简默认 SearchRequest / PromptTemplate / minScore(VectorStore, RerankModel, SearchRequest)项目用法自定义 topK、相似度阈值(VectorStore, RerankModel, SearchRequest, PromptTemplate, Double minScore)还可自定义 Prompt 模板与重排最低分(VectorStore, RerankModel, SearchRequest, PromptTemplate, Double minScore, int order)完整版含 Advisor 执行顺序参数说明默认值vectorStore向量检索来源—rerankModel重排模型如DashScopeRerankModel—searchRequest初检参数topK、threshold 等默认空 SearchRequestpromptTemplate把 query 文档拼进 Prompt 的模板内置英文 RAG 模板minScoreRerank 得分下限低于此值的文档丢弃0.1六、两种方法的区别对比项search()reRank()核心调用vectorStore.similaritySearch(request)ChatClientRetrievalRerankAdvisor是否 Rerank否是DashScopeRerankModel是否调用 LLM否是ChatModel生成最终答案返回值ListDocument初检结果String自然语言回答适用场景调试检索、验证入库质量、只要文档不要生成完整 RAG 问答检索 → 重排 → 生成query 来源SearchRequest.query(...).user(...)覆盖query七、RetrievalRerankAdvisor 核心源码类路径com.alibaba.cloud.ai.advisor.RetrievalRerankAdvisorspring-ai-alibaba-dashscope2.0.0-M1.1实现 Spring AI 的BaseAdvisor在 ChatClient 调用链中插入before / after钩子。1 整体流程调用: chatClient.prompt().user(什么是机器学习).call() │ ▼ ┌─ before() ─────────────────────────────────────────────┐ │ ① 取用户问题 │ │ userMessage request.prompt().getUserMessage() │ │ │ │ ② 组装检索请求(复制 searchRequest,只覆盖 query) │ │ SearchRequest.from(searchRequest) │ │ .query(userMessage.getText()) // 用户问题 │ │ .filterExpression(过滤条件) // 见 doGetFilter │ │ .build() │ │ │ │ ③ 初检 │ │ documents vectorStore.similaritySearch(②) │ │ │ │ ④ 原始结果存进上下文(重排前的,供 after() 用) │ │ context.put(qa_retrieved_documents, documents) │ │ │ │ ⑤ 重排 doRerank(): │ │ a. 空结果 → 直接返回 │ │ b. new RerankRequest(用户问题, 初检文档) │ │ c. rerankModel.call() → 打分 │ │ d. 过滤 score minScore(默认 0.1) │ │ e. 按分数降序排序 │ │ f. 取出 Document 列表 │ │ │ │ ⑥ 把重排后的文档拼成上下文文本 │ │ documentContext 各文档 text 用换行连接 │ │ │ │ ⑦ 渲染默认模板 │ │ promptTemplate.render({query, question_answer_context})│ │ → 生成一段问题资料要求的文本 │ │ │ │ ⑧ 用增强后的文本替换/追加用户消息,继续传下去 │ │ prompt.augmentUserMessage(增强文本) │ └──────────────────────────────────────────────────────────┘ │ ▼ ChatModel.call(增强后的 prompt) ← 大模型基于文档回答 │ ▼ ┌─ after() ───────────────────────────────────────────────┐ │ ⑨ 把 context 里的原始文档写进 ChatResponse.metadata │ │ (只为了观察/调试,不影响回答) │ └─────────────────────────────────────────────────────────┘ │ ▼ 返回答案2 before()检索 → 重排 → 拼 Prompt逻辑还原基于 2.0.0-M1.1 反编译OverridepublicChatClientRequestbefore(ChatClientRequestrequest,AdvisorChainchain){MapString,ObjectcontextnewHashMap(request.context());UserMessageuserMessagerequest.prompt().getUserMessage();// ① 用【用户真实问题】覆盖 SearchRequest.query不是 builder 里的占位 querySearchRequestsearchRequestToUseSearchRequest.from(this.searchRequest).query(userMessage.getText())// ← 关键以 user 消息为准.filterExpression(doGetFilterExpression(context)).build();// ② VectorStore 向量初检ListDocumentdocumentsthis.vectorStore.similaritySearch(searchRequestToUse);context.put(qa_retrieved_documents,documents);// ③ Rerank 精排documentsdoRerank(request,documents);// ④ 把重排后的文档正文拼成上下文字符串StringdocumentContextdocuments.stream().map(Document::getText).collect(Collectors.joining(System.lineSeparator()));// ⑤ 用 PromptTemplate 渲染{query} {question_answer_context}StringaugmentedUserTextthis.promptTemplate.render(Map.of(query,userMessage.getText(),question_answer_context,documentContext));// ⑥ 替换用户消息交给 ChatModelreturnrequest.mutate().prompt(request.prompt().augmentUserMessage(augmentedUserText)).context(context).build();}3 doRerank()调用 RerankModel 打分、过滤、排序protectedListDocumentdoRerank(ChatClientRequestrequest,ListDocumentdocuments){if(CollectionUtils.isEmpty(documents)){returndocuments;}// 构造重排请求query 用户问题documents 初检结果RerankRequestrerankRequestnewRerankRequest(request.prompt().getUserMessage().getText(),documents);// 调用 DashScope Rerank APIRerankResponseresponsethis.rerankModel.call(rerankRequest);if(responsenull||response.getResults()null){returndocuments;// 重排失败则退回初检结果}// 过滤 minScore 按得分降序 取 Documentreturnresponse.getResults().stream().filter(doc-doc!nulldoc.getScore()minScore)// 默认 minScore 0.1.sorted(Comparator.comparingDouble(DocumentWithScore::getScore).reversed()).map(DocumentWithScore::getOutput).collect(Collectors.toList());}步骤作用RerankRequest(query, documents)把用户问题 初检文档列表交给重排模型rerankModel.call(...)调用百炼 Rerank API每条文档得到一个 relevanceScorefilter(score minScore)剔除低相关文档默认阈值 0.1sorted(reversed)按相关分从高到低排序4 after()回写检索结果OverridepublicChatClientResponseafter(ChatClientResponseresponse,AdvisorChainchain){// 把 before 阶段存入 context 的 qa_retrieved_documents 挂到 ChatResponse.metadata// 便于上层拿到「最终用了哪些文档」做溯源...}八、DashScopeRerankModel 调用链类路径com.alibaba.cloud.ai.dashscope.rerank.DashScopeRerankModelOverridepublicRerankResponsecall(RerankRequestrequest){// 1. 合并默认 optionsmodel、topN 等DashScopeRerankOptionsoptionsmergeOptions(request.getOptions(),defaultOptions);// 2. 组装 DashScope API 请求体DashScopeApiSpec.RerankRequestapiRequestcreateRequest(request,options);// input.query 用户问题// input.documents 各 Document 的正文列表// parameters.top_n 重排后保留条数// 3. HTTP 调用百炼 Rerank 接口带 RetryTemplateResponseEntityRerankResponseentitydashScopeApi.rerankEntity(apiRequest);// 4. 把 API 返回的 index relevanceScore 映射回 DocumentWithScoreListDocumentWithScoreresultsoutput.results().stream().map(result-DocumentWithScore.builder().withScore(result.relevanceScore()).withDocument(request.getInstructions().get(result.index())).build()).toList();returnnewRerankResponse(results,metadata);}组件职责DashScopeRerankAutoConfiguration读取spring.ai.dashscope.rerank.*注册DashScopeRerankModelBeanDashScopeRerankModel封装 HTTP 调用把 API 结果映射为DocumentWithScoreRetrievalRerankAdvisor编排「初检 → 重排 → Prompt → 生成」九、小结问题答案为什么 Rerank向量检索快但粗Rerank 对 topK 候选做精排提高注入 LLM 的上下文质量searchvsreRank前者只检索返回 Document后者走 Advisor 自动检索 重排 生成还要手动 similaritySearch 吗reRank不需要Advisor 的before()里已调用query 写谁search用 SearchRequest.queryreRank里 query 是占位以.user(...)为准核心类RetrievalRerankAdvisor编排DashScopeRerankModel百炼重排 API
返回列表