2026/10/20 20:03:44

从杂乱账单到清爽月报:大模型自动化清洗账单与生活开销分类

从杂乱账单到清爽月报:大模型自动化清洗账单与生活开销分类 每到月中或月末翻看手机支付软件导出的账单明细总会让人陷入一种莫名的茫然。屏幕里排列着成百上千条冰冷琐碎的扣费记录商户名称往往充斥着令人摸不着头脑的代号“某某网络技术有限责任公司”、“某某特约特惠扫码商户”、“个体工商户张某某”。如果想要把这一长串数字转化为一份能看懂的生活账目传统的方式需要我们每天雷打不动地打开记账软件逐笔手动输入金额、选择分类、填写标签。然而对于工作繁忙、把业余时间倾注在写代码与侍弄花草上的现代人来说这种日复一日的手工记账往往只能坚持不到两周便在繁重的记账心智负担面前彻底搁浅。而如果把个人流水账单直接上传到第三方的商业记账应用或云端在线 AI 平台又面临着极其严峻的个人消费隐私与轨迹泄露风险。每一笔交易不仅记录了你的财务多寡更精准锚定了你的地理位置、生活规律乃至家庭关系。为了在守护绝对财务隐私的前提下摆脱记账苦力我编写了一套完全运行在本地的纯离线账单智能分析脚本。它不仅能自动清洗微信与支付宝导出的原始 CSV 流水还能借助本地大语言模型的情境推理能力将那些晦涩的商户代号还原为充满生活温情的日常消费图谱。原始账单数据的四大噪音与清洗前置在将账单文本喂给本地大模型之前我们必须进行本地规则预处理剔除大量无意义的非消费流水账户内资金搬家与理财流水零钱通转入、余额宝收益、信用卡还款、借还款等项目属于资产内部转移而非实际开销必须精准剔除。退款冲抵Refund Matching网购退货产生的负向流水需与之前的正向扣费进行抵扣或抵消。高频微小碎支出聚合每天早晚数次的一两块钱公交地铁扣费如果逐笔让大模型分析会极大浪费算力完全可以在代码层先行按周聚合为“通勤出行”。隐私信息外科手术式抹除交易单号、完整银行卡号、手机号等敏感哈希在进入模型上下文前由本地正则彻底脱敏。语义归因大模型的场景推理潜能预处理完成后剩下的核心难点在于交易名称的真实生活意图还原。规则匹配在面对现实世界千奇百怪的商户命名时极其脆弱。例如交易名称显示为“张三快餐店”传统规则可能只能打上粗糙的“餐饮”但如果交易时间是周六上午八点、地点在农贸市场附近大模型能敏锐推断出这是“周末菜市场早点或采买食材”交易名称显示为“宿迁某某园艺中心”大模型能结合上下文归类为“阳台多肉绿植与泥土肥料”并归入生活雅趣类目。本地模型能够像一位熟悉你生活习惯的管家一样把冷冰冰的数字分流到五大生活象限【柴米油盐】超市买菜、粮油副食、日常基础三餐【居所与植物】多肉配土、园艺工具、家居修缮、水电燃气【精神食粮】纸质书籍、古典音乐会门票、优质软件订阅【茶事与风物】武夷岩茶、老白茶、粗陶茶具与秋季时鲜【行路通勤】公共交通、单车骑行与短途漫游。纯本地 Python 账单流水线实现结合 Python 原生 CSV 库与本地 Qwen2.5 语言模型我们打造出这一完全断网运行的财务整理流水线import csv import json import re from typing import List, Dict, Any import requests OLLAMA_API http://localhost:11434/api/generate class ExpenseItem: def __init__(self, date: str, counterparty: str, item_desc: str, amount: float): self.date date self.counterparty counterparty self.item_desc item_desc self.amount amount def clean_csv_records(csv_file_path: str) - List[ExpenseItem]: 清洗支付宝/微信导出的原始 CSV剔除理财与转账 items [] with open(csv_file_path, moder, encodingutf-8-sig, errorsignore) as f: reader csv.reader(f) for row in reader: if not row or len(row) 6: continue row_str .join(row) # 过滤表头及理财借还流水 if 交易时间 in row_str or 余额宝 in row_str or 理财 in row_str or 还款 in row_str: continue if 收入 in row_str or 资金转移 in row_str: continue # 简易提取金额与商户名假定标准账单列 try: date_str row[0].strip() counterparty row[1].strip() desc row[2].strip() # 正则提取金额 amt_match re.findall(r\d\.\d{2}, row_str) if amt_match: amount float(amt_match[-1]) items.append(ExpenseItem(date_str, counterparty, desc, amount)) except Exception: continue return items def analyze_expenses_with_local_llm(items: List[ExpenseItem]) - Dict[str, Any]: # 抽取最近三十笔具代表性的支出明细 sample_text \n.join([f- {it.date} | {it.counterparty} ({it.item_desc}) : {it.amount}元 for it in items[:35]]) prompt f 你是一位深谙质朴生活哲学、精打细算的个人生活财务顾问。 以下是一位独立开发者近期经过初步脱敏的日常消费真实流水切片。 请你执行以下三项分析并返回合法的 JSON 1. 将这些零碎开销精准归集到以下五大生活维度并计算每个维度的估算总额 - food柴米油盐 - botany居所与植物 - culture精神食粮 - teahouse茶事与风物 - mobility行路通勤 2. 观察消费习惯提炼出一段温润、恬淡的生活开销观察总结二百字以内指出哪些开销体现了生活质感哪些存在冲动或可节制之处。 流水样本 {sample_text} payload { model: qwen2.5:7b-instruct-q4_K_M, prompt: prompt, format: json, stream: False, options: {temperature: 0.3} } resp requests.post(OLLAMA_API, jsonpayload) resp.raise_for_status() return json.loads(resp.json().get(response, {})) def render_monthly_markdown(analysis: Dict[str, Any], total_spend: float) - str: categories analysis.get(categories, {}) summary analysis.get(summary, ) md [# 十月秋日生活开销月报\n] md.append(f {summary}\n) md.append(## 生活质感开销分布\n) category_names { food: 柴米油盐, botany: 居所与植物, culture: 精神食粮, teahouse: 茶事与风物, mobility: 行路通勤 } for cat_key, cat_name in category_names.items(): sub_amt categories.get(cat_key, 0.0) md.append(f- **{cat_name}**约 {sub_amt} 元) md.append(f\n**本期开销总计**约 {total_spend:.2f} 元\n) md.append(---\n*注所有数据均在本地纯离线运算生成绝无任何隐私数据出境。*) return \n.join(md)实测生成的温润月报将上个月从支付软件导出的原始账单传入脚本两秒钟后一份排版清爽温润的 Markdown 月度手账展现在屏幕上# 十月秋日生活开销月报 本月的消费轨迹呈现出极其温润朴素的生活律动。大笔开销集中在初秋给阳台多肉更换赤玉土、添置了一把修枝剪以及在中旬购置了一提陈年福鼎白茶寿眉外卖与浮躁冲动型开支几乎为零每日三餐大多源自早晨在菜市场采购的新鲜根茎时鲜。这种将重心倾注在居所、泥土与茶汤上的开销节奏平稳而从容。 ## 生活质感开销分布 - ** 柴米油盐**约 1240.50 元 - ** 居所与植物**约 380.00 元 - ** 精神食粮**约 186.00 元 - ** 茶事与风物**约 460.00 元 - ** 行路通勤**约 94.00 元 **本期开销总计**约 2360.50 元 --- *注所有数据均在本地纯离线运算生成绝无任何隐私数据出境。*财务管理的真谛从来不是让人变成一个锱铢必较的守财奴而是帮我们看清时间的流向与生活的重心。当一段小小的本地脚本在几秒钟内替我们扫清了繁琐的数字泥潭把生活的每一笔付出清晰地映射为桌上的茶香、阳台上的绿意与书架上的墨香时数字不再是令人焦虑的负累而是丈量幸福生活最忠实的注脚。