Chapter 02

第一个 Skill:PDF 表单填写

把最少的代码、最少的 markdown 凑出一个能跑起来的 Skill。目标:让 Claude 读你给的 PDF,自动识别字段,按用户给定的数据填好并导出。

前置条件

为什么从 Claude Code 开始
Claude Code 的 Skill 迭代最快——你改完文件保存,下一次调用就生效。API / Claude.ai 的 Skill 管理要上传打包,适合 Skill 成熟后再迁移。

Step 1: 创建 Skill 目录

# 用户级 Skill(所有项目都能用)
mkdir -p ~/.claude/skills/pdf-form-filler/scripts
mkdir -p ~/.claude/skills/pdf-form-filler/references
cd ~/.claude/skills/pdf-form-filler

# 或项目级 Skill(只在当前项目生效)
mkdir -p .claude/skills/pdf-form-filler/scripts

Claude Code 会自动扫 ~/.claude/skills/ 与项目的 .claude/skills/。项目级优先级更高——同名 Skill 会覆盖用户级。

Step 2: 写 SKILL.md

---
name: pdf-form-filler
description: >
  自动填写 PDF 可填表单(AcroForm)。
  激活条件:用户提供 PDF 路径,且要求"填表"、
  "fill form"、"自动填"、"签这个表"。
  支持文本域、单选、多选、日期。不处理签字图片,
  签字域只能留空或插入文字。
allowed-tools: Bash, Read, Write
---

# PDF 表单填写

当用户需要填写 PDF 表单时使用本 Skill。

## 工作流

1. 用 `scripts/detect_fields.py <pdf>` 列出所有字段,返回 JSON。
2. 根据用户给的数据,生成 `data.json`(字段名 → 值)。
3. 用 `scripts/fill.py <pdf> <data.json> <out.pdf>` 填充。
4. 打印 out.pdf 的路径给用户。

## 边界

- 遇到 `FieldType: Signature` 的字段,按 `references/signature-guide.md` 处理。
- 金额字段务必按 `references/amount-format.md` 校验小数位。
- 输入 PDF 不是可填表单(AcroForm)时,明确告诉用户"这是扫描件,需先 OCR",不要自己硬填。
description 写法的关键
description 不只是介绍——它是 Claude 的激活判据。写清楚在什么输入下激活、不处理什么,Claude 会更准确地知道何时调用这个 Skill。
反例:description: PDF 工具——含糊,Claude 可能一见 PDF 就激活,但你的 Skill 只处理可填表单。

Step 3: 写 detect_fields.py

# scripts/detect_fields.py
import sys, json
from pypdf import PdfReader

def main(pdf_path: str):
    reader = PdfReader(pdf_path)
    fields = reader.get_fields() or {}
    result = []
    for name, f in fields.items():
        result.append({
            "name": name,
            "type": f.get("/FT", ""),
            "value": f.get("/V", ""),
        })
    print(json.dumps(result, ensure_ascii=False, indent=2))

if __name__ == "__main__":
    main(sys.argv[1])

Step 4: 写 fill.py

# scripts/fill.py
import sys, json
from pypdf import PdfReader, PdfWriter

def main(pdf_in, data_json, pdf_out):
    data = json.load(open(data_json))
    reader = PdfReader(pdf_in)
    writer = PdfWriter(clone_from=reader)
    for page in writer.pages:
        writer.update_page_form_field_values(page, data)
    with open(pdf_out, "wb") as f:
        writer.write(f)
    print(f"OK: {pdf_out}")

if __name__ == "__main__":
    main(*sys.argv[1:])

Step 5: 写两份 reference

references 不会默认加载,Claude 只在读到"签字域"、"金额"时才去 grep 读取,不占激活期 token。

# references/signature-guide.md

PDF 签字域(FieldType=Sig)是特殊字段,pypdf 无法写入图片签名。
遇到时的策略:
1. 如果用户给了文字签名(如"张三"),插入文字,不插图片。
2. 如果用户要图片签,告知"需用 PyPDF2 + reportlab 叠加,超出本 Skill 范围"。
3. 保留字段为空,不要报错。

# references/amount-format.md

金额字段校验:
- 保留 2 位小数:`f"{amount:.2f}"`
- 不加货币符号(表单里一般有 $ 或 ¥ 的印刷符号)
- 大于 999 的要加千分位:`f"{amount:,.2f}"`

Step 6: 在 Claude Code 里调用

# 启动 Claude Code,进入你有 PDF 的目录
claude

# 对话:
> 帮我填一下 expense.pdf,数据在 data.json

Claude 会做这些事:

  1. 扫描本地 Skills,看到 pdf-form-filler 的 description 匹配"填表"
  2. 激活 Skill,读完整的 SKILL.md
  3. 按工作流调用 detect_fields.py,拿到字段列表
  4. 对照 data.json 生成映射
  5. 遇到"金额"字段,主动 read references/amount-format.md
  6. 运行 fill.py,把结果写到 expense_filled.pdf
  7. 返回文件路径
Claude 没激活你的 Skill?
最常见的原因:description 太模糊。把它改明确,或者在 Claude Code 里直接说 "use pdf-form-filler skill to ..."——显式激活永远有效。

Step 7: 迭代

用几个不同的 PDF 测试,看哪里不对。常见迭代点:

本章你已经掌握
Skill 目录结构、SKILL.md 的 YAML + 正文写法、脚本与 references 的分工、在 Claude Code 里的调用流程。这已经是一个能跑的最小闭环——下一章开始深入 SKILL.md 的规范细节。

本章小结