Python+OpenAI自动记账:自然语言转结构化账目实战
简介这是一份面向个人开发者与财务自动化爱好者的智能记账工具源码包基于 OpenAI 接口与 Python 实现可将账单、发票等非结构化财务文档自动解析为结构化账目适合具备一定 Python 基础、希望实践 AI 财务场景的读者。压缩包共 51 个文件约 37KB以 36 个 py 脚本为核心辅以 yaml/yml 配置、json、ini、makefile 等工程文件并包含 README 说明与测试用例目录按 prompts、routers、models、utils、tests 等模块划分结构清晰。资源围绕数据获取、预处理、信息抽取、结构化、整合验证与报告可视化六个环节展开涵盖邮件与 PDF 解析、OpenAI 自然语言理解、Notion 集成及日志与错误处理等实现思路。目前已有 238 人学习下载适合作为 AI 记账方向的练手项目或二次开发起点。1. 从手动记账到对话入账这套 Python 工具到底省掉了哪几步每个月月底对着账单流水一行行敲进 Excel 的人大概都动过「能不能让程序自己记」的念头。这套基于 OpenAI 接口实现的自动记账工具核心思路就是把「记一笔」这件事从填表变成说话——你输入「午饭 28 块微信」它返回一条结构化账目自动落到本地文件或数据库里。整个项目是纯 Python 实现没有前端框架依赖跑起来就是一个命令行交互程序适合两类人一是想拿它当日常记账工具、又不想装一堆 App 的开发者二是想找一个「LLM 接口调用 结构化输出解析」练手项目的新手。它解决的不是记账本身而是「自然语言到结构化数据」这一段最烦人的转换。下面按「它怎么把一句话变成一条账」到「怎么改、怎么防翻车」的顺序拆开讲。2. 自然语言转结构化账目OpenAI 接口调用与字段解析2.1 为什么用 Chat Completions 而不是自己写正则手动记账最痛的点在于输入格式不统一。有人写「午饭28」有人写「中午吃饭花了二十八块」还有人写「打车 15.5 支付宝」。正则表达式能覆盖前两种第三种带支付渠道的就容易漏。这套工具选择调用 OpenAI 的对话接口把「理解意图」这件事交给模型代码只负责把模型返回的 JSON 解析成固定字段。常见做法是构造一个 system prompt明确告诉模型输出格式。比如要求返回{amount: float, category: str, note: str, payment: str}四个字段并且只返回 JSON、不要额外解释。这样做的代价是每次记账都要发一次网络请求延迟在几百毫秒到两秒之间好处是新增一种说法不用改代码改 prompt 就行。我一般会把 prompt 拆成两部分一部分是固定的字段定义和输出约束另一部分是动态拼接的当前日期和用户输入。日期必须由代码注入不能让模型自己猜否则「昨天午饭」这种相对时间会算错。2.2 一次完整调用的代码骨架下面这段是核心调用逻辑省略了异常重试部分后面单独讲。import os import json from openai import OpenAI client OpenAI(api_keyos.getenv(OPENAI_API_KEY)) SYSTEM_PROMPT 你是一个记账助手。用户会用自然语言描述一笔支出。 请提取以下字段并以 JSON 返回不要输出任何其他文字 - amount: 金额浮点数单位元 - category: 分类从[餐饮,交通,购物,居住,娱乐,医疗,其他]中选一个 - note: 简短备注不超过10个字 - payment: 支付方式从[微信,支付宝,现金,银行卡,其他]中选一个 如果信息缺失amount 填 0其余填其他。 def parse_expense(user_input: str, today: str) - dict: # today 由调用方传入格式 YYYY-MM-DD用于解析昨天上周五等相对时间 resp client.chat.completions.create( modelgpt-4o-mini, # 记账场景对模型能力要求不高mini 足够 messages[ {role: system, content: SYSTEM_PROMPT}, {role: user, content: f今天是{today}。{user_input}} ], temperature0, # 结构化输出必须关掉随机性 response_format{type: json_object} # 强制返回合法 JSON ) raw resp.choices[0].message.content return json.loads(raw)逻辑说明temperature0是关键参数记账不需要创造性任何随机性都会导致同一句话两次解析出不同分类。response_format设为json_object后模型不会返回带 markdown 代码块的文本省掉一层清洗。model选 mini 版本是因为字段抽取属于简单任务用大模型成本翻十几倍但准确率提升有限。参数说明today必须由外部传入而不是在函数内取datetime.now()原因是批量补录历史账目时相对时间要基于账目发生日而不是运行日。这个坑我在测试时踩过——补录上周的账结果「昨天」全算成了运行日的前一天。2.3 字段校验与本地落盘模型返回的 JSON 不能直接信。金额可能是字符串28分类可能返回不在枚举里的值支付方式可能为空。落盘前必须过一层校验。VALID_CATEGORIES {餐饮, 交通, 购物, 居住, 娱乐, 医疗, 其他} VALID_PAYMENTS {微信, 支付宝, 现金, 银行卡, 其他} def validate(record: dict) - dict: # 金额强制转 float失败则置 0 并标记待确认 try: record[amount] round(float(record.get(amount, 0)), 2) except (TypeError, ValueError): record[amount] 0.0 record[note] [金额待确认] record.get(note, ) # 分类和支付方式做白名单过滤 if record.get(category) not in VALID_CATEGORIES: record[category] 其他 if record.get(payment) not in VALID_PAYMENTS: record[payment] 其他 return record校验之后写入 CSV 或 SQLite。CSV 的好处是随时能用 Excel 打开核对坏处是并发写入容易冲突SQLite 适合长期积累后做统计查询。我一般先用 CSV 跑一周确认解析准确率稳定后再迁到 SQLite。3. 把工具跑起来环境配置、交互循环与数据存储3.1 依赖安装与密钥管理项目依赖很轻核心就一个 openai 包。Python 版本建议 3.9 以上因为response_format参数在旧版 SDK 里不支持。python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate pip install openai python-dotenv密钥不要写死在代码里。常见做法是建一个.env文件内容为OPENAI_API_KEY你的key然后在入口文件顶部用load_dotenv()加载。.env必须加进.gitignore否则推到公开仓库等于把 key 送人。我见过有人把 key 写在代码注释里然后截图发群这种血泪经验不用多解释。3.2 交互循环与退出机制命令行工具的核心是一个 while 循环读一行、解析一行、写一行。但直接input()裸循环有两个问题一是 CtrlC 退出时可能丢最后一条未落盘的记录二是连续输入多条时没有反馈不知道哪条成功了。from datetime import date from dotenv import load_dotenv load_dotenv() def main(): print(输入账目回车提交输入 q 退出。) buffer [] while True: try: line input( ).strip() except (EOFError, KeyboardInterrupt): break if line.lower() q: break if not line: continue try: record parse_expense(line, date.today().isoformat()) record validate(record) record[date] date.today().isoformat() buffer.append(record) print(f 已记录{record[category]} {record[amount]}元 {record[note]}) except Exception as e: print(f 解析失败{e}请换一种说法) # 退出时统一落盘避免每条都写文件 save_to_csv(buffer) print(f本次共记录 {len(buffer)} 条。)逻辑说明用buffer暂存而不是每条都写文件是为了减少磁盘 IO也方便退出时一次性处理。save_to_csv以追加模式打开文件如果文件不存在则先写表头。异常捕获放在单条解析上而不是整个循环这样一条失败不会导致程序退出。参数说明date.today().isoformat()返回2025-01-15这种格式比时间戳可读性好也方便后续按日期筛选。如果要做时区处理把date.today()换成带时区的datetime.now(tz)即可但记账场景一般不需要精确到小时。3.3 CSV 与 SQLite 的选型对比维度CSVSQLite打开方式Excel、文本编辑器需要 SQL 客户端或代码并发写入差多进程会覆盖好支持锁统计查询需要 pandas 或手动遍历直接 SQL 聚合迁移成本低纯文本中需要建表适合阶段前两周验证解析准确率长期使用、月度统计我的习惯是先用 CSV 跑一段时间确认模型对常见说法的解析准确率能到九成以上再写一个迁移脚本把 CSV 导入 SQLite。迁移脚本不复杂读 CSV 逐行 insert 即可但要注意金额字段的类型转换。4. 避坑与排查五条实际踩过的记录4.1 模型返回的 JSON 带 markdown 代码块现象json.loads报Expecting value: line 1 column 1打印原始内容发现是json\n{...}\n。原因早期 SDK 或未设置response_format时模型习惯把 JSON 包在代码块里。解决设置response_format{type: json_object}如果 SDK 版本不支持就在json.loads前加一层清洗用正则去掉首尾的标记。4.2 金额被解析成字符串导致统计求和报错现象CSV 里金额列混着28和28用 pandas 求和时字符串被当 0 处理。原因模型有时返回数字有时返回字符串json.loads不会强制类型。解决在validate里统一float()转换转换失败置 0 并标记。不要依赖模型保证类型一致。4.3 相对时间解析错位现象补录「昨天午饭」记录日期却是运行日的前一天而不是账目实际发生日。原因prompt 里的「今天」用了datetime.now()补录场景下这个值不对。解决把日期作为参数传入parse_expense补录时传账目发生日。这个改动很小但影响所有涉及「昨天」「上周」的输入。4.4 网络超时导致整条记录丢失现象输入后卡住十几秒然后报连接错误这条账没记上。原因默认没有设超时网络抖动时请求挂起。解决在OpenAI()初始化时传timeout10并在调用外层加一次重试。重试不要超过两次否则用户等太久。重试仍失败就把原始输入追加到一个pending.txt下次启动时提示补录。4.5 分类枚举太细导致模型乱选现象把分类从 7 个扩到 20 个后「其他」的比例反而上升模型经常选一个不相关的细分类。原因枚举值越多模型在边界模糊时越容易随机选。解决分类控制在 10 个以内且每个分类在 prompt 里给一个简短示例。比如「餐饮吃饭、外卖、咖啡」。示例比枚举名更能锚定模型判断。5. 进阶技巧用 few-shot 示例把解析准确率再提一档跑通基础版本后如果发现某些说法反复解析错最有效的改进不是换更大的模型而是在 system prompt 里加 few-shot 示例。做法是把几条「输入 → 期望 JSON」的样例拼进 prompt让模型照着格式走。FEW_SHOT 示例1 输入午饭28微信 输出{amount:28.0,category:餐饮,note:午饭,payment:微信} 示例2 输入打车15.5支付宝 输出{amount:15.5,category:交通,note:打车,payment:支付宝} 示例3 输入买书花了六十多 输出{amount:60.0,category:购物,note:买书,payment:其他} SYSTEM_PROMPT SYSTEM_PROMPT \n FEW_SHOT逻辑说明示例要覆盖三类边界——带支付方式的、金额是约数的、分类容易混淆的。每条示例控制在两行以内太多会挤占上下文窗口反而降低对当前输入的注意力。示例里的金额和分类必须和枚举定义一致否则模型会学到矛盾的规则。参数说明few-shot 示例放在 system prompt 末尾比放在开头效果好因为模型对靠近用户输入的内容注意力更高。如果示例超过 5 条考虑改用微调或换用支持 function calling 的接口把字段定义做成工具描述让模型按 schema 输出。验证改进效果的方法很简单准备 30 条真实说法的测试集改 prompt 前后各跑一遍统计字段完全正确的比例。我一般要求金额和分类两项都对的才算通过支付方式允许有误差。测试集要包含口语、缩写、带渠道、带约数四种类型每种至少 5 条。从那以后我每次改 prompt 都强制走一遍这个 30 条测试集不再凭感觉判断「好像变准了」。这套工具的价值不在于用了什么模型而在于把「输入容错」和「输出校验」这两层做扎实模型换哪家都能跑。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

IIR滤波器从设计到落地:选型、结构、量化与调试实战

IIR滤波器从设计到落地:选型、结构、量化与调试实战

1. 从“IIR滤波器(2)”说起:为什么第一篇讲完还得再开一篇如果你看过我之前写的那篇IIR滤波器入门,大概会记得我们把双线性变换法从头推了一遍,最后落到了一个能跑的低通滤波器上。那篇发出去之后,后台收到…

2026/10/12 18:55:33 阅读更多 →
ESP32 ModbusTCP分片缓存设计:解决TCP粘包与分包问题

ESP32 ModbusTCP分片缓存设计:解决TCP粘包与分包问题

做现场总线对接的工程师,应该都经历过这么一种魔幻场景:设备连上了,从站也正常回数据,可一套 ModbusTCP 跑上几个小时,偶尔就冒出几个“超时”或“寄存器读到一半”的坏帧。再到抓包工具里一看,大悲&#x…

2026/10/12 18:55:33 阅读更多 →
物联网系统集成避坑指南:从设备选型到交付验收的实战经验

物联网系统集成避坑指南:从设备选型到交付验收的实战经验

直接这些年做物联网系统集成,踩过的坑比走过的桥还多。尤其在设备选型、协议对接和现场实施这几个环节,几乎每个项目都要交一笔学费。今天不绕弯子,把几个高频雷区连同排查思路一起列出来,给准备做集成的朋友一个参考。1. 需求分析…

2026/10/12 18:55:33 阅读更多 →

最新新闻

AnyPS5:面向PS5开发者模式的USB协议级通信方案解析

AnyPS5:面向PS5开发者模式的USB协议级通信方案解析

项目标题:“AnyPS5”这个名称本身带有强烈的指向性与模糊性并存的特点——它既像一个技术代号,又像一句口号;既暗示兼容性、泛用性(Any),又锚定在PS5这一具体硬件平台。但问题来了:它不是索尼官…

2026/10/12 22:59:48 阅读更多 →
Android集成百度地图SDK:AK鉴权、Gradle配置与白屏避坑指南

Android集成百度地图SDK:AK鉴权、Gradle配置与白屏避坑指南

简介:面向Android开发初学者的百度地图SDK接入教程资源包,围绕在Android Studio中集成百度地图、完成地图展示与基础定位展开。内容从添加Gradle依赖、申请API密钥、配置Manifest权限与meta-data,到MapView初始化、定位回调、地图点击监听、M…

2026/10/12 22:59:48 阅读更多 →
对象字面量报错全解析:TypeScript多余属性检查机制与修复方案

对象字面量报错全解析:TypeScript多余属性检查机制与修复方案

如果你在 TypeScript 项目里见过这条报错:Object literal may only specify known properties, and xxx does not exist in type 某类型,说明你已经撞上了 TS 最经典的一道门槛。它几乎是每个 TS 开发者都会遇到的“第一块石头”:明明属性名、…

2026/10/12 22:59:48 阅读更多 →
Docker容器化部署实战:大学生兼职平台从构建到编排

Docker容器化部署实战:大学生兼职平台从构建到编排

简介:基于Docker技术构建的大学生兼职平台完整项目资源,面向Java开发学生及毕业设计人群,覆盖源码、数据库脚本与开发文档,用于快速掌握兼职信息发布系统的实现与部署。压缩包共535个文件、大小约2.99MB,其中包含188个…

2026/10/12 22:59:48 阅读更多 →
虚拟生物技术公司:AI智能体如何重构药物研发全流程

虚拟生物技术公司:AI智能体如何重构药物研发全流程

前几天在预印本平台上刷到一篇很有意思的论文,某顶尖高校团队提出了一套叫“虚拟生物技术公司”的体系,用AI智能体来跑药物研发全流程。说实话,我平时对“AI颠覆制药”这类标题已经有点脱敏了,但仔细看完他们设计的完整工作流之后…

2026/10/12 22:59:48 阅读更多 →
企业级AI Agent落地指南:从流程自动化到安全边界的实践路径

企业级AI Agent落地指南:从流程自动化到安全边界的实践路径

1. 先看清 Cowork 的本质:AI 从“顾问”变成“执行者”1.1 问答式 AI 与工作区式 AI 的区别我经常碰到有朋友说:AI 我每天都在用,有什么新鲜的?已经用它写了很多周报和 PPT 了。这是典型的问答式使用。可如果你把一个完整任务交给…

2026/10/12 22:58:48 阅读更多 →

日新闻

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

复古胶片颗粒感噪点合成器:Canvas ImageData 像素高斯杂色注入算法

在数码相机、高清显示屏与现代矢量图形技术高度发达的今天,画面可以做到绝对的锐利、平滑与无瑕。然而,当一张秋日手账插画或拍立得照片过于“平整无瑕”时,往往会散发出一种冰冷生硬的“数码塑料感(Digital Plasticity&#xff0…

2026/10/12 0:00:59 阅读更多 →
活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

活字印刷古籍线装排版:Canvas 竖排文字与栏线自适应算法

在现代网页与移动端设计中,横排(Horizontal Layout)早已经成为了绝对的主流。然而,当我们翻开泛黄的线装古籍、宋版木刻诗集,或是欣赏一张茶道雅集的手写便签时,那种**自上而下纵向书写、自右向左逐列铺展&…

2026/10/12 0:00:59 阅读更多 →
周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

周日晚间的“精神松绑减震器”:无压力情绪倾倒箱与温和轻声陪伴

每到周日的晚上八点到十点,很多人心里都会悄悄亮起一盏警示灯。 在心理学上,这种现象有一个专门的称谓——“周日夜晚焦虑症(Sunday Scaries)”。明天又是周一,闹钟又要重新在七点响彻卧房;脑海里仿佛有一个…

2026/10/12 0:00:59 阅读更多 →

周新闻

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

流感时间序列预测实战:ARIMA/LSTM全流程拆解与避坑指南

简介:基于 ARIMA、LSTM、Transformer 等模型的流感时间序列预测 Python 源码,面向计算机相关专业课程设计与期末大作业学生,以及项目实战学习者。内容覆盖预处理、平稳性检验、定阶、残差分析、多模型对比预测的完整时序建模流程,…

2026/10/12 0:16:30 阅读更多 →
影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别

影刀RPA新手教程:键盘模拟输入实战——输入文本与模拟按键的区别 做影刀RPA自动化,十个新手有八个栽在"往输入框里填东西"这件事上:要么填不进去,要么填了一半,要么直接把原来内容追加在后面。这背后的根因&…

2026/10/12 0:16:38 阅读更多 →
影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容

影刀RPA新手教程:阅文起点小说数据采集实战——书籍信息与章节内容 1. 认识影刀:什么场景该用RPA采小说数据 起点中文网的页面结构相对稳定——分类榜单、书籍详情、章节内容三块独立页面,跳转链路清晰。这种场景非常适合影刀自动化&#x…

2026/10/12 0:16:43 阅读更多 →

月新闻

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 21:05:09 阅读更多 →
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 14:48:49 阅读更多 →
黑夜航拍船只数据集训练YOLOV5模型全流程解析

黑夜航拍船只数据集训练YOLOV5模型全流程解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/10/12 18:11:17 阅读更多 →