返回博客
·AI技术

RAG 系统踩过的坑,都是钱买的

做 RAG 系统别一上来就搞框架

#LLM#RAG#向量数据库

# RAG 系统踩过的坑,都是钱买的

先说个数据:我们团队做 RAG 系统前后花了将近三个月,烧了大概六万块云资源费,最后上线的版本跟第一个 MVP 几乎一模一样。听起来很蠢对吧?但这里面每一个坑都挺有代表性的,写出来让大家避一避。

坑一:先搞向量数据库,再想数据怎么切

我们第一个版本的错误流程是:先选了 Pinecone 做向量数据库,选了 BGE-large 做 embedding 模型,然后才开始整理数据。

结果发现:我们的文档格式很乱——PDF 扫描件、Word 文档、HTML 页面、Excel 表格混在一起。直接丢进 embedding 模型里,切出来的 chunk 质量差到离谱。有的 chunk 只有半句话,有的 chunk 包含了整个页面的元数据(页眉页脚导航栏),检索出来全是噪声。

**正确的做法**:先花两周时间整理数据源。搞清楚你的文档长什么样、什么格式、大概多少量级。格式清洗比选 embedding 模型重要十倍。

我们后来重做的时候,先做了一个数据管道:PDF 用 OCR 转文本,Word 直接解析,HTML 抽正文,Excel 转 markdown 表格。花了一周时间,但后续的检索质量提升了至少一个量级。

坑二:Chunk 大小不是越大越好

这是一个普遍的误区。很多人觉得 chunk 越大上下文越完整,检索效果越好。实际上不是。

我们的测试数据:

  • chunk_size=256(约 128 个中文字符):准确率 62%
  • chunk_size=512:准确率 71%
  • chunk_size=1024:准确率 68%(反而下降了)
  • chunk_size=2048:准确率 55%(断崖式下跌)
  • 原因很简单:chunk 太大之后,检索出来的内容里面混入了大量无关信息,LLM 处理的时候注意力被分散,反而影响回答质量。而且 chunk 越大,embedding 的语义集中度越低。

    **结论**:对于中文内容,chunk_size 在 300-500 字符区间效果最好。而且要用重叠(overlap)来保证语义连续性,我们用的是 50-100 字符的重叠。

    坑三:不要只用向量检索

    纯向量检索有个致命缺陷:它只能找到"语义相似"的内容,找不到"精确匹配"的内容。

    举个例子:用户问"合同编号 HT-2025-0892 的签署方是谁",向量检索大概率会给你一堆关于合同签署的通用内容,而不是这个具体编号的信息。

    我们后来加了 Hybrid Search——向量检索 + BM25 关键词检索——然后把两个结果用 Reciprocal Rank Fusion 合并。准确率从 71% 提升到了 84%。

    代码上不算复杂:

    from sentence_transformers import SentenceTransformer

    from elasticsearch import Elasticsearch

    model = SentenceTransformer('BAAI/bge-large-zh')

    es = Elasticsearch(['http://localhost:9200'])

    def hybrid_search(query: str, top_k: int = 10):

    # 向量检索

    query_embedding = model.encode(query).tolist()

    vector_results = es.search(

    index='docs',

    body={

    'size': top_k,

    'query': {

    'script_score': {

    'query': {'match_all': {}},

    'script': {

    'source': 'cosineSimilarity(params.q, \'embedding\') + 1.0',

    'params': {'q': query_embedding}

    }

    }

    }

    }

    )

    # BM25 检索

    keyword_results = es.search(

    index='docs',

    body={

    'size': top_k,

    'query': {

    'multi_match': {

    'query': query,

    'fields': ['title', 'content'],

    'type': 'best_fields'

    }

    }

    }

    )

    # RRF 合并

    return rrf_rank(vector_results, keyword_results, top_k)

    坑四:评估比实现重要

    这是我最后悔没有早点做的事。我们前两个月一直在"调模型""调参数""换数据库",但从来没有系统性地评估过效果。

    直到有一天产品负责人问"我们这系统到底准不准",我们愣是答不上来。

    后来我们做了一套评估体系:

  • 从真实用户问题里采样 200 条
  • 2. 每条问题人工标注"期望答案"

    3. 用 Retriever F1、Answer Relevancy、Context Precision 三个指标量化评估

    做完评估之后发现:我们换了三个 embedding 模型,效果差异不超过 3%;但 chunk 策略的调整带来了 15% 的提升。

    **教训**:先建评估体系,再优化。没有评估的优化就是拍脑袋。

    坑五:忘记处理"我不知道"的情况

    最后一个坑,但可能是最致命的。我们最初版本的 RAG 系统有一个问题:当检索结果不相关时,它还是会硬着头皮回答,而且看起来"很有自信"。

    用户问"我们的差旅报销标准是什么",检索结果里根本没有这个内容,但模型会基于一些无关的文档片段编一个答案出来,还带着一股"我确定是这样"的语气。

    这个在 AI 安全里叫"幻觉",但在业务场景里叫"事故"。

    解决方案是用一个"置信度阈值"——当检索到的 chunk 和问题的语义相似度低于某个阈值时,直接返回"抱歉,我暂时没有找到相关信息",而不是硬答。

    我们在生产环境设的阈值是 cosine_similarity > 0.72,低于这个值的查询走 fallback 流程,转人工或者提示用户换一种问法。这个设置让误答率从 18% 降到了 3%。

    一句话总结

    RAG 系统的核心不是选哪个模型、用哪个向量数据库,而是**数据质量**和**评估体系**。先把这两件事做好,其他的都是锦上添花。