咨询发布 发表于 2026-2-14 14:22:33

用LlamaIndex搭多文档RAG:父子分块加混合检索的踩坑手记

为什么不是朴素RAG

朴素RAG(一个chunk一个向量,top-k检索)跑了一周就发现三个问题:长文档被切碎上下文丢失,多个文档之间引用错乱,准确率不到60%。改用父子分块加混合检索后,准确率拉到85%,记录一下踩过的坑。

父子分块怎么搞

核心思路:检索用小块(200字),返回用大块(父块2000字)。LlamaIndex里用SentenceWindowNodeParser或者HierarchicalNodeParser都行。我用的是后者,配AutoMergingRetriever,相邻小块命中超过3个自动合并成父块,上下文不丢。


[*]分块:父块2000字,子块2000字再切200字,父子用关系链关联。
[*]索引:子块建向量索引,父块用docstore存原始文本。
[*]检索:query子块索引top-10,命中的子块去重取父,合并后塞给LLM。


混合检索的坑

只跑向量检索精度不够,加BM25关键词检索,做融合。LlamaIndex有QueryFusionRetriever,把vector加bm25两个检索器结果做RRF融合。权重默认各0.5,但我的文档专业词多,BM25提到0.6准确率高5个点。

坑在Embedding模型。我一开始用OpenAI text-embedding-3,中文文档准确率70%。换成BGE-M3中文专模型后到84%。BGE-M3同时支持稠密加稀疏加ColBERT三种向量,一个模型顶三个检索器,省事。

部署代码骨架


from llama_index.core import VectorStoreIndex, StorageContext, load_index_from_storage
from llama_index.core.node_parser import HierarchicalNodeParser
from llama_index.retrievers import AutoMergingRetriever
from llama_index.core.query_engine import RetrieverQueryEngine

parser = HierarchicalNodeParser.from_defaults(chunk_sizes=)
nodes = parser.get_nodes_from_documents(docs)
auto_retriever = AutoMergingRetriever.from_defaults(retriever, storage_context)
engine = RetrieverQueryEngine.from_args(auto_retriever)
response = engine.query("xxx条款怎么规定的")


最大成本坑是重排。top-10召回塞给LLM太多,加个bge-reranker-v2重排取top-3,token量砍60%,准确率不降反升。reranker跑CPU也行,单次重排200ms,能接受。

https://www.metk.cn/img/posts/llamaindex_rag_chunking.jpg

野渡的猫 发表于 2026-2-15 15:06:24

有个坑提醒一下,接口一变整套流程都得跟着改,最好提前做抽象层。

秋刀小筑 发表于 2026-2-15 18:34:01

说实话这个投入产出比确实得看行业,我们做传统制造的,算下来还不如人工。

有点困2 发表于 2026-2-16 01:29:15

这个结论我保留意见,至少在我们行业不太成立,可能跟样本有关。

陆离 发表于 2026-2-16 11:52:07

帖子里那个数字挺关键的,不过不同规模的团队差异会很大,不能直接套。

言默北岛 发表于 2026-2-17 01:42:36

这个成本账算得很实在,我这边也是类似情况,量小的时候真没必要自己折腾。

听风62 发表于 2026-2-17 19:00:42

写得挺到位的,不过我觉得还是要区分"能用"和"好用",中间差着一大截。

打盹的猫杂谈 发表于 2026-2-18 15:46:26

用过类似的,前期调优确实费人,但稳定跑了之后省心不少,值得。

一叶杂谈 发表于 2026-2-19 15:59:47

我之前也研究过这个方向,最后放弃了,主要是我这边数据量根本不够。

晚风随笔 发表于 2026-2-20 19:40:45

成本这块还可以再拆细一点,隐性的人力投入其实占大头。
页: [1] 2 3 4 5 6
查看完整版本: 用LlamaIndex搭多文档RAG:父子分块加混合检索的踩坑手记