当前位置: 首页 > news >正文

企业级开源智能体系统 RAG优化升级

首先要申明 这不仅是一个rag系统,是一个智能agent系统可以搭载rag。rag系统是其中一个重要的环节。这个版本做的迭代是rag部分的优化。

rag系统的优化策略分为三步走,事前(如何分块) 事中(如何检索刀有效块) 事后(召回优化)。

优化思路:

技术原理
Query2Doc利用 LLM 生成伪文档,将查询与伪文档拼接后检索,弥补查询信息不足
HyDE(假设文档嵌入)生成假设性答案并嵌入,可选与原始查询嵌入取平均,用向量检索
子问题拆解将复杂问题分解为多个子问题,分别检索后回答
查询改写生成查询的转述版本,增加领域关键词提升召回率
Step-Back 提示通过少样本示例,将具体问题抽象为更一般性的问题,更容易匹配到相关文档
Multi-Query(多查询生成)LLM 从不同角度生成多个查询变体,分别检索后取并集去重,提升召回率
RAG Fusion(递归融合检索)Multi-Query + RRF 倒数排名融合,多查询共识的文档排名更高,提升排序质量
PRF(伪相关反馈)首轮检索 Top-K 结果中提取关键词扩展查询,再检索,数据驱动的自举策略
语义扩展(Embedding Expansion)在词向量空间中找查询关键词的近义词/相关词扩展查询,无需 LLM,速度快
上下文查询重构多轮对话中补全指代词和省略信息,生成独立可检索的完整查询
RaFe(排序反馈改写)小模型改写查询→检索→评估排序质量→反馈优化,形成可学习的改写闭环
技术原理
Auto-Merging(自动合并检索)多层树状索引,子块命中超阈值自动合并为父块,避免零散返回
Multi-Vector / ColBERT(多向量检索)一个文档对应多个 token 级向量,迟交互机制做词级精细匹配
知识图谱索引提取实体和关系建图,通过路径遍历支持多跳推理检索
RAPTOR(层级递归索引)递归聚类+摘要构建多层树,检索时适配不同抽象层级
元数据过滤索引向量索引附加结构化元数据,先硬过滤再向量检索,精准缩小范围
SPLADE(稀疏学习索引)学习型稀疏向量,兼得 BM25 关键词匹配 + 语义理解能力

以下是鄙人的一家之言,仅供参考!!!

通用型的系统,做文档上传->分块->自然语言问题->查询数据给模型->返回结果。

工程上优化的再好普适性的也就是60分往上,很难说做到所有场景都是90分。

最好的rag问答,是数据清洗完之后再分块,然后将通用性的问答沉淀到FAQ,这个才是首选,技术角度提升效果有限。

不要一个机器人挂不同业务的文档库,可以做一个简单的意图识别,不同的业务甚至同一个业务不同的模块都可以拆分为一个机器人,通过意图识别去路由对应的机器人进行问答。

这个是爱码士认为的最优解。以上优化大部分是非技术角度的,今天给大家带来技术角度的优化。是事中、事后的优化,事前部分的优化下个版本迭代,给大家提供一种思路,花钱能解决的事情千万别写代码。

此次的整体流程升级

用户提问后,系统经过4 个阶段从知识库中找到最相关的文档片段:

BM25 + 向量双路召回 → RRF 融合排名 → CrossEncoder 重排 → 置信度自适应加权出最终结果

1️⃣双路并行检索(BM25 + 向量语义检索)

想象你要在图书馆找一本书,有两种查找方式:

检索方式生活比喻技术原理优势劣势
BM25 全文检索关键词查字典 比如搜"苹果",找所有包含"苹果"的文档统计查询词在文档中出现的频率 (词频越高越相关)✅ 精准匹配关键词 ✅ 速度快❌ 不懂语义 ❌ “苹果手机"搜不到"iPhone”
向量语义检索意思找朋友 比如你说"想吃水果",朋友递给你苹果把文字转成向量(数字数组) 计算相似度(余弦相似度)✅ 理解语义 ✅ “苹果手机"能匹配"iPhone”❌ 可能忽略关键词 ❌ 计算慢

2️⃣RRF 智能排序融合(Reciprocal Rank Fusion)

问题:文档 A 在 BM25 排第 1,在向量检索排第 2,它应该是总榜第几名? 使用RRF算法的目的是将两个榜单合并

3️⃣CrossEncoder 高精度重排

什么是 CrossEncoder?

想象你是阅卷老师,有两种批改方式:

模型类型比喻工作原理精度速度
BiEncoder(向量检索用)快速初筛 给每份试卷单独打分分别计算 query 和文档的向量 然后算相似度⭐⭐⭐🚀 快
CrossEncoder(重排用)精细批改 逐字逐句对比把 query 和文档拼在一起 用注意力机制深度交互⭐⭐⭐⭐⭐🐢 慢
BiEncoder: query → [向量] ↘ 余弦相似度 → 0.85 文档 → [向量] ↗CrossEncoder: [query + 文档] → [深度交互] → 分数 0.92

4️⃣位置感知加权融合

这是什么意思?

根据文档在 RRF 榜单中的排名位置,动态调整"RRF 分数"和"重排分数"的权重比例。

🎯 **完整流程串联 **

场景:用户搜索"苹果手机多少钱"

Step 1: 双路并行检索
BM25 路径(关键词匹配): "苹果手机价格" → 第 1 名(包含完整关键词)"苹果报价" → 第 2 名(包含"苹果")"手机多少钱" → 第 3 名(包含"手机")向量路径(语义匹配):"iPhone 15 售价" → 第 1 名(语义等价)"苹果手机价格" → 第 2 名(语义 + 关键词)"华为手机报价" → 第 3 名(都是手机)两路同时跑,耗时从 100ms 降到 50ms!
Step 2: RRF 融合
文档"苹果手机价格": BM25 排名第 1 → RRF 分数 = 1/(60+1+1) = 0.0161 向量排名第 2 → RRF 分数 = 1/(60+2+1) = 0.0159 合计 = 0.032,排总榜第 1 因为是冠军,额外奖励 +0.05 → 最终 0.082文档"iPhone 15 售价": BM25 没进前 10 → 0 分 向量排名第 1 → 1/(60+1+1) = 0.0161 合计 = 0.0161,排总榜第 2取 Top30 进入下一轮...
Step 3: CrossEncoder 重排
对 Top30 逐个精细打分: "苹果手机价格" → 原始分 2.5 → sigmoid 后 0.92 → 高度相关 ⭐⭐⭐⭐⭐ "iPhone 15 售价" → 原始分 1.8 → sigmoid 后 0.86 → 高度相关 ⭐⭐⭐⭐⭐ "华为手机报价" → 原始分 0.3 → sigmoid 后 0.57 → 中等相关 ⭐⭐⭐
Step 4: 位置感知加权
Top1 "苹果手机价格": RRF 分数=0.082,重排分=0.92 最终分 = 0.082×0.75 + 0.92×0.25 = 0.292Top2 "iPhone 15 售价": RRF 分数=0.016,重排分=0.86 最终分 = 0.016×0.75 + 0.86×0.25 = 0.227Top15 "苹果官方公告"(后排逆袭): RRF 分数=0.008,重排分=0.95 最终分 = 0.008×0.40 + 0.95×0.60 = 0.573 ← 直接冲进前 3!

二、此次升级整体改动

2.1 新旧架构对比

【旧架构】单路向量检索 Query → Embedding → Milvus Search → TopK → Context【新架构】混合检索流水线 (8 Stages) Query ──┬→ Milvus 向量召回 ──┐ └→ BM25 关键词召回 ──┘→ 合并 → RRF融合 → 归一化 → 重排 → 自适应融合 → 截断 → 组装

2.2 新增模块总览

src/main/java/com/isy/rag/bootstrap/rag/retrieval/kb/├── assemble/│ └── KbContextAssembler.java # Stage8: 上下文组装器├── blend/│ └── ConfidenceAdaptiveScoreBlender.java # Stage6: 自适应分数融合器├── config/│ ├── ElasticsearchConfig.java # ES 客户端配置│ └── KbRetrievalProperties.java # 混合检索配置项 (rag.kb.hybrid.*)├── cutoff/│ └── KbResultCutoff.java # Stage7: TopK + 阈值双重截断器├── es/│ └── KbEsIndexService.java # ES 索引服务 (BM25 + IK分词)├── fusion/│ ├── KbRrfFusion.java # Stage3: RRF 融合器│ └── ScoreNormalizer.java # Stage4: Min-Max 归一化器├── merge/│ └── KbCandidateMerger.java # Stage2: 同chunk候选合并器├── model/│ ├── KbCandidate.java # 候选统一模型 (6类分数)│ ├── KbCandidateSource.java # 命中来源枚举 (VECTOR/BM25/BOTH)│ ├── KbRetrievalRequest.java # 检索请求 (含effective默认值)│ ├── KbRetrievalResult.java # 检索结果 (含阶段耗时统计)│ └── RelevanceLevel.java # 相关性等级枚举├── pipeline/│ └── KbHybridRetrievalPipeline.java # 8阶段流水线编排器├── rerank/│ ├── KbReranker.java # 重排器接口│ ├── KbRerankerConfig.java # 重排器 Spring 配置 (条件注入)│ ├── NoopKbReranker.java # 空实现降级│ └── RemoteKbReranker.java # 远程 CrossEncoder 重排└── retriever/ ├── KbRetriever.java # 召回器接口 ├── KbBm25Retriever.java # BM25 召回 (ES/MySQL双后端) └── KbVectorRetriever.java # 向量召回 (Milvus)

三、8 阶段流水线详细设计

Stage 1: 并行混合召回

设计思路:向量语义召回 + BM25 关键词召回并行执行,互不阻塞

实现要点

  • 使用CompletableFuture+ 固定2线程池并行执行
  • 异常隔离:单路失败不影响另一路,记录 warning 继续流程
  • 向量召回:通过EmbeddingModel生成查询向量 → Milvus ANN 检索 → 赋 vectorRank
  • BM25 召回:支持双后端(elasticsearch/mysql),通过配置切换
  • ES 后端:增量同步 chunk → ES BM25 + IK 分词,适合生产环境
  • MySQL 后端:全量加载 chunk → 内存计算 BM25,适合开发/测试

关键代码

  • KbVectorRetriever.retrieve()— 向量召回
  • KbBm25Retriever.retrieve()— BM25 召回,ES 失败自动降级到 MySQL

Stage 2: 同 Chunk 候选合并

设计思路:同一 chunk 被两路同时召回时,保留双路所有分数信息

实现要点

  • chunkId合并,KbCandidateMerger.mergeAll()处理多列表合并
  • 合并时使用coalesce策略:优先使用已有数据
  • 合并后自动更新matchedBy字段:VECTOR/BM25/BOTH
  • 双路命中的 chunk 在后续 RRF 融合中将获得更高分数

Stage 3: RRF 融合

设计思路:基于排名的融合 (Reciprocal Rank Fusion),公平合并不同检索器的结果

公式

rrfScore(d) = Σ weight_i × (1 / (k + rank_i) + bonus(rank_i))

创新点 — bonus 融入公式

  • 传统 RRF 只用1/(k+rank),本方案将 rank1/rank2-3 奖励直接融入公式
  • 避免了"先排序 → 加分 → 再排序"的二次排序问题
  • 默认参数:rrfK=60,vectorWeight=0.7,bm25Weight=0.3,rank1Bonus=0.05,rank2To3Bonus=0.02

为什么用 RRF 而非直接加权融合

  • 向量分数范围[0, 1],BM25 分数范围[0, +∞),量纲完全不同
  • RRF 基于排名计算,天然消除了分数量纲不一致的问题

Stage 4: RRF 分数归一化

设计思路:将 RRF 原始分数映射到[0, 1],为后续与 rerank 分数融合做准备

公式

normalizedRrf = (rrfScore - minRrf) / (maxRrf - minRrf)

边界处理

  • 所有分数相等时统一设为1.0
  • rrfScore为 null 的候选跳过归一化

Stage 5: CrossEncoder 重排

设计思路:对候选进行 query-document 对的语义精排,弥补检索阶段"只看单路"的不足

实现要点

  • 远程重排:调用bge-rerankerFastAPI 服务,Python 端已做 Sigmoid 归一化
  • Spring 条件注入:配置了reranker-url时创建RemoteKbReranker,否则NoopKbReranker
  • 降级策略:远程调用失败时自动降级,使用normalizedRrfScore作为rerankScore
  • 重排后为每个候选设置RelevanceLevel:高度相关(≥0.8) / 中等相关(≥0.5) / 一般相关(≥0.2) / 低相关(<0.2)

Stage 6: 自适应分数融合

设计思路:替代固定位置权重,根据 CrossEncoder 的置信度动态调整融合权重

核心洞察

  • Sigmoid 输出0.5表示模型最不确定
  • 0.5越远,模型越自信,应赋予更高权重

公式

certainty = 2 × |rerankScore - 0.5|rerankerWeight = baseRerankerWeight + certainty × adaptiveFactorrerankerWeight = clamp(rerankerWeight, minRerankerWeight, maxRerankerWeight)finalScore = normalizedRrfScore × (1 - rerankerWeight) + rerankScore × rerankerWeight

默认参数baseRerankerWeight=0.35,adaptiveFactor=0.35,min=0.30,max=0.75

效果

  • 当重排模型高度自信时(score 接近 0 或 1),重排权重最高可达 0.75
  • 当重排模型不确定时(score 接近 0.5),重排权重最低降到 0.30,更多依赖检索分数

Stage 7: TopK + 阈值双重截断

设计思路:双重防线过滤低质量分块,防止噪声进入 LLM 上下文

过滤条件(按顺序):

  1. finalScore >= finalScoreThreshold(默认 0.45)
  2. rerankScore >= rerankThreshold(默认 0.55,无 rerankScore 时跳过)
  3. 数量不超过maxChunks

Stage 8: 上下文组装

设计思路:将最终候选组装为 LLM 可消费的上下文 + 前端可展示的引用信息

实现要点

  • chunkId 去重(防止重复)
  • finalScore降序排列
  • 上下文格式:【文档N:xxx.pdf | chunk=3 | score=0.82】\n内容\n
  • 最大字符数限制(默认 8000)
  • 引用信息携带完整分数字段:vector_score,bm25_score,rrf_score,normalized_rrf_score,rerank_score,final_score,relevance_level,matched_by

四、数据模型设计

4.1 KbCandidate — 候选统一模型

一个KbCandidate在流水线中流转,逐阶段积累分数:

Stage1: chunkId, docId, docName, content, vectorScore, vectorRank, bm25Score, bm25Rank, matchedByStage2: (合并后) matchedBy 更新为 BOTHStage3: rrfScoreStage4: normalizedRrfScoreStage5: rerankRawScore, rerankScore, relevanceLevelStage6: finalScore

6 类分数的生命周期

分数产生阶段范围用途
vectorScoreStage1[0, 1]向量相似度原始分
bm25ScoreStage1[0, +∞)BM25 原始分
rrfScoreStage3(0, 0.1]RRF 融合原始分
normalizedRrfScoreStage4[0, 1]RRF 归一化分
rerankScoreStage5[0, 1]CrossEncoder 重排分
finalScoreStage6[0, 1]最终融合分(排序/截断依据)

4.2 KbCandidateSource — 命中来源

枚举值含义前端标签样式
VECTOR仅向量命中向量召回蓝色
BM25仅关键词命中关键词召回橙色
BOTH双路同时命中双路命中紫色

4.3 RelevanceLevel — 相关性等级

等级分数范围是否纳入前端标签
HIGHLY_RELEVANT≥ 0.8高度相关 (绿)
MODERATELY_RELEVANT≥ 0.5中等相关 (蓝)
SOMEWHAT_RELEVANT≥ 0.2一般相关 (黄)
LOW_RELEVANCE< 0.2低相关 (红)

五、配置体系设计

5.1 application.yml 配置

rag: kb: hybrid: enabled:true # 混合检索开关 vector-top-k:30 # 向量召回数 bm25-top-k:30 # BM25 召回数 bm25-backend:elasticsearch# BM25 后端 (elasticsearch / mysql) rrf-top-n:30 # RRF 融合保留数 rrf-k:60 # RRF 常数 k vector-weight:0.7 # 向量权重 bm25-weight:0.3 # BM25 权重 rank1-bonus:0.05 # Rank1 奖励 rank2-to3-bonus:0.02 # Rank2-3 奖励 rerank-enabled:true # 重排开关 reranker-url:http://localhost:8100/rerank# 重排服务地址 rerank-top-n:30 # 重排候选数 rerank-threshold:0.55 # 重排分数阈值 final-score-threshold:0.45# 最终分数阈值 base-reranker-weight:0.35# 基础重排权重 adaptive-factor:0.35 # 自适应因子 min-reranker-weight:0.30# 最小重排权重 max-reranker-weight:0.75# 最大重排权重

5.2 降级策略

外部服务配置调整降级行为
Milvus 不可用向量召回返回空列表,BM25 单路工作
ES 不可用bm25-backend: mysql自动降级到 MySQL 内存 BM25
Reranker 不可用注释reranker-urlNoopKbReranker生效,用归一化 RRF 分数代替
全部不可用hybrid.enabled: false回退到传统纯向量检索

六、前端展示增强

6.1 引用卡片增强

每个文档引用卡片新增:

  • 命中来源标签向量召回/关键词召回/双路命中(彩色标签)
  • 相关性等级高度相关/中等相关/一般相关/低相关(分级标签)
  • 最终分数:显示finalScore数值
  • 分数详情展开:显示完整分数链向量分 → BM25分 → RRF分 → 重排分 → 最终分

6.2 管理后台 Bot 配置增强

  • Bot 配置页面新增混合检索配置项展示
  • 追踪详情页新增KB_RETRIEVE节点的检索模式标识

七、可观测性设计

7.1 统一日志标识

全链路使用[KB检索]前缀,支持grep "[KB检索]"一键过滤:

日志标识打印内容
[KB检索][入口]query, kbIds, maxChunks
[KB检索][模式选择]hybridEnabled, bm25Backend, 选择模式
[KB检索][Stage1-向量召回]召回数, topK, Top3 chunkId+vecScore+docName
[KB检索][Stage1-BM25召回]召回数, topK, backend, Top3 chunkId+bm25Score+docName
[KB检索][Stage2-候选合并]合并后数, 双路/仅向量/仅BM25 统计
[KB检索][Stage3-RRF融合]输入/输出数, rrfK, weights, Top3 rrfScore+matchedBy
[KB检索][Stage4-分数归一化]候选数, 归一化分数范围 [min, max]
[KB检索][Stage5-重排]reranker名称, 候选数, Top3 rerankScore+level
[KB检索][Stage6-自适应融合]候选数, weights, Top3 normRrf+rerank+final
[KB检索][Stage7-截断]输入/输出/截断数, 阈值, 逐条最终候选摘要
[KB检索][Stage8-上下文组装]候选数, 引用数, 字符数
[KB检索][总出口]mode, confidence, chunkCount, duration
[KB检索][出口]confidence, refCount, contextLen, duration

7.2 链路追踪

每个 Stage 的耗时通过KbRetrievalResult.recordStageDuration()记录,通过TraceEventPublisher发布到追踪系统,在管理后台的追踪详情页可查看。


八、新增依赖

<!-- Elasticsearch Java Client --><dependency> <groupId>co.elastic.clients</groupId> <artifactId>elasticsearch-java</artifactId> <version>8.15.0</version></dependency><dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId></dependency><dependency> <groupId>jakarta.json</groupId> <artifactId>jakarta.json-api</artifactId> <version>2.1.3</version></dependency>

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

http://www.gsyq.cn/news/1438291.html

相关文章:

  • Webpack深度解析:从核心原理到React项目实战配置指南
  • 从中文屋到数学课堂:如何超越符号操作,培养真正的数学理解
  • 别再调包了!手把手教你用NumPy从零实现Householder QR分解(附完整代码)
  • 别再用老方法了!在浪潮服务器上给WinServer 2012 R2配RAID 1,这些BIOS设置细节才是关键
  • Infineon XC16x/XC2xxx调试端口配置与Flash编程实践
  • 想让LQR控制器跟踪轨迹?别急着调参,先搞懂‘增广系统’这个核心概念
  • 别再只听个响!手把手教你用AudioExpert和U 964搭建汽车RNC降噪测试系统
  • RT-Thread实战:用信号量、互斥量和事件集搞定嵌入式多线程数据同步(附完整代码)
  • 多智能体系统架构风险:从分布式系统视角看AI协同的工程挑战
  • 从‘发热怪’到‘冷静王’:我的DCDC电源模块升级实战(XL4003 vs 传统LDO)
  • 告别采样难题:手把手教你用差分运放给交流信号加个2.5V直流偏置(附Multisim仿真文件)
  • 告别串口!手把手教你用J-Link RTT在STM32上实现彩色日志打印与交互调试
  • Cadence Virtuoso新手避坑指南:手把手教你画反相器并跑通第一个仿真(附常见错误排查)
  • 基于电话线DTMF信号的远程电器控制系统设计与实现
  • Venusaur项目全面解析:高效句子嵌入模型的终极指南
  • Pyecharts 3D散点图实战:用‘点的大小和透明度’讲好你的数据故事
  • 手机电脑互传文件太慢?试试这个被遗忘的宝藏:HandShaker修改版保姆级安装配置指南(支持Win/Mac)
  • 手把手教你搞定Paradigm SKUA-GOCAD 2022.06.20安装与破解(附详细图文步骤)
  • 别再花钱买电话系统了!手把手教你用VMware虚拟机+FreePBX 16搭建企业免费内网电话(附静态IP避坑指南)
  • 告别老古董SigmaStudio!ADI新宠SigmaStudio+ 2.1图形化编程初体验(附21569开发板实战)
  • TurboQuant TQ3_4S格式详解:为什么它是Qwen3.6模型本地部署的最佳选择?[特殊字符]
  • MOSS-TTS-v1.5:革命性多语言AI语音合成工具完全指南
  • 避坑指南:Orange Pi 5 Plus启用硬件接口(UART/I2C等)时,90%的人会遇到的3个问题
  • zlibrary地址
  • 终极炉石传说模改工具:HsMod完整使用指南
  • JSP基础知识
  • Arm GIC-700中断控制器架构与虚拟化优化实践
  • SpringBoot项目里,@JsonFormat和@DateTimeFormat用错了?一个真实接口报错案例带你避坑
  • 别再只用默认模型了!手把手教你用SnowNLP训练专属影评情感分析模型(Python实战)
  • 医学图像分析新思路:当DETR遇见可变形注意力,如何解决白细胞检测的“特征稀疏”与“尺度不一”难题?