[{"data":1,"prerenderedAt":426},["ShallowReactive",2],{"content-/cheap-ocr-model-bench-process":3,"all-pages-for-dir":407,"related-/cheap-ocr-model-bench-process":408,"og-image-/cheap-ocr-model-bench-process":425},{"id":4,"title":5,"body":6,"category":386,"concepts":387,"description":388,"extension":389,"meta":390,"navigation":391,"ogImage":387,"path":392,"project_name":393,"published":394,"publishedAt":395,"seo":396,"source":397,"stem":398,"tags":399,"todo":387,"unpublished":394,"updatedAt":387,"__hash__":406},"pages/2026-09/2026-09-18/cheap-ocr-model-bench-process.md","手書き伝票のOCRを安いモデルで試した記録：DeepSeek と Gemini の同条件ベンチと、Gemini Flash での全件照合",{"type":7,"value":8,"toc":375},"minimark",[9,14,18,21,25,28,31,34,37,41,44,55,78,81,84,88,95,98,101,108,115,125,128,132,135,146,149,153,168,179,182,192,273,278,281,284,287,290,293,296,305,309,312,315,318,322,325,328,331,334,341,344,368,371],[10,11,13],"h1",{"id":12},"手書き伝票のocrを安いモデルで試した記録","手書き伝票のOCRを安いモデルで試した記録",[15,16,17],"p",{},"朝、DeepSeek V4 Flash を API で試してみたくなった。\n記帳業務での正確さを試し、画像を渡せるなら OCR の精度も見たい。",[15,19,20],{},"比べる相手は、記帳アプリで使ってきた Gemini である。\n安いモデルに替えても、同じ伝票を同じだけ読めるのか。",[22,23,24],"h2",{"id":24},"去年の記帳アプリを掘り起こす",[15,26,27],{},"Claude Code に調べてもらうと、V4 Flash はすでに退役していた。\nいま API で呼ぶと、2026年9月10日に出た V4.1 Flash に振り替わる。\nV4.1 Flash は画像入力にネイティブで対応しているので、記帳の精度と OCR の精度を同じモデルで試せる。",[15,29,30],{},"試す材料には心当たりがあった。\n去年の3月ごろ、手書きの売上伝票を読んで仕訳にする記帳アプリを作っている。\nどのリポジトリだったかを忘れていて、少し考えてから思い出した。\nアプリを起動してもらうと、ある事業者の手書き伝票と、画面で直して確定した正解データが見つかった。\n処理をそろえたいので、既存のプロンプトを読ませ、使っていた Gemini のモデル名もメモさせた。",[15,32,33],{},"修正前の Gemini の出力は、残っていなかった。\nアプリは OCR の結果を行に直接書き、画面での修正がその行を上書きする。\n生テキスト用の列は全行空で、バックアップの DB 3本もすべて修正後の値と一致した。\n「当時の Gemini」とは比べられないので、同じプロンプトと同じスキーマで Gemini を今日もう一度回すことになった。\nプレビュー版のモデルなので、当時と同一とは言い切れない。",[15,35,36],{},"対象は、アプリでいま開いているバッチの78枚にした。\nいまのスキーマで処理した最後のバッチで、正解データの項目がそろっている。\n送る前に、顧客名の行だけを白く塗る。\n3枚で確かめると、日付の行は残り、名前の行だけが消えていた。",[22,38,40],{"id":39},"チャージ2ドルとapiキーの置き場所","チャージ2ドルと、APIキーの置き場所",[15,42,43],{},"DeepSeek は前払い制で、チャージは2ドルで足りると見積もってもらった。\n69枚を3条件で回すパイロットなら0.5ドルに届かず、全量963枚を thinking 込みで回しても1〜2.5ドルで収まる。\n平日の日本時間10〜13時と15〜19時は単価が倍になるので、全量はそれ以外の時間に回す。",[15,45,46,47,51,52,54],{},"引っかかったのはキーの置き場所だ。\n見積もりの報告には、キーを 1Password に入れてアプリの ",[48,49,50],"code",{},".env"," に書く前提、とあった。\n1Password に入れるのに ",[48,53,50],{}," にも書くとはどういうことか、と聞き返した。\nあわせて、1Password に空の項目を作ってもらえれば、そこへ自分で入れる、と頼んだ。",[15,56,57,58,60,61,64,65,67,68,71,72,74,75,77],{},"Claude Code の説明では、この環境のルールで正本は 1Password、",[48,59,50],{}," はそこから書き出したコピーである。\nWindows では ",[48,62,63],{},"op run"," が実行のたびに承認ダイアログを出すので、何十回も起動するアプリ本体は ",[48,66,50],{}," に書き出して使っている。\n今回のベンチは1プロセスを1回起動するだけなので、起動時に ",[48,69,70],{},"op read"," で 1Password から直接読めば ",[48,73,50],{}," は要らない。\n「",[48,76,50],{}," に書く前提」は撤回され、1Password には空の項目が用意された。",[15,79,80],{},"DeepSeek 側でキーに付ける名前も相談した。\n勧められたのは、リポジトリ名に用途を足した名前である。\n用途と機体が後で分かれば、漏れたときにそのキーだけを失効できる。\n発行したキーを 1Password の認証情報の欄に入れ、値を画面に出さないまま疎通を確かめてもらった。",[15,82,83],{},"ベンチ用のスクリプトを書く段で、書き込みが止まった。\n書いてもらってかまわないし、明示的に OK を出してもだめなのかと返し、オートモードを切らずに進めたいと伝えた。\n明示の OK を受けて許可ルールが効き、スクリプトは書き込めた。",[22,85,87],{"id":86},"最初の2枚とthinking-を切った78枚","最初の2枚と、thinking を切った78枚",[15,89,90,91,94],{},"スクリプトはローカルの動作確認まで通ったが、実行の段で止まった。\nそこでベンチのコマンドは、行頭に ",[48,92,93],{},"!"," を付けて自分で打った。",[15,96,97],{},"まず2枚。\n9秒、6,287トークンで返り、日付も金額も摘要も、2枚とも正解と一致した。\nマスクした顧客名は空で返ってきている。",[15,99,100],{},"1枚あたりいくらかを円で聞いた。\n実測は入力1,740トークン、出力1,400トークン前後で、出力の大半は thinking だった。\n公式単価（ピーク時で100万トークンあたり入力0.30ドル、出力1.20ドル）に当てはめ、1ドル150円で換算すると、1枚1円に届かない。\n同時に、thinking を切るとさすがに精度が落ちるのか、とも聞いた。",[15,102,103,104,107],{},"thinking を切って、顧客名を塗った1枚をそのまま渡す条件（",[48,105,106],{},"masked","）で78枚を回した。\n58秒、13万7,824トークンで全件が返る。\n金額3項目がすべて合ったのは65枚（83%）だった。\n実務にはまだ足りないが、誤りの型ははっきりしていた。",[15,109,110,111,114],{},"次に、画像を上下2つに割って渡した（",[48,112,113],{},"masked-split","）。\n38秒で終わり、金額は少し上がり、日付は下がった。",[15,116,117,118,121,122,124],{},"残りの3条件（thinking あり、temperature 0、3部位に切り出す ",[48,119,120],{},"masked-crops","）は、まとめて打った。\n2行目以降の行頭の ",[48,123,93],{}," が bash の否定演算子として効き、終了コードが反転して「失敗」と表示された。\nしかも120秒の制限にかかり、バックグラウンドへ退避されている。\n出力ファイルを確かめてもらうと、3本とも78枚分の応答が保存されていた。\n失敗は、thinking ありの2枚だけだった。",[15,126,127],{},"5条件がそろうと、thinking を切ると落ちるという見立ては外れた。\n金額の一致は増えず、所要は4倍になり、費用も4倍以上に膨らんだ。\nそのうえ、明細に無い商品の売上を作る、足し間違える、JSON の前にスキーマを復唱して出力が壊れる、という副作用が出た。\nDeepSeek で成績が最もよかったのは、3部位に切り出し、thinking なし、temperature 0 の組み合わせだった。",[22,129,131],{"id":130},"dgx-spark-で回すなら","DGX Spark で回すなら",[15,133,134],{},"このベンチは、NVIDIA の DGX Spark で手元に置けるかの検証も兼ねている。\nそこで、DGX Spark でも thinking を使えるのかを聞いた。",[15,136,137,138,141,142,145],{},"thinking 自体はローカルでも使える。\nクラウド限定の機能ではなくモデルに組み込まれた挙動で、推論サーバー側のフラグで切り替える（vLLM や SGLang ならテンプレート引数の ",[48,139,140],{},"thinking","、llama.cpp なら ",[48,143,144],{},"--reasoning on/off","）。\n問題は thinking ではなく、いま API で測っている V4.1 Flash が1台に載らないことだった。\n1台の128GBに収まらず、3台か4台を束ねる構成になる。\nそれなら今は300万〜400万円かかる、というのが自分の理解だった。",[15,147,148],{},"ここで、thinking が要らないという結果が効く。\nDGX Spark で回す場合でも、thinking なしで済めば速度が10倍違う。",[22,150,152],{"id":151},"gemini-も同じスクリプトで回す","Gemini も同じスクリプトで回す",[15,154,155,156,159,160,163,164,167],{},"DeepSeek の結果が出たところで、Gemini も同じ条件で回すよう頼んだ。\nGemini 用の別スクリプトは作らず、同じ ",[48,157,158],{},"bench.py"," に ",[48,161,162],{},"--provider gemini"," を足してもらった。\n同じ画像加工、同じプロンプト、同じ採点を通すには、1本にまとめるのが比較の前提になる。\n",[48,165,166],{},"compare"," サブコマンドで、両者が1つの表に並ぶ。",[15,169,170,171,174,175,178],{},"ここでもキーでつまずいた。\n環境変数に入っていた Gemini のキーは、文字だけの最小呼び出しで「API key not valid」を返した。\n失効したか、差し替え済みである。\nアプリのインポート機能も同じ環境変数を読むので、次に使うときに落ちる可能性がある。\n新しいキーを 1Password に入れると、",[48,172,173],{},"gemini-3-flash-preview"," から応答が返った。\n",[48,176,177],{},"thinkingLevel=minimal"," を付けると思考トークンがゼロになるので、DeepSeek の thinking なしとほぼ同じ条件で比べられる。",[15,180,181],{},"Gemini は3本を1本ずつ打ったが、3本とも120秒の制限にかかってバックグラウンドへ回った。\nしばらくして「これ進んでますか」と聞いた。",[15,183,184,185,187,188,191],{},"2本は止まっていて、残る1本は22枚まで進んで途切れていた。\n新しいキーを確かめる途中で、",[48,186,70],{}," が一度「authorization timeout」で失敗した（1Password アプリ側の承認かロックの可能性）。\n読み直すとキーは有効で、小さな呼び出しを7回続けても通ったので、無料枠ではないと分かった。\n失敗した分だけを同じ出力フォルダへ再実行する ",[48,189,190],{},"--resume"," を、スクリプトに足してもらった。",[193,194,199],"pre",{"className":195,"code":196,"language":197,"meta":198,"style":198},"language-bash shiki shiki-themes vitesse-light vitesse-light","bench.py run --provider gemini --key-source op --condition masked --thinking off --temperature 0\nbench.py run --key-source op --resume \u003C前回の出力フォルダ>\n","bash","",[48,200,201,245],{"__ignoreMap":198},[202,203,206,209,213,217,220,223,226,229,232,235,238,241],"span",{"class":204,"line":205},"line",1,[202,207,158],{"class":208},"senZ8",[202,210,212],{"class":211},"sdGka"," run",[202,214,216],{"class":215},"snbK4"," --provider",[202,218,219],{"class":211}," gemini",[202,221,222],{"class":215}," --key-source",[202,224,225],{"class":211}," op",[202,227,228],{"class":215}," --condition",[202,230,231],{"class":211}," masked",[202,233,234],{"class":215}," --thinking",[202,236,237],{"class":211}," off",[202,239,240],{"class":215}," --temperature",[202,242,244],{"class":243},"sM54T"," 0\n",[202,246,248,250,252,254,256,259,263,266,270],{"class":204,"line":247},2,[202,249,158],{"class":208},[202,251,212],{"class":211},[202,253,222],{"class":215},[202,255,225],{"class":211},[202,257,258],{"class":215}," --resume",[202,260,262],{"class":261},"stQ0i"," \u003C",[202,264,265],{"class":211},"前回の出力フォル",[202,267,269],{"class":268},"sG7-3","ダ",[202,271,272],{"class":261},">\n",[15,274,275,277],{},[48,276,190],{}," で1本ずつ回し直すと、アプリと同じ設定の1本は再開から約10分で78枚がそろった。\nthinking 最小、temperature 0 の1本は52秒、3部位の切り出しは62秒で終わった。",[15,279,280],{},"thinking 最小、temperature 0 の Gemini は、金額3項目の全一致が75枚（96.2%）で、既定設定の74枚と変わらない。\n所要は1枚2.6秒、費用は0.067ドルで、既定の4分の1だった。\n摘要だけは既定のほうが少し良い（71対67）。",[22,282,283],{"id":283},"結局どちらが優秀だったのか",[15,285,286],{},"結果を公開記事にまとめさせたあとで、結論をつかみ損ねて聞き直した。\nGemini がやはり優秀だったのか、それとも日付を見れば DeepSeek のほうが良かったのか。",[15,288,289],{},"総合では、ほぼ互角だった。\n金額は Gemini（78枚中75対70）、日付は DeepSeek（66対55）が強い。\n日付と金額の両方が合った枚数は、DeepSeek が59、Gemini が55だった。\n78枚の試験では、4枚の差は誤差の範囲に収まる。",[15,291,292],{},"間違え方は違った。\nDeepSeek は細い「1」と「7」で落ち、Gemini は年と月で落ちる。\nGemini の日付誤り23件のうち19件が、年か月の誤りだった。\n途中の報告では誤りを26件（うち年と月で22件）と数えていたが、記事を書く段で実測値に数え直された。",[15,294,295],{},"プロンプトで「その月の伝票の束だ」と伝えていたから、実運用の Gemini はうまくいっていたのではないか、とも聞いた。\nこれは違った。\n今回使ったのはアプリのプロンプトそのままで、年月のヒントは入っていない。\n実運用でも Gemini は同じ年月の誤りを出していて、それを自分が画面で直していたことになる。\n修正前の出力が残っていないので、何件直したのかは分からない。",[15,297,298,299,304],{},"条件ごとの表と誤読の実例は、公開記事 ",[300,301,303],"a",{"href":302},"/deepseek-vs-gemini-handwritten-slip-ocr","手書き伝票のOCRで、DeepSeek V4.1 Flash と Gemini 3 Flash を同じプロンプトで比べた"," に置いた。",[22,306,308],{"id":307},"安さとデータの置き場所","安さと、データの置き場所",[15,310,311],{},"費用は78枚で DeepSeek が7円、Gemini が10円ほどで、全量の963枚でも DeepSeek は100円弱、Gemini は130円ほどで済む（1ドル150円で換算）。",[15,313,314],{},"それでも、結果を聞いたあとで口にしたのは値段の話ではなかった。\nDeepSeek のサーバーにデータが保管されるリスクは、桁違いに高い。\nみんなが欲しいのは安い OCR ではなく、顧問先のデータを外に出さない処理環境である。\nClaude Code の確認でも、DeepSeek の API は利用規約上、入力が中国のサーバーに保管され、学習にも使われうる。\n税理士がそのまま使う選択肢にはならない。",[15,316,317],{},"Claude のチームプランや Codex のビジネス向けプランもあるが、やはり高い。\nAPI なら従量課金で学習には使われないものの、予算として取りにくい。\nそれなら問題は同じなのではないかと聞くと、Claude Code の答えもそうだった。\n従量課金はいくらかかるか分からないので予算の行に書けず、金額が小さくても稟議に通らない。",[22,319,321],{"id":320},"午後番号表の写真を-gemini-flash-で読み直す","午後、番号表の写真を Gemini Flash で読み直す",[15,323,324],{},"別のリポジトリでも、画像から CSV を作る OCR が途中で止まっていた。\nどこを確認すればいいかを忘れていたので、置き場所をエクスプローラーで開き、見るべきファイルを選択した状態にしてもらった。",[15,326,327],{},"1ページ目を30個ほど照らし合わせたところで、面倒になった。\nさっき 1Password に Gemini のキーを入れていたので、それを使ってもらう。\nこれまでの読み取りは、3.7 Flash 系だったはずだ。\n3.8 Flash にして推論レベルを0にし、全画像をもう一度通すといくらかかるかを聞いた。",[15,329,330],{},"料金と使えるモデルを調べてもらい、API 用のスクリプトで1枚目のトークン数と精度を実測してから、42枚を全部読み直させた。\n正式版の CSV と突き合わせると、5,666件すべてが一致し、数字の不一致はゼロだった。\n料金は実測で0.39ドル（約59円）だった。",[15,332,333],{},"1つだけ、3つ目の数字が空欄の行が出た。\n紙で見ても、3つ目の数字はたしかに書かれていない。\n画像と同じなので間違いではなく、空欄のままでよいと伝えた。\nその判断は計画書に書き残させ、正式版の CSV はその行が入っていない今のままとして、コミットとプッシュを頼んだ。",[15,335,336,337,340],{},"元の写真もプッシュして、Mac から取れるのかも聞いた。\nHEIC の42枚（合計約59MB）は9月15日のコミットでプッシュ済みで、Mac で ",[48,338,339],{},"git pull"," すれば取れる。",[22,342,343],{"id":343},"振り返り",[345,346,347,351,359,365],"ul",{},[348,349,350],"li",{},"thinking を切れば落ちる、と思っていた。DeepSeek でも Gemini でも thinking は金額の一致を増やさず、所要と費用だけを押し上げた",[348,352,353,355,356,358],{},[48,354,93],{}," を付けたコマンドを複数行まとめて打つと、2行目以降の ",[48,357,93],{}," が否定演算子として効く。「失敗」と表示されても、出力ファイルを見るまで失敗とは決められない",[348,360,361,362,364],{},"120秒で裏へ回ったベンチは、失敗分だけやり直す ",[48,363,190],{}," があれば、最初から回し直さずに済んだ",[348,366,367],{},"番号表は、人が30個で止めたところを、42枚、5,666件の機械照合が引き継いだ。空欄の1行は、紙を見ても空欄だった",[15,369,370],{},"年と月の誤りは、伝票の束の年月をプロンプトに渡せば減るのか。\nプロンプトや書き方を工夫すれば精度は上がりそうだが、既存アプリと同じプロンプトという今回の前提から外れるので、まだ試していない。",[372,373,374],"style",{},"html pre.shiki code .senZ8, html code.shiki .senZ8{--shiki-default:#59873A;--shiki-dark:#59873A}html pre.shiki code .sdGka, html code.shiki .sdGka{--shiki-default:#B56959;--shiki-dark:#B56959}html pre.shiki code .snbK4, html code.shiki .snbK4{--shiki-default:#A65E2B;--shiki-dark:#A65E2B}html pre.shiki code .sM54T, html code.shiki .sM54T{--shiki-default:#2F798A;--shiki-dark:#2F798A}html pre.shiki code .stQ0i, html code.shiki .stQ0i{--shiki-default:#AB5959;--shiki-dark:#AB5959}html pre.shiki code .sG7-3, html code.shiki .sG7-3{--shiki-default:#393A34;--shiki-dark:#393A34}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}html.dark .shiki span {color: var(--shiki-dark);background: var(--shiki-dark-bg);font-style: var(--shiki-dark-font-style);font-weight: var(--shiki-dark-font-weight);text-decoration: var(--shiki-dark-text-decoration);}",{"title":198,"searchDepth":247,"depth":247,"links":376},[377,378,379,380,381,382,383,384,385],{"id":24,"depth":247,"text":24},{"id":39,"depth":247,"text":40},{"id":86,"depth":247,"text":87},{"id":130,"depth":247,"text":131},{"id":151,"depth":247,"text":152},{"id":283,"depth":247,"text":283},{"id":307,"depth":247,"text":308},{"id":320,"depth":247,"text":321},{"id":343,"depth":247,"text":343},"dev",null,"記帳アプリの手書き伝票78枚を、既存と同じプロンプトで DeepSeek と Gemini に読ませた日の試行錯誤。APIキーを1Passwordから読む運用、thinking の要否、120秒で裏へ回ったベンチの再開、データの保管先の論点、午後の Gemini Flash による全件照合まで。","md",{},true,"/cheap-ocr-model-bench-process","tax-assistant",false,"2026-09-18T00:00:00.000Z",{"title":5,"description":388},"make-diary","2026-09/2026-09-18/cheap-ocr-model-bench-process",[400,401,402,403,404,405],"OCR","DeepSeek","Gemini","1Password","記帳","DGX Spark","Pq41ZsfWU28Aw9YshbO26RQKN3s-qyPeT0Y6bD7UuBg",[],[409,410,414,418,422],{"title":303,"path":302,"publishedAt":395},{"title":411,"path":412,"publishedAt":413},"手書き数値表42枚のOCRで、マルチモーダルLLMをレート制限ごとに乗り換えた記録","/handwritten-table-images-to-csv","2026-09-16T00:00:00.000Z",{"title":415,"path":416,"publishedAt":417},"表の画像をCSVに起こすOCRを、Claude CodeとGemini 3.1 Pro（agy）で突き合わせた記録","/image-table-ocr-two-model-crosscheck","2026-09-15T00:00:00.000Z",{"title":419,"path":420,"publishedAt":421},"2026年8月2日の開発日記 - WindowsからMacへ環境を移した一日","/2026-08-02-diary","2026-08-02T00:00:00.000Z",{"title":423,"path":424,"publishedAt":421},"WindowsからMacへ開発環境を移す初日にやったこと","/mac-dev-environment-bootstrap","https://log.eurekapu.com/og/blog/cheap-ocr-model-bench-process.png?v=2026-09-18T00%3A00%3A00.000Z&title=%E6%89%8B%E6%9B%B8%E3%81%8D%E4%BC%9D%E7%A5%A8%E3%81%AEOCR%E3%82%92%E5%AE%89%E3%81%84%E3%83%A2%E3%83%87%E3%83%AB%E3%81%A7%E8%A9%A6%E3%81%97%E3%81%9F%E8%A8%98%E9%8C%B2%EF%BC%9ADeepSeek%20%E3%81%A8%20Gemini%20%E3%81%AE%E5%90%8C%E6%9D%A1%E4%BB%B6%E3%83%99%E3%83%B3%E3%83%81%E3%81%A8%E3%80%81Gemini%20Flash%20%E3%81%A7%E3%81%AE%E5%85%A8%E4%BB%B6%E7%85%A7%E5%90%88&author=Kei%20Komatsu&sig=ece7cc731987266d",1789885490847]