RAG 知识库构建与运维
适用场景:将企业文档、运维手册、FAQ 沉淀为可检索的知识库,通过 RAG 实现精准问答。
1. RAG 架构概览
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ 文档源 │ ──▶ │ 预处理 │ ──▶ │ Embedding │
│ (PDF/MD/DB) │ │ (解析/切分) │ │ 向量化 │
└─────────────┘ └──────────────┘ └──────┬──────┘
│
▼
┌─────────────┐ ┌──────────────┐ ┌─────────────┐
│ 用户查询 │ ──▶ │ 检索 │ ──▶ │ LLM 生成 │
│ │ │ (向量相似度) │ │ 带上下文回答 │
└─────────────┘ └──────────────┘ └─────────────┘
2. Embedding 模型选型
2.1 主流模型对比
| 模型 | 维度 | 最大 token | 中文支持 | 部署方式 |
|---|---|---|---|---|
text-embedding-3-small |
1536/512/256 | 8191 | ✅ | API / Ollama |
bge-m3 |
1024 | 8192 | ✅✅ | 本地 Ollama |
text-embedding-3-large |
3072 | 8191 | ✅ | API |
GPTFuzz/bge-large-zh |
1024 | 512 | ✅✅ | 本地 |
2.2 Ollama 部署 Embedding
# 下载 bge-m3
ollama pull bge-m3
# 测试生成
curl http://localhost:11434/api/embeddings -d '{
"model": "bge-m3",
"prompt": "Kubernetes Pod 处于 Pending 状态的原因"
}'
2.3 OpenAI 兼容接口
若使用 LangChain / LlamaIndex,配置统一接口:
from langchain.embeddings import OllamaEmbeddings
embeddings = OllamaEmbeddings(
model="bge-m3",
base_url="http://localhost:11434"
)
3. 文档预处理
3.1 格式支持
| 格式 | 解析工具 | 注意事项 |
|---|---|---|
| Markdown | markdown 原生 |
保留标题层级 |
pypdf / pdfplumber |
表格需特殊处理 | |
| Word | python-docx |
样式信息丢失 |
| HTML | BeautifulSoup |
清洗脚本标签 |
| JSON | 原生 | 嵌套结构展平 |
3.2 切分策略
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=512, # 每块最大 token
chunk_overlap=64, # 块间重叠,避免语义断裂
length_function=len,
separators=["\n\n", "\n", "。", " ", ""]
)
chunks = splitter.split_text(document_content)
关键参数:
- chunk_size:根据 Embedding 模型最大 token 调整(bge-m3 支持 8192)
- chunk_overlap:建议 10-15% 的 chunk_size
- separators:按语义边界切分,优先使用 \n\n(段落)
4. 向量数据库配置
4.1 ChromaDB(轻量级,适合小规模)
import chromadb
from chromadb.config import Settings
client = chromadb.PersistentClient(path="/data/chroma/knowledge-base")
collection = client.get_or_create_collection(
name="ops-manuals",
metadata={"hnsw:space": "cosine"}
)
# 批量插入
collection.add(
documents=chunks,
embeddings=embeddings.embed_documents(chunks),
ids=[f"doc_{i}" for i in range(len(chunks))]
)
4.2 Milvus(生产级,适合大规模)
from pymilvus import connections, Collection, utility
connections.connect("default", host="milvus", port="19530")
# 创建集合(若不存在)
if not utility.has_collection("ops_knowledge"):
from pymilvus import CollectionSchema, FieldSchema, Collection
fields = [
FieldSchema(name="id", dtype=DataType.INT64, is_primary=True),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR, dim=1024),
FieldSchema(name="content", dtype=DataType.VARCHAR, max_length=65535),
FieldSchema(name="source", dtype=DataType.VARCHAR, max_length=512),
]
schema = CollectionSchema(fields, "Ops knowledge base")
collection = Collection("ops_knowledge", schema)
# 创建索引
index = {"index_type": "IVF_FLAT", "metric_type": "COSINE", "params": {"nlist": 128}}
collection.create_index("embedding", index)
collection.load()
5. 检索与生成
5.1 检索优化
# 相似度阈值过滤
results = collection.query(
query_embeddings=embeddings.embed_queries([question]),
n_results=5,
where={"source": {"$eq": "network"}}
)
# 仅返回相似度 > 0.6 的结果
filtered = [r for r, score in zip(results['documents'], results['distances']) if score < 0.4]
5.2 Prompt 模板
RAG_PROMPT = """你是一个运维专家助手。基于以下上下文回答问题:
<context>
{context}
</context>
问题:{question}
要求:
1. 仅基于上下文回答,不编造信息
2. 若上下文不足,明确说明
3. 提供可操作的解决方案
"""
5.3 完整流程
from langchain.chains import RetrievalQA
from langchain.llms import Ollama
from langchain.vectorstores import Chroma
# 初始化
db = Chroma(persist_directory="/data/chroma/knowledge-base", embedding_function=embeddings)
llm = Ollama(model="qwen2.5:7b", base_url="http://localhost:11434")
# 检索 QA
qa_chain = RetrievalQA.from_chain_type(
llm=llm,
retriever=db.as_retriever(
search_kwargs={"k": 5, "score_threshold": 0.6}
),
return_source_documents=True
)
response = qa_chain({"query": "Nginx 502 错误如何排查?"})
print(response["result"])
6. 运维监控
6.1 索引健康检查
# ChromaDB
ls -lh /data/chroma/
sqlite3 /data/chroma/chroma.sqlite3 "SELECT COUNT(*) FROM documents;"
# Milvus
milvus-cli> show collections
milvus-cli> show entities ops_knowledge
6.2 性能指标
| 指标 | 监控方式 | 告警阈值 |
|---|---|---|
| 检索延迟 | Prometheus histogram | P99 > 500ms |
| 召回率 | RAGAS faithfulness | < 0.7 |
| 缓存命中率 | Redis stats | < 80% |
| 向量库磁盘 | node_disk_usage | > 85% |
6.3 定期更新策略
#!/bin/bash
# update_rag_index.sh
COLLECTION="ops_knowledge"
DATE=$(date +%Y%m%d)
# 增量更新
python3 scripts/incremental_ingest.py \
--collection $COLLECTION \
--since "$DATE-7" \
--embed-model bge-m3
# 全量重建(每周日)
if [ "$(date +%u)" -eq 7 ]; then
python3 scripts/full_rebuild.py --collection $COLLECTION
fi
7. 常见问题排查
问题 1:检索结果与查询无关
原因:Embedding 模型不匹配或相似度阈值过高。
解决:
# 降低阈值
search_kwargs={"k": 10, "score_threshold": 0.3}
# 切换 Embedding 模型
embeddings = OllamaEmbeddings(model="bge-m3")
问题 2:长文档切分后语义断裂
原因:chunk_size 过小或 separator 设置不当。
解决:
splitter = RecursiveCharacterTextSplitter(
chunk_size=1024,
chunk_overlap=128,
separators=["\n## ", "\n# ", "\n\n", "\n", " "]
)
问题 3:向量库内存溢出
原因:向量数量过大,索引未优化。
解决:
- Milvus:增加 nlist 参数,调整索引类型(HNSW / IVF_PQ)
- Chroma:升级到 0.5+ 版本,启用持久化
问题 4:多语言混合检索效果差
原因:单一 Embedding 模型无法覆盖所有语言。
解决:使用多语言模型(bge-m3、mxbai-embed-large)或分语言建库。