最近在做一个人事制度问答的RAG demo,用的bge-m3 + faiss + qwen。制度文档里有大量表格和条款引用,我一开始按markdown标题切chunk,每块500字左右。结果发现很多问题:比如用户问“年假和事假冲突怎么算”,系统老是检索到讲“年假定义”的段落,而不是真正讲“请假审批流程”的那段。我试过加长chunk到800字,也试过加overlap,效果都不稳。想请教下大家,这种带结构化文本的文档,chunk策略一般怎么设计?是不是应该先把表格和正文分开处理,还是直接上rerank更靠谱?目前预算有限,不想一开始就上太重的东西。
RAG系统检索质量差,是不是我chunk切法有问题?
全部回复
共 23 条这个问题其实挺典型的,结构化文档直接按字数硬切确实很容易把语义切碎。你遇到的问题本质上是query和chunk的语义空间没对齐,问的是“冲突怎么算”,但“年假定义”那段里可能也有“年假”“请假”这些高频词,向量检索就容易被带偏。我觉得你可以先把表格和正文分开处理,表格单独转成自然语言描述再入库,比如把一行数据改写成“员工入职满一年可享受5天年假”这种句子,检索命中率会高不少。另外条款引用那块,可以试试在chunk里保留它所属的章节标题路径,当作上下文前缀拼进去,这样embedding里就带上了层级信息。至于rerank,预算有限的话可以先不上模型,用bge-m3本身的稀疏向量做混合检索,或者加个简单的关键词召回兜底,成本几乎为零。你现在这个规模,先把chunk的语义完整性做好,比急着上rerank收益大得多。
你这个情况我遇到过,大概率不是chunk长度的问题,是切法把语义单元切碎了。markdown标题切的话,“请假审批流程”和“年假定义”很可能被分到同一块或者相邻块里,检索时语义相似度区分不开。建议试试按条款粒度切,每个条款带上一级标题做上下文锚点,表格单独走结构化提取。预算有限的话先别上rerank,把chunk边界调对了收益比加rerank大得多。
你这个问题我踩过类似的坑,切法只是表象,核心是召回和排序没分家。按markdown标题切对纯文本还行,但制度文档里表格和条款引用一多,语义就被切碎了,“年假和事假冲突”这种问法压根不在任何单块里完整出现。我建议表格单独抽出来走结构化检索,正文再按条款粒度切,别死磕固定字数,条款边界天然比500字合理。然后别急着上rerank,先看看你的topk是不是取太少了,很多时候答案在第8、第10条被砍掉了。预算有限的话,bge-m3本身可以同时做dense和sparse,用混合检索把关键词召回补上,这块几乎零成本。真正要加rerank的话,bge-reranker-base这种轻量级也就够用了,不用一上来就上大模型。另外你那个query其实隐含了多跳,先定位请假流程再算冲突规则,单次检索确实容易翻车,可以考虑让qwen先改写query再检索。