为什么需要这份检查清单
RAG(检索增强生成)系统从原型到生产环境之间存在巨大鸿沟。开发环境跑得很好的RAG,上线后经常出现:检索不准、生成幻觉、响应慢、成本高、无法扩展等问题。本文总结了25个关键检查项,覆盖RAG系统生产部署的完整生命周期。
检查清单总览
数据层 (5项) ████████████░░░░ ✓ 5/5
检索层 (6项) ████████████░░░░ ✓ 6/6
生成层 (5项) ████████████░░░░ ✓ 5/5
工程层 (4项) ████████████░░░░ ✓ 4/4
监控层 (3项) ████████████░░░░ ✓ 3/3
运维层 (2项) ████████████░░░░ ✓ 2/2
一、数据层检查项(5项)
1. 文档预处理质量验证
class DocumentPreprocessor:
"""生产级文档预处理流水线"""
def process(self, documents):
processed = []
for doc in documents:
# 检查项1a: 编码一致性
assert doc.encoding == 'utf-8', f"非UTF-8编码: {doc.path}"
# 检查项1b: 去重
if self._is_duplicate(doc):
continue
# 检查项1c: 质量过滤
if not self._quality_check(doc):
continue
# 检查项1d: PII脱敏
doc.content = self._redact_pii(doc.content)
processed.append(doc)
return processed
def _quality_check(self, doc):
"""文档质量检查"""
checks = {
"最小长度": len(doc.content) > 50,
"非乱码": self._check_encoding_quality(doc.content),
"语言检测": self._detect_language(doc.content) in ['zh', 'en'],
"信息密度": len(doc.content) / len(set(doc.content)) < 100,
}
return all(checks.values())
✅ 检查项1:所有文档经过编码验证、去重、质量过滤和PII脱敏。
2. 分块策略合理性
def chunk_document(text, strategy="semantic", chunk_size=512, overlap=64):
"""
生产级文档分块
关键:不要只按字符数分块,要考虑语义完整性
"""
if strategy == "semantic":
# 语义分块:优先在段落、句子边界分割
paragraphs = text.split('\n\n')
chunks = []
current_chunk = ""
for para in paragraphs:
if len(current_chunk) + len(para) <= chunk_size:
current_chunk += para + "\n\n"
else:
if current_chunk:
chunks.append(current_chunk.strip())
# 保留overlap
words = current_chunk.split()
current_chunk = ' '.join(words[-overlap//4:]) + "\n\n" + para
return chunks
elif strategy == "recursive":
# 递归分块:按层级分隔符分割
separators = ['\n\n', '\n', '。', ';', ',', ' ']
# 递归使用不同分隔符,直到块大小合适
...
✅ 检查项2:分块策略考虑语义边界,块大小匹配嵌入模型最优输入长度,设置合理overlap。
3. 嵌入模型选型与评估
✅ 检查项3:嵌入模型在领域数据上的检索准确率经过评估,且选择了最优维度。
| 嵌入模型 | 维度 | 中文支持 | 推理速度 | MTEB得分 |
|---|---|---|---|---|
| bge-large-zh-v1.5 | 1024 | 原生 | 快 | 64.8 |
| bge-m3 | 1024 | 原生 | 中等 | 68.1 |
| text-embedding-3-large | 3072 | 支持 | 快 | 69.2 |
| GTE-Qwen2-7B | 3584 | 原生 | 慢 | 72.3 |
4. 向量数据库容量规划
def vector_db_capacity_planning(
num_documents, # 文档数量
avg_chunks_per_doc, # 每文档平均分块数
embedding_dim, # 嵌入维度
metadata_per_chunk, # 每块元数据大小(bytes)
growth_rate_monthly, # 月增长率
planning_horizon_months=12,
):
"""向量数据库容量规划"""
initial_vectors = num_documents * avg_chunks_per_doc
projected_vectors = initial_vectors * (1 + growth_rate_monthly) ** planning_horizon_months
# 每向量存储 = 维度 * 4字节(FP32) + 元数据
bytes_per_vector = embedding_dim * 4 + metadata_per_chunk
initial_storage = initial_vectors * bytes_per_vector
projected_storage = projected_vectors * bytes_per_vector
return {
"初始向量数": initial_vectors,
"12月后向量数": int(projected_vectors),
"初始存储(GB)": initial_storage / 1e9,
"12月后存储(GB)": projected_storage / 1e9,
"推荐内存(GB)": projected_storage / 1e9 * 0.3, # 索引约占30%
}
✅ 检查项4:向量数据库容量按12个月增长规划,预留50%余量。
5. 数据更新机制
✅ 检查项5:建立了增量更新流程,支持文档增删改的向量实时同步。
二、检索层检查项(6项)
6. 混合检索策略
class HybridRetriever:
"""混合检索:向量检索 + BM25 + 重排序"""
def __init__(self, vector_store, bm25_index, reranker):
self.vector_store = vector_store
self.bm25_index = bm25_index
self.reranker = reranker
def retrieve(self, query, top_k=10, top_n=3):
# 1. 向量检索(语义匹配)
vector_results = self.vector_store.search(
query, k=top_k
)
# 2. BM25检索(关键词匹配)
bm25_results = self.bm25_index.search(
query, k=top_k
)
# 3. 融合结果(RRF算法)
fused = self._reciprocal_rank_fusion(
vector_results, bm25_results
)
# 4. 重排序
reranked = self.reranker.rerank(
query, fused[:top_k*2], top_n=top_n
)
return reranked
def _reciprocal_rank_fusion(self, *ranked_lists, k=60):
"""倒数排名融合"""
scores = {}
for ranked_list in ranked_lists:
for rank, doc in enumerate(ranked_list):
if doc.id not in scores:
scores[doc.id] = 0
scores[doc.id] += 1.0 / (k + rank)
# 按融合分数排序
sorted_ids = sorted(scores, key=scores.get, reverse=True)
return [doc for doc in ranked_lists[0] if doc.id in sorted_ids]
✅ 检查项6:采用向量检索 + BM25混合策略,使用RRF算法融合,并接入Cross-Encoder重排序。
7. 查询改写与扩展
class QueryRewriter:
"""查询改写:提升检索召回率"""
def rewrite(self, query, llm, conversation_history=None):
# 1. 指代消解
if conversation_history:
query = self._resolve_coreference(query, conversation_history, llm)
# 2. 查询扩展:生成多个改写版本
expansions = llm.generate(f"""
将以下查询改写为3个不同表述版本,保持语义一致:
原查询:{query}
输出JSON数组格式。
""")
# 3. HyDE:生成假设性答案用于检索
hyde_answer = llm.generate(f"""
假设你要回答这个问题:{query}
写一段简短的回答(100字以内),不需要准确。
""")
return {
"original": query,
"expansions": json.loads(expansions),
"hyde": hyde_answer,
}
✅ 检查项7:实现了指代消解、查询扩展和HyDE等查询增强技术。
8. 检索结果过滤与权限控制
✅ 检查项8:检索结果按用户权限过滤,支持文档级别的访问控制。
9. 召回率与精确率评估
def evaluate_retrieval(retriever, test_cases):
"""
检索质量评估
test_cases: [{"query": "...", "relevant_docs": [...], ...}]
"""
total_recall = 0
total_precision = 0
total_mrr = 0
for case in test_cases:
results = retriever.retrieve(case["query"], top_k=10)
retrieved_ids = {r.id for r in results}
relevant_ids = set(case["relevant_docs"])
# 召回率
recall = len(retrieved_ids & relevant_ids) / len(relevant_ids)
total_recall += recall
# 精确率
precision = len(retrieved_ids & relevant_ids) / len(retrieved_ids)
total_precision += precision
# MRR
for rank, r in enumerate(results):
if r.id in relevant_ids:
total_mrr += 1.0 / (rank + 1)
break
n = len(test_cases)
return {
"Recall@10": total_recall / n,
"Precision@10": total_precision / n,
"MRR": total_mrr / n,
}
✅ 检查项9:在标注测试集上评估检索质量,Recall@10 > 0.85,MRR > 0.7。
10. 检索延迟优化
✅ 检查项10:P95检索延迟 < 200ms,通过缓存、索引优化和并发检索实现。
11. 多路召回策略
✅ 检查项11:针对不同查询类型(事实型、推理型、浏览型)配置不同的检索策略。
三、生成层检查项(5项)
12. Prompt模板工程化
class PromptManager:
"""生产级Prompt管理"""
TEMPLATES = {
"rag_answer": """
请基于以下检索到的上下文回答用户问题。
## 上下文信息
{context}
## 用户问题
{question}
## 回答要求
1. 仅基于上下文信息回答,不要编造信息
2. 如果上下文不足以回答问题,明确说明"根据现有信息无法回答"
3. 引用信息时标注来源编号 [1]、[2] 等
4. 保持回答简洁、准确、结构化
## 回答""",
"rag_with_history": """
## 对话历史
{conversation_history}
## 检索到的上下文
{context}
## 当前问题
{question}
请结合对话历史和上下文回答当前问题。""",
}
def render(self, template_name, **kwargs):
template = self.TEMPLATES[template_name]
# 注入上下文(带引用标注)
if 'context' in kwargs:
kwargs['context'] = self._format_context(kwargs['context'])
return template.format(**kwargs)
def _format_context(self, retrieved_docs):
"""格式化检索结果,添加引用编号"""
formatted = []
for i, doc in enumerate(retrieved_docs, 1):
formatted.append(f"[{i}] (来源: {doc.metadata.get('source', '未知')})\n{doc.content}")
return "\n\n".join(formatted)
✅ 检查项12:Prompt模板版本化管理,支持A/B测试,包含引用标注和拒答机制。
13. 幻觉检测与防护
class HallucinationGuard:
"""幻觉检测与防护"""
def __init__(self, llm, similarity_threshold=0.7):
self.llm = llm
self.threshold = similarity_threshold
def check(self, answer, retrieved_context, query):
checks = {
"事实一致性": self._check_factual_consistency(answer, retrieved_context),
"信息来源": self._check_source_attribution(answer, retrieved_context),
"拒答逻辑": self._check_refusal_logic(answer, retrieved_context, query),
}
passed = all(checks.values())
return {"passed": passed, "checks": checks}
def _check_factual_consistency(self, answer, context):
"""检查答案中的事实是否都能在上下文中找到支持"""
# 将答案分解为事实陈述
claims = self._extract_claims(answer)
for claim in claims:
# 计算与上下文的语义相似度
similarity = self._compute_similarity(claim, context)
if similarity < self.threshold:
return False
return True
✅ 检查项13:部署了幻觉检测机制,对生成内容进行事实一致性校验。
14. 流式响应处理
✅ 检查项14:支持流式响应输出,首Token延迟 < 500ms。
15. 上下文窗口管理
✅ 检查项15:动态管理上下文窗口,在检索结果、对话历史和生成长度之间合理分配Token预算。
16. 生成质量评估
✅ 检查项16:建立生成质量评估pipeline,包含自动指标(faithfulness、relevance)和人工抽检。
四、工程层检查项(4项)
17. API设计规范
# RAG API 规范设计
POST /api/v1/rag/query
Request:
{
"query": "用户问题",
"conversation_id": "会话ID",
"filters": {
"source": ["doc_type:pdf"],
"date_range": {"start": "2026-01-01"}
},
"options": {
"top_k": 3,
"stream": true,
"include_sources": true,
"max_tokens": 2048
}
}
Response (SSE):
data: {"type": "retrieval", "sources": [...]}
data: {"type": "token", "content": "答"}
data: {"type": "token", "content": "案"}
data: {"type": "done", "metadata": {"latency_ms": 1200}}
✅ 检查项17:API遵循RESTful规范,支持流式响应、过滤、分页和错误处理。
18. 并发与限流
✅ 检查项18:实现了请求队列、并发控制、限流和降级策略。
19. 成本控制
class CostController:
"""RAG系统成本控制"""
def __init__(self, config):
self.limits = config
def estimate_cost(self, query, retrieved_docs):
"""预估单次查询成本"""
# 检索成本
retrieval_cost = len(retrieved_docs) * 0.0001 # 向量检索
# Prompt Token成本
prompt_tokens = len(query) // 2 + sum(
len(doc.content) // 2 for doc in retrieved_docs
)
# 生成成本
estimated_output_tokens = min(
self.limits.max_output_tokens,
prompt_tokens # 粗略估计
)
total_cost = (
prompt_tokens * self.limits.input_price_per_1k / 1000 +
estimated_output_tokens * self.limits.output_price_per_1k / 1000 +
retrieval_cost
)
return total_cost
def check_budget(self, user_id, estimated_cost):
"""检查用户预算"""
used = self.get_user_usage(user_id)
limit = self.get_user_limit(user_id)
return used + estimated_cost <= limit
✅ 检查项19:实现了Token级成本追踪和用户级预算控制。
20. 安全与合规
✅ 检查项20:输入输出内容安全过滤,日志脱敏,符合数据驻留要求。
五、监控层检查项(3项)
21. 全链路追踪
class RAGTracer:
"""RAG全链路追踪"""
def trace_request(self, request_id, query):
spans = {
"query_rewrite": {"start": None, "end": None, "result": None},
"retrieval": {"start": None, "end": None, "results": []},
"reranking": {"start": None, "end": None, "results": []},
"prompt_construction": {"start": None, "end": None},
"generation": {"start": None, "end": None, "tokens": 0},
"hallucination_check": {"start": None, "end": None, "passed": None},
}
# 记录每个阶段的时间和结果
# 上传到追踪系统(如Jaeger/LangSmith)
return spans
✅ 检查项21:实现了从查询输入到生成输出的全链路追踪,可视化每个阶段的延迟和质量。
22. 在线评估指标
✅ 检查项22:实时监控以下核心指标:
| 指标 | 目标值 | 告警阈值 |
|---|---|---|
| 检索Recall@10 | >0.85 | <0.80 |
| 端到端延迟P95 | <2s | >3s |
| 幻觉率 | <5% | >10% |
| 用户满意度 | >4.0/5 | <3.5/5 |
| 日均成本/用户 | <$0.5 | >$1.0 |
23. 数据飞轮闭环
✅ 检查项23:建立了用户反馈收集→标注→评估→优化的数据飞轮。
六、运维层检查项(2项)
24. 部署架构
# 生产级RAG部署架构
production_rag:
load_balancer:
type: nginx
ssl: true
rate_limit: "100 req/min per user"
api_servers:
replicas: 3
resources:
cpu: 4
memory: 8Gi
hpa:
min: 3
max: 10
cpu_target: 70%
retrieval_service:
replicas: 2
vector_db: "Milvus cluster (3 nodes)"
cache: "Redis (query→results, TTL=3600)"
generation_service:
model: "DeepSeek-V3 API"
fallback: "Qwen-Max API"
timeout: 30s
monitoring:
tracing: "LangSmith"
metrics: "Prometheus + Grafana"
alerts: "AlertManager → Slack"
✅ 检查项24:部署架构支持水平扩展、故障转移和灰度发布。
25. 灾备与回滚
✅ 检查项25:制定了数据备份、服务降级和版本回滚预案,RTO < 30分钟。
上线前自检流程
Day -7: 完成所有25项检查
Day -5: 压力测试(2x预期流量)
Day -3: 安全审计与渗透测试
Day -1: 灰度发布(10%流量)
Day 0: 全量发布 + 24小时on-call
Day +7: 首次运行回顾
这份检查清单来自多个RAG生产项目的实战经验。每个检查项背后都有踩过的坑和交过的学费。建议在上线前逐项核对,不要跳过任何一项——生产环境的每一次故障,往往都源于某个"以为不重要"的检查项。