半个月前 Daniel Nwaneri 在 dev.to 上发了个给 POS 代理操作员做的记账应用,我翻完把里面一组数字抄了下来:
(她提供的 5 条真实银行提醒,由她本人标注)
款项类型 客户姓名
关键词规则 5/5 0/3
Gemma 3 1B 4/5 3/3
一个八百多兆、跑在 WebGPU 上的模型,认款项类型输给了几行关键词规则;认客户姓名的时候,规则一条都没对。这两行数据摆在一起,比任何“该不该用 LLM”的争论都有用——它说明的不是谁强谁弱,是这两件事本来就不该交给同一种东西去做。
先把场景说清楚
哈科特港的这位操作员,客户用手机银行转钱给她,她按每 5,000 奈拉收 150 奈拉的费用,然后付等额现金,一天十来笔到二十笔。她的开户行 Moniepoint 每进一笔钱就发一封邮件,当地管这个叫 credit alert,她全靠这封邮件判断钱到没到。原来记在手抄本上,费时间;而且账一旦对不上,她索性就不核了。
这个细节我盯了很久。记账工具真正的对手不是别的记账工具,是“对不上就不记了”这件事。客户嘴上说转了、钱没到的情况经常发生,她照样没有办法,因为她连一个能回头查的记录都没有。
最值得借鉴的不是模型
是作者在写模型之前多做的那一步:先量一遍规则能到哪。
多数人拿到这个需求,第一反应是“把邮件丢给模型,让它输出结构化 JSON”,然后收工。我一开始也这么想,直到看见后面那串数字——如果真按这个思路做,她要为一个关键词能干到 5/5 的活儿,在手机上多下 859MB,多等几秒到几十秒,多承担一次 GPU 掉线的风险。
所以他的原则是:代码能完成的部分全部交给代码,模型只负责代码做不到的那一件事。那“一件事”就是客户姓名。因为尼日利亚各家银行在提醒里写“TRANSFER TO [客户名] [银行名]”的格式互不相同,作者原本预期的 “TRANSFER FROM” 压根没出现过,正则在这里是对不上的——这个坑我觉得比模型选型有意思得多。
拆开看看这个分工落到代码里是什么样
粘贴一封 Moniepoint 提醒
├─ 关键词规则 → 时间、金额、款项类型(4 类固定:客户转账 / 自己买话费 / 银行返现 / 失败退回)
├─ 模型 → 客户姓名(唯一必须靠它的一项)
└─ 守卫 → 不合格就退回“未读取”,不影响上面两项
金额合计完全不经过模型。哪怕模型没加载完、哪怕 GPU 中途掉了,每一行的金额、时间、类型照样在,日报总额照样是对的。这一条我认为是整篇文章里最硬的工程决定——把“不确定的那部分”放进一个可以整体丢弃的盒子里,盒子坏了,账还是对的。
守卫那一层也不是走个形式,四道检查加一次重试:
输出必须是 JSON
类型必须落在固定列表里
姓名必须是从提醒原文复制、且含字母的文本
答案里出现的数字必须能在原提醒里找到
姓名结尾的银行名由代码截掉
失败重试 1 次,仍失败 → 姓名记为未读取
我自己的经验是,这种“只允许做一件事”的约束写得越死,越容易在出问题的时候知道是谁的问题。反过来,一个什么都能干的 prompt,出错时你连从哪查起都不知道。
到她的手机上,前面搭的东西塌了一半
她的手机是 Tecno Camon 17 Pro,Android 11。系统报告支持 WebGPU,然后拒绝提供 GPU 适配器。作者测了 CPU 版(int8):他的笔记本上每封 36 秒,30 类里只对 1 类。→ 于是应用在她的手机上直接提示“需要 GPU”,而不是默默开始下那 1GB。这个决定我觉得比模型选哪一版更能看出人有没有真的把东西交到别人手上过。
顺带说一句,他自己那台 Pixel 8a 上状态是 ready (webgpu),姓名能正常填,所以这不是代码写错了,是设备层的差异。这类问题你在本地怎么测都测不出来。
4G 下模型下载还会无声停滞,不报错、不退出、就卡住。他为此实现了分片续传:
每片 8MB,落地即保存
15 秒没有新数据 → 自动重试
中断后从最后一片继续,不从头开始
改完之后在她手机上完整下完了。另外运行途中 GPU 掉线过一次,报 Device was lost,他把逻辑改成首次调用失败就停并提示重新加载,而不是把后面所有行都标成不确定——这个改动的方向我认,出错的时候停下来,比猜下去强。
我最看重的,是她其实还没真正用上
手机跑不动 Gemma,目前只能记日记账,姓名识别得靠笔记本;她已答应换手机。作者把这段原原本本写进去了,没有含糊成“已在真实用户处部署”。
我见过太多这类文章在这一步模糊处理,读的时候你得自己去猜“到底上线没有”。他把这句话写出来,前面那些准确率数字我才愿意信。
评论区两条我也顺手记一下。Kevin Hall 问那次漏读是被守卫拒了还是模型返回了空值,并且建议把守卫拦截次数记进结果里——这个我认为该做,不然“模型不行”和“守卫太严”永远分不开。Emily Woods 建议用稳定的银行参考号而不是金额加时间来区分“同一条提醒重复粘贴”和“两笔真实的同额转账”,这条我完全同意,金额加时间判重本来就迟早会误判。
划重点
第一,动手接模型之前,先用一小批真实数据量一遍规则能到哪一步,这一步花的时间比选模型划算得多;第二,把模型圈在一件事上,其余全部交给代码,并且在设计上保证模型整段失效时核心数字仍然正确;第三,先在目标设备上跑一遍再谈上线,报告支持 WebGPU 和真的给出适配器是两回事;第四,出问题的时候宁可停下并提示,也不要继续猜——猜出来的数据混进账本,比没有数据更麻烦。
这篇就记到这里。你可以拿手上任何一封“银行提醒邮件”试着拆一遍:哪些字段是死的、哪些字段每次写法都不一样,拆完再决定要不要请模型进来。