从零构建企业知识库问答系统 —— 理解检索、增强、生成的每个环节
| 问题 | 纯 LLM | RAG 解决 |
|---|---|---|
| 知识过时 | 训练数据截止到某日期,不知道"今天"的事 | 检索最新文档 实时更新知识库 |
| 幻觉 | 遇到不知道的会"编"一个看起来像真的答案 | 提供参考答案 约束 LLM 生成 |
| 私有知识盲区 | 没见过企业内部文档 | 接入内部文档 让 LLM 基于事实作答 |
员工手册、技术文档、产品FAQ → 智能问答机器人
产品说明 + 历史工单 → 自动回答用户问题
法规库/文献库 → 辅助律师/医生查找信息
把用户问题和知识库文档都转成向量,用余弦相似度找最接近的。
[System]
你是一个基于内部知识库回答问题的助手。
规则:
1. 优先使用下面提供的文档内容回答
2. 如果文档中没有相关信息,请说"知识库中暂无相关信息"
3. 回答时引用文档编号
[Context - 检索到的文档]
[文档1] 标题:办公政策 | 内容:年假15天,带薪病假7天...
[文档2] 标题:公司介绍 | 内容:AI学习科技有限公司成立于2024年...
[User Question]
我们公司年假多少天?
请基于以上知识库内容回答用户问题。
LLM 基于增强后的 Prompt,用 temperature=0.2(低温度 = 少幻觉)生成答案。
temperature=0.1~0.3(事实问答) max_tokens=500(控制长度)
chunk_size=200字, chunk_overlap=50字
| 策略 | 做法 | 适用场景 | 推荐 |
|---|---|---|---|
| 固定大小 | 每 500 字硬切 | 通用文档 | ⭐ |
| 语义分句 | 按句号/段落自然切 | 规范文本 | ⭐⭐ |
| 递归分块 | 先段落→再句子→最后硬切 | 任何文本 | ⭐⭐⭐ |
| 滑动窗口 | 固定大小 + overlap | 结合以上策略 | ⭐⭐⭐ |
中文建议 300-800 字
建议 chunk_size 的 10-20%
搜 "技术栈"
搜 "技术栈"
搜 "API-Key配置"
公式: score(d) = Σ 1/(k + rank_i(d)) (k=60)
| 文档 | 向量排名 | BM25 排名 | RRF 分数 | 最终排名 |
|---|---|---|---|---|
| API-Key 配置指南 | #3 | #1 | 1/(60+3) + 1/(60+1) = 0.0323 | #1 |
| 密钥管理系统 | #1 | #3 | 1/(60+1) + 1/(60+3) = 0.0323 | #2 |
| 认证与授权 | #2 | #5 | 1/(60+2) + 1/(60+5) = 0.0315 | #3 |
| Bi-Encoder (双塔) | Cross-Encoder (交叉) | |
|---|---|---|
| 速度 | 快 | 慢 |
| 精度 | 一般 | 高 |
| 预缓存 | 可以(文档向量预计算) | 不可以(每次重新计算) |
| 适用阶段 | 粗召回 | 精排 |
就是把历史消息都塞进 LLM 的 messages 列表:
messages = [
{"role": "system", "content": "你是知识库助手..."}, ← System Prompt
{"role": "user", "content": "AI Tutor月费多少钱?"}, ← 历史第1轮
{"role": "assistant", "content": "月费29元。"}, ← 历史第1轮
{"role": "user", "content": [检索结果 + "那年费呢?"]} ← 当前问题
]
# 每轮对话后
max_messages = max_history_turns * 2 # user + assistant = 1轮
if len(history) > max_messages:
history = history[-max_messages:] # 只保留最近的
TF-IDF 检索
硬编码文档
简单 Prompt
理解 RAG 核心链路
ChromaDB
bert-base-chinese
持久化
语义搜索
批量导入
自动分块
来源追溯
知识库管理
多轮对话
历史管理
Token 预算
上下文理解
向量+BM25
RRF融合
Cross-Encoder
工业级召回
| 维度 | Step 1 | Step 2 | Step 3 | Step 4 | Step 5 |
|---|---|---|---|---|---|
| 检索方式 | TF-IDF | 向量 | 向量 | 向量 | 混合+重排 |
| Embedding | 无 | BERT 768d | BERT 768d | BERT 768d | BERT 768d |
| 向量数据库 | 无 (sklearn) | ChromaDB | ChromaDB | ChromaDB | ChromaDB |
| 分块 | 整篇文档 | 整篇文档 | 递归 500字 | 递归 500字 | 递归 500字 |
| 多轮对话 | 无 | 无 | 无 | 10 轮记忆 | 10 轮记忆 |
| 关键词检索 | TF-IDF | 无 | 无 | 无 | BM25 |
| 重排序 | 无 | 无 | 无 | 无 | Cross-Encoder |
| 指标 | Step 1 | Step 5 | 提升 |
|---|---|---|---|
| 召回率@5 | ~40% | ~85% | 2.1x |
| 对同义词 | 完全不支持 | 良好 | — |
| 多轮对话 | 不支持 | 支持 | — |
| 持久化 | 无 | ChromaDB | — |
| 文档量 | ~100 篇 | ~10000 篇 | 100x |
| 单次查询延迟 | <50ms | <200ms | 可接受 |
| 组件 | 选择 | 理由 |
|---|---|---|
| 文档解析 | PyMuPDF (fitz) | 中文 PDF 提取最稳定 |
| 分词 | jieba | 轻量中文分词 |
| Embedding | bert-base-chinese | 本地缓存,离线可用,768维 |
| 向量数据库 | ChromaDB | 轻量,零配置,pip install 即可 |
| LLM | DeepSeek Chat | 中文好,价格低 |
| 关键词检索 | BM25 (rank-bm25) | 比 TF-IDF 更精准 |
| 重排序 | bge-reranker-base | 中文 Cross-Encoder 精排 |
| 模型 | 维度 | 特点 | 适用阶段 |
|---|---|---|---|
| bert-base-chinese | 768 | 通用中文,本地离线 | 入门 |
| BAAI/bge-large-zh-v1.5 | 1024 | 中文 SOTA,召回率 +10-15% | 进阶 |
| shibing624/text2vec-base-chinese | 768 | CoSENT 训练,句向量专用 | 可选 |
bge-large-zh-v1.5 替换 bert-base-chinese,召回率再提升 10-15%
Streamlit / Gradio 构建交互界面
RAGAS 框架量化评估检索和生成质量