RAG智慧问答项目
智慧问答系统
核心技术:
Python+LangChain+Milvus+BGE-M3+BGE-Reranker-Large+bert-base-chinese微调+Qwen2.5-14B (INT8)+光明AI大模型+PaddleOCR+MySQL+Redis+FastAPI+Docker+Vue3+Typescript
项目描述:
针对电力员工查阅安规、运规时面临的三大核心难题——通用大模型对电力术语易产生幻觉、千亿参数光明大模型API响应超60秒、长尾问题未被知识库覆盖——本项目构建了一套基于RAG的电力规程问答系统,实现"提问→检索→生成"全流程自动化,千亿参数光明大模型+人工专家座席兜底,在保证100%回答率的同时兼顾秒级响应。
项目职责:
架构设计:负责系统整体架构设计,构建L1 Redis缓存、L2 BM25关键词、L3 Milvus语义检索、L4光明大模型、L5供电服务指挥中心人工专家座席兜底的五级检索架构;
知识库构建:设计Parent-Child分块策略(子块300/父块1200/重叠50),完成50+座变电站运规资料的迁移验证;
检索优化:基于BGE-M3实现稠密+稀疏混合检索(WeightedRanker 1.0/0.7),引入BGE-Reranker-Large精排,实现4种检索策略的LLM动态路由;
意图识别:微调bert-base-chinese实现意图二分类(准确率94%),实现通用问题与专业问题的智能分流;
质量评估:引入RAGAS评估框架,从答案忠实度、答案相关度、上下文召回率等维度量化系统表现,驱动迭代优化。
项目亮点:
五级漏斗检索:缓存命中率65%,平均响应秒级,光明大模型+人工专家座席兜底保证100%回答率;
混合检索+精排:相比纯语义检索,混合检索+精排后Top2 相关性显著提升,基于用户反馈统计的答案可用率达95%+;
分块策略优化:基于文档结构分析确定300/1200最佳比例,检索精度与上下文完整性兼顾;
意图驱动路由:二分类准确率94%,无效检索得到根本控制,系统负载显著降低;
动态策略路由:基于Qwen2.5-14B对4种检索策略动态选择,有效保证了长尾问题的召回。
项目成果:
完成全州50+座110kV及以上核心变电站安规、运规资料迁移入库验证;
员工获取答案时间从原来的分钟级(自行查阅文档+光明AI大模型)缩短至:高频问题(缓存/关键词命中)秒级返回答案(占比~65%),常规RAG问题首token约5秒以内(占比~32%),长尾兜底问题(占比~3%)30-60秒,显著降低了操作人员对专业知识的获取时间,为安全生产真正赋能。
通过 RAGAS 离线评估,混合检索+精排在 context_precision / recall 上均优于单一稠密检索;
实际业务场景中,基于线上用户好评/差评反馈统计,答案可用率达 95%+。
项目整体架构
一、五级命中策略
L1 Redis缓存:query先查Redis问答对高频缓存(TTL7*24h),命中直接返回给用户,未命中进入下一级
问题1:多轮记忆上下文是如何管理的?
Redis命中同时通过 Redis Hash 处理用户的(query+userid)后得到 session_id
通过session_id更新当前上下文对话到 Redis(TTL 30min)仅保留最近5轮,
此处redis和mysql不用存储本次QA,默认库内是有本次QA数据的,之前rag和光明大模型缓存
问题2:rag库或者光明大模型更新了,那之前缓存的旧数据怎么办?
rag库或者光明大模型更新,我们默认会清理redis和mysql中的缓存数据,重新走一套新的缓存
问题3:redis的TTL选择7*24h和 30min的意义?
TTL7*24h:因电力标准规范一般比较固定,默认TTL7*24h内规则不会改变
TTL30min:多轮上下文记忆sessionid来自于query+userid,默认一轮对话最多30min
问题4:为什么使用redis存储当前上下文?
考虑到高并发能力和mysql的读写延迟(redis比mysql块10倍)
L2 BM25关键词:利用MySQL问答对进行BM25关键词匹配,阈值得分≥0.9直接返回答案给用户(同时异步更新当前对话上下文到 redis),<0.9进入下一级
问题5:L1和L2为什么不交给大模型整合输出?
我们出于返回loading性能考虑:redis返回速度性能比大模型的再加工快了太多了
成本考虑:多调用一次Qwen,算力和时间都是成本
幻觉风险考虑:LLM的再加工可能导致出现幻觉
问题6:为什么把BM25阈值定在 0.9?
因为电力场景要求高精度,不能乱答。通过日志分析发现,0.9 以上命中后用户满意度很高,低于 0.9 的大概率是用户换了一种说法,我们就放行进入下一级语义检索。核心原则就是:宁可多查一次,也不能给错答案。”
问题7:BM25是什么?
BM25 是 TF-IDF(词频\逆文档频率) 的进阶版,
加了两项优化:一是限制词频的无限增长,二是对长文档进行惩罚。这样算出来的分数更合理。
L3 意图识别+Milvus检索:
意图识别(bert-base-chinese二分类,准确率94%)
通用问题→Qwen2.5-14B(INT8)整合答案,直接返回
专业问题→Qwen2.5-14B进行问题改写,分化为4种策略(直接/子查询/HyDE/回溯)
改写后query对接Milvus:粗排(稠密+稀疏混合检索,WeightedRanker 1.0/0.7)→精排(BGE-Reranker-Large)→返回TopK
结合redis近5轮上下文经Qwen2.5-14B整合后返回结果,
同步更新redis上下文缓存,redis问答对缓存,mysql问答对缓存
问题8:为什么选择bert-base-chinese做二分类?
第一,任务特性。我们只需要区分 通用问题 和 专业规程问题,这是一个相对简单的语义分类任务,不是复杂推理,BERT 参数量(1.1亿)足够胜任。
第二,效果验证。我们在大模型生成的5000条标注数据上微调,准确率、召回率、F1值均在93%→94%之间,完全满足业务需求。
第三,成本优势。BERT 推理只需10ms,可以CPU部署,几乎零成本。如果换成大模型做分类,每次调用要2秒以上,成本高几十倍,完全没有必要。
我们也考虑过其他模型,比如 RoBERTat,效果会有1-2个点的提升,但推理耗时略高,考虑到我们94%的准确率已经够用,所以保持 bert-base-chinese 不变。”
问题9:为什么选择Qwen2.5-14B(INT8)
我们选择 Qwen2.5-14B 并做 INT8 量化,主要基于以下考虑:
第一,效果与成本的平衡。14B 参数量在开源模型中属于效果最好的梯队之一,中文理解能力出色。我们对比过 7B 和 14B,7B 在处理复杂问题时生成质量明显弱一些,所以最终选了 14B。
第二,INT8 量化解决了显存瓶颈。FP16 需要 28GB 显存,超越了 RTX 4090 的 24GB 上限。量化到 INT8 后,显存降到 14-16GB,效果损失不到 2%,却可以部署在单卡上,硬件成本降低了 50% 以上。
第三,职责分离。简单任务(意图分类)用 BERT 做,复杂任务(改写、生成)才用 Qwen14B。这样既保证了复杂问题的回答质量,又控制了整体成本。
第四,国产化适配。Qwen 是国内主流开源模型,满足电力行业信创要求。”
问题10:介绍以下子查询/HyDE/回溯?
子查询 复杂问 → 拆成多个子问, 比如乔丹和科比有什么区别?
HyDE(假设文档检索)问题 → 生成假设答案 → 用答案检索, 比如gpt的变体有哪些?
回溯问题检索 复杂问 → 简化为更基础的问题 冰箱可以装下大象吗?
问题11:为什么选择milvus,还有哪些选择
Milvus 原生支持稠密+稀疏混合检索,与我们的 BGE-M3 比较契合, BGE-M3可生成归一化后的稠密和稀疏向量,索引可以通过配置内积处理(归一化+内积等价于余弦), 能够同时保证语义理解和关键词匹配的召回率, FAISS 适合本地验证,Chroma 更偏向轻量开发,企业级生态还是的milvus,尤其契合电力场景的稳定性
Milvus索引类型:
Milvus索引原理是聚类+倒排索引,聚类负责快速划定目标区域,倒排索引保证了在指定目标区域内快速找到目标向量
FLAT:暴力搜索,内存占用高,查询极慢
IVF_FLAT:通过K-means聚类算法将空间划分为nlist个区域,查询只查询指定的nprobe个区域,内存占用中等,查询极快,聚类保证了区域的查询速度,倒排索引保证了向量查询速度
IVF_SQ8:在IVF聚类基础上再进行量化处理,内存占用低,查询更快,但有查询精度丢失
IVF_PQ:在 IVF 聚类基础上,使用乘积量化进行超高压缩
考虑到项目数据量在10万量级,且对召回率和稳定性要求极高,最终选用了 IVF_FLAT。它与 HNSW 相比内存占用更低,与 IVF_SQ8/PQ 相比能保证无损的召回率,与 FLAT 相比则大幅提升了查询速度。我们根据官方的经验,设置 nlist=128 的初始值
问题12:为什么选择BGE-Reranker-Large,还有哪些选择
从中文优化、本地部署、性价比三个维度 ,我们也考虑了其他模型, 最终我们还是考虑选择BGE家族的rerank模型, 与 BGE-M3 形成 BGE 全家桶,技术栈统一,维护成本低, 当然这个结论是我们老大定的
问题13:Qwen策略改写超时(3s)或失败如何处理?
直接降级到直接检索策略
L4 光明大模型:Milvus未返回TopK时(服务挂掉或未命中),调用光明AI大模型查询,查询成功将光明AI大模型查询结果直接返回给用户,同步更新redis上下文缓存,redis问答对缓存,mysql问答对缓存,返回失败或者返回超时进入L5专家座席兜底
L5专家兜底:当光明大模型未返回任何信息时,由Qwen2.5-14B大模型结合当前上下文对话内容,提示用户知识库查询无结果,并向用户提供供电服务指挥中心专家座席联系方式
同步更新redis上下文缓存
(后期我们这里打算项目二期升级,集成agent,结合mcp架构自动下发专家咨询工单)
二、文档入库操作
文档加载:支持PPT/Word/PDF/图片等格式,提取段落、表格文本;图片使用PaddleOCR提取文字(面积占比>50%的图片处理, 性能与效果的综合考量)
分块策略:自定义ChineseRecursiveTextSplitter(加入中文标点识别,先打散再贪心合并)。父块1200/子块300/重叠50(基于文档分析:段落平均300,每标题下4-5段)
向量化入库:BGE-M3 embedding将子块向量化入库,子块metadata冗余存储父块信息(空间换时间)
三、文档查库操作
Query向量化:策略处理后的query经BGE-M3 tokenizer转为向量
Milvus混合检索:同时检索稠密向量+稀疏向量(均归一化,直接内积计算相似度),加权融合得TopK
Rerank精排:BGE-Reranker-Large对粗排结果精排,得到最终TopK
结果返回:从子块metadata中取出父块内容返回(语义更完整)
用户反馈闭环:每次问答结束后提供“好评/差评”点赞按钮入口,反馈数据落日志,关联session_id、query、BM25得分、答案来源(L2/L3/L4)、用户评价等字段,用于后续阈值校准与Bad Case分析
问题14:Bad Case有哪些:
一是长答案生成偏慢(用户觉得等得久),二是极少数 RAG 未命中导致走了光明兜底。
问题15:长答案慢,你们打算怎么优化?
前端对长答案增加进度提示,降低用户焦虑;考虑用小模型(如 Qwen2.5-7B)先给摘要,再详细展开;
问题16:RAG 未命中怎么解决?
知识库确实缺失:定期分析未命中 query,反向补充文档或优化 chunk;
检索没召回:分析未命中案例,针对性调整检索策略(如放宽阈值、调整权重、优化 query 改写 Prompt)。
RAGA评估专题
引入RAGAS评估框架,从答案忠实度、答案相关度、上下文召回率等维度量化系统表现,驱动迭代优化。
问题17:介绍一下你们的评估闭环?
我们引入了 RAGAS 评估框架对系统进行量化评估。主要评估四个指标:
忠实度faithfulness:rag答案是否基于检索到的上下文,判断有没有幻觉;
答案相关性answer_relevancy:rag答案与问题是否匹配;
上下文相关性context_precision:rag检索到的内容是否与问题相关(精度);
上下文召回率context_recall:rag检索到的内容是否覆盖了必要信息(召回率)
内测期,我们利用电网现存的安规题库,抽取500条真实样本,包含QA,将500个Q通过电网VPN放到内网部署的RAG系统去跑,然后拿到500组数据,对象中的属性包括
question:真实问题
ground_truth:题库标准答案
answer:RAG生成的答案
contexts: rerank模型召回的topk上下文
拿到数据集后,我们在外网选取不同于qwen2.5:14b和BGE-M3的线上大模型和 embedding模型,避免运动员当裁判的情况发生,然后加载ragas 的evaluate,得出
faithfulness: 0.92, 上线标准至少0.9,保证没有出现幻觉胡说,不撒谎
answer_relevancy: 0.88,上线标准至少0.85,保证rag答案切题,不跑题
context_precision: 0.85,上线标准至少0.8,保证rag检索精度高,少噪声
context_recall: 0.80 上线标准至少0.8,保证rag检索内容大部分覆盖必要证据,少遗漏
电力行业要求较高,各指标的上线标准必须达标才可上线
问题18:为什么用不同的 LLM 做评估?
为了避免运动员当裁判。如果用 Qwen2.5-14B 评估自己生成的结果,分数可能会虚高。所以我们在外网选用了不同的模型(如 deepseek )作为评估裁判,确保评分的客观性。
问题19:500 条样本够吗?怎么保证代表性?
500 条是内测阶段的样本量,覆盖了安规题库中的主要场景。我们按照文档章节分层采样,确保各个知识点都有覆盖。上线后会持续从线上日志采样,逐步扩充。
问题20:如果某个指标不达标,怎么优化?
faithfulness 低 → 有撒谎, 优化 Prompt,要求“不确定就说不知道”
answer_relevancy 低 → 有跑题, 检查检索结果是否相关,优化 Rerank(调权重、换模型) 优化 Prompt,强调“只回答与问题相关的内容”
context_precision 低 → 有噪声, 提高检索阈值,加强 Rerank 力度,减少召回数量
context_recall 低 → 有遗漏, 调整分块策略,增加多路召回
开发FastAPI接口,支持REST API和WebSocket流式输出
问题21:为什么选择FastAPI?
接口层用 FastAPI 实现,选它是因为异步高性能、自动生成文档、参数校验方便。REST API 处理同步请求,WebSocket 处理流式输出——大模型逐 token 生成时实时推给前端,用户边看边等,体验更好。选 WebSocket 不选 SSE,是因为它支持全双工,后续可以扩展用户取消生成等控制指令;
FastAPI 提供 REST API 和 WebSocket 两种接口。REST 处理同步查询,WebSocket 实现大模型流式输出,逐 token 推送,提升用户体验。
问题22:有没有遇到感觉不好处理的的问题
RAGAS 评估框架以及如何优化可以达到生产上线标准
问题23:你们这个系统表现方式是如何集成的?
该项目是集成在公司内网环境pc端的知识问答系统,
入口内嵌在原有供电服务指挥系统的一个知识查询模块
问题24:实际模型的训练时常,显存情况,内存情况?(待补充)
训练阶段:bert-base-chinese 在 5000 条标注数据上微调约 20-30 分钟,显存占用 2-3GB
推理阶段:Qwen2.5-14B (INT8) 单次推理显存 14-16GB;
整体系统可部署在单张 RTX 4090 (24GB) 上,无需多卡
成本优势:通过 BERT 分流 60% 通用问题,实际 Qwen 调用量降低 60%+,显著节省算力成本
