分享处理大规模文档的RAG系统经验,涵盖数据处理、检索优化等实战痛点,对生产级应用有直接参考价值。
过去 8 个月,我一直奋战在 RAG 一线。现在,我想分享一下:哪些方法真正有效,哪些只是浪费了我们的时间。我们为 Usul AI(900 万页)和一家未公开名称的法律 AI 企业(400 万页)构建了 RAG。
我们最初是跟着 YouTube 教程入门的。先用 Langchain,后来转向 Llamaindex。短短几天,我们就做出了一个可以运行的原型,进展让我们非常乐观。我们用一小部分数据(100 份文档)进行了测试,结果看起来非常好。接下来几天,我们开始在生产数据集上运行整套 pipeline,并在一周内让所有功能都跑了起来——简直不可思议。
但事实并非如此。最终结果并不理想,而且只有终端用户才能察觉到问题。接下来的几个月里,我们逐一重写系统中的各个部分,直到性能达到预期水平。下面是我们采取过的措施,并按照 ROI 排序。
并非所有上下文都能通过用户的最后一个 query 捕获。我们让 LLM 审阅整个对话线程,并生成多个语义 query 和关键词 query。随后,我们并行处理所有这些 query,再把结果传给 reranker。
这种方式让我们可以覆盖更广的信息范围,也不必依赖 hybrid search 计算出来的单一分数。
这是你能添加的、价值最高的 5 行代码。经过 reranking 后,chunk 的排序发生了很大变化,幅度比你预想的还要明显。
如果传入足够多的 chunk,reranking 往往能弥补糟糕的系统配置。我们发现,理想的 reranker 配置是:输入 50 个 chunk,输出 15 个 chunk。
这部分需要投入大量精力,你的大部分时间很可能都会花在这里。
我们为两家企业分别构建了自定义流程。一定要深入理解数据、检查生成的 chunk,并确认:
最开始,我们只把 chunk 文本传给 LLM。后来通过实验发现,如果同时注入相关 metadata,例如标题、作者等,能够大幅改善上下文质量和回答效果。
许多用户提出的问题其实无法通过 RAG 回答,例如“总结这篇文章”或“这是谁写的”。
我们创建了一个轻量级 router,用来识别这类问题,并通过 API 调用配合 LLM 直接回答,而不是启动完整的 RAG 系统。
Azure -> Pinecone -> Turbopuffer(价格便宜,原生支持关键词搜索)
Custom
默认使用 Unstructured.io,企业项目使用自定义方案(听说 Chonkie 不错)
text-embedding-3-large,尚未测试其他方案
None -> Cohere 3.5 -> Zerank(知名度较低,但实际效果很好)
GPT 4.1 -> GPT 5 -> GPT 4.1,由 Azure credits 覆盖费用
我们把所有经验都整理进了一个采用 MIT license 的开源项目:agentset-ai/agentset。如果你有任何问题,欢迎联系我们。