恒美微站 Logo 恒美微站
  • 首页
  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心
  • 联系我们

Python+OpenAI自动记账:自然语言转结构化账目实战

  • 首页
  • 资讯中心
  • /
  • Python+OpenAI自动记账:自然语言转结构化账目实战

相关资讯

非局部均值降噪算法:原理、实现与参数调优实战 2026/10/12 18:50:09
.NET Core WebAPI GET请求参数收不到?模型绑定原理与排查实战 2026/10/12 18:50:09
Spring依赖注入原理与实战:从IoC容器到三级缓存与踩坑指南 2026/10/12 18:50:09

最新资讯

java.lang.foreign受限方法报错排查:--enable-native-access模块授权指南
自动化测试平台建设实战:从用例管理到报告通知的完整链路
Floyd-Warshall求传递闭包:解决奶牛排名中的关系推导问题
Ceph分布式存储实战:核心概念、集群部署与块存储案例
DFS字符串分割建模:从HDU2266看表达式生成与前导零处理
手写LL(1)语法分析器:从FIRST/FOLLOW到可调试Java实现

今日推荐

Debian新手入门:从部署到日常操作的完整指南
MongoDB复制集扩缩容实战:从rs.add到选主事故复盘
条形码目标检测数据集实战:从YOLOv8训练到部署

本周热门

UE动画修改实战:从资产编辑到重定向与蒙太奇驱动
统计随机数生成器攻击下的KLJN安全密钥交换协议Matlab仿真
政务API安全治理:资产测绘、低代码编排与行标对标实践

本月精选

我发现了一个新思路:用 Remotion + Claude Code 像写代码一样自动化生成短视频
Windows下 Codex 中 Chrome 和 Computer Use 插件不可用问题排查及解决参考方式:TaoToken 统一 Key 配置与验证
2026 大模型集体涨价:用 Python 做企业 Token 成本测算与选型避坑(附配置)

Python+OpenAI自动记账:自然语言转结构化账目实战

发布时间:2026/10/12 18:55:10
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 条测试集不再凭感觉判断「好像变准了」。这套工具的价值不在于用了什么模型而在于把「输入容错」和「输出校验」这两层做扎实模型换哪家都能跑。希望帮到你。本文还有配套的精品资源点击获取

关于恒美微站

恒美微站专注于为个体商户、工作室提供极简自助建站服务,让每个人都能轻松拥有专业网站。

快速链接

  • 关于我们
  • 建站服务
  • 主题模板
  • 案例展示
  • 资讯中心

服务项目

  • 可视化建站
  • 拖拽编辑
  • 主题定制
  • SEO 优化
  • 网站托管

联系方式

  • 📍 地址:北京市朝阳区建国路 88 号
  • 📞 电话:400-888-8888
  • ✉️ 邮箱:info@hmyw.cn
  • 🕐 时间:周一至周日 9:00-18:00

© 2024 恒美微站 hmyw.cn 版权所有 | 京 ICP 备 12345678 号