2026-09-03 · 原文发布日
小票 OCR 加 AI 分类的报销自动化
报销自动化模板:员工通过 n8n 表单上传小票,文件存 Google Drive 后交 Mindee OCR 提取商户、金额、日期等字段,再由 GPT-4o 判定费用类别、公私属性和置信度,低置信度拦截进人工;按小票号和金额在 PostgreSQL 查重后入库并通知 Slack,每天还定时汇总消费数据发 Slack 看板,OCR 失败和缺字段都有对应告警。
原文要点
该模板由 WeblineIndia 发布在 n8n 官方模板库(编号 19130),免费。流程:n8n 表单接收小票文件与可选金额、备注;校验文件存在后上传 Google Drive 并送 Mindee OCR 排队,轮询取回商户、金额、日期、类别、小票号和原始文本;商户或金额缺失则 Slack 告警转人工;再交 OpenAI 分类(最终类别、公私属性、费用类型、置信度),低置信度拦截;按小票号加金额在 PostgreSQL 查重,重复则告警,否则入库并通知 Slack;另有每日定时任务查询消费统计发 Slack 看板。需配置 Mindee(HTTP Header Auth)、OpenAI、Slack、Google Drive OAuth、PostgreSQL 五套凭据,并自建含 14 列的 expenses 表。
这次做成什么
在自有 n8n 实例上复刻这条小票报销流水线:表单上传小票→OCR 提取→AI 分类→查重入库→Slack 通知,并附带每日汇总。因模板页面不提供逐项参数截图,本站给出一套可照着搭的节点顺序、建表 SQL、分类提示词与一条合成测试数据,未核实的界面选项标注为需在原模板核对。
准备什么
- 一个可登录的 n8n 实例(自托管或云版),能创建表单触发器与定时触发器
- Mindee 账号及 API Key(用于 HTTP Header Auth 方式调用 OCR)
- OpenAI API Key、Slack 工作区及应用凭据、Google Drive OAuth2 凭据
- 一个 PostgreSQL 数据库及建表权限,以及一个可写入的 Google Drive 文件夹
具体怎么做
建表与凭据准备
在 PostgreSQL 执行下文建表 SQL 创建 expenses 表(14 列与模板插入字段一致)。在 n8n 凭据页依次新建:Mindee 的 HTTP Header Auth(Header 名按 Mindee 文档为 Authorization,值为 Token 你的key,具体格式需在 Mindee 控制台核对)、OpenAI、Slack、Google Drive OAuth2、Postgres 五套凭据,全部用测试账号先连通。
搭表单触发与文件校验
新建工作流,添加 Form Trigger 节点,表单字段设为:receipt(文件,必填,限图片或 PDF)、amount(数字,选填)、notes(文本,选填)。后接 IF 节点判断二进制文件是否存在(表达式取 {{$binary.receipt}} 非空),不存在则走 Slack 告警分支提示重新上传。
上传 Drive 并送 OCR
IF 为真后接 Google Drive 节点(Operation 选 Upload,目标文件夹选你准备的测试文件夹),记录返回的文件链接。再接 HTTP Request 节点调用 Mindee 收据接口提交文件,随后用 Wait 节点加 HTTP Request 轮询取结果(模板采用排队后轮询的方式,具体轮询间隔与 model_id 需按你的 Mindee 模型在原模板核对)。OCR 返回失败时接 Slack 节点发告警。
字段校验与 AI 分类
用 Code 或 Set 节点从 OCR 结果中提取 merchant、amount、date、category、receipt_number、raw_text。IF 节点判断 merchant 和 amount 均非空,任一缺失则发 Slack 人工审核告警并终止该分支。通过后接 OpenAI 节点,粘贴下文分类提示词,要求输出 JSON(final_category、business_or_personal、expense_type、confidence),再接 IF 拦截 confidence 低于阈值(本站练习设 0.7,可按需调整)的记录进人工队列。
查重入库与通知
合并 OCR 字段、AI 分类结果与 Drive 链接后,用 Postgres 节点执行 SELECT 查重(按 receipt_number 与 amount 匹配)。查到重复走 Slack 告警;无重复则 INSERT 进 expenses 表并发 Slack 成功消息,消息里带上商户、金额、类别和票据链接。
每日汇总看板
另建一条路径:Schedule Trigger(每日一次,时间自定)→ Postgres 查询(按 category 分组求和、按 business_or_personal 统计)→ Slack 节点把结果排版成看板消息发送到指定频道。先用合成测试数据跑通整条链路再切换正式表单。
可直接复制的材料
PostgreSQL expenses 建表 SQL(本站按模板列名编写)
列名对应原模板插入字段;user_id 来源需在表单中补充或在流程内映射,原模板未给出取值方式。
CREATE TABLE IF NOT EXISTS expenses (
id SERIAL PRIMARY KEY,
amount NUMERIC(12,2) NOT NULL,
user_id VARCHAR(64),
merchant VARCHAR(255) NOT NULL,
currency VARCHAR(8) DEFAULT 'CNY',
expense_date DATE,
category VARCHAR(64),
subcategory VARCHAR(64),
ai_category VARCHAR(64),
business_or_personal VARCHAR(16),
expense_type VARCHAR(64),
confidence NUMERIC(4,3),
receipt_number VARCHAR(128),
raw_text TEXT,
receipt_url TEXT,
created_at TIMESTAMP DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_expenses_dedup ON expenses (receipt_number, amount);OpenAI 费用分类提示词(本站独立撰写)
本站独立编写的示例提示词,占位符需在 n8n 中替换为实际表达式;类别集合应按公司报销制度调整。
你是企业报销审核助手。根据下面的 OCR 小票信息,判断费用归类,只输出 JSON,不要输出任何其他文字。
小票信息:
商户:{{merchant}}
金额:{{amount}} {{currency}}
日期:{{date}}
OCR 原始文本:{{raw_text}}
员工备注:{{notes}}
输出格式(严格遵守):
{"final_category":"餐饮|交通|住宿|办公用品|培训|差旅其他 之一","business_or_personal":"business|personal|unclear","expense_type":"一句话费用说明","confidence":0到1之间的小数}
判定规则:
1. 商户名含酒店、机票、铁路关键词的归为住宿或交通。
2. 金额明显异常(超过 5000 元或与商户类型不符)时 confidence 不得超过 0.5。
3. 文本无法支持任何判断时 final_category 填“差旅其他”,confidence 填 0.3。查重 SQL 与一条合成测试数据
测试数据为本站虚构;正式使用前请删除并改用真实表单提交。
-- 查重(Postgres 节点,参数化写法示意)
SELECT id FROM expenses
WHERE receipt_number = $1 AND amount = $2
LIMIT 1;
-- 合成测试数据(虚构,用于跑通流程)
-- merchant: 杭州云栖便利连锁(文三路店)
-- amount: 86.50
-- currency: CNY
-- expense_date: 2026-08-28
-- receipt_number: TEST-RC-20260828-001
-- notes: 项目组加班餐补采购输入与输出示例
以上为本站虚构演示输出,未实际运行该工作流,Slack 消息格式需在自建节点中按此排版。
输入
员工在 n8n 表单上传一张虚构小票照片,OCR 后得到:merchant=杭州云栖便利连锁(文三路店),amount=86.50,currency=CNY,expense_date=2026-08-28,receipt_number=TEST-RC-20260828-001,备注为“项目组加班餐补采购”。对应输出
AI 分类返回 {"final_category":"餐饮","business_or_personal":"business","expense_type":"项目组加班餐补采购食品","confidence":0.88};查重 SQL 返回 0 行;INSERT 成功;Slack 成功频道收到:“✅ 报销已入库|杭州云栖便利连锁(文三路店)|¥86.50|餐饮|置信度 0.88|票据链接:https://drive.google.com/示例链接”。次日定时看板消息含:“昨日共 1 笔,合计 ¥86.50;分类:餐饮 1 笔;business 1 笔 / personal 0 笔”。做完检查这些
- 上传一张测试小票后,Google Drive 目标文件夹内出现对应文件且链接可打开
- merchant 或 amount 为空时,流程不发 INSERT,只在 Slack 人工审核频道出现告警
- 重复提交同一 receipt_number 与 amount 时,第二次只收到重复告警,表内仍只有一条记录
- 每日定时触发后,Slack 看板消息中的合计金额与数据库 SELECT SUM(amount) 结果一致
容易卡住的地方
- Mindee 的鉴权头格式、model_id 和轮询间隔需以你的 Mindee 控制台为准,原模板页面未给出具体值,填错会导致 OCR 提取失败
- 低分辨率或反光的小票照片会让 confidence 偏低被拦截,这是模板设计行为而非故障,需要引导员工重拍
- Google Drive OAuth 凭据过期或目标文件夹未授权会导致上传失败,需在凭据页重新连接
- 查重依赖 receipt_number 与 amount 两个字段,OCR 没识别出小票号时查重失效,可能产生重复入库
- OpenAI 与 Mindee 调用均可能产生费用,练习时建议用少量测试图片
本站借助AI整理来源事实,独立编写中文操作指南与示例。示例不代表实际运行结果;来源效果尚未由本站独立复现。付费模板与模型、服务费用分别计算。
- 原文标题
- Track and classify expenses with Mindee OCR, GPT-4o, PostgreSQL and Google Drive
- 原作者
- WeblineIndia
- 原始发布日期
- 2026-09-03T13:05:09.503Z
- 来源
- https://n8n.io/workflows/19130