从 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 能力做成可执行流程
简短大纲
pdfskill 解决的不是“知道几个 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 可以映射到 pypdf 或 qpdf。这就是好入口的价值:用用户语言触发,用工程语言执行。
我们写自己的 skill 时,常犯的毛病是把 description 写得像项目简介:
本 skill 用于增强文档处理能力,并支持多种格式转换。
听起来很全面,实际触发很虚。更好的写法是列任务动词:
当用户要读取、生成、拆分、合并、校验、发布、同步某类对象时使用。
Agent 看到动词,才知道什么时候该上场。
二、主文档不贪多:先给 80% 场景一条路
SKILL.md 的结构很克制:
- Overview:说明主线能力。
- Quick Start:用
pypdf读 PDF、提取文本。 - Python Libraries:
pypdf、pdfplumber、reportlab分别负责什么。 - Command-Line Tools:
pdftotext、qpdf、pdftk。 - Common Tasks:扫描 PDF OCR、水印、图片提取、密码保护。
- Quick Reference:任务、最佳工具、命令或代码一张表。
- 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 才能做三件事:
- 先检查阅读顺序、标题层级、表格结构和图片引用是否合理。
- 再根据目标格式渲染 Markdown,比如普通 Markdown、GitHub Markdown、MyST Markdown 或 Pelican 文章格式。
- 最后做验收:图片文件是否存在,表格列数是否一致,标题是否跳级,页眉页脚是否被误收录。
这才是“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 里,数据契约有三个作用:
- 稳定上下文:不要把关键状态只放在自然语言里。
- 方便校验:脚本可以检查字段 ID、页码、取值、坐标是否合理。
- 支持返工:错了改 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 把验证写进流程:
- 填表前,先校验 bounding boxes。
- 填写字段时,校验字段 ID、页码、checkbox/radio/choice 的合法取值。
- 填完后,把输出 PDF 转成图片。
- 人或 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”的完整方案。
第二,依赖安装说明可以更完整。文档里出现了 pypdf、pdfplumber、reportlab、pdf2image、pytesseract、pypdfium2、Poppler、ImageMagick 等工具,但如果用户环境缺依赖,Agent 还需要自己判断怎么安装。一个 requirements.txt 或 install 小节会更稳。
第三,部分脚本可以补一点输入校验。例如 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 可以按这个顺序写:
- Trigger:用户说什么时必须使用。
- Scope:支持什么,不支持什么。
- Quick Start:最常见任务的最短路径。
- Decision Tree:先判断类型,再走分支。
- Data Contract:中间 JSON、配置、表格格式,或者文档块 schema。
- Output Contract:最终文件格式,例如 Markdown 的标题、表格、图片、元数据规范。
- Scripts:每个脚本的输入、输出、失败含义。
- Verification:怎样算完成,怎样发现错位、遗漏、越权、格式错误。
- Troubleshooting:常见坑和 fallback。
- Security Notes:敏感数据、权限、临时文件、日志、依赖风险。
这里最重要的不是目录,而是思想:把 skill 从“提示词文档”升级成“可执行工作系统”。
总结
pdf skill 值得借鉴的地方,不是它知道 pypdf、pdfplumber、qpdf 这些工具。工具清单网上到处都有。
真正值得学的是它的工程结构:入口清楚,主次分明;复杂任务先分流;中间结果结构化;关键节点用脚本兜住;最后还有验证闭环。真正需要补的,是 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 国际许可协议进行许可。