Skip to content

在 AI 超级智能体项目中你是如何实现 RAG 知识库构建的? ​

  • 标签:后端、编程导航

🏛 业务架构师 ​

我的 RAG 知识库构建流程按**"知识运营流水线"**设计(不是一次性工程):

1. 知识接入:多源文档(Markdown、PDF、网页、Confluence)——文本抽取是第一道质量关,PDF 表格抽取的质量直接决定后续答案质量(垃圾进垃圾出)。

2. 清洗与切分:去噪(页眉页脚、乱码)后按语义切分——我的策略是**"标题层级 + 段落边界 + 512 token 滑动窗口(10% 重叠)"**:切太碎丢失上下文、切太大稀释语义,切分粒度是检索质量的第一杠杆,我按文档类型分别调优(FAQ 按问答对切、手册按章节切)。

3. 元信息标注:自动 enricher 打关键词、来源、时间、分类标签——元数据是检索过滤与权限控制的抓手。

4. 向量化入库:Embedding 模型批量化(降成本提吞吐)写入向量库。

5. 运营闭环(业务架构的重点):知识更新机制——文档变更触发增量重建(否则知识库三个月就过期,用户对"过时答案"的信任崩塌是 RAG 产品最大的死因);权限模型前置——检索时按用户可见范围过滤,不能让搜索越权泄密;质量反馈——用户点踩/纠错回流,驱动切分与检索策略迭代。

踩过的坑:早期全库一套切分参数,运营吐槽"答非所问"——后来按知识类型分库分策略(制度文档 vs 操作手册),命中率显著提升。RAG 的本质是知识管理工程,模型只是末端环节。

🏗 系统架构师 ​

我按"离线建库 → 在线检索 → 增量维护"三段讲 RAG 知识库构建:

1. 离线建库(ETL 管道):

  • 读取:TikaDocumentReader 支持 PDF/Word/HTML/Markdown 等;文档源对接对象存储/本地目录;
  • 清洗:去页眉页脚、乱码处理、格式转换(表格转 Markdown 语义保留);
  • 切分:TokenTextSplitter 按语义单元分段(chunk size 500~1000 token,overlap 10%~20% 防语义割裂);标题层级感知的切分(不把一章切开)效果更好;
  • 元信息标注:来源、标题、章节、关键词(KeywordMetadataEnricher LLM 自动提取)——用于后续过滤与溯源;
  • 向量化:EmbeddingModel(text-embedding 系列)批量生成向量(批处理降成本);
  • 入库:VectorStore(我用 pgvector——与业务库同栈省运维)+ 原文表(chunk 全文、元信息 JSONB)。

2. 在线检索:问题 → 向量化 → 相似度 Top-K(K=5~10)→ 阈值过滤 → 上下文拼接(附来源引用)→ 生成。

3. 增量维护:新文档走同一管道入库;文档按 content_hash 去重,更新时删旧 chunk 再插新;定期全量重建防向量漂移。

关键调优点:切分粒度与 K 值对效果影响大于模型本身;检索前加多查询扩展/查询重写提升召回;低质 chunk(太短/无信息)入库前过滤。知识库质量 = 数据治理质量,RAG 上限在数据工程。

💻 全栈开发专家 ​

我的 RAG 知识库构建是一条异步 ETL 流水线(文档上传后立即返回任务 id,后台处理完回写状态):

text
上传文档(docx/pdf/md/网页)
 → ① 解析:TikaDocumentReader 抽取文本(PDF 扫描件先过 OCR)
 → ② 清洗:去页眉页脚/目录/乱码,格式归一
 → ③ 切分:TokenTextSplitter(分段 + overlap,保留标题层级进 metadata)
 → ④ 元信息增强:
      KeywordMetadataEnricher 自动提取关键词(用于检索过滤)
      记录 source/文档类型/章节标题等业务元数据
 → ⑤ 向量化:EmbeddingModel 批量转向量(分批 20 条调用,省配额提速)
 → ⑥ 入库:VectorStore.add()(PGVector,带 metadata)
 → ⑦ 状态回写 + 失败重试

代码骨架:

java
List<Document> docs = new TikaDocumentReader(resource).get();
docs = docs.stream().map(this::clean).toList();
List<Document> chunks = splitter.apply(docs);
chunks.forEach(c -> c.getMetadata().put("source", fileName));
enricher.accept(chunks);                    // 关键词标注
vectorStore.add(chunks);                    // 内部自动 embed

工程上踩的坑:

  1. 切分是效果的最大变量:按 token 切容易把表格/代码拦腰切断,我按"标题层级 + 段落"优先、token 兜底的混合切分,检索准确率明显提升;
  2. 上传大文档阻塞:一律异步任务 + 进度查询,失败可重跑(记录处理到哪个 chunk);
  3. 重复上传:按文件 hash 幂等,先删旧 chunk(按 source metadata 过滤删除)再插入新版本。