一、项目流程介绍1. 上半部分一、上半部分高频 FQA 来自业务咨询汇总经 CSV 导入 ERP 存入 MySQL日常单条数据增量录入(通过ERP新增/编辑功能)通过定时任务进行全量刷新。MySQL 数据通过定时全量或实时增量同步到 Redis。① 查询先查 Redisredis_client.get_data(fanswer:{query})② 命中(有Value)则直接返回return json.loads(data) 返回json③ 未命中(无Value)则进入 MySQL做 BM25 相似度计算先分词jieba.lcut(text)再计算BM25得分bm25.get_scores(query_tokenizer)将分数归一化获取softmax得分softmax_scoresself._softmax(scores)根据softmax得分获取最高分的索引idmax_idsoftmax_scores.argmax()再根据最高得分的索引id获取最高得分max_scoresoftmax_scores[max_id]④ 当分值达到一定阈值(如: 0.85) 就获取答案并返回根据最高得分的索引id获取数据库中原始问题original_questionself.original_questions[max_id]并根据问题查询答案answermysql_client.fetch_answer(original_question)同时将用户问题与答案回写至 Redis(redis_client.set_data(fanswer:{query}, fetch_answer)、client.set(key, json.dumps(value))转字符串)⑤ 低于阈值说明不是高频问题走 Milvus 做 RAG。这样既保证高频 ms 级响应又避免低频问题被错误匹配。“整体是「高频 MySQLRedis 快路径低频 Milvus 准路径」的分层设计。”Q为什么 Redis 命中就直接返回MySQL 还要 BM25Redis不负责相似度的判定它存的是已验证过的、通过了BM25 判定的 Query答案MySQL 负责首次或缓存过期的BM25相似度检索通过后把结果缓存至Redis。Redis 不负责「像不像」的判定只负责「之前算过没有」的加速。QRedis「命中」一般如何判定本项目中key ‘answer:{query}’ 精确匹配。进行 精确 / 归一化精确匹配最常见用 normalize(query) 作为Key即Key normalize(query) 查Redis缓存2. 下半部分二、下半部分整体思路是存储侧 先加载文档再进行解析、切块、向量化后入库检索侧先做意图识别专业问题走向量检索粗排 精排取 TopK 片段作 Context再交给 LLM 生成答案。2.1 数据存储数据存储从文档到向量库先加载文档再通过 OCR如 PaddleOCR 识别文件中的文字和图片解析成一个长字符串可能达万字级。再进行父子块切分子块用于精准检索、父块用于完整回答切分后的每个块即 Document仍是文本向量化稠密 稀疏后写入 Milvus每条记录通常包含① 稀疏向量如 BM25 类做关键词检索 ② 稠密向量来自 Embedding做语义相似度检索 ️③ 文本字符每个 Document 的原文本④子块 / 父块 及关联字段便于子块检索、父块响应稠密 稀疏支持混合检索语义 关键词提高召回质量。2.2 数据检索数据检索从 Query 到 LLM 回答用户 Query 先经 BERT 进行意图识别① 通用问题走 通用LLM(不查本地知识库不做 Embedding 和 Milvus 检索)② 专业问题对 Query Embedding与库中文档向量做 Cosine 相似度检索通过粗排混合检索召回后再精排语义过滤剔除与 Query 无关的片段取与用户问题 语义最相关的TopK文档片段 作为 Context将 Context 原始 Query 拼接作为 LLM 输入由 LLM 生成最终 Response。QMySQL 和 Milvus区别1. MySQL 是关系型数据库存结构化数据靠 SQL 做精确查询和条件过滤适合业务数据、事务、增删改查。MySQL 结构化 SQL 精确查2. Milvus 是向量数据库存 Embedding 向量靠相似度检索如 Cosine找语义相近的内容适合 RAG、语义搜索、推荐等非结构化检索。Milvus 向量化 相似度 语义搜一句话MySQL 解决「查得准」Milvus 解决「搜得像」。Q什么是结构化数据1. 结构化数据有固定格式、固定字段能按 行和列 整齐存放的数据。例子用户表id | 姓名 | 手机号2. 非结构化PDF、Word、图片、长文本没有固定字段不好直接用 SQL 查3. 半结构化JSON、日志有一定格式有字段、有层级不是表但能看出里面有哪些字段Q关系型数据库和非关系型数据库1. 关系型数据库数据存成表行 列表与表可通过外键关联如MySQL2. 非关系型数据库NoSQL不拘于表结构 不必统一列名每条数据格式可以灵活不同如Redis键值缓存、Milvus向量语义检索Q为何父子切块如果只切大块一个块里多个知识点检索不精准只切小块上下文不足回答不完整。为兼顾检索精度与回答完整性对长字符串做两级切分细粒度子块Child Chunk用于精准检索 负责找、粗粒度父块Parent Chunk用于完整回答 负责答 — 即检索用子块响应时按答案长度选择短答案用子块答案过长如 100 字用父块。Q为什么检索用子块、回答用父块子块粒度小Embedding 更聚焦召回更准父块上下文完整LLM 生成更连贯。检索定位知识点回答需要足够上下文。Q稠密和稀疏向量分别解决什么稀疏向量Sparse Vector如 BM25 类做关键词检索稠密向量Dense Vector来自 Embedding做语义相似度检索实际项目中常做 混合检索Hybrid Search稀疏向量稠密向量兼顾语义理解与关键词精确匹配。Q粗排和精排区别【降低大模型幻觉的场景一】粗排混合检索召回后精排语义过滤剔除与 Query 无关的片段保证 Context 质量降低幻觉。粗排混合检索召回用(稠密 稀疏向量)混合检索快速召回大量候选精排语义过滤精排语义过滤剔除与 Query 无关的片段保证 Context 质量降低幻觉。Q如何解决幻觉从 路由 → 检索 → 过滤 → 生成 及 FAQ 等全链路控制幻觉1. 路由层意图识别限定回答范围。专业问题必须走本地知识库通用问题走通用 LLM。避免该查库的专业问题乱走通用 LLM。2. 检索层RAG grounding用检索到的真实文档片段作 Context。专业问题先从 Milvus 检索到与用户问题 语义最相关的TopK文档片段 作Context再将 Context 原始 Query 拼接送入 LLM让它主要基于这些片段组织答案让答案有文档依据。避免模型臆造。3. 过滤层精排过滤无关 Context。 粗排混合检索召回后再精排语义过滤剔除与 Query 无关的片段保证Context质量降低幻觉。避免脏 Context 进 LLM 导致「顺着错误材料编故事」。4. 生成层Prompt 拒答。仅依据给定文档Context 回答无依据则拒答。不猜测、不引入 Context 外知识避免模型越界、过度补全。5. FAQ 层高频 FAQ 阈值拦截。MySQL BM25 低于阈值则说明不是高频问题、不强行返回答案转 RAG。避免高频误匹配、答非所问。总结该查库的查库FAQ 层、该过滤的过滤过滤层、该拒答的拒答生成层——把 LLM 限制在正确、相关、有依据的 Context里。Q精排和 Prompt 区别精排是 进 LLM 前 进行Context过滤进 LLM 前过滤Prompt 进 LLM 后 约束模型生成行为进 LLM 后约束。一个洗输入一个管输出。Q整个流程中哪块最耗时如果是数据入库最耗时的是OCR 解析 和 批量向量化属于离线任务不直接影响在线查询 RT但会影响文档更新时效。在线查询里最快的是 Redis 命中毫秒级返回。Redis 未命中走 MySQL BM25一般是毫秒到几十毫秒仍属于高频快路径。进入 RAG 后耗时明显上升LLM 生成 Response 通常是最大瓶颈秒级检索侧里精排和Milvus 混合检索 Query Embedding 次之BERT 意图识别相对最轻。离线入库时OCR和批量向量化最耗时。所以性能优化上高频靠 Redis 缓存RAG 靠控制 TopK/精排规模、Embedding 缓存、LLM 流式输出等手段。