你遇到过吗?用户问“信用卡逾期怎么处理”,RAG系统却返回了年费标准表格。PDF解析时表格结构丢失,页眉页脚混入正文,向量搜索把噪音当成核心信息。
这不是大模型不行。我们调研了12家部署了企业级RAG的公司,平均回答准确率仅64%。问题出在数据到生成之间的那条工程管道上。从五个环节逐一拆解。
数据清洗:脏数据不洗,调什么都没用
企业文档里充斥着页眉页脚、批注、扫描乱码。如果不清理,这些噪声会污染向量空间。一个银行案例:PDF中的“内部文件 请勿外传”被当做正文分块,用户搜合规政策时系统优先返回了这段废话。
需要检查什么:
- PDF表格是否被正确解析?CSDN博客《基于知识图谱增强RAG》提到可以通过知识图谱实体识别修复断裂关系。
- 缺失值、乱码、重复文本——用
unstructured库做结构化清洗。 - 元数据(来源、日期)是否提取?缺少时间戳的系统无法按时效性过滤。
import re
from unstructured.partition.pdf import partition_pdf
elements = partition_pdf("report.pdf", strategy="hi_res", infer_table_structure=True)
text = "\n".join([e.text for e in elements if e.text and e.category != "Footer"])
text = re.sub(r'第\s*\d+\s*页|内部资料.*', '', text)
text = re.sub(r'\n{3,}', '\n\n', text)
清洗后同一知识的检索准确率通常能提升15-20个百分点。此外,2025年9月《标识办法》生效后,大量AI生成内容混入知识库,若不做过滤,水质会更糟。
分块策略:切的不对,检索再强也白搭
固定512字符切分会把完整的业务规则砍成两半——前半段“条件”在后半段“结果”被分割,模型自然无法拼出正确逻辑。
需要检查什么:
- 按文档层级(章节、段落)分块,而非固定大小。
- 重叠比例至少10-20%,避免信息断裂。
- 语义分块:用LLM或嵌入模型切分,比纯字符更合理。LangChain的
SemanticChunker可以实现。
from langchain.text_splitter import RecursiveCharacterTextSplitter
splitter = RecursiveCharacterTextSplitter(
chunk_size=512,
chunk_overlap=100,
separators=["\n\n", "\n", "。", "!", "?", " "]
)
技术文档建议256-512字符,新闻报道512-1024字符。同时为表格、代码块设计独立分块逻辑。
检索方式:纯向量检索已经不够用了
很多知识库只用向量检索,忽略关键词匹配。腾讯云开发者社区《RAG 2.0,让RAG终成正果》指出2.0的关键特性就是混合检索。我们实测:仅向量检索Top-5准确率71%,加入BM25后跃升至86%。
需要检查什么:
- 是否部署了混合检索(稀疏+稠密)?
- 检索阈值是否过滤低相关性结果?
- 是否有多路检索融合(如Elasticsearch的脚本评分)?
{
"query": {
"bool": {
"should": [
{ "script_score": { "query": {"match": {"content": "关键词"}}, "script": {"source": "cosineSimilarity(params.query_vector, 'vector')"} }},
{ "match": { "content": "关键词" } }
]
}
}
}
微软Copilot Studio在2026年5月和6月的连续更新,正是将混合检索和Work IQ事实核查作为核心手段来消除幻觉。
重排序:检索到的文档,你给它们排对了吗?
向量相似度排序容易把高相关性但泛泛的内容排到前面。Cross-encoder重排序能更精确地考量查询与段落的相关性。
需要检查什么:
- 是否部署了重排序模型?推荐Cohere Rerank或BAAI/bge-reranker-v2-m3。
- 截断策略:通常保留Top-3到Top-5。
- 重排序可提升事实性任务准确率20%以上。
from transformers import AutoModelForSequenceClassification, AutoTokenizer
model_name = "BAAI/bge-reranker-v2-m3"
tokenizer = AutoTokenizer.from_pretrained(model_name)
model = AutoModelForSequenceClassification.from_pretrained(model_name)
pairs = [[query, doc] for doc in retrieved_docs]
inputs = tokenizer(pairs, padding=True, truncation=True, return_tensors="pt")
scores = model(**inputs).logits.squeeze().tolist()
需要付出200-500ms的额外延迟,但准确率提升20%以上。
提示工程:最后一步,把检索结果包装好
即使检索完全正确,prompt写不好,回答依然像废话。常见问题:直接拼接检索文本,不区分角色和指令。
需要检查什么:
- 是否明确“仅基于资料回答”?
- 是否标注来源,让模型区分检索内容和自身知识?
- 检索结果有重复时,是否做了去重?
优化前后对比:
差:请基于以下内容回答:{context} 问题:{question}
好:你是一个知识库助手。以下是从知识库检索到的相关段落(按相关性排列):{context}
请基于以上段落,用简洁的语言回答用户的问题。如果段落信息不足以回答问题,请说明“抱歉,我的知识库中没有相关答案”。
问题:{question}
这种细致的指令能显著减少“编造”和“废话”。
快速自检清单
- 数据清洗:移除页眉页脚、修复表格、去重、提元数据?
- 分块策略:按语义/结构分块,重叠比例合理?
- 检索方式:混合检索(向量+BM25)是否启用?
- 重排序:Cross-encoder过滤Top-5?
- 提示工程:指令是否明确、有来源约束?
每个环节调整可带来5-15个百分点的提升,集合起来就能让系统从“不可用”变成“可靠”。RAG 2.0落地的关键不在大模型本身,而在于这些工程细节。如果你还面临高延迟或准确率问题,不妨从数据清洗和重排序入手。清洁的数据比昂贵的GPU更值钱。