发布于 Wed Apr 15 2026 08:00:00 GMT+0800 (中国标准时间)
实战RAG知识库
知识库准备实战:从 Notion / 飞书 / Confluence 到 RAG 的全流程
知识库做不好,再贵的 LLM 也是浪费。本文给出导出 → 清洗 → 分块 → 入库的可复制流程,附 Python 脚本。
知识库准备的核心矛盾#
源数据(Notion / 飞书 / Confluence / Word)天然不是为 RAG 设计的:
- 包含目录、TOC、装饰性内容
- 表格被丢失结构
- 大量”老旧文档”和”草稿”
直接丢进 RAG 的结果:检索一堆无关内容、回答幻觉、用户骂街。
标准流程#
源系统 → 导出 → 清洗 → 切分 → 增强 → 向量化 → 入库 → 评估
步骤 1:导出#
| 源 | 工具 |
|---|---|
| Notion | 官方导出 → Markdown |
| 飞书云文档 | feishu-doc-export 或 API |
| Confluence | confluence-markdown-exporter |
| Word / PDF | unstructured 库 |
步骤 2:清洗(Python 脚本)#
import re
from pathlib import Path
def clean(text: str) -> str:
# 去掉 Notion 导出的 emoji 标题前缀
text = re.sub(r'^[\U0001F300-\U0001FAFF]\s*', '', text, flags=re.MULTILINE)
# 去掉空白 alt 图片
text = re.sub(r'!\[\]\([^)]+\)', '', text)
# 合并多余空行
text = re.sub(r'\n{3,}', '\n\n', text)
# 去掉「目录」「TOC」段落
text = re.sub(r'(?ms)^#+\s*(目录|TOC).*?(?=^#)', '', text)
return text.strip()
for p in Path('docs/raw').rglob('*.md'):
out = Path('docs/clean') / p.relative_to('docs/raw')
out.parent.mkdir(parents=True, exist_ok=True)
out.write_text(clean(p.read_text()))
步骤 3:切分策略#
不要默认按 500 字硬切,根据文档类型选:
| 文档类型 | 推荐切分 |
|---|---|
| FAQ / Q&A 对 | 按问答对切,1 问 1 答 = 1 chunk |
| 教程 / 手册 | 按二级标题切,保留上下文 |
| API 文档 | 按 endpoint 切,包含参数 + 示例 |
| 政策 / 合同 | 按条款编号切 |
步骤 4:内容增强#
bge-m3 等模型对问句 Embedding 比对陈述句更稳。把每个 chunk 加一个「这一段在回答什么问题」前缀:
prefix = llm.generate(
f"用一句话总结这段文本回答了什么问题:\n{chunk}"
)
augmented = f"问题:{prefix}\n答案:{chunk}"
实测能让 MRR@5 提升 3-8 个百分点。
步骤 5:评估#
每次知识库更新后跑一遍评估集:
# eval_set.jsonl 每行:{"question": "...", "expected_chunk_id": "..."}
hits = []
for item in eval_set:
results = retriever.search(item['question'], top_k=5)
hit_rank = next((i for i, r in enumerate(results)
if r.id == item['expected_chunk_id']), None)
hits.append(hit_rank)
mrr5 = sum(1/(r+1) for r in hits if r is not None and r < 5) / len(hits)
print(f"MRR@5: {mrr5:.3f}")
低于上次结果 5% 立刻报警,回滚改动。