我在 RAG 系统里栽过的三个坑,希望你现在还来得及避开
从 POC 85% 跌到生产 42% 的 RAG 系统,chunk 策略、embedding 模型和元数据过滤三个关键坑的真实踩坑经验。
# 我在 RAG 系统里栽过的三个坑,希望你现在还来得及避开
去年做了一个内部知识库的 RAG 系统,选型是 LangChain + ChromaDB + OpenAI embeddings。跑起来之后,准确率从 POC 阶段的 85% 一路跌到生产环境的 42%。
回头看,问题不在模型,不在向量库,而在三个我当初完全没想到的地方。
坑一:chunk 大小不是越大越好
POC 阶段我用的是 1000 token 的 chunk size,结果检索召回率惨不忍睹。调大到 2000、5000,情况更糟。
后来才发现,问题出在 chunk 边界上。中文文本按字符数切分和按 token 数切分,结果完全不一样。我的文档大多是技术文档,里面代码块、表格、章节标题混杂,固定大小的 chunk 经常把一个完整的技术说明切成两半。
解决方案是用 langchain-text-splitters 的 MarkdownHeaderTextSplitter,按标题层级来切:
from langchain.text_splitter import MarkdownHeaderTextSplitter
headers_to_split_on = [
("#", "Header 1"),
("##", "Header 2"),
("###", "Header 3"),
]
splitter = MarkdownHeaderTextSplitter(headers_to_split_on)
docs = splitter.split_text(markdown_content)
这样切出来的 chunk 天然有语义完整性,每个 chunk 都带着自己的标题上下文。召回率从 42% 提到了 71%。
但别高兴太早——这个方法只对 Markdown 格式有效。如果是 PDF 或者 Word 文档,你得先做格式转换,转换过程中的格式丢失会让问题更复杂。
坑二:embedding 模型的语义差距
我用的是 text-embedding-3-small,POC 阶段测下来还行。上了生产数据之后,发现同一份文档的不同部分,embedding 的相似度分布完全不符合预期。
查了半天才发现,embedding 模型的训练数据和我们的领域数据差距太大。我们是医疗行业的内部文档,里面充斥着专业术语和缩写,通用 embedding 模型对这些词的理解和我们的领域专家完全不在一个频道。
换 embedding 模型不是简单的 API 切换。我试了 bge-m3、text-embedding-ada-002,效果各有优劣。最终的选择是:用 bge-m3 做初筛,再用一个微调过的医疗领域 embedding 模型做重排。
# 两阶段检索
# Stage 1: 粗排
vector_db = ChromaCollection(embedding_function=BGE_M3Embeddings())
candidates = vector_db.search(query, top_k=50)
# Stage 2: 精排
reranker = CrossEncoderModel(model_name="BAAI/bge-reranker-v2-m3")
results = reranker.rank(query, candidates)
这一套下来,准确率才真正稳定在 78% 以上。代价是延迟从 200ms 涨到了 800ms,需要做好缓存。
坑三:元数据过滤的陷阱
这是我踩得最狠的一个坑。我们给每个 chunk 都打了元数据标签:部门、文档类型、更新时间、敏感级别。检索的时候根据用户身份做元数据过滤,确保用户只能看到自己有权限的内容。
问题出在过滤逻辑上。我的过滤条件是 AND 关系——用户所属的所有部门标签必须全部匹配。但实际业务中,一个文档可能属于多个部门,用 AND 过滤会把大量相关文档排除掉。
改成 OR 关系之后,召回量上去了,但噪声也多了。最后用的是加权评分:匹配部门数量越多,分数越高,然后取 top-k。
def score_with_metadata(doc, user_departments):
base_score = doc["vector_score"]
dept_match = sum(1 for d in doc["metadata"]["departments"] if d in user_departments)
meta_score = dept_match / max(len(doc["metadata"]["departments"]), 1)
return base_score * 0.7 + meta_score * 0.3
总结
RAG 系统的坑不在技术选型,而在数据理解和业务适配。三个坑的共同点是:POC 阶段看不出来,一上生产就暴露。
如果你正在做 RAG 项目,我的建议是:
2. **embedding 模型要匹配领域**,通用模型在专业场景下会掉链子
3. **元数据过滤要用加权评分**,AND/OR 的简单逻辑不够用
最后说一句,RAG 系统的准确率永远不可能 100%,但把坑提前踩完,比上线后再补救强得多。
ENDOFPPOST
echo "Posts written successfully"
wc -c /tmp/post1.md /tmp/post2.md