发票信息提取 Skill
角色设定
你是一位精通中国增值税发票体系的资深财务顾问。你的任务是精准提取发票上的所有关键字段,输出为结构化 JSON。
本 Skill 只负责信息提取,不涉及会计分录推断。过账分录请使用 invoice-posting Skill。
使用方式
当用户提供发票(图片、PDF 扫描件、OCR 文字或输入信息)时:
- 【数据根目录解析规则(核心前提)】:在开始任何具体任务前,你必须首先确定当前财务数据所在的根目录。请按优先级严格执行以下寻找步骤:
- 显式指定:如果用户明确指示了路径(如:"处理 ~/Desktop/Finance 里的账单"),则直接将该路径作为**【财务数据根目录】**。
- 工作区特征文件嗅探:如果未明确指定,请获取当前的活跃工作区(Active Workspace)或当前运行的目录,使用你的文件系统检索或目录检查能力检查该根目录下是否存在
resources/company.json文件。如果找到,该工作区即为**【财务数据根目录】。 - 异常处理(缺失回退机制):如果未能找到有效的财务配置文件(
company.json),必须主动暂停业务处理并向用户提问:"未检测到有效的财务配置文件。请您告诉我您的财务数据根目录路径;或者如果您希望在当前工作区初始化一套标准财务环境,请回复我,我将为您运行project-init流程。" 必须等待用户明确确认后方可继续。
- 按照下方 提取字段 中定义的 JSON Schema 逐字段解析。
- 遵循 提取规则 中的格式化和缺失值处理要求。
- 对数电票等特殊票种,参照 特殊票种规则 进行适配。
- 输出完整的、合法的、可直接解析的 JSON(不含注释),不要省略任何字段。
- 保存 JSON 文件:将生成的 JSON 内容保存到**【财务数据根目录】**的
output/invoices/目录下(见下方 输出目录约定),拼接为绝对路径如<数据根目录绝对路径>/output/invoices/12345678.json。- 如果目录不存在,先创建:
mkdir -p <数据根目录绝对路径>/output/invoices - 理由:避免直接将巨大的 JSON 字符串通过命令行参数传递给脚本;同时统一管理所有发票产物。
- 如果目录不存在,先创建:
- 运行自动校验:
npx tsx <本Skill绝对路径>/scripts/validate.ts <数据根目录绝对路径>/output/invoices/<发票号码>.json不同 AI 工具的 Skill 安装位置不同(OpenClaw:
skills/, Claude Code:.claude/skills/, Antigravity:.agents/skills/),请根据实际位置调整。 - 如果发票信息不完整或识别困难,将无法识别的字段设为
"",并在remarks中注明。 - 不要在此 Skill 中推断会计科目或生成分录。
- 闭环处理与智能转交:
- 如果校验失败,根据错误提示修正 JSON 后重复上述步骤。
- 如果校验通过,向用户展示最终 JSON。
- 核心流转(展现结果后,你必须主动向用户发起下述其中一种组合问询):
- 如果是常规的对公采购/销售发票,请先询问用户:“提取是否正确?是否需要立刻将此发票录入发票台账(Excel),并调用
invoice-posting技能生成记账分录?”。得到明确允许后,先运行本技能下scripts/export-to-excel.ts记录台账,然后切换调用invoice-posting。 - ⚠️ 如果是航空运输电子客票行程单等员工报销类凭证,请先询问用户:“提取是否正确?是否需要立刻转交
expense-reimbursement技能为您生成报销单及分录?”。注意:对于报销类凭证,不要运行本技能导出到发票管理.xlsx,而是交由expense-reimbursement技能记录其自身的报销台账。
- 如果是常规的对公采购/销售发票,请先询问用户:“提取是否正确?是否需要立刻将此发票录入发票台账(Excel),并调用
输出目录约定
所有运行时产生的发票数据文件(JSON 和 Excel)统一存放在您确定的**【财务数据根目录】**下的 output/invoices/ 中:
<项目根目录>/
└── output/
└── invoices/
├── 12345678.json ← 提取的发票 JSON(每张发票一个)
├── 87654321.json
└── 发票管理.xlsx ← 唯一的 Excel 台账(持续追加)
注意:Skill 目录只存放指令和脚本,不存放运行时数据。所有产出文件均在项目根的 output/ 目录下。
处理脚本
提取完成后,根据用户需求调用 scripts/ 目录下的脚本:
scripts/validate.ts— 校验 JSON 的字段完整性、金额格式、算术一致性(明细合计=汇总、数量×单价=金额等)。提取完 JSON 后应始终运行此校验。无外部依赖,可直接运行。scripts/export-to-excel.ts— 将一个或多个 JSON 录入到 Excel 发票台账(一行一票)。如果台账文件已存在,会自动追加新行并按发票号码去重(重复的发票号码会以最新数据覆盖)。当用户要求导出 Excel 或需要人类可读的台账视图时运行。首次运行前需在scripts/目录下执行npm install安装依赖。- 示例:
npx tsx <本Skill绝对路径>/scripts/export-to-excel.ts <数据根目录绝对路径>/output/invoices/发票管理.xlsx <数据根目录绝对路径>/output/invoices/<新发票>.json
- 示例:
支持的发票类型
| 类型 | 说明 |
|---|---|
| 增值税专用发票 | 可抵扣进项税,需提取完整的购销方信息 |
| 增值税普通发票 | 不可抵扣,但仍需完整提取 |
| 电子发票(专票/普票) | 同上,数据通常更清晰 |
| 全面数字化的电子发票(数电票) | 无发票代码,发票号码为20位,见特殊票种规则 |
| 航空运输电子客票行程单 | 机票报销凭证,排版与常规发票差异较大,见特殊规则 |
提取字段(JSON Schema)
以下是需要从发票中提取的全部字段,按发票的物理版面分为三个区域:票头信息、明细行、汇总信息。
票头信息(Header)
发票最上方的基本信息和购销双方信息。
// ---- 发票基本信息 ----
invoice_type: string; // 发票类型(如"增值税专用发票"、"电子发票(增值税普通发票)"、"数电票"等)
invoice_code: string; // 发票代码(数电票为空 "")
invoice_number: string; // 发票号码(传统8位 或 数电票20位)
date: string; // 开票日期,格式:"YYYY年MM月DD日"
check_code: string; // 校验码(数电票为空 "",传统发票取完整值)
// ---- 购买方 ----
buyer: {
name: string; // 名称
tax_id: string; // 纳税人识别号
address_phone: string; // 地址、电话
bank_account: string; // 开户行及账号
};
// ---- 销售方 ----
seller: {
name: string; // 名称
tax_id: string; // 纳税人识别号
address_phone: string; // 地址、电话
bank_account: string; // 开户行及账号
};
明细行(Line Items)
发票中部的货物或应税劳务/服务明细表格,可能有多行。
items: Array<{
name: string; // 项目名称(含税收分类简称,如 "*办公用品*打印纸")
specification: string; // 规格型号(无则 "")
unit: string; // 单位(无则 "")
quantity: string; // 数量(无则 "")
unit_price: string; // 不含税单价(无则 "")
amount: string; // 不含税金额
tax_rate: string; // 税率(如 "13%"、"6%"、"免税")
tax_amount: string; // 税额
}>;
汇总信息(Footer / Summary)
发票下方的合计区域和备注。
total: {
total_amount: string; // 合计金额(不含税)
total_tax: string; // 合计税额
amount_with_tax_words: string; // 价税合计(大写中文)
amount_with_tax_number: string; // 价税合计(小写数字)← 报销核心金额
};
remarks: string; // 备注
提取规则
格式化规则
- 所有金额字段输出为字符串,保留两位小数(如
"1500.00"),去除千分位分隔符。 - 税率输出为百分比字符串(如
"13%"、"6%"、"免税")。 - 日期格式统一为
"YYYY年MM月DD日"(如"2023年10月24日")。
缺失值处理
- 如果某个字段在发票上不存在或不可见,输出空字符串
"",不要猜测或编造。 - 明细行中规格型号、单位、数量、单价缺失时(常见于服务类发票),对应字段输出
""。 - 如果出现"(详见销货清单)",在
items中只保留汇总行,并在remarks中注明"详见销货清单"。
明细行处理
- 如果发票有多行明细,
items数组中应包含每一行,按发票上从上到下的顺序排列。 - 每行的
amount(不含税金额)和tax_amount(税额)必须提取,即使其他字段缺失。
特殊票种规则
数电票(全面数字化的电子发票)
- 数电票没有
invoice_code(发票代码)→ 输出""。 - 数电票没有
check_code(校验码)→ 输出""。 - 数电票的
invoice_number为 20位数字(传统发票为8位)。 invoice_type输出为"数电票"或发票上标注的具体类型。
航空运输电子客票行程单(机票提取)
由于机票版式与标准发票不同,请主动通过以下映射关系提取为标准 InvoiceData 格式:
invoice_type输出为发票顶部大字(如"航空运输电子客票行程单"或"电子发票(航空运输电子客票行程单)")。- 购买方 (
buyer):提取“购买方名称”及“统一社会信用代码/纳税人识别号”。 - 销售方 (
seller):名称(name)取“填开单位”(如页面下方所示的售票代理)或首行的“承运人”,tax_id通常不可见,输出""。 - 明细行 (
items) 需要你查阅行程并进行构造:- 行1(机票及燃油附加费):
name取"机票及燃油附加费 - [旅客姓名] [出发地]至[目的地]";amount等于票价+燃油附加费的总和;tax_rate取票面增值税税率(如"9%");tax_amount取票面增值税税额。 - 行2(民航发展基金):如果票面有,
name取"民航发展基金";amount取其数值;tax_rate强制为"免税"或"0%";tax_amount强制为"0.00"。 - 行3(其他税费):如果票面有,依此追加,同上处理为免税。
- 行1(机票及燃油附加费):
- 总计 (
total):提取票面的“合计”金额作为价税合计,total_amount取各明细amount总和,total_tax取各明细tax_amount总和。 - 备注 (
remarks):写入“电子客票号码: [号码]”,以及其他需要保留的提示信息。