[Bug] naive_merge “custom delimiter” branch silently bypasses chunk_token_num, splitting on stray bare chars

当 parser_config.delimiter 中包含反引号包裹的 token(即“自定义分隔符”)时, rag.nlp.naive_merge 会进入 has_custom 分支,完全跳过 chunk_token_num 合并逻辑,把每个 re.split 片段直接当成一个 chunk,导致

快速结论:parser_config.delimiter 中包含反引号包裹的 token(即“自定义分隔符”)时,rag.nlp.naive_merge 会进入 has_custom 分支,完全跳过 chunk_token_num 合并逻辑,把每个 re.split 片段直接当成一个 chunk,导致 chunk 数量暴增。排查时优先确认 delimiter 字段是否含有不配对或多余的反引号。

适用环境:Issue 已确认环境为 RAGFlow v0.27.0(Docker 镜像 infiniflow/ragflow:v0.27.0),Parser 为 naive (General),输入文件 a.txt(2,978,660 字节),chunk_token_num=512。Issue 中未提供操作系统、Python、CUDA、显卡或其他依赖版本。

最快修复方案:暂无确认的一步修复方案。Issue 讨论中给出的方向是修改 naive_mergehas_custom 分支,让自定义分隔符拆分后的片段也走 _merge_paragraph_groups 合并逻辑,而不是直接 cks.append。该改动尚未合并,且需要同步更新 test_naive_merge.py 中的既有测试 test_custom_delimiter_ignores_chunk_size,否则 CI 会按现有断言判定为回归。

注意事项:当前自定义分隔符忽略 chunk_token_num 是被测试用例 test_custom_delimiter_ignores_chunk_size 明确断言的“现有行为”,修复属于行为变更。此外 parse_delimiter_field 会把反引号外的每个字符都当作单字符分隔符,与 Go 侧 CompileDelimiterPatternListkeepBare=false)的解析行为存在分歧,修复合并逻辑本身不解决分隔符解析分歧。

问题场景

在 RAGFlow 中使用 naive(General)解析器对文本文件做分块时,如果知识库的 parser_config.delimiter 中写入了反引号包裹的自定义分隔符,rag.nlp.naive_merge(以及 naive_merge_with_images)和 deepdoc.parser.txt_parser.RAGFlowTxtParser.parser_txt 会走一条特殊分支,绕过 chunk_token_num 合并。Issue 中用一个 2.8 MB 的文本文件、chunk_token_num=512 复现,最终产生约 430,000 个 chunk,每个只有 1–2 个 token,而预期应为约 1,400 个 chunk。该行为在 UI tooltip 中没有说明,用户只能通过直接修改数据库中的 parser_config 才能恢复。

报错原文

[Bug] naive_merge "custom delimiter" branch silently bypasses chunk_token_num, splitting on stray bare chars

parsed_dels: ['  ', '\n\n', '. ', '\n', ' ']
has_wrapped_delimiter: True
STAGE 1 TxtParser: 1334 sections          ← correct
STAGE 2 naive_merge: 429006 chunks        ← 300× too many
  min=2, max=14, avg=2.6

原因分析

最可能的原因是:naive_merge 中的 has_custom 分支在 has_wrapped_delimiter(delimiter) 返回 True 时,会把 re.split 得到的每个片段直接 cks.append,不经过 chunk_token_num 的合并判断。代码注释本身也写明了意图:Custom delimiters ignore chunk_token_num: each segment is its own chunk.

进一步地,parse_delimiter_field 会把反引号外的每个字符都当成独立的单字符分隔符,因此不配对的反引号会让裸空格等字符泄漏进 parsed_dels,随后 compile_delimiter_pattern 把这些字符全部交给 re.split。Issue 中的 delimiter 为 "\n` `` ``\n\n``. `",反引号不配对,解析结果为 [' ', '\n\n', '. ', '\n', ' ']。作为对比,Go 侧 CompileDelimiterPatternListkeepBare=false(主分隔符路径)会丢弃裸条目,只启用被包裹的内容,因此不会在这些裸字符上切分;children_delimiters 路径的 keepBare=true 才会启用裸条目,但那是另一套列表。

Issue 讨论同时确认:PR #17203(2026-08-01 合并)只修复了默认(非自定义)路径上的软上限越界问题,其 out-of-scope 说明中明确保留了自定义分隔符分支;PR #17692(仍开放)修复的是 _merge_cks / naive_merge_docx,属于另一条合并路径,不是 naive_merge 里的 has_custom 分支。

环境排查

  • 确认 RAGFlow 版本是否为 v0.27.0(Issue 复现版本,Docker 镜像 infiniflow/ragflow:v0.27.0)。
  • 确认解析器是否为 naive(General)。
  • 检查 knowledgebase.parser_config 中的 delimiter 字段,是否存在反引号包裹 token、反引号数量不配对或存在空反引号对。
  • 确认 chunk_token_num 的实际取值(Issue 中为 512)。
  • 对比 Stage 1(RAGFlowTxtParser.parser_txt)与 Stage 2(naive_merge)的输出 chunk 数量,定位问题发生在哪一阶段。
  • Issue 未提供操作系统、Python、CUDA、PyTorch、显卡信息,这些项目无需作为已知条件核对。

解决步骤

  1. 先确认触发条件:检查 parser_config.delimiter 是否包含反引号包裹内容。可优先尝试调用 parse_delimiter_fieldhas_wrapped_delimiter 打印解析结果,参考 Issue 复现脚本中的输出,确认 has_wrapped_delimiterTrueparsed_dels 中混入了裸字符。
  2. 分别统计 Stage 1 与 Stage 2 的产物数量:若 parser_txt 返回的 section 数正常(如 1,334),而 naive_merge 返回的 chunk 数量异常放大(如 429,006),即可确认问题出在 naive_mergehas_custom 分支。
  3. 若必须立即恢复:Issue 指出只能通过直接修改数据库中的 parser_config 来改变行为,例如调整 delimiter 使其不再走自定义分支。Issue 未给出具体的 SQL 或 UI 操作步骤,执行前请先备份对应知识库配置。
  4. 若按 Issue 讨论方向修复代码,可优先尝试:去掉 naive_mergehas_custom 的 early return,让自定义分隔符拆分出的片段同样进入共享的 _merge_paragraph_groups 合并路径,或保留 custom_patternre.split 之后复用默认路径的合并调用。该方案在 Issue 中仅为建议,尚未合并。
  5. 同步更新测试:test_naive_merge.pytest_custom_delimiter_ignores_chunk_sizechunk_token_num=1000 断言恰好 3 个 chunk(partA、partB、partC)。若采用上述修复,三段会被合并为一段,需要把 chunk_token_num 调整为能单独容纳每个片段、但不能同时容纳全部片段的真实值,否则 CI 会按假回归拒绝该修复。

验证方法

用同一个 2.8 MB 文本文件和相同的 chunk_token_num=512 重新跑一遍两阶段流程:Stage 1 的 section 数应与修复前一致(约 1,334),Stage 2 的 chunk 数应从 429,006 量级回落到接近预期的千级(Issue 预期约 1,400),且 chunk 的 token 分布不再是最小 2、最大 14、平均 2.6 这种碎片化形态。同时确认默认(非自定义)分隔符路径的既有测试仍然通过,避免合并逻辑共用后引入回归。

参考来源

infiniflow/ragflow #18552

GamsGo AI

AI 工具推荐

想把多个 AI 模型放在一个入口?

GamsGo AI 集成 ChatGPT、DeepSeek、Gemini、Claude、Midjourney、Veo 等常用模型,适合写作、绘图、视频和日常 AI 工作流。

了解 GamsGo AI

推广链接:通过此链接购买,我可能获得佣金,不影响你的价格。

这个方案解决了吗?

celebrityanime
celebrityanime
文章: 24058

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注