本文分享了作者基于知识库构建问答系统的实战经验详细拆解了从文档处理、清洗、切块到索引增强、向量化和混合检索的完整流程。作者强调了文档质量、切块方式、标题利用和Query Rewrite对RAG效果的关键影响并指出数据和检索设计比模型更重要。此外文章还介绍了开源项目地址和在线体验环境为有RAG实践需求的读者提供了宝贵的参考价值。这段时间我基于知识库做了一套问答系统。一开始的想法其实很简单 把已有的文档用“问答”的方式更方便地用起来。做的过程中也踩了一些坑。有些地方效果还可以有些地方也还有不少可以继续优化。这篇文章主要是把这次实现过程中的一些做法整理一下。如果你刚好也在做 RAG或许能有一点参考价值。 整体思路一个简单的 RAG 流程拆解这套实现主要是基于Spring AI Alibaba ReactAgent来做 Agent 编排 向量检索使用的是Qdrant。如果从流程上看可以拆成四个阶段文档处理 → 索引增强 → 检索 → 问答生成对应到实现大概是文档处理语雀 / Markdown → 清洗 → 切块索引增强提取标题、关键词、摘要检索向量检索 BM25 融合排序问答Query Rewrite Agent 多次检索 生成答案这几部分拼在一起就是一条比较完整的 RAG 链路。 第一步先解决“文档从哪里来”知识源我这边主要用了两类语雀知识库本地 Markdown 文档这里有一个小处理 不只是拿正文 会把目录结构一起保留下来因为在后面切块的时候目录其实就是天然的上下文信息。⚙️ 第二步文档清洗这一层比较基础但有必要文档拿到之后我没有直接做 embedding。而是先做了一轮清洗去掉无关图片去掉注释和杂质保留代码块统一成 Markdown 文本这一层不复杂但如果不做后面的问题会被放大。✂️ 第三步切块Chunking 比想象中更重要RAG 里一个很容易被忽略的点是 文档怎么切很多实现是固定 token 切分或者简单按段落切但这样容易有一个问题 上下文被切断我这边采用的是目录结构 字数控制大致规则内容不长 → 一个块太长 → 按一级标题切还长 → 按二级标题再长 → 按段落核心逻辑类似这样ListMarkdownUtils.ChunkResult chunks MarkdownUtils.splitWithContext(content, docContext);for (MarkdownUtils.ChunkResult chunk : chunks) { FeaturePoint point extractFromChunk(chunk);}这里我比较在意一点每个 chunk 都必须有“能承接上下文的标题”不是为了好看而是为了表达来自哪篇文档属于哪个目录当前在讲什么可以理解为 每个 chunk 是一个“最小语义单元”而不是一段随机文本 第四步索引增强不是只存正文切块之后我没有直接入向量库。而是做了一步“信息补充” 提取关键词 摘要这里其实有一个小调整过程一开始我是用 Agent 来做关键词提取的。但后面用下来做了一次改动关键词提取改成了代码实现原因比较实际关键词提取更偏规则型任务用代码更稳定、可控调整成本也更低摘要这块如果有需要仍然可以用模型辅助。最终会把这些信息一起存下来QaPair pair QaPair.builder() .featureTitle(point.title()) .featureKeyword(point.keywords()) .featureSummary(point.summary()) .featureContent(point.content()) .build();这里一个比较直观的体会是不是所有环节都适合用 Agent规则明确的地方用工程逻辑反而更合适。 第五步向量化拼的不只是内容在向量化时我没有只用正文。而是把这些信息拼在一起 标题 关键词 摘要 正文再写入 Qdrant。原因是 在企业场景里很多关键信息其实在标题和关键词里比如菜单名字段名功能名如果只 embedding 正文反而容易丢信息。可以简单理解为 我不是在存“内容”而是在存“更容易被检索到的内容” 第六步检索向量 BM25 的混合检索检索这一层我没有只用向量检索。因为在实际场景里纯向量检索会有一些问题对精确词不敏感有时候语义相关但不准确所以这里做了一层混合检索向量检索负责语义召回BM25负责关键词命中RRF对多路结果做融合排序核心逻辑类似这样ListDocument vectorResults performVectorSearch(query, vectorTopK, similarityThreshold);ListDocument keywordResults performKeywordSearch(query, bm25TopK);ListDocument mergedResults mergeWithRRF(vectorResults, keywordResults, finalTopK);这样处理之后在我的测试场景里 命中效果会相对稳定一些尤其是一些“精确名称类问题”。 第七步Query Rewrite多轮对话的关键在多轮对话场景下我加了一层 Query Rewrite。用户问题不会直接进入检索而是先改写 当前问题 最近几轮对话 → 一个完整问题比如用户说“这个怎么配”“为什么不行”如果直接查基本命不中。改写之后会变成一个更明确的问题再进入检索。本质上这一步是在做Query Reformulation查询重写用来解决对话中的上下文缺失问题。 第八步让 Agent 参与“检索过程”最后才进入问答阶段。这里我没有做成 检索一次 → 直接生成答案而是让 ReactAgent 可以多次调用检索工具比如换关键词再查多轮查再组织答案核心注册方式类似return ReactAgent.builder() .name(QA-Chat-Agent) .model(chatModel) .methodTools(vectorSearchTool) .build();这种方式更接近 “在查资料”而不是“直接生成” 一些实践中的体会仅供参考这部分不算结论只是这次实现的一些感受 文档质量会直接影响最终效果 切块方式对检索影响很大 标题不是装饰而是检索的一部分 多轮对话里Query Rewrite 很有必要 Agent 不一定越多越好分工清晰更重要如果用一句话总结RAG 里模型很重要但数据和检索设计更关键 开源 体验这套实现我整理了一下也开源了一版 GitHub 地址https://github.com/liochaoo/yuncheng-agent-qa Gitee 地址https://gitee.com/liochaoo/yuncheng-agent-qaREADME 里包含了完整的流程说明包括文档处理与切块策略向量化与 Qdrant 存储混合检索实现Query Rewrite 逻辑Agent 调用链路如果你在做类似的 RAG 场景可以参考或改造。同时我也部署了一版在线体验的环境 https://www.yunbangong100.com:31190/agent假如你从2026年开始学大模型按这个步骤走准能稳步进阶。接下来告诉你一条最快的邪修路线3个月即可成为模型大师薪资直接起飞。阶段1:大模型基础阶段2:RAG应用开发工程阶段3:大模型Agent应用架构阶段4:大模型微调与私有化部署配套文档资源全套AI 大模型 学习资料朋友们如果需要可以微信扫描下方二维码免费领取【保证100%免费】配套文档资源全套AI 大模型 学习资料朋友们如果需要可以微信扫描下方二维码免费领取【保证100%免费】