「发票报销」Skill:把贴发票这件事交给 AI
一条命令,从一堆零散的电子发票 PDF、微信截图、扫描水单,变成一份可以直接提交审批的报销汇总 PDF。本文记录这个 WorkBuddy Skill 的设计思路与技术实现。
一、痛点:报销季的手工地狱
每次出差回来,报销材料的整理都是一场修行:
- 电子发票 PDF 若干张(数电票,各平台下载)
- 微信里保存的发票截图、酒店水单照片若干张
- 夸克扫描王扫的纸质收据若干份
手工流程是:逐张打开 → 抄发票号、日期、金额 → 拼成 Excel → 排版打印 → 贴票。一次报销少则半小时,多则一小时,而且抄错一个发票号就要重来。
这类任务的特点恰好是 AI 的舒适区:模式固定、规则明确、重复劳动。于是就有了「发票报销」Skill。
二、设计思路:文件夹即报销期间
Skill 约定了一个极简的目录协议,用户唯一要做的事是把同一批报销的材料丢进同一个文件夹:
在此基础上,整个流水线只需要一条命令:
(目录参数可省略,默认
~/Desktop/发票管理)三条核心设计决策
- 文件夹名即业务标识:文件夹名(如日期区间)直接成为报告标题和输出文件名,无需额外配置。
.done后缀实现幂等:处理完的文件夹改名为20260718-20260723.done,重复执行自动跳过,中断重跑零成本。
- 双类型分流:电子发票(有文本层的 PDF)走正则解析;扫描件/图片走多模态视觉识别。两条路径各司其职。
三、流水线全景

整条流水线四个步骤、两次分流:入口处按"PDF 有无文本层"分成正则解析与多模态识别双路径(确定性归代码,智能归模型);出口处按"审批用还是打印用"分成汇总 PDF 与水单 PDF 双输出。JSON 作为中间产物把提取与生成解耦,
.done 后缀形成幂等闭环。四、技术拆解
Skill 由三个 Python 脚本组成,串成一个数据流水线(JSON 作为中间产物):
脚本 | 职责 |
scripts/extract_invoices.py | 扫描目录,提取发票信息,输出 JSON |
scripts/generate_summary_pdf.py | 读取 JSON,为每个文件夹生成 PDF 汇总报告 |
scripts/rename_folders.py | 将已处理文件夹重命名加 .done |
依赖:Python 3.6+、PyMuPDF(fitz)、Pillow、reportlab。
4.1 步骤一:双路径提取(extract_invoices.py)
核心是一个分流判断——PDF 里有没有文本层:
路径 A:电子发票正则解析。 数电票的文本层结构非常规整,发票号(20 位数字)、开票日期、购买方/销售方、三段金额(金额/税额/价税合计)都能用正则稳定提取:
路径 B:扫描件/图片多模态识别。 银行水单、酒店收据这类扫描件没有文本层,脚本只负责把图片从 PDF 里抽出来(存到
/tmp),打上 needs_ocr: true 标记,剩下的交给 AI 的视觉能力逐张识别。这里我沿用了 ayee-picture2markdown 沉淀的 Strict Faithfulness(严格忠实)铁律:
- 只输出图片上实际可见的内容,绝不推断、绝不臆造
- 看不清的字用
□或[?]占位,并标注「识别不确定」
- 宁可留空,不可编造——报销单上一个编造的发票号比一个空格严重得多
4.2 步骤二:生成 PDF 报告(generate_summary_pdf.py)
每个文件夹生成两份 PDF,分而治之是刻意设计:
- 汇总 PDF(
20260718-20260723.pdf):发票表格(序号/文件名/类型/发票号/公司/金额)+ 合计金额 + 电子发票原件图片。审批人一页看完所有信息,附上原件,免翻附件。
- 水单 PDF(
20260724-20260726_水单.pdf):扫描件(水单、收据)单独成册,方便出纳查看打印。
中文字体是 reportlab 的经典坑。解决方案是按优先级依次尝试 macOS 系统字体:
4.3 步骤三:.done 幂等收尾(rename_folders.py)
处理完即打标。下次执行时
extract_invoices.py 里的目录过滤自动跳过:这是整个 Skill 里我最喜欢的一行代码——幂等性把"中途失败要不要重跑"这个问题从设计上消灭了。
五、最终输出
一个细节:
20260723-20260724(缺发票) 这种文件夹名里的中文备注会被原样保留到输出文件名——文件夹命名协议天然支持用户自由扩展,无需额外字段。六、已发布 SkillHub:一行命令装走
这个 Skill 已经发布到 SkillHub:@user_ff7200d6/expensereimbursement(v1.0.0)。任何 AI Coding 客户端都可以直接安装使用。
安装方法
先装 SkillHub CLI(macOS / Linux 一行命令):
然后按你所用客户端的 skills 目录安装,以 WorkBuddy 为例:
各客户端的 skills 目录对照(来自 SkillHub 安装文档):
AI Client | Skills 路径 |
Claude Code | ~/.claude/skills/ |
Cursor | ~/.cursor/skills/ |
Windsurf | ~/.codeium/windsurf/skills/ |
Codex | ~/.codex/skills/ 或 .agents/skills/ |
Gemini CLI | ~/.gemini/skills/ |
WorkBuddy | ~/.workbuddy/skills/ |
注意:--dir是必需参数,必须指向你客户端的真实 skills 目录,否则装到默认的./skills/不会被识别;安装后需重启会话生效。
装好之后,一句
/发票报销 就能跑起来整条流水线——这也是我理解 Skill 生态的正确打开方式:把踩过的坑、定下的铁律、写好的脚本打包成一个可分发的工件,别人拿到的不是一段要自己复现的教程,而是五秒钟内可用的能力。七、经验总结
- 让确定性归代码,让智能归模型。 正则能稳定搞定的(电子发票文本层)绝不用大模型;正则无能为力的(扫描件视觉理解)才交给多模态。这条边界划清楚后,准确率和速度兼得。
- 幂等性是批处理脚本的生命线。 一个
.done后缀胜过十页容错逻辑。
- Strict Faithfulness 在财务场景是刚需不是洁癖。 识别不确定就标注不确定,AI 输出可信度低于 100% 时,宁可让用户人工补一眼。
- JSON 作为流水线中间产物。 提取和生成分离,任何一步都可以单独重跑、单独调试。
本文对应 Skill 已发布至 SkillHub(
@user_ff7200d6/expensereimbursement),关联阅读:ayee-picture2markdown(图片识别忠实原则的来源)、ayee-arch-designer(Skill 的架构设计规范)。- Author:ayee
- URL:http://preview.tangly1024.com/article/3c78d88b-b050-802e-a14a-fdb9f374b213
- Copyright:All articles in this blog, except for special statements, adopt BY-NC-SA agreement. Please indicate the source!
Relate Posts
