レシートの読み取りを AI に任せて、確認だけ人に残した理由
ふたかけには、レシートを撮ると店名・日付・金額が自動で入る機能がある。読み取りには Claude の画像認識を使っている。
精度はかなり良い。それでも「撮ったらそのまま保存」という導線は作らなかった。必ず確認画面を挟む。
自動化できるところを自分で止めているので、その理由を書く。
何を任せて、何を任せなかったか
まず、任せた範囲を明確にしておく。1枚のレシートから取るのは次の5つだけだ。
- 店名
- 日付
- 合計金額
- 大分類の推定(食費・日用品など)
- 支払い方法の推定
品目の分解はやらない。 「レシートの明細を1行ずつ読んで、卵は食費、洗剤は日用品、と自動で振り分ける」ことは技術的には可能だが、第1段階では作らないと決めた。1枚のレシート=1件の記録に留めている。
理由は、品目分解を入れると確認しなければならない項目が10倍に増えるからだ。5項目なら目視で確かめられるが、30行の明細それぞれの分類が合っているかを確認するのは、手で入力するより明らかに面倒になる。自動化が人の作業を増やすなら、それは自動化ではない。
「確認せずに保存」を作らなかった理由
さて本題で、なぜ確認を必須にしたか。
読み取りが間違う確率が高いからではない。間違ったときに気づけないからだ。
この2つは似ているようで全く違う。考えてみてほしい。レシートを撮って、確認せずに保存する。金額が 1,280円 のところ 1,230円 と読まれていたとする。あなたはいつ気づくだろうか。
たぶん、気づかない。手元にレシートはもう無いか、あっても見返さない。家計簿の合計は50円ずれたまま、以後ずっと正しい数字として扱われる。
家計簿の誤りは、時間が経つほど直せなくなる。 買った本人の記憶が唯一の照合手段なのに、その記憶は数日で消える。確認できるのは、レシートを手に持っている今この瞬間だけだ。
だから確認画面は、面倒を課しているのではなく、唯一確認できるタイミングを逃さないためにそこにある。
読めなかったものを、推測で埋めない
もうひとつ、実装上のルールがある。
読み取れなかった値は、推測して埋めずに空のまま返す。
たとえば日付が印字かすれで読めなかったとき、「たぶん今日だろう」と埋めることはできる。たいてい当たる。しかし当たったかどうかを利用者は判断できない。空欄なら「あ、日付が入っていない」と気づいて自分で入れるが、それらしい値が入っていたら素通りする。
もっともらしい間違いは、空欄よりたちが悪い。 これは家計簿に限らず、AI に何かを読ませるとき全般に言えることだと思っている。
差し替えられるようにしてある
技術的な作りの話を少しだけ。
OCR の処理は、アプリ本体から見て1つの差し替え可能な層として分離してある。「画像を渡すと、店名・日付・金額などが返ってくる」というかたちだけを決めておいて、その中身が Claude なのか別のエンジンなのかは外から見えない。
こうしてあるのは、画像認識の分野が動きの速い領域だからだ。今より安いモデル、速いモデル、精度の高いモデルが出たときに、差し替えがアプリ全体の改修にならないようにしておきたかった。
実際にネットワークに出ていくのはこの層の内側だけで、他のどの画面も外部と通信しない。「レシートを撮ったときだけ画像が外に出る」という説明が、そのままコードの構造になっている状態にしてある。
コストの話
外部の AI を使う以上、1枚あたりのコストがかかる。ふたかけの場合、画像を長辺1568ピクセルに縮めて送っていて、1枚あたりおよそ0.7円だ。
この数字を出しているのは、無料プランに読み取り回数の上限がある理由がここにあるからだ。「なんとなく制限している」のではなく、実費が発生する処理だから上限がある。有料プランで上限が外れるのも同じ理屈で、費用が利用者側で回収できる形になって初めて無制限にできる。
こういう内訳は隠さずに書いておいたほうがいいと思っている。制限の理由が分かっていれば、上限に当たったときに納得できるからだ。
まとめると
- 読み取りは AI に任せる。ただし任せる範囲を5項目に絞る(品目分解はしない)
- 確認は人に残す。読み取り精度の問題ではなく、間違いに気づける唯一のタイミングを逃さないため
- 読めなかったものは推測で埋めない。もっともらしい間違いは空欄より危険
- OCR は差し替え可能な層に閉じ込め、外部通信をそこだけに限定する
自動化するときに一番考えるべきなのは「どこまで自動化できるか」ではなく、「間違ったとき、それに誰がいつ気づくか」だと思う。気づける人が誰もいない自動化は、便利ではなく危険だ。