构建企业级RAG系统的12个工程决策
📍 本文是「LLM进阶:从会用到底层精通」专题的第 6/10 篇 | 难度:🌿 进阶 | 预计阅读 22 分钟
学习目标
🎯 学完本文后,你将能够:
- 根据文档类型选择最优的Chunking策略
- 在主流Embedding模型间做出数据驱动的选型决策
- 理解HyDE和Re-ranking对检索质量的实际影响
- 设计幻觉检测与评估体系
- 画出12个工程决策的完整决策树
1. 为什么RAG"看起来简单,落地很烂"?
2023年RAG刚火时,无数团队一周跑通demo——LangChain调通,文档丢进去,问啥都能答。然后呢?上线第二周就翻了。因为demo能跑和线上能打之间,隔着12个工程决策。
三种经典翻车:
翻车一:方向对了,细节全错。 用户问"Q3退货率多少",系统返回一堆"退货政策"——都跟退货有关,但没一个带数字。这是Chunking和检索策略的锅。
翻车二:编得比查得好。 检索到不相关内容,LLM硬编了一个有理有据的答案。检索精度差叠加Prompt设计缺陷。
翻车三:第二轮变回第一轮。 追问"那B产品呢",系统忘了前面在讨论退货率,又从头检索。没做上下文管理。
2. 12个工程决策逐一拆解
决策① 文档解析
PDF里可能有双栏排版、表格、页眉页脚,PyPDF2大概率读出乱码。
🛠️ 实战经验:按文件特征做路由——纯文本走pdfplumber,表格密集型走Unstructured。200页PDF解析可能跑2-3分钟,必须异步处理+缓存。
决策② Chunking策略
🛠️ 实战经验:默认512 token + 10% overlap + Recursive。跑RAGAS评估看context_precision和context_recall的trade-off再调整。chunk大小和Embedding模型绑定——BGE-large最大输入512 token,切1024会被截断。
决策③ Embedding模型选型
🛠️ 实战经验:别只看MTEB排行榜。用你自己数据做100条测试集,算NDCG@5,谁高用谁。数据不能出境的直接选BGE-M3本地部署。
决策④ 向量数据库选型
🛠️ 实战经验:100万以内Chroma足够,千万级Qdrant很能打。团队没运维经验别硬上Milvus。
决策⑤ 检索策略
🛠️ 实战经验:直接上Hybrid。BM25索引开销极小,RRF的k值默认60大多数场景work。
决策⑥ HyDE增强检索
先让LLM生成一段"假设性完美答案",用这个答案的Embedding去检索而非原始问题。因为query和document不在同一语义空间。
🛠️ 实战经验:FAQ场景几乎无提升。加复杂度路由:简单查询不走HyDE,复杂查询才走,平衡延迟和效果。
决策⑦ Re-ranking
初检索(Bi-Encoder)追求召回率返回Top-100;Re-ranking(Cross-Encoder)追求精确率精排留Top-5。Cohere Re-rank v3.5延迟约200-500ms,本地BGE-Reranker更快。
🛠️ 实战经验:投入产出比最高的优化,Top-3命中率可从67%提到89%。initial_k至少50,否则Re-ranking无米之炊。
决策⑧ Prompt模板设计
核心原则:① 只能基于给定上下文回答 ② 强制引用来源编号 ③ 无答案时直接拒答 ④ 保留chunk ID支持跳转原文。
🛠️ 实战经验:"不允许使用自己的训练知识"不加,LLM就会自己补。引用编号对不上=高风险,可拦截约40%幻觉。
决策⑨ 幻觉检测
三阶梯:① Faithfulness评分(RAGAS LLM-as-Judge)② 实体级验证(数字、日期回溯)③ Self-RAG(反思token,效果最好但最复杂)。
🛠️ 实战经验:起步只做第一阶。在线服务中引用编号对不上直接拦截。不建议一上来搞Self-RAG。
决策⑩ 多轮对话上下文管理
query rewriting:把"那B产品呢"改写为"B产品的退货率是多少";窗口管理:保留最近N轮(3-5轮足够)。
🛠️ 实战经验:rewriting用便宜小模型(gpt-4o-mini),效果差别不大,成本差10倍。
决策⑪ 知识库更新策略
🛠️ 实战经验:增量更新三步:新文档写入→旧chunk标记删除→向量索引compact。版本号一定要记,答不上来可信度归零。
决策⑫ 评估体系(RAGAS)
六指标无需人工标注:Context Precision、Context Recall、Faithfulness、Answer Relevancy、Answer Correctness、Aspect Critique。
🛠️ 实战经验:先跑Context Precision + Recall + Faithfulness。每次工程改进跑一遍RAGAS看分数。没有评估驱动的RAG优化就是瞎子摸象。
3. 决策树总结
graph TD
A[① 文档解析] --> B[② Chunking策略]
B --> C[③ Embedding模型]
B --> D[⑤ 检索策略]
C --> D
D --> E[⑥ HyDE增强]
E --> F[⑦ Re-ranking]
C --> F
F --> G[⑧ Prompt模板]
G --> H[⑨ 幻觉检测]
D --> I[⑩ 多轮上下文]
I --> G
B --> J[④ 向量数据库]
J --> K[⑪ 知识库更新]
B --> L[⑫ RAGAS评估]
G --> L
H --> L
style A fill:#e1f5fe
style L fill:#fff3e0
from llama_index.core import (
VectorStoreIndex, SimpleDirectoryReader, Settings
)
from llama_index.core.node_parser import SentenceSplitter
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core.postprocessor import SentenceTransformerRerank
from llama_index.llms.openai import OpenAI
Settings.llm = OpenAI(model="gpt-4o-mini", temperature=0)
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
Settings.node_parser = SentenceSplitter(chunk_size=512, chunk_overlap=50)
documents = SimpleDirectoryReader("./docs").load_data()
index = VectorStoreIndex.from_documents(documents, show_progress=True)
reranker = SentenceTransformerRerank(
model="BAAI/bge-reranker-large", top_n=5
)
query_engine = index.as_query_engine(
similarity_top_k=20,
node_postprocessors=[reranker]
)
response = query_engine.query("2024年Q3的退货率是多少?")
print(response)这12个决策是一张因果网,牵一发动全身。
4. 代码实践:LlamaIndex完整Pipeline
from llama_index.core import (
VectorStoreIndex, SimpleDirectoryReader, Settings
)
from llama_index.core.node_parser import SentenceSplitter
from llama_index.embeddings.openai import OpenAIEmbedding
from llama_index.core.postprocessor import SentenceTransformerRerank
from llama_index.llms.openai import OpenAI
Settings.llm = OpenAI(model="gpt-4o-mini", temperature=0)
Settings.embed_model = OpenAIEmbedding(model="text-embedding-3-small")
Settings.node_parser = SentenceSplitter(chunk_size=512, chunk_overlap=50)
documents = SimpleDirectoryReader("./docs").load_data()
index = VectorStoreIndex.from_documents(documents, show_progress=True)
reranker = SentenceTransformerRerank(
model="BAAI/bge-reranker-large", top_n=5
)
query_engine = index.as_query_engine(
similarity_top_k=20,
node_postprocessors=[reranker]
)
response = query_engine.query("2024年Q3的退货率是多少?")
print(response)
🛠️ 实战经验:上生产加三样:错误重试、结果缓存(高频问题TTL 1小时)、异步化(吞吐量提升3-5倍)。
5. 常见误区
❌ Embedding越大越好:E5-mistral-7b比BGE-M3的NDCG@5差距不到1%,但推理延迟差8倍。
❌ RAG = 向量搜索 + LLM:文档量十万级、并发百级时,缺任何环节都出问题。
❌ GraphRAG是下一代RAG:图索引token消耗是普通RAG的5-20倍,简单问答杀鸡用牛刀。
练习
延伸阅读
📖 下一篇:第7篇:千卡训练实战——分布式通信优化与故障恢复,深入千卡集群的AllReduce优化、流水线并行调度和训练中断自动恢复。