从 PDF Skill 学到什么:把 AI 能力做成可执行流程

Posted on 三 20 5月 2026 in Tech

Abstract 从 PDF Skill 学到什么:把 AI 能力做成可执行流程
Authors Walter Fan
Category AI Engineering
Status v0.1
Updated 2026-05-21
License CC-BY-NC-ND 4.0

从 PDF Skill 学到什么:把 AI 能力做成可执行流程

简短大纲

  • pdf skill 解决的不是“知道几个 PDF 库”,而是把 PDF 任务拆成可执行流程
  • 它最值得借鉴的地方:触发清楚、分层文档、决策分流、数据契约、验证闭环
  • 但如果目标是把 PDF 解析成符合预期格式的 Markdown,它还缺少核心工作流
  • 表单填写工作流是全篇精华:先判定,再提取,再填值,再校验,再验收
  • 写自己的 skill 时,可以照着它做一套“任务路由 + 工具箱 + 验证卡”

PDF 这种活,最容易把 AI 逼成手艺人

PDF 是个很有意思的文件格式。它看起来像一张纸,实际上里面可能是文本、图片、表单字段、注释、字体、坐标系、加密信息和各种历史包袱的混合体。

你对 AI 说:“帮我填一下这个 PDF 表格。”这句话听起来很简单,像让同事顺手签个名。可真干起来,坑马上来了:这个 PDF 是可填写表单,还是扫描图片?坐标是从左下角算,还是从左上角算?复选框的 checked value 是 /On,还是别的值?填完之后,Adobe Reader 能不能正常显示?

所以我看这个 pdf skill 时,第一感觉不是“哇,里面列了好多库”,而是:它把一个容易靠手感乱试的任务,整理成了一套可执行、可回退、可验证的流程。

不过,如果你的期待是“把 PDF 解析成一篇结构正确、表格不乱、图片有引用、层级清楚的 Markdown”,那这个 skill 还不够。它更像 PDF 操作工具箱,不是完整的 PDF-to-Markdown 解析器。

这正是 AI Skill 设计里最值得学,也最值得警惕的地方。好的 skill 不是一本百科全书,也不是一段漂亮 prompt。它更像一份给老练工程师看的 runbook:什么时候触发,先做什么,分支怎么走,输出什么中间产物,怎么知道自己没搞砸。缺少 runbook 的地方,再多库名也补不上。


一、它先把入口收窄:只要碰 PDF,就该触发

这个 skill 的元数据很朴素:

name: pdf
description: Use this skill whenever the user wants to do anything with PDF files...

这句话的设计很关键。它没有把触发条件写成“高级 PDF 处理”这种含糊词,而是直接覆盖常见用户意图:读取、提取文本和表格、合并、拆分、旋转、水印、创建 PDF、填表、加密解密、提取图片、OCR。

这带来两个好处。

第一,Agent 不必猜。“用户提到 .pdf 文件,或者要生产 PDF”,就进入这个 skill。触发边界清楚,减少了模型在技能选择阶段的犹豫。

第二,用户不必懂术语。用户说“把这个扫描件里的文字弄出来”,skill 可以把它映射到 OCR;用户说“合并几个文件”,skill 可以映射到 pypdfqpdf。这就是好入口的价值:用用户语言触发,用工程语言执行。

我们写自己的 skill 时,常犯的毛病是把 description 写得像项目简介:

本 skill 用于增强文档处理能力,并支持多种格式转换。

听起来很全面,实际触发很虚。更好的写法是列任务动词:

当用户要读取、生成、拆分、合并、校验、发布、同步某类对象时使用。

Agent 看到动词,才知道什么时候该上场。


二、主文档不贪多:先给 80% 场景一条路

SKILL.md 的结构很克制:

  1. Overview:说明主线能力。
  2. Quick Start:用 pypdf 读 PDF、提取文本。
  3. Python Libraries:pypdfpdfplumberreportlab 分别负责什么。
  4. Command-Line Tools:pdftotextqpdfpdftk
  5. Common Tasks:扫描 PDF OCR、水印、图片提取、密码保护。
  6. Quick Reference:任务、最佳工具、命令或代码一张表。
  7. Next Steps:复杂场景去 reference.md,表单场景去 forms.md

这个结构有个朴素原则:主文档负责让 Agent 快速动起来,参考文档负责兜住复杂情况。

如果把所有高级内容都塞进 SKILL.md,Agent 每次调用都要在长篇说明里游泳,像在日志系统里搜一个异常堆栈。反过来,如果主文档太薄,只写“请使用 pypdf 处理 PDF”,那遇到表格、扫描件、表单字段、坐标转换时就会开始现场编故事。

pdf skill 的分层比较舒服:

层次 文件 作用
入口层 SKILL.md 覆盖常见 PDF 操作,给快速路径和工具选择
深水区 reference.md 收纳高级库、复杂命令、性能建议和疑难处理
专项流程 forms.md 专门处理 PDF 表单填写这种高风险任务
执行层 scripts/ 把容易出错的操作做成脚本

这也提醒我们:skill 文档不是越长越好,而是要有信息架构。主路、支路、工具箱、验收点,各归各位。


三、它最大的缺口:没有 PDF-to-Markdown 的输出契约

这里要泼一盆冷水。

如果用户真正想要的是“把 PDF 解析成符合预期格式的 Markdown”,当前这个 pdf skill 并不能让人满意。

它能做什么?可以抽文本,可以抽表格,可以 OCR,可以把 PDF 转成图片,也可以处理表单。但这些能力离“高质量 Markdown”还有一段距离。把文本抽出来,不等于 Markdown;把表格抽成二维数组,不等于一张可读的 Markdown 表;把页面渲染成图片,也不等于知道哪些图该被引用、放在哪里、配什么说明。

PDF-to-Markdown 至少要解决五个问题:

问题 只抽文本会怎样 Markdown 需要什么
标题层级 标题和正文混在一起 推断 ###### 层级
段落顺序 多栏、页眉、页脚可能乱入 阅读顺序、去页眉页脚、合并换行
表格 单元格错位或变成散文本 Markdown table 或 HTML table 的稳定输出
图片与公式 要么丢失,要么只剩 OCR 文本 提取图片资产,并在 Markdown 中引用
可验证性 看似有内容,结构其实不对 输出契约、样例对比、格式检查

当前 skill 没有定义这些东西。它没有 pdf_to_markdown.py,没有 Markdown 输出 schema,没有图片资源目录规范,没有表格降级策略,也没有“怎样判断 Markdown 符合预期”的验收方法。

这就像修了一条很好的进货通道,但没有仓库货架。文本、表格、图片都进来了,最后往地上一摊,说“货到了”。用户当然不满意,因为用户要的是能上架、能搜索、能发布、能二次编辑的 Markdown。

一个合格的 PDF-to-Markdown skill,应该单独加一条工作流:

PDF -> 页面分析 -> 块提取 -> 结构归一化 -> Markdown 渲染 -> 质量校验

中间最好不要直接从 PDF 跳到 Markdown,而是先落到结构化 JSON,例如:

{
  "pages": [
    {
      "page": 1,
      "blocks": [
        {
          "type": "heading",
          "level": 2,
          "text": "System Overview",
          "bbox": [72, 88, 420, 116]
        },
        {
          "type": "paragraph",
          "text": "This section describes...",
          "bbox": [72, 130, 520, 180]
        },
        {
          "type": "table",
          "rows": [["Name", "Role"], ["API", "Entry point"]],
          "bbox": [72, 210, 520, 310]
        },
        {
          "type": "image",
          "path": "images/page1_figure1.png",
          "caption": "Architecture diagram",
          "bbox": [100, 340, 480, 560]
        }
      ]
    }
  ]
}

有了这个中间层,Agent 才能做三件事:

  1. 先检查阅读顺序、标题层级、表格结构和图片引用是否合理。
  2. 再根据目标格式渲染 Markdown,比如普通 Markdown、GitHub Markdown、MyST Markdown 或 Pelican 文章格式。
  3. 最后做验收:图片文件是否存在,表格列数是否一致,标题是否跳级,页眉页脚是否被误收录。

这才是“parse PDF to Markdown as expected format”的核心。不是再补一个库名,而是补一条从版面理解到格式渲染的流水线。


四、表单填写才是它的精华:先分流,再动手

如果只看普通 PDF 操作,这个 skill 是一份不错的工具清单。但真正让我觉得有借鉴价值的,是 forms.md

它开头就写得很硬:

CRITICAL: You MUST complete these steps in order. Do not skip ahead to writing code.

这不是语气强硬,而是任务本身需要强约束。PDF 表单填写一旦跳步,很容易出现“看起来填了,实际没填对”的情况。最糟糕的是,错误不一定会立刻报出来,可能是打开时显示异常、打印时错位、提交到别的系统时字段丢失。

所以它第一步不是写代码,而是判定 PDF 类型:

python scripts/check_fillable_fields.py <file.pdf>

然后分两条路:

分支 判断 方法
Fillable fields PDF 内置可填写字段 提取字段信息,生成 field_values.json,用字段 ID 写入
Non-fillable fields 没有表单字段 通过结构提取或视觉估算坐标,用注释方式填入文本

这就是工程味道。

许多 AI 失败,不是因为不会写代码,而是因为没有先判断问题类型。拿到 PDF 就直接生成填表脚本,看似积极,实际是在赌。这个 skill 则把赌变成流程:先问“它是什么”,再决定“怎么做”。


五、它把隐含知识变成数据契约

PDF 表单最麻烦的不是代码,而是中间状态。字段 ID 是什么?字段在哪一页?坐标是什么?复选框怎么选中?这些东西如果只存在 Agent 的“脑子里”,下一步就很容易漂。

pdf skill 的处理方式是:把中间状态写成 JSON。

可填写表单会先提取字段信息:

[
  {
    "field_id": "last_name",
    "page": 1,
    "rect": [100, 200, 250, 220],
    "type": "text"
  }
]

然后再创建 field_values.json

[
  {
    "field_id": "last_name",
    "description": "The user's last name",
    "page": 1,
    "value": "Simpson"
  }
]

非可填写表单则使用 fields.json,明确页面尺寸、label bounding box、entry bounding box、待写入文本、字号等。

这个设计很值得借鉴。它相当于给 Agent 加了一层“工作台”。每一步都有可见产物,用户和 Agent 都能检查。比起“我已经理解了字段位置”,JSON 更诚实。

在复杂 skill 里,数据契约有三个作用:

  1. 稳定上下文:不要把关键状态只放在自然语言里。
  2. 方便校验:脚本可以检查字段 ID、页码、取值、坐标是否合理。
  3. 支持返工:错了改 JSON,不必重写整段逻辑。

一句话:把 AI 的临场判断,沉淀成可检查的中间文件。


六、脚本不大,但每个都卡在关键节点

这个 skill 的 scripts/ 目录并不复杂,但很实用:

脚本 作用
check_fillable_fields.py 判断 PDF 是否有可填写表单字段
extract_form_field_info.py 提取字段 ID、类型、页码、坐标和选项
fill_fillable_fields.py 根据 JSON 填写可填写字段,并校验字段和值
extract_form_structure.py 从非可填写 PDF 中提取文本标签、线条、复选框和行边界
check_bounding_boxes.py 检查坐标框是否重叠、输入框高度是否够用
convert_pdf_to_images.py 把 PDF 转成图片,方便视觉检查
create_validation_image.py 在图片上画出 label 和 entry 的框,辅助验收

这些脚本有个共同点:它们都不试图“一口气把世界解决”。每个脚本只负责一个确定动作,输入输出清楚。

这比写一个巨大的 process_pdf.py 更适合 Agent。因为 Agent 最怕的不是工具少,而是工具太黑盒。小脚本让它能一步一步推进:检查、提取、填写、验证。每一步失败了,也知道该修哪一层。

我尤其喜欢 check_bounding_boxes.py 这种脚本。它检查两个很具体的问题:坐标框是否相交、输入框高度是否小于字体大小。这不是什么宏大算法,但非常工程化。它抓的是“肉眼迟早会发现,但越晚发现越烦”的错误。


七、它有验证闭环,而不是只负责生成

很多 AI 工作流停在“生成输出”这一步。比如填完 PDF,就说“大功告成”。老程序员看到这里通常会皱眉:你说完成了,谁验的?

forms.md 把验证写进流程:

  1. 填表前,先校验 bounding boxes。
  2. 填写字段时,校验字段 ID、页码、checkbox/radio/choice 的合法取值。
  3. 填完后,把输出 PDF 转成图片。
  4. 人或 Agent 再检查文字位置是否正确。

这是一条很好的 Agent 工作流准则:凡是输出带视觉效果、格式约束或外部系统兼容性的任务,都不能只看脚本退出码。

PDF 尤其如此。脚本成功写出文件,不代表文件看起来对;文件看起来对,也不代表表单字段被正确写入;字段写入了,也不代表另一个阅读器能正常显示。

所以好的 skill 应该把“完成”的定义写清楚。不是“生成了文件”,而是“生成文件,并经过某种检查”。


八、它没有假装世界很干净

另一个可取之处,是它承认 PDF 世界很脏。

比如 forms.md 里,非可填写表单又分成三种处理方式:

  • 结构提取优先:如果 PDF 里能提取文本标签和线条,就用结构坐标。
  • 视觉估算兜底:如果是扫描件,就转图片、裁剪局部、人工或视觉分析坐标。
  • 混合方式:结构能识别大部分字段,但有些圆形 checkbox 或复杂图形识别不到,就混合处理。

这比“统一使用 OCR 解决”靠谱得多。真实工程里没有银弹。好流程不是假装所有输入都标准,而是承认输入分层,然后给每一层一条合理路径。

SKILL.md 里还有一些很具体的坑,例如 ReportLab 不要直接用 Unicode 上下标字符,因为内置字体可能渲染成黑块。这类提醒看似小,实际很珍贵。它来自踩坑经验,不是 API 文档的复述。

一个 skill 有没有用,很多时候就看它有没有这些“坑边护栏”。


九、可以借鉴的设计模式

把这个 pdf skill 拆开看,我认为有八个模式值得复用。

1. 触发词写用户任务,不写能力口号

不要写“增强 PDF 处理能力”,要写“读取、合并、拆分、填表、OCR、加密、提取图片”。动词越具体,Agent 越容易触发。

2. 主文档只覆盖高频路径

SKILL.md 应该像机场指示牌,不是城市规划图。让 Agent 快速知道该走哪条路;复杂细节放到引用文档。

3. 高风险任务单独成文

表单填写比普通合并拆分复杂得多,所以它有 forms.md。这说明 skill 可以按风险分层:普通任务走快速路径,高风险任务走强约束流程。

4. 先判定类型,再选择流程

check_fillable_fields.py 是一个很小的脚本,但它决定了后续路线。很多业务 skill 也需要这种“第一问”:

  • 这是新增还是修改?
  • 这是公开数据还是敏感数据?
  • 这是可自动处理还是需要人工确认?
  • 这是结构化输入还是图片/自由文本?

先分流,后执行。

5. 中间状态结构化

JSON 文件让流程可检查、可修改、可复跑。对于 Agent,这比长篇自然语言记忆可靠。

6. 输出格式要有契约

如果任务目标是 Markdown、JSON、CSV、测试报告、设计文档,就不能只说“输出一个文件”。要写清楚标题、表格、图片、代码块、元数据、目录结构和验收规则。否则 Agent 很容易交出“内容大概有了,格式全靠猜”的半成品。

7. 小脚本卡住关键风险

不要急着做万能脚本。先把最容易错、最值得验证的节点做成脚本:字段检查、坐标检查、格式检查、依赖检查、输出预览。

8. 验收步骤写进 skill,而不是留给用户猜

“生成了”不等于“完成了”。skill 应该告诉 Agent 怎么确认结果可靠,尤其是文档、图片、代码、配置、发布、数据迁移这类任务。


十、如果让我继续改,它还可以更工程化一点

当然,这个 skill 也不是没有改进空间。

第一,应该补一条 PDF -> Markdown 专项流程。至少包括页面块提取、标题层级推断、表格转 Markdown、图片落盘与引用、页眉页脚清理、输出格式校验。没有这条流程,它就不应该被包装成“PDF 转 Markdown”的完整方案。

第二,依赖安装说明可以更完整。文档里出现了 pypdfpdfplumberreportlabpdf2imagepytesseractpypdfium2、Poppler、ImageMagick 等工具,但如果用户环境缺依赖,Agent 还需要自己判断怎么安装。一个 requirements.txtinstall 小节会更稳。

第三,部分脚本可以补一点输入校验。例如 check_fillable_fields.py 直接读 sys.argv[1],参数缺失时会报 Python 异常。作为示例脚本可以接受,但如果作为生产级 skill,最好给出清晰 usage 和错误信息。

第四,输出目录处理可以更友好。convert_pdf_to_images.py 会把图片写到输出目录,但脚本本身没有创建目录。如果目录不存在,用户会遇到低价值错误。

第五,安全和隐私提醒可以更前置。PDF 很可能包含合同、证件、财务报表或个人信息。skill 可以提醒:不要把敏感 PDF 上传到不可信服务;中间图片、JSON、提取文本要按敏感数据处理;临时文件用完要清理。

这不是推翻原设计,而是把评价边界说清楚:它的核心骨架很好,适合做 PDF 操作类 runbook;但如果目标是 PDF-to-Markdown,就必须补上结构解析和格式渲染这条主链路。


十一、照着它写自己的 skill:一个可抄模板

如果要把这个经验迁移到自己的 AI Skill,我会用下面这套结构:

my-skill/
  SKILL.md
  reference.md
  workflows/
    high-risk-task.md
    pdf-to-markdown.md
  scripts/
    detect_type.py
    extract_context.py
    extract_blocks.py
    render_markdown.py
    validate_input.py
    apply_change.py
    verify_output.py
  schemas/
    document_blocks.schema.json
  examples/
    sample_input.json
    sample_output.json
    expected_output.md
  LICENSE.txt

SKILL.md 可以按这个顺序写:

  1. Trigger:用户说什么时必须使用。
  2. Scope:支持什么,不支持什么。
  3. Quick Start:最常见任务的最短路径。
  4. Decision Tree:先判断类型,再走分支。
  5. Data Contract:中间 JSON、配置、表格格式,或者文档块 schema。
  6. Output Contract:最终文件格式,例如 Markdown 的标题、表格、图片、元数据规范。
  7. Scripts:每个脚本的输入、输出、失败含义。
  8. Verification:怎样算完成,怎样发现错位、遗漏、越权、格式错误。
  9. Troubleshooting:常见坑和 fallback。
  10. Security Notes:敏感数据、权限、临时文件、日志、依赖风险。

这里最重要的不是目录,而是思想:把 skill 从“提示词文档”升级成“可执行工作系统”。


总结

pdf skill 值得借鉴的地方,不是它知道 pypdfpdfplumberqpdf 这些工具。工具清单网上到处都有。

真正值得学的是它的工程结构:入口清楚,主次分明;复杂任务先分流;中间结果结构化;关键节点用脚本兜住;最后还有验证闭环。真正需要补的,是 PDF-to-Markdown 这种“从版面到结构化文档”的输出契约。

一句话:好 skill 不是让 AI 更会说,而是让 AI 更会做;更进一步,是让 AI 按约定格式交付,并且知道做完以后怎么验。

行动清单

  • [ ] 给你的 skill 写清楚触发条件:用户说哪些动词时必须使用。
  • [ ] 把任务分成高频简单路径和高风险专项流程。
  • [ ] 为复杂流程设计一个中间数据契约,不要只靠自然语言记忆。
  • [ ] 如果有 Markdown、JSON、CSV 这类目标格式,先写输出契约,再写转换脚本。
  • [ ] 在最容易出错的节点放小脚本:检测、提取、校验、预览、验收。
  • [ ] 明确完成标准:脚本成功、输出存在、内容正确、格式可用、敏感数据不泄露。

Review Card

  • 威胁快照:PDF 可能含个人信息、合同、财务或内部资料。
  • 验证路径:执行前判定 PDF 类型,执行中校验字段/坐标/文档块,执行后检查 Markdown 结构、图片引用和表格格式。
  • Secret 与隐私:临时文本、图片、JSON 不应进入日志、仓库或不可信服务。
  • 依赖说明:记录 Python 包、系统工具和许可证,避免 Agent 临时乱装依赖。
  • 测试建议:至少准备一个可填写表单、一个扫描件、一个坐标复杂的非填写表单、一个含标题/表格/图片的 PDF-to-Markdown 样例做回归。

本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可。