1. 为什么 PDF 智能阅读助手值得做成 Claude Skill扫描版 PDF 里的文字搜不到、复制不了几十页的合同要逐行翻找关键条款上百份发票需要逐个提取金额和税号——这些事如果每次都手动来一遍时间成本高得离谱。Claude Skill 的价值就在这里它不需要你写 App、不需要部署后端服务一份 Markdown 描述文件加上几个可调用的工具脚本就能让 Claude 获得专项的 PDF 处理能力。用户只需要说一句“帮我提取这份合同里的金额和签署日期”Skill 自动判断文件类型、选择处理引擎、调用 LLM 分析最后返回结构化结果。这篇教程聚焦的是配置落地不是概念科普。我会带你从零搭出一条完整的链路PDF 文件进来 → 判断是文本型还是扫描型 → 走 OCR 或直接提取 → 转成带页码标注的 Markdown → 送给 LLM 做问答或结构化提取。整条链路里LLM 调用这一环用 TaoToken 统一通道来打通你不需要分别去对接多家模型厂商的 Key 和接口格式。适合谁看有 Python 基础、想在本地快速跑通 PDF→OCR→Markdown→LLM 问答的开发者以及正在给 Claude Skill 写工具层、需要一套可复制配置骨架的人。我试过把 OCR、文本提取、LLM 调用三块分别用不同方式拼起来踩过的坑主要集中在两处一是 OCR 引擎在不同机器上的可用性差异极大二是 LLM 接口的鉴权和参数格式每家都不一样换一个模型就要改一遍代码。所以这篇的配置骨架会重点解决这两个问题——OCR 做三级降级LLM 走统一通道。2. TaoToken 前置准备统一 Key 与 API 通道在写 Skill 的工具脚本之前先把 LLM 调用这一层的基础设施准备好。TaoToken 在这里扮演的角色是统一 API 通道你申请一个 Key就能通过同一套接口规范调用不同模型省去为每个模型单独维护 base_url、鉴权头和参数映射的麻烦。对于 Claude Skill 这种需要频繁切换模型做分析任务的场景这一点很实用。你需要做的准备动作只有三步。第一步打开官网 https://taotoken.net/?utm_sourcetaotoken_aicg_blog_endutm_mediumcsdnutm_campaignrewriteutm_content 注册账号。第二步进入控制台 https://taotoken.net/console?utm_sourcetaotoken_aicg_blog_endutm_contentconsole 创建一个 API Key。第三步把 Key 保存到本地环境变量里不要硬编码进脚本。# Linux / macOS写入 shell 配置文件 export TAOTOKEN_API_KEYsk-你的Key # Windows PowerShell当前会话生效 $env:TAOTOKEN_API_KEYsk-你的KeyAPI 的基础地址是 https://taotoken.net/api 注意这个地址不带任何查询参数直接作为 base_url 使用。如果你后续要接 Claude Code 这类编码工具可以走 Coding Plan 通道 https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 如果只是想先在网页里验证模型响应是否符合预期用模型对话 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 快速试一句就行。注意Key 只显示一次创建后立刻复制保存。如果怀疑泄露去控制台重新生成旧 Key 会立即失效。3. 可复制配置settings.json 与 config.toml 骨架Claude Skill 的配置分两层一层是 Skill 自身的元信息与工具声明放在settings.json另一层是运行时的模型与 OCR 参数放在config.toml。下面两份骨架可以直接复制到你的项目根目录改掉路径和 Key 引用即可。3.1 settings.jsonSkill 元信息与工具注册{ name: pdf-smart-reader, version: 1.0.0, description: PDF 智能阅读助手文本提取、OCR、Markdown 转换、LLM 问答, triggers: [ 读PDF, 提取PDF, PDF转Markdown, 扫描件识别, 合同提取, 发票提取, 论文摘要, PDF问答 ], tools: [ { name: extract_text, description: 从文本型 PDF 提取文字保留页码标注, entry: tools/pdf_tools.py:extract_text_pdf }, { name: smart_ocr, description: 对扫描型 PDF 执行 OCR三级引擎自动降级, entry: tools/pdf_tools.py:smart_ocr }, { name: to_markdown, description: 将提取结果转为带标题层级的 Markdown, entry: tools/pdf_tools.py:to_markdown }, { name: ask_llm, description: 将 Markdown 内容送入 LLM 做问答或结构化提取, entry: tools/llm_tools.py:ask_llm } ], env: { TAOTOKEN_API_KEY: ${TAOTOKEN_API_KEY} } }这份配置里triggers决定了用户说什么话能唤醒 Skilltools把每个能力映射到具体的 Python 函数入口。env段用${}语法引用环境变量避免 Key 出现在版本控制里。3.2 config.toml模型与 OCR 运行时参数[llm] base_url https://taotoken.net/api api_key_env TAOTOKEN_API_KEY model claude-3-5-sonnet max_tokens 4096 temperature 0.2 timeout 60 [ocr] # 三级降级顺序tesseract - marker - pymupdf engine_priority [tesseract, marker, pymupdf] tesseract_lang chi_simeng min_text_length 100 marker_min_ram_gb 8 [pdf] max_pages_per_chunk 20 page_marker_format [第{page}页] supported_ext [.pdf, .md, .json, .txt] [prompt] contract_schema {合同标题,签约方,合同金额,签署日期,有效期,违约责任} invoice_schema {发票号码,开票日期,销售方,购买方,价税合计} text_truncate 10000temperature 0.2是为了让结构化提取更稳定减少 LLM 自由发挥导致 JSON 字段缺失。text_truncate 10000控制送入模型的字符上限大约对应 2500 token给回复留足余量。OCR 的engine_priority数组就是降级顺序代码里按这个顺序逐个尝试。4. 验证请求用一份样例 PDF 跑通全链路配置写好了接下来用一份真实的样例 PDF 验证整条链路。我准备了一份两页的扫描版合同 PDF命名为sample_contract.pdf放在data/目录下。4.1 文本提取与 OCR 降级先写工具函数核心是判断 PDF 是文本型还是扫描型然后走对应路径。import fitz # pymupdf import os def extract_text_pdf(filepath, max_pagesNone): doc fitz.open(filepath) text_parts [] pages min(len(doc), max_pages or len(doc)) for i in range(int(pages)): text doc[i].get_text() if text.strip(): text_parts.append(f[第{i1}页]\n{text}) doc.close() return \n\n.join(text_parts) def smart_ocr(filepath): # 第一级pytesseract轻量沙箱可用 try: text ocr_tesseract(filepath) if text and len(text) 100: return text, pytesseract except Exception: pass # 第二级marker-pdf高精度需 8GB RAM try: import marker text, _ ocr_marker(filepath) if text: return text, marker-pdf except (ImportError, MemoryError): pass # 第三级pymupdf 直接提取终极兜底 return extract_text_pdf(filepath), pymupdf_fallback运行提取python -c from tools.pdf_tools import extract_text_pdf, smart_ocr text, engine smart_ocr(data/sample_contract.pdf) print(f引擎: {engine}) print(f字符数: {len(text)}) print(text[:300]) 预期输出类似引擎: pymupdf_fallback 字符数: 1240 [第1页] 甲方某某科技有限公司 乙方某某信息技术服务有限公司 合同金额人民币 128,000 元 签署日期2024 年 3 月 15 日 ...如果输出里engine是pytesseract说明你的环境装了 Tesseract 且识别成功如果是pymupdf_fallback说明前两级都不可用但至少拿到了兜底结果不会报错中断。4.2 转 Markdown 并送入 LLM 问答拿到文本后转成 Markdown 结构再调用 TaoToken 通道做问答。import os import requests def ask_llm(markdown_text, question): api_key os.environ[TAOTOKEN_API_KEY] url https://taotoken.net/api/v1/chat/completions headers { Authorization: fBearer {api_key}, Content-Type: application/json } payload { model: claude-3-5-sonnet, max_tokens: 2048, temperature: 0.2, messages: [ {role: system, content: 你是 PDF 文档分析助手只根据给定内容回答。}, {role: user, content: f文档内容\n{markdown_text[:10000]}\n\n问题{question}} ] } resp requests.post(url, headersheaders, jsonpayload, timeout60) resp.raise_for_status() return resp.json()[choices][0][message][content]执行验证python -c from tools.pdf_tools import smart_ocr from tools.llm_tools import ask_llm text, _ smart_ocr(data/sample_contract.pdf) answer ask_llm(text, 这份合同的金额和签署日期分别是多少) print(answer) 成功时你会看到类似这样的响应根据文档内容 - 合同金额人民币 128,000 元 - 签署日期2024 年 3 月 15 日到这里PDF→OCR→Markdown→LLM 问答的完整链路就跑通了。整个过程你只配了一个 Key、一份 settings.json、一份 config.toml没有为不同模型分别写适配代码。5. 本篇常见错排查链路跑通不代表一帆风顺下面这几个报错是我在实际配置中遇到频率最高的按现象、原因、解决三段式列出来。报错一KeyError: TAOTOKEN_API_KEY现象是脚本启动就崩提示找不到环境变量。原因通常是你在当前终端会话里没有 export或者用了 IDE 的内置终端但环境变量没继承。解决方式在运行脚本前先echo $TAOTOKEN_API_KEY确认能打印出值如果为空重新执行第 2 节的 export 命令或者把变量写进.env文件用python-dotenv加载。报错二requests.exceptions.HTTPError: 401 Client Error现象是请求发出去了但被拒绝。原因一般是 Key 拼写错误、Key 已失效、或者 Authorization 头格式不对。检查两点头必须是Bearer sk-xxx格式中间有一个空格Key 是否在控制台被重新生成过导致旧的失效。去 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 核对当前有效的 Key。报错三TesseractNotFoundError现象是 OCR 第一级直接抛异常。原因是系统没装 Tesseract 二进制只装了 Python 包pytesseract是不够的。解决Ubuntu 下sudo apt install tesseract-ocr tesseract-ocr-chi-simmacOS 下brew install tesseract tesseract-lang。装完后用tesseract --version确认。如果装不了不用慌降级逻辑会自动走到 pymupdf 兜底。报错四OCR 输出全是乱码或空字符串现象是smart_ocr返回的文本长度很短、内容不可读。原因通常是扫描件分辨率太低或者语言包没装对。检查config.toml里的tesseract_lang是否包含chi_sim如果是英文文档改成eng识别率更高。另外确认 PDF 页面渲染时的 DPI 不低于 200太低会导致字符粘连。报错五LLM 返回内容被截断现象是回答到一半突然没了。原因是max_tokens设得太小或者输入文本太长挤占了输出空间。解决把config.toml里的max_tokens调到 4096同时确认text_truncate没有把关键内容截掉。如果文档确实很长走分页处理每次只送 20 页。报错六ModuleNotFoundError: No module named fitz现象是导入 pymupdf 失败。原因是包名和导入名不一致安装时要写pip install pymupdf导入时写import fitz。确认安装成功后重启 Python 进程。6. 接入文档与后续动作配置骨架和验证流程到这里就完整了。如果你在接入过程中遇到鉴权或参数格式的问题直接翻接入文档 https://taotoken.net/doc?utm_sourcetaotoken_aicg_blog_endutm_contentdocutm_campaignrewrite 里面有各接口的字段说明和示例请求。需要管理或新建 Key 的时候去 API Keys 页面 https://taotoken.net/api-keys?utm_sourcetaotoken_aicg_blog_endutm_contentapi-keysutm_campaignrewrite 。如果你打算把这个 PDF 助手接到长期运行的编码或 Agent 工作流里Coding Plan https://taotoken.net/coding-plan?utm_sourcetaotoken_aicg_blog_endutm_contentcoding-planutm_campaignrewrite 的额度模型更适合持续调用。想先快速验证某个模型对中文合同的理解能力模型对话 https://taotoken.net/models?utm_sourcetaotoken_aicg_blog_endutm_contentmodelsutm_campaignrewrite 里贴一段文本就能试。最后分享一个实用技巧把config.toml里的engine_priority顺序按你的实际环境调整。如果你确定部署机器有 8GB 以上内存且装了 marker把marker提到第一位识别精度会明显好于 tesseract如果是轻量沙箱环境保持tesseract在前、pymupdf兜底就行。这个顺序改一行配置就能切换不用动代码。