RAG(Retrieval-Augmented Generation)是目前大模型落地最常见的架构之一。原理说起来不复杂:先检索相关文档,再把检索结果塞进上下文让模型回答。但真正在生产环境跑起来之后,你会发现坑几乎全在工程细节里。
这篇文章记录我在实际项目中踩过的五个典型陷阱,以及对应的思考。
陷阱一:检索质量被 Embedding 模型的选择锁死
很多团队在 RAG 项目初期会随手选一个 Embedding 模型——比如 OpenAI 的 text-embedding-3-small 或者某个开源模型。一旦数据量上来、索引建好,想换模型就意味着全量重建索引。
问题不在于”换模型麻烦”,而在于很多人根本没意识到 Embedding 模型的选择直接决定了检索的天花板。如果你的文档是中文技术文档,而 Embedding 模型对中文理解一般,那无论你后面怎么调 top-k、怎么 rerank,检索结果都不会好。
建议:在项目早期就用一小批标注数据做 Embedding 模型的横向对比。不需要很多——50 到 100 个 query-document pair 就够做初步筛选了。
陷阱二:Chunk 策略不是”切 500 token”那么简单
最常见的 Chunk 策略是按固定长度切分,比如每 500 token 一个 chunk,前后重叠 50 token。这在简单场景下可以工作,但一旦文档结构复杂——比如有表格、有代码块、有多级标题——固定切分就会破坏语义完整性。
一个被切成两半的表格,检索出来拼进 prompt,模型看到的就是半张表。它不会报错,但会”一本正经地胡说八道”。
更好的做法是结合文档结构做语义切分:
- 按标题层级切分,保证每个 chunk 是一个完整的段落或小节
- 对表格和代码块做特殊处理,整块保留
- 给每个 chunk 附加元数据:来源文档、章节路径、页码
这些元数据在后面做 rerank 和来源标注时非常有用。
陷阱三:Top-K 检索不等于”相关”
检索返回的 top-5 结果,很可能有 3 个是噪声。尤其是当用户的 query 比较模糊、或者文档库里有大量相似但不相关的内容时。
举个例子:用户问”怎么部署 Redis 集群”,检索可能会返回”Redis 性能调优”、“Redis 数据类型介绍”、“Redis 集群配置参数”等结果。它们都和 Redis 相关,但只有最后一个真正匹配用户意图。
解决这个问题,最有效的手段是加一层 Reranker。用 Cross-Encoder 对 query 和每个候选 chunk 做精排,把真正相关的内容推到前面。这一步的 latency 代价大约在 100-200ms,但对回答质量的提升是非线性的。
如果不想加 Reranker,至少要在 prompt 里告诉模型:“以下是检索到的参考资料,请自行判断哪些与问题相关,忽略不相关的内容。“
陷阱四:幻觉不是模型的问题,是你的上下文不够好
用户最常抱怨的 RAG 问题是”模型编造了不存在的内容”。但大多数时候,这不是模型主动在”骗人”,而是你给它的上下文不够好,它只能根据自己的参数知识来补全。
减少幻觉的关键不是换一个”更诚实”的模型,而是:
- 提高检索召回率——确保真正相关的文档被检索到
- 在 prompt 里明确约束——“如果参考资料中没有相关信息,请直接说不知道”
- 做来源标注——让模型引用具体的 chunk,用户可以自己验证
- 加一层后处理——检查回答中的关键声明是否有对应的 chunk 支持
这四步做下来,幻觉率可以从 30% 降到 5% 以下。
陷阱五:评估体系缺失导致优化没有方向
最后一个陷阱,也是最致命的:没有评估就没有迭代。
很多 RAG 项目的”优化”过程是这样的:调了一个参数,问了几个问题,感觉好像好了一点,就上线了。然后用户反馈”不好用”,又调回去。
一个最小可用的评估体系需要:
- 一组固定的 query-answer pair(至少 50 个,覆盖常见问题和边界情况)
- 检索质量指标:Recall@K、MRR,衡量检索环节的好坏
- 生成质量指标:忠实度(答案是否来自检索结果)、相关性(是否回答了用户的问题)
- 端到端指标:用户满意度、完成率
不需要一开始就完美。先用 50 个 case 跑通自动评估流程,每次改动前后跑一遍对比,就已经比”凭感觉”强十倍了。
最后
RAG 的核心价值是”让模型用你的数据回答问题”,但这个过程中的每一步——分块、嵌入、检索、重排、生成、评估——都有可能成为瓶颈。
不要迷信”端到端”。把每一步拆开看、拆开调,才是 RAG 工程化的正确姿势。