先看现象。用 openai 1.55 的 Python SDK 调 gpt-4o-2024-11-20 读一张 2400×3200 的小票照片,问「合计金额是多少」,模型把数量与单价那一列读成金额,回答 128.00,实际合计 256.00。把 detail 设成 high 也没改善,在提示词里写「仔细看最后一行」还是错,同一批 10 张里错了 4 张。

真正麻烦的地方在于,几个原因的现象几乎一样。整图缩到 768 宽后小票文字只剩几个像素,金额列糊在一起。少数情况下是小票是斜着拍的,行没有对齐,模型按列读串了行。

少数情况下是detail=high 只提高切块数量,不会对局部做增强。

不容易想到的是,提示词没限定输出格式,模型倾向返回看起来合理的数字。

第一件事是按金额区域裁出下半部分单独识别

python -c "from PIL import Image;im=Image.open('bill.jpg');w,h=im.size;im.crop((0,int(h*0.55),w,h)).save('bill_bottom.jpg',quality=92)"

随后把裁剪出来的区域放大两倍再送模型

python -c "from PIL import Image;im=Image.open('bill_bottom.jpg');im.resize((im.width*2,im.height*2)).save('bill_big.png')"

接着用同一请求对比整图与裁图的结果

curl https://api.openai.com/v1/chat/completions -H "Authorization: Bearer $KEY" -H 'Content-Type: application/json' -d '{"model":"gpt-4o-2024-11-20","messages":[{"role":"user","content":[{"type":"text","text":"只返回合计金额数字"},{"type":"image_url","image_url":{"url":"data:image/png;base64,...","detail":"high"}}]}]}'

等前面都确认过,再记录裁剪图的尺寸与识别结果做回归

python -c "from PIL import Image;im=Image.open('bill_big.png');print(im.size)"

怎么算真的好了,看的是同一批现象。裁剪后模型返回 256.00 与人工核对一致,同批 10 张小票的金额全部对上,错行的情况不再出现。

票据类识别别指望一次整图搞定,先按字段区域裁切再放大,成本比反复调提示词低得多,也更容易做成回归用例。如果同一现象隔几天又出现,说明根因没找到,别当偶发处理。

作者 9823189