PageIndex 研究

PageIndex 研究

  1. 短文档直接合并
  2. 切分文档(切分阈值)
python 复制代码
- num_tokens / expected_parts_num = 「理想均分」时每块的大小;
- max_tokens = 「硬上限」;
- 阈值取两者的中点。
expected_parts_num = math.ceil(num_tokens / max_tokens) # 至少要切几块
average_tokens_per_part = math.ceil(((num_tokens / expected_parts_num) + max_tokens) / 2)
  1. 贪心累加+overlap:章节边界不可能一定对应切分阈值(块边界),每相邻两组共享 1 页,边界同时出现在「上一组的尾部」和「下一组的头部」
python 复制代码
for i, (page_content, page_tokens) in enumerate(zip(page_contents, token_lengths)):
    if current_token_count + page_tokens > average_tokens_per_part:   # 加这页会超阈值
        subsets.append(''.join(current_subset))                       # ① 先把当前组存下来
        overlap_start = max(i - overlap_page, 0)                       # ② 新组从「前一页」开始
        current_subset = page_contents[overlap_start:i]                #    (默认回退1页=overlap)
        current_token_count = sum(token_lengths[overlap_start:i])
    current_subset.append(page_content)                                # ③ 再把当前页加入新组
    current_token_count += page_tokens

关键在 overlap_page=1:每相邻两组共享 1 页。边界页同时出现在「上一组的尾部」和「下一组的头部」。

为什么必须 overlap?

因为章节边界不可能正好对齐我们强加的「块边界」。 一个节标题可能出现在第 X 页底部(恰是第 N 组最后一页),而正文流到第 N+1 组。没有 overlap 时:

  • 第 N 组的 LLM 看到标题但内容被截断,无法判定该节「起始页」;
  • 第 N+1 组的 LLM 只看到无标题的正文,没法锚定 physical_index

overlap 1 页后,边界页两组都可见 → 跨边界的节能被一致地定位。在两个调用场景里这正是关键:

  • process_no_toc:第一块用 generate_toc_init 建树,后续块用 generate_toc_continue 续写树(:586-589)。overlap 让续写处能正确衔接。
  • process_toc_no_page_numbers:树已知,逐块用 add_page_number_to_toc 定位每节起始页(:611-612)。overlap 保证边界上的节不丢、不重。

大节点递归细分(处理「检索单元过大」的节点),触发条件:页数+Token(避免了过度碎片化)。如:

  • 避免页多但内容稀疏(附录等,细分会得到近乎空的叶子,无意义)
  • Token密,但页少。本身就是紧凑单元,不必拆分