用AI打造智能语音记账系统:从需求到实现的全流程

本文记录了我与AI助手(严主任)一起,从零开始搭建智能语音记账系统的完整过程。系统实现了通过自然语言对话自动记账,并同步到飞书多维表格的功能。

一、背景与需求

作为一名普通用户,我一直在寻找一种更便捷的记账方式。传统的记账APP需要手动选择分类、填写金额,操作繁琐。我的需求很简单:

“说出来,就能记上账”

具体来说:

  • 通过自然语言描述消费(如”中午吃海底捞花了355元”)
  • AI自动解析金额、分类、日期
  • 自动写入我的飞书记账本
  • 无需手动选择分类

二、技术方案选型

2.1 数据存储:飞书多维表格

我选择飞书多维表格作为记账本的存储载体,原因:

  • 云端存储,多端同步
  • 支持丰富的字段类型(单选、日期、公式等)
  • 支持自动化流程
  • 便于后续数据分析

2.2 技术架构

用户语音/文字 → AI解析 → 飞书Bitable API → 记账本

核心组件:

  • 自然语言解析:提取金额、分类、日期、成员
  • 智能分类:基于语义分析匹配消费类型
  • 飞书API:Bitable写入接口

三、实现过程

3.1 第一步:API权限检查

首先检查对飞书记账本的访问权限:

import requests

APP_TOKEN = “your_app_token” TABLE_ID = “your_table_id”

获取字段信息

url = f”https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE_ID}/fields” resp = requests.get(url, headers={“Authorization”: f”Bearer {token}”})发现的问题

  • ✅ 可以读取表结构
  • ✅ 可以写入文本、数字、日期字段
  • 级联单选字段无法通过API写入

我的账本原本使用级联字段(一级分类关联二级分类),但飞书API不支持写入这种带条件的级联字段。

解决方案:将级联字段改为普通单选字段,牺牲部分联动约束,换取API可写入性。

3.2 第二步:自然语言解析

实现核心解析逻辑:

def parse_natural_language(text):
    result = {
        'amount': None,
        'category1': None,
        'category2': None,
        'member': '默认成员',
        'date': int(datetime.now().timestamp() * 1000),
        'transaction_type': '支出'
    }
    
    # 提取金额
    # 支持:35、35.5、35块、35块5、35元
    
    # 智能分类分析
    # ...
    
    return result

金额提取支持多种格式:

  • “35” → 35.0
  • “35.5” → 35.5
  • “35块” → 35.0
  • “35块5” → 35.5
  • “35元” → 35.0

3.3 第三步:智能分类的实现

这是整个系统最核心的部分。我实现了两层分类策略

第一层:精确关键词匹配

CATEGORY_KEYWORDS = {
    "外卖": ("食", "外卖"),
    "食材": ("食", "食材"),
    "加油": ("行", "加油"),
    "打车": ("行", "打车"),
    # ... 61个分类
}

第二层:语义推理(Fallback)

当没有直接匹配的关键词时,基于语义规则推理:

# 食的推理
if any(word in text for word in ['吃', '饭', '餐', '火锅', '烧烤', '餐厅']):
    if any(word in text for word in ['外卖', '美团', '饿了么']):
        return '食', '外卖'
    elif any(word in text for word in ['零食', '水果', '奶茶']):
        return '食', '零食水果'
    else:
        return '食', '馆子'

效果对比

  • 输入:”今天去吃了海底捞355元”
  • 旧方案:无法识别(”海底捞”不在关键词列表)
  • 新方案:食-馆子(基于”吃”+”餐厅”语义)

3.4 第四步:飞书Bitable写入

def add_record_to_bitable(record_data, token):
    url = f"https://open.feishu.cn/open-apis/bitable/v1/apps/{APP_TOKEN}/tables/{TABLE_ID}/records"
    
    fields = {
        "交易类型": record_data['transaction_type'],
        "日期": record_data['date'],
        "金额": record_data['amount'],
        "备注": record_data['remark'],
        "年份": datetime.fromtimestamp(record_data['date']/1000).strftime("%Y")
    }
    
    # 分类使用文本名称(不是ID)
    if record_data['category1']:
        fields['一级分类'] = record_data['category1']
    if record_data['category2']:
        fields['二级分类'] = record_data['category2']
    
    resp = requests.post(url, headers={...}, json={"fields": fields})
    return resp.json()

关键发现

  • 写入单选字段时,使用选项名称(如”食”)而非选项ID
  • 使用ID会导致飞书显示为ID文本(如”opt5rwyvJY”)

四、遇到的问题与解决

问题1:级联字段无法写入

现象:尝试写入级联字段时返回错误:

cascade single select with conditions is not supported

解决:将级联字段改为普通单选字段,在代码层面维护分类映射关系。

问题2:选项名称显示为ID

现象:飞书表格中分类显示为”opt5rwyvJY”而非”食”

原因:使用了选项ID而非选项名称写入

解决:改用选项名称(如”食”、”外卖”)写入

问题3:二级分类名称有空格

现象:二级分类如”外卖 “(带2个空格),导致匹配失败

解决
1. 手动清理飞书表格中的选项名称,删除多余空格
2. 代码中兼容处理(去除空格匹配)

问题4:分类映射不完整

现象:”海底捞”无法匹配到”食-馆子”

解决:增加语义推理层,基于关键词(如”吃”、”餐厅”)智能推断分类,而非仅依赖精确匹配。

五、最终效果

使用方式

支持两种输入格式:

带前缀

记账:中午吃海底捞355元
记账:昨天加油300块

无前缀

今天外卖35
给宝宝买奶粉289

识别能力

输入 识别结果 说明
“今天去吃了海底捞355元” 食-馆子,355元 基于”吃”+”餐厅”语义
“昨天加油300块” 行-加油,300元 关键词匹配
“给宝宝买奶粉289” 娃-宝宝食品,289元 成员识别为”核桃Zr”
“打车去公司28元” 行-打车,28元 关键词+语义
“看电影花了50” 休闲娱乐-影视文化,50元 语义推理

六、技术亮点

1. 分层分类策略

  • 第一层:精确关键词匹配(高准确率)
  • 第二层:语义推理(高覆盖率)

2. 多维度信息提取

  • 金额:多种格式兼容
  • 日期:相对/绝对日期
  • 成员:自动识别
  • 收入/支出:自动判断

3. 容错设计

  • 分类无法识别时留空,不阻止记账
  • 日期默认今天
  • 成员使用默认值

七、代码分享

完整代码已开源在GitHub(可根据实际情况补充链接),核心文件:

  • accounting.py:主程序
  • accounting_cli.py:命令行入口
  • ACCOUNTING_GUIDE.md:使用文档

核心依赖:

pip install requests

八、总结与展望

通过这个项目,我实现了一个真正零操作门槛的记账方式:

  • ✅ 不用打开APP
  • ✅ 不用选择分类
  • ✅ 不用填写表单
  • ✅ 说出来就记好

未来优化方向
1. 接入语音识别,直接语音记账
2. 增加消费趋势分析
3. 自动识别重复消费(如”又是麦当劳”)
4. 与预算系统联动,超支预警

*本文记录了我与AI助手(严主任)共同开发记账系统的完整过程。从需求提出到最终落地,历时约6小时,全程通过自然语言对话完成,无需编写复杂代码。*

*作者:老达*
*日期:2026-02-27*