You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

LlamaIndex节点创建:生成Chunk时如何跟踪PDF页码?

实现跨页Chunk并跟踪来源页码的方案

你可以通过两种核心方式实现需求——既保留跨段落/跨页的Chunk完整性,又能准确跟踪来源页码:

方法一:先合并连续页的不完整段落,再拆分并标记页码范围

这种方式先处理PDF加载逻辑,判断连续页的文本是否属于同一未完成段落,合并后再生成带页码元数据的Document,最后用你当前的TokenTextSplitter和SimpleNodeParser拆分。

代码示例

import pdfplumber
from llama_index import Document, SimpleNodeParser, TokenTextSplitter

def load_pdf_with_merged_blocks(pdf_path):
    # 提取每页文本及页码
    page_items = []
    with pdfplumber.open(pdf_path) as pdf:
        for page_num, page in enumerate(pdf.pages, start=1):
            page_items.append({"page": page_num, "text": page.extract_text().strip()})
    
    # 合并连续页的不完整段落
    merged_blocks = []
    if not page_items:
        return []
    current_block = {"pages": [page_items[0]["page"]], "text": page_items[0]["text"]}
    for item in page_items[1:]:
        prev_text_end = current_block["text"][-1] if current_block["text"] else ""
        # 判断前一页末尾是否为不完整段落(可根据实际标点调整规则)
        if prev_text_end not in ('.', '!', '?', '”', '’'):
            current_block["pages"].append(item["page"])
            current_block["text"] += " " + item["text"]
        else:
            merged_blocks.append(current_block)
            current_block = {"pages": [item["page"]], "text": item["text"]}
    merged_blocks.append(current_block)
    
    # 生成带页码元数据的Document列表
    docs = []
    file_name = pdf_path.split("/")[-1]
    for block in merged_blocks:
        page_range = f"{min(block['pages'])}-{max(block['pages'])}" if len(block['pages'])>1 else f"{block['pages'][0]}"
        docs.append(Document(
            text=block["text"],
            metadata={"file_name": file_name, "pages": page_range}
        ))
    return docs

# 初始化拆分器与解析器
text_splitter = TokenTextSplitter(chunk_size=512, chunk_overlap=64)
parser = SimpleNodeParser(text_splitter=text_splitter)

# 加载PDF并生成Nodes
pdf_docs = load_pdf_with_merged_blocks("target_document.pdf")
nodes = parser.get_nodes_from_documents(pdf_docs)

# 查询时获取页码信息
# (假设已构建index并生成query_engine)
response = query_engine.query("你的查询问题")
for node in response.source_nodes:
    print(f"来源页码:{node.metadata['pages']} | 文件:{node.metadata['file_name']}")
    print(f"片段内容:{node.text[:200]}...\n")

方法二:插入页码标记后拆分,再解析标记获取页码范围

这种方式先将整个PDF的文本拼接,插入页码标记,再拆分Chunk,最后通过解析Chunk中的标记确定覆盖的页码范围,无需提前判断段落完整性。

代码示例

import pdfplumber
from llama_index import Document, SimpleNodeParser, TokenTextSplitter

def load_pdf_with_page_markers(pdf_path):
    full_text = ""
    file_name = pdf_path.split("/")[-1]
    with pdfplumber.open(pdf_path) as pdf:
        for page_num, page in enumerate(pdf.pages, start=1):
            # 在每页文本前插入页码标记
            full_text += f"[PAGE:{page_num}]\n{page.extract_text().strip()}\n"
    return Document(text=full_text, metadata={"file_name": file_name})

def attach_page_metadata(nodes):
    for node in nodes:
        # 从Chunk文本中提取所有页码标记
        page_numbers = []
        for token in node.text.split():
            if token.startswith("[PAGE:") and token.endswith("]"):
                try:
                    page_num = int(token[6:-1])
                    page_numbers.append(page_num)
                except ValueError:
                    continue
        if page_numbers:
            min_page = min(page_numbers)
            max_page = max(page_numbers)
            node.metadata["pages"] = f"{min_page}-{max_page}" if min_page != max_page else f"{min_page}"
        else:
            node.metadata["pages"] = "未知"
    return nodes

# 加载PDF并拆分
doc = load_pdf_with_page_markers("target_document.pdf")
text_splitter = TokenTextSplitter(chunk_size=512, chunk_overlap=64)
parser = SimpleNodeParser(text_splitter=text_splitter)
nodes = parser.get_nodes_from_documents([doc])
nodes = attach_page_metadata(nodes)

# 查询时获取页码信息
response = query_engine.query("你的查询问题")
for node in response.source_nodes:
    print(f"来源页码:{node.metadata['pages']} | 文件:{node.metadata['file_name']}")

方案对比

  • 方法一更适合优先保证段落完整性的场景,元数据直接标记Chunk对应的原始页码范围,无需后续解析。
  • 方法二更灵活,不需要提前定义段落结束规则,适合文本格式复杂的PDF。

内容的提问来源于stack exchange,提问作者Joanne B

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.08 23:21:08