☰
garden-skills 的 kb-retriever 实战指南:PDF 读取与分析的完整工具链与方法论
2026/10/3 8:41:31 网站建设 项目流程
  • 人工智能
  • AI 技能/插件
  • 提示工程

【免费下载链接】garden-skills

ConardLi's open-source Skills collection, featuring web design, knowledge retrieval, image generation, and more.

项目地址:https://gitcode.com/GitHub_Trending/we/garden-skills
点击查看免费下载

本文以 pdf_reading.md 为骨架,系统讲解在本地知识库检索场景(garden-skills 项目中的 kb-retriever Skill)下如何正确读取和分析 PDF:从 pdftotext 快速文本提取、pdfplumber 表格与布局提取,到扫描件 OCR、加密 PDF 解密与批量处理,再到结合 grep 的渐进式检索方法论。读完你将掌握一套"先学习、再处理、后检索"的 PDF 处理工作流,能够在真实知识库中高效提取信息而不浪费任何 token。

为什么先读本文档:kb-retriever 的强制学习机制

garden-skills 仓库中的 kb-retriever 是一个面向本地多格式知识库(Markdown / PDF / Excel)的检索与问答 Skill,其核心设计原则是先学习、再处理:当候选文件集合中出现 PDF 时,Agent 被强制要求先阅读 references/pdf_reading.md,理解推荐的工具与方法后,才能动手处理文件,严禁跳过学习步骤直接对原始二进制 PDF 进行检索。

在 SKILL.md 的"遇到 PDF 或 Excel 文件时的强制检查清单"中明确列出了四步:

  • ✅ 已读取对应的 references 文档学习处理方法
  • ✅ 已理解推荐的工具和命令
  • ✅ 已将文件处理(提取/转换)完成
  • ⏭️ 现在可以开始检索

并明确禁止:"在未读取 pdf_reading.md 的情况下直接尝试处理 PDF"、"跳过文件处理步骤,直接对原始 PDF/Excel 进行检索"。因此,本文档是任何 PDF 处理动作的前置知识,必须在使用之前完整阅读。

快速决策表:按场景选择工具

不同 PDF 的处理目标对应不同的工具选型。以下是核心决策依据:

场景推荐工具原因命令/代码示例
纯文本提取(最常见)pdftotext 命令最快最简单pdftotext input.pdf output.txt
需要保留布局pdftotext -layout保持原始排版pdftotext -layout input.pdf output.txt
需要提取表格pdfplumber表格识别能力强page.extract_tables()
需要元数据pypdf轻量级reader.metadata
扫描PDF(图片)OCR (pytesseract)无其他选择先转图片再OCR

从工具形态看,决策表实际上覆盖了三条路线:命令行工具(poppler-utils 全家桶)、Python 库(pypdf / pdfplumber / pypdfium2)以及OCR 兜底路线(pdf2image + pytesseract)。文档给出明确的推荐优先级(从高到低):

  1. pdftotext 命令行工具——最快,适合大多数 PDF
  2. pdfplumber——适合需要保留布局或提取表格
  3. pypdf——轻量级,适合简单提取
  4. OCR——仅用于扫描 PDF 或无法直接提取文本的情况

这一优先级与 kb-retriever 的整体性能理念一致:README.zh-CN.md 强调"渐进式检索,grep 优先 + 窗口读取,从不整文件加载,大语料下也能控制住 token"——而 pdftotext 作为最快的提取工具自然成为首选。

快速开始:使用 pdftotext(推荐路线)

pdftotext 来自 poppler-utils 工具包,是所有场景中最快的文本提取方案。使用时有一条铁律:必须将输出保存到文件,不要直接输出到终端(stdout),否则会占用大量 token。

# ✅ 正确:提取文本到文件(最快最简单) pdftotext input.pdf output.txt # ✅ 正确:保留布局并输出到文件 pdftotext -layout input.pdf output.txt # ✅ 正确:提取特定页面到文件 pdftotext -f 1 -l 5 input.pdf output.txt # 第1-5页 # ❌ 错误:不要使用 stdout(会占用大量 token) # pdftotext input.pdf -

使用流程(这也是 kb-retriever 检索 PDF 的标准链路):

  1. 使用 pdftotext 提取文本到临时文件
  2. 使用 grep 或 Read 工具对生成的文本文件进行检索
  3. 只读取匹配部分的上下文,而非全文

在 SKILL.md 的 PDF 检索策略中,这一流程被进一步细化为完整工作流:读取处理方法指南 → 根据data_structure.md选择最相关的 1-3 个候选 PDF → 用 pdftotext 提取到文件 → 用 grep 对提取结果执行关键词搜索 → 对每个命中只读取命中附近范围的上下文(上下数十行或相邻几页)→ 保存「文件名 + 页码/大致位置 + 文本片段」→ 应用多轮迭代检索机制。

超大 PDF 的分页控制

对于超大 PDF,README.zh-CN.md 给出了明确的实践建议:使用按页范围抽取pdftotext -f 1 -l 10,对结果文本 grep,然后只读取匹配页面附近的内容,避免一次性处理整个文件。

Python 库详解

pypdf——轻量级基本文本提取与元数据

pypdf 是 BSD 许可的轻量级库,适合简单提取。它的两大优势是元数据读取与极低的依赖开销:

from pypdf import PdfReader reader = PdfReader("document.pdf") # 提取全部文本 for page in reader.pages: text = page.extract_text() print(text) # 提取元数据 meta = reader.metadata print(f"Title: {meta.title}") print(f"Author: {meta.author}") print(f"Subject: {meta.subject}") print(f"Creator: {meta.creator}")

也可以先获取页数再决定是否继续:

from pypdf import PdfReader # 读取 PDF reader = PdfReader("document.pdf") print(f"Pages: {len(reader.pages)}") # 提取文本 text = "" for page in reader.pages: text += page.extract_text()

pypdf 同时支持加密 PDF 的解密(详见下文"处理加密 PDF"章节),因此在需要处理受密码保护的文件时,它是首选。

pdfplumber——带布局的文本与表格提取

pdfplumber(MIT 许可)是结构化数据提取的主力,特别擅长表格识别与按坐标精确定位。它的 API 设计以page为操作单元,逐页处理天然适配"渐进式"理念。

提取文本(保留布局):

import pdfplumber with pdfplumber.open("document.pdf") as pdf: for page in pdf.pages: text = page.extract_text() print(text)

提取表格:

with pdfplumber.open("document.pdf") as pdf: for i, page in enumerate(pdf.pages): tables = page.extract_tables() for j, table in enumerate(tables): print(f"Table {j+1} on page {i+1}:") for row in table: print(row)

高级表格提取(转为 DataFrame):结合 pandas 可以将多页表格合并导出为 Excel,适合知识库中常见的数据报表类 PDF:

import pandas as pd with pdfplumber.open("document.pdf") as pdf: all_tables = [] for page in pdf.pages: tables = page.extract_tables() for table in tables: if table: # 检查表格非空 df = pd.DataFrame(table[1:], columns=table[0]) all_tables.append(df) # 合并所有表格 if all_tables: combined_df = pd.concat(all_tables, ignore_index=True) combined_df.to_excel("extracted_tables.xlsx", index=False)

带坐标的精确文本提取:当只需要提取页面特定区域的文本(例如合同中的签字栏、表单中的指定字段)时,可以基于字符坐标或边界框操作:

import pdfplumber with pdfplumber.open("document.pdf") as pdf: page = pdf.pages[0] # 提取所有字符及其坐标 chars = page.chars for char in chars[:10]: # 前10个字符 print(f"Char: '{char['text']}' at x:{char['x0']:.1f} y:{char['y0']:.1f}") # 按边界框提取文本 (left, top, right, bottom) bbox_text = page.within_bbox((100, 100, 400, 200)).extract_text()

复杂表格的高级设置:对于无明确边框线或线条断裂的复杂表格,可以自定义提取策略参数,并借助可视化调试定位问题:

import pdfplumber with pdfplumber.open("complex_table.pdf") as pdf: page = pdf.pages[0] # 自定义表格提取设置 table_settings = { "vertical_strategy": "lines", "horizontal_strategy": "lines", "snap_tolerance": 3, "intersection_tolerance": 15 } tables = page.extract_tables(table_settings) # 可视化调试 img = page.to_image(resolution=150) img.save("debug_layout.png")

其中vertical_strategy/horizontal_strategy控制竖线与横线的检测策略(lines表示仅依赖实际绘制的线条),snap_tolerance控制线条吸附容差(像素),intersection_tolerance控制线条交点判定容差,取值越大越容易合并断裂的线条。渲染调试图可用于人工核对表格边界识别是否正确。

pypdfium2——快速渲染与文本提取

pypdfium2(Apache/BSD 许可)的强项是高性能页面渲染,即把 PDF 页面转成位图,这是 OCR 与可视化预览的关键步骤:

import pypdfium2 as pdfium # 加载 PDF pdf = pdfium.PdfDocument("document.pdf") # 提取文本 for i, page in enumerate(pdf): text = page.get_text() print(f"Page {i+1} text length: {len(text)} chars")

将 PDF 页面渲染为图片:

import pypdfium2 as pdfium from PIL import Image pdf = pdfium.PdfDocument("document.pdf") # 渲染单页 page = pdf[0] # 第一页 bitmap = page.render( scale=2.0, # 高分辨率 rotation=0 # 不旋转 ) # 转换为 PIL Image img = bitmap.to_pil() img.save("page_1.png", "PNG") # 处理多页 for i, page in enumerate(pdf): bitmap = page.render(scale=1.5) img = bitmap.to_pil() img.save(f"page_{i+1}.jpg", "JPEG", quality=90)

scale参数控制渲染倍率(2.0 即 200% 分辨率,适合后续 OCR 的精度要求),rotation控制旋转角度(0/90/180/270),quality是 JPEG 压缩质量(0-100,90 为高质量默认推荐值)。

命令行工具全家桶(poppler-utils)

除 pdftotext 外,poppler-utils 还提供渲染与图片提取工具,构成完整的命令行处理链路。

pdftotext——完整参数说明

# ✅ 提取文本到文件 pdftotext input.pdf output.txt # ✅ 保留布局提取到文件 pdftotext -layout input.pdf output.txt # ✅ 提取特定页面到文件 pdftotext -f 1 -l 5 input.pdf output.txt # 第1-5页 # ✅ 提取带坐标的文本到 XML 文件(用于结构化数据) pdftotext -bbox-layout document.pdf output.xml # ❌ 避免:不要省略输出文件名(会输出到 stdout) # pdftotext input.pdf

参数含义:-layout尽可能保持原始排版(多栏文档建议开启);-f <页>/-l <页>指定提取页范围(从第 f 页到第 l 页);-bbox-layout输出包含每个词坐标信息的 XML,可用于后续结构化解析。

pdftoppm——高级图片转换

# 转换为 PNG,指定分辨率 pdftoppm -png -r 300 document.pdf output_prefix # 转换特定页面范围,高分辨率 pdftoppm -png -r 600 -f 1 -l 3 document.pdf high_res_pages # 转换为 JPEG,指定质量 pdftoppm -jpeg -jpegopt quality=85 -r 200 document.pdf jpeg_output

-r <dpi>指定渲染分辨率(300 为印刷标准,600 适合高精度 OCR),-jpegopt quality=<0-100>控制 JPEG 压缩质量。

pdfimages——提取嵌入图片

当 PDF 本身包含图片资源(而非文本层)时,直接提取比渲染页面快得多:

# 提取所有图片 pdfimages -j input.pdf output_prefix # 列出图片信息(不提取) pdfimages -list document.pdf # 以原始格式提取 pdfimages -all document.pdf images/img

-j输出 JPEG 格式,-list仅列出图片的页面位置、类型、尺寸等信息便于预筛选,-all以原始嵌入格式提取所有图片。

OCR 提取:扫描 PDF 的兜底方案

当 PDF 没有文本层(如扫描件、传真件),任何文本提取工具都会返回空结果。此时唯一的方案是 OCR:先把页面转成图片,再用 pytesseract 识别文字。

# 需要: pip install pytesseract pdf2image import pytesseract from pdf2image import convert_from_path # PDF 转图片 images = convert_from_path('scanned.pdf') # OCR 每一页 text = "" for i, image in enumerate(images): text += f"Page {i+1}:\n" text += pytesseract.image_to_string(image) text += "\n\n" print(text)

仓库自带的兜底脚本

kb-retriever 在 scripts/convert_pdf_to_images.py 中提供了一个现成的 PDF 转图片工具,正是为"文本抽取一无所获的扫描版 PDF"准备的兜底脚本。它的实现逻辑值得参考:

import os import sys from pdf2image import convert_from_path def convert(pdf_path, output_dir, max_dim=1000): images = convert_from_path(pdf_path, dpi=200) for i, image in enumerate(images): # Scale image if needed to keep width/height under `max_dim` width, height = image.size if width > max_dim or height > max_dim: scale_factor = min(max_dim / width, max_dim / height) new_width = int(width * scale_factor) new_height = int(height * scale_factor) image = image.resize((new_width, new_height)) image_path = os.path.join(output_dir, f"page_{i+1}.png") image.save(image_path) print(f"Saved page {i+1} as {image_path} (size: {image.size})") print(f"Converted {len(images)} pages to PNG images")

运行方式(命令行入口要求恰好两个参数):

python scripts/convert_pdf_to_images.py input.pdf output_dir/

脚本要点:以 200 dpi 渲染每一页;当页面宽度或高度超过max_dim(默认 1000 像素)时按比例缩放,既控制图片体积又保留可读性;每页输出为page_{n}.png并打印实际尺寸。该脚本可作为 OCR 流程的前置步骤,把 PDF 页面批量转为 PNG 后再交给 pytesseract 识别,其自动缩放到 1000 像素以内的策略也天然适配 LLM 视觉输入的尺寸限制。

处理加密 PDF

知识库中常出现受密码保护的 PDF。pypdf 提供了解密 API,qpdf 命令行则适合脚本化批处理。

pypdf 解密:

from pypdf import PdfReader try: reader = PdfReader("encrypted.pdf") if reader.is_encrypted: reader.decrypt("password") # 解密后可正常提取文本 for page in reader.pages: text = page.extract_text() print(text) except Exception as e: print(f"Failed to decrypt: {e}")

注意reader.is_encrypted用于先判断加密状态,decrypt("password")传入密码后即可正常提取。

qpdf 命令行解密:

# 使用 qpdf 解密(需要知道密码) qpdf --password=mypassword --decrypt encrypted.pdf decrypted.pdf # 检查加密状态 qpdf --show-encryption encrypted.pdf

批量处理:整目录 PDF 文本提取

知识库通常是成百上千个 PDF 的集合,逐个处理不现实。文档给出了带日志与异常容错的批量提取脚本:

import os import glob from pypdf import PdfReader import logging logging.basicConfig(level=logging.INFO) logger = logging.getLogger(__name__) def batch_extract_text(input_dir): """批量提取文本""" pdf_files = glob.glob(os.path.join(input_dir, "*.pdf")) for pdf_file in pdf_files: try: reader = PdfReader(pdf_file) text = "" for page in reader.pages: text += page.extract_text() output_file = pdf_file.replace('.pdf', '.txt') with open(output_file, 'w', encoding='utf-8') as f: f.write(text) logger.info(f"Extracted text from: {pdf_file}") except Exception as e: logger.error(f"Failed to extract text from {pdf_file}: {e}") continue

关键点:用glob收集目录内所有 PDF;逐文件 try/except 保证单个失败不影响整体;输出同名.txt文件;通过 logging 记录进度与错误。这与 kb-retriever "逐页或分块处理大文件"的内存管理原则一致。

性能优化:token 经济学的核心实践

处理 PDF 的最大风险不是 CPU 或内存,而是把大量文本直接灌进 LLM 上下文导致的 token 爆炸。文档给出的五条优化原则:

  1. 文件输出优先:始终将 pdftotext 输出保存到文件,然后用 grep/Read 检索,避免直接输出到终端占用大量 token
  2. 大型 PDF:使用流式方式逐页处理,避免一次性加载整个文件
  3. 文本提取:pdftotext最快;pdfplumber 适合结构化数据和表格
  4. 图片提取:pdfimages比渲染页面快得多
  5. 内存管理:逐页或分块处理大文件

其中第 1 条在 SKILL.md 中被反复强调:PDF 检索策略明确要求"使用pdftotext input.pdf output.txt将文本提取到文件,不要直接输出到 stdout(避免占用大量 token)"。整套 kb-retriever 的"grep 优先 + 窗口读取(limit ≈ 200–500 行)+ 最多 5 轮迭代收紧关键词"的渐进式检索机制,正是建立在这条优化原则之上。

快速参考表

任务最佳工具命令/代码
提取文本pdfplumberpage.extract_text()
提取表格pdfplumberpage.extract_tables()
命令行提取pdftotextpdftotext -layout input.pdf
OCR 扫描PDFpytesseract先转图片再OCR
提取元数据pypdfreader.metadata
PDF转图片pypdfium2page.render()

可用包一览

包用途许可证
pypdf基本操作BSD
pdfplumber文本和表格提取MIT
pypdfium2快速渲染和提取Apache/BSD
pytesseractOCRApache
pdf2imagePDF转图片MIT
poppler-utils命令行工具GPL-2

在 kb-retriever 中的完整落地流程

最后,将本文档与 SKILL.md 的总体流程串联起来,一个完整的 PDF 知识库检索闭环是:

  1. 导航:沿着每层目录的data_structure.md判断答案可能在哪些文件(优先选择与问题主题高度匹配的领域目录和文件)
  2. 学习:在处理 PDF 前必须先读取 references/pdf_reading.md(注意它位于 Skills 目录下而非 Knowledge 目录下),重点了解 pdftotext 命令、pdfplumber 用法、表格提取方法和快速决策表
  3. 处理:用推荐工具把 PDF 提取为文本文件(优先 pdftotext),表格用 pdfplumber,扫描件走 OCR
  4. 检索:grep 关键词定位,只读命中附近的窗口,保存「文件名 + 页码/大致位置 + 文本片段」
  5. 迭代:最多 5 轮,每轮收紧关键词(同义词、上下位词、业务缩写),直到信息足够支撑回答

回答时遵循"先给结论、再给依据、最后附来源"的格式(如"来源:design/api_gateway.pdf 第 3 页附近"),信息缺失时明确告知并提示用户缩小范围。这套从工具选型到 token 控制的方法论,就是 kb-retriever 在本地知识库场景下高效处理 PDF 的完整答案。

  • 人工智能
  • AI 技能/插件
  • 提示工程

【免费下载链接】garden-skills

ConardLi's open-source Skills collection, featuring web design, knowledge retrieval, image generation, and more.

项目地址:https://gitcode.com/GitHub_Trending/we/garden-skills
点击查看免费下载

相关推荐

上一篇:CANN ops-nn 算子实战:MaxPoolingGrad(最大池化反向传播)算子原理与 aclnn 调用指南
下一篇:CANN ops-transformer 中 ApplyRotaryPosEmbGrad 算子详解:双路旋转位置编码反向计算的融合实现与调用指南

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询