納品書の突合をClaudeで進める手順 — 受領書のスキャン画像と請求データを照合
手書きの受領印が入った納品書や、斜めに撮った受領書の画像をClaudeに読ませ、請求データと突き合わせる手順です。数量の比較はコード側に任せ、再確認が要る行だけ人に戻します。
納品書や受領書のスキャン画像を請求データと突合するときは、Claudeに「画像から行を読み取って構造化する」ところまでを任せ、数量や金額の比較は普通のコードで行う分担が安定します。画像の読み取りは、斜めの撮影や手書きの受領印があると誤りが混じるからです。比較まで一度に頼むと、読み違いと照合ミスが区別できなくなります。
発注書・納品書・請求書をPDFで揃えて三点照合する流れはClaudeで発注書・納品書・請求書を三点照合する手順にまとめています。この記事は入口が違い、倉庫や現場で撮影した納品書の写真、押印のある受領書のスキャンを起点にします。
画像入力で突合するときの分担
画像から始まる突合では、Claudeに二つの仕事を分けて渡します。
- 画像に写っている納品書の明細と受領印を、決まった形のJSONに書き起こす
- 書き起こした結果と請求データの差を、スクリプトで機械的に出す
この分担にする理由は、画像の読み取りが確率的な処理だからです。Claudeの画像理解には、低品質・回転した画像・200ピクセル未満の小さい画像で誤読や作り話をしうる、という制約があります。数や位置の出力も概算にとどまると説明されています。
読み取りを誤る可能性があるなら、誤りが紛れ込む場所を一か所に絞るほうが検証しやすくなります。書き起こしの段階で「読めなかった」と言わせ、比較の段階は誤りようのないコードに置けば、差異が出たときに原因が画像か請求データかを切り分けられます。
人に戻す行は、次の三種類です。
- 数量・品番が請求データと食い違う行
- Claudeが判読できないと自己申告した行
- 受領印がない、または日付が読めない納品書
撮影・スキャンの条件を先に決める
画像の質は結果を左右します。画像理解の条件として、画像が鮮明でぼやけていないこと、重要な文字が小さすぎないことが挙がっています。次の点は撮影ルールとして現場に伝えておく価値があります。
- 納品書全体をなるべく正面から撮る。斜めに撮ると文字が歪み、誤読の原因になる
- 受領印と手書きの日付を、切り取らずに写す。拡大のために文脈を削らない
- 圧縮を重ねない。JPEGやWebPの強い圧縮は文字を読みにくくする。送る前に、実際にAPIへ渡す画像を目で確認する
対応形式はJPEG・PNG・GIF・WebPです。GIFはアニメーションに対応せず、先頭フレームだけが使われます。スマートフォンで撮ったHEIC形式の写真は対応形式に入っていないため、JPEGなどへ変換してから渡します。
解像度とトークンの関係
Claudeは画像を28×28ピクセルのパッチに分けて読みます。画像1枚のトークン数は、幅÷28と高さ÷28をそれぞれ切り上げて掛けた値です。大きすぎる画像は縮小されてから処理されます。
モデル世代で変わる画像の上限
標準モデル
1568px
長辺の上限。最大1568トークン
Claude 4.7以降
2576px
長辺の上限。最大4784トークン
2000×1500ピクセルの画像なら、標準モデルでは1269×952に縮小されて1564トークン、4.7以降では縮小されず3888トークンです。細かい品番や数量が並ぶ納品書は、縮小による文字の潰れは、高解像度側のほうが起きにくくなります。代わりにトークンは約2.5倍に増えるため、納品書が十分に鮮明なら、あらかじめ縮小して送るとコストを抑えられます。
手順:画像を書き起こして請求データと突き合わせる
スキャン画像から差異リストを作る流れ
- 1
画像を正しい向きに回し、1納品書1リクエストで送る
向きが横倒しの画像は誤読の元です。送る前に回転し、納品書1枚(複数ページなら全ページ)を1リクエストにまとめます。
- 2
画像を先に、指示文を後に置く
画像を渡すときは、画像を先に、テキストを後に置く構成が推奨されています。複数枚送るなら、画像の前に「納品書1枚目:」のような短いラベルを付け、指示文から名前で呼べるようにします。
- 3
出力をJSONに固定し、読めない箇所を申告させる
自由な文章では後工程で拾えません。品番・品名・数量の各行に「判読できたか」の項目を持たせ、受領印は有無と日付を別に出させます。
- 4
請求データとの比較はスクリプトで行う
書き起こしたJSONと請求CSVを品番で突き合わせ、差異と再確認の理由を一覧にします。
書き起こしのリクエスト
Pythonで、納品書の画像1枚と指示文を送る例です。モデル名はAPIドキュメントの画像入力の例に載っているものに合わせています。契約中のモデル名に置き換えてください。
import anthropic, base64, pathlib
client = anthropic.Anthropic()
image = base64.standard_b64encode(
pathlib.Path("nohinsho_001.jpg").read_bytes()
).decode()
prompt = pathlib.Path("prompt.txt").read_text(encoding="utf-8")
message = client.messages.create(
model="claude-opus-5-5",
max_tokens=4096,
messages=[{"role": "user", "content": [
{"type": "text", "text": "納品書1枚目:"},
{"type": "image", "source": {
"type": "base64",
"media_type": "image/jpeg",
"data": image}},
{"type": "text", "text": prompt},
]}],
)
pathlib.Path("read.json").write_text(
message.content[0].text, encoding="utf-8")画像の渡し方は、base64、URL、Files APIのfile_idの3通りです。社内の書類をURLで公開するのは現実的でないので、実務ではbase64かFiles APIになります。Files APIは一度アップロードすれば何度も参照でき、同じ納品書を再度読ませる場面でリクエストを軽くできます。AmazonBedrockとGoogle Cloudでは、base64だけが使えます。
prompt.txtの中身は、たとえば次のような形にします。
添付は取引先から受け取った納品書の画像です。
次のJSONだけを返してください。説明文は不要です。
{
"受領印": {"有無": true/false, "日付": "YYYY-MM-DD か null",
"判読": "clear か unclear"},
"行": [{"品番": "...", "品名": "...", "納品数量": 数値,
"判読": "clear か unclear"}]
}
ルール:
- 読めない文字を推測で補わず、判読を unclear にする
- 数量の手書き訂正がある行は、訂正後の値を入れ、判読を unclear にする
- 画像にない行は作らない「推測で補わない」「画像にない行は作らない」と明記するのは、誤読と作り話の両方を避けるためです。判読の申告は完全ではないので、次の突合スクリプトでは申告に頼らず、数値の食い違いも独立に検出します。
請求データとの突合スクリプト
請求CSVは品番,品名,請求数量,単価の列を持つ想定です。次のスクリプトは、書き起こしと請求データを品番で突き合わせ、再確認の理由を付けて出力します。
import csv, json
read = json.load(open("read.json", encoding="utf-8"))
bill = {r["品番"]: r for r in csv.DictReader(
open("billing.csv", encoding="utf-8"))}
review = []
stamp = read["受領印"]
if not stamp["有無"] or stamp["判読"] == "unclear":
review.append(("-", "受領印が無い、または日付が不明"))
seen = set()
for row in read["行"]:
code = row["品番"]
seen.add(code)
b = bill.get(code)
if b is None:
review.append((code, "請求データに無い品番"))
elif row["納品数量"] != float(b["請求数量"]):
review.append((code, f"納品{row['納品数量']} / 請求{b['請求数量']}"))
if row["判読"] == "unclear":
review.append((code, "読み取りに自信なし。画像を目視"))
for code in bill.keys() - seen:
review.append((code, "請求にあるが納品書に写っていない"))
for code, reason in review:
print(code, reason)最後の「請求にあるが納品書に写っていない」は、画像入力で特に起きやすい差異です。納品書の下端が切れていたり、複数ページの2枚目を撮り忘れていたりすると、請求側にだけ行が残ります。数量差と同じ扱いで人に戻します。
差異が出たときの再確認を人に戻す運用
出力の各行には、人が最初に何を見るかが分かる理由を付けます。理由ごとの見る先は次のとおりです。
| 理由 | 最初に見るもの | 起きやすい原因 |
|---|---|---|
| 数量が食い違う | 最初に見るもの納品書の画像の該当行 | 起きやすい原因手書き訂正、読み違い、本当の過不足 |
| 読み取りに自信なし | 最初に見るもの画像の該当行 | 起きやすい原因斜め撮影、かすれ、重なった押印 |
| 請求にあるが写っていない | 最初に見るもの撮影した枚数・ページ | 起きやすい原因撮り漏れ、画像の端の切れ |
| 受領印が無い・日付不明 | 最初に見るもの受領書の現物 | 起きやすい原因押し忘れ、印影の薄さ |
数量が食い違う行は、画像の読み違いと実際の過不足のどちらかです。画像を見れば前者は数秒で片づきます。後者は取引先への問い合わせという業務判断になり、Claudeの出番ではありません。
落とし穴
受領印の日付を検収日として自動確定しない
手書きの日付は読み違いが起きやすく、押印日と検収日が一致するとも限りません。Claudeが返した日付は「画像から読めた値」として一覧に載せ、検収日の確定は人が画像と見比べて行います。
読み取りに自信がないと申告された行は、画像を人が見る前提で用意しておきます。画像理解には精度の限界があり、完全な精度が要る用途では人の確認を外さないよう注意されています。突合の結果は検収の根拠ではなく、人が見る場所を絞るための下書きです。
枚数が増えたときの扱い
納品書が月に数十枚になると、リクエストの上限が効いてきます。
- claude.aiでは1メッセージ20枚まで、1枚10MBまで
- APIでは、200kトークンのコンテキストウィンドウのモデルで1リクエスト100枚、その他のモデルで600枚。1枚の上限は、API直接利用で10MB(base64化後)、BedrockとGoogle Cloudでは5MB
- 1枚の寸法は最大8000×8000ピクセル
1リクエストに20枚を超える画像を入れると、全画像に対してより厳しい寸法制限が適用されます。過去の会話ターンの画像を再送した分も数えられ、超えた画像はinvalid_request_errorで拒否されます。回避は、各画像の長辺を2000ピクセル以内に縮小するか、画像を20枚以下に保つかです。
突合の単位は1納品書1リクエストにしておけば、この制限に当たる場面はほぼありません。取引先ごとの納品書を一度にまとめて読ませるより、1枚ずつ並列に投げて結果のJSONを束ねるほうが、読み違いの原因も追いやすくなります。
画像のメタデータは読まれない
画像に埋め込まれた撮影日時などのメタデータは、Claudeに渡されません。撮影日を検収の証跡にしたいなら、ファイル名や取り込みシステムの記録など、画像の外で残します。送った画像はAPIリクエストの処理後に自動削除され、保存されません。手元の証跡が必要なら、原本は自社の保管場所に残します。
スキャンPDFとして届く納品書は、引用機能の扱いに注意が要ります。PDFの引用で根拠の位置を示せるかについてはClaudeのCitationsでスキャンPDFを引用できない理由と回避策で扱っています。
読み取り精度の確認方法
最初の数十枚は、Claudeの書き起こしを全件、画像と見比べます。誤りの傾向(手書きの「1」と「7」、薄い印影、複数行にまたがる訂正)が分かれば、撮影ルールかプロンプトで手当てできます。日本語の書類を読ませたときの精度の見方はClaude VisionでOCRした日本語PDFの精度をどう見極めるかに整理しています。
領収書やレシートの写真を経費に仕分ける流れはClaudeで領収書・レシートの写真から経費を仕分ける手順にあります。納品書は明細の行数が多く、品番との突合が加わる分、書き起こしの形式を固定する重みが大きくなります。
よくある質問
納品書の画像をClaude.aiに直接アップロードして突合してもよいか
1メッセージ20枚までという枠内なら、アップロードして同じ指示を出せます。繰り返す業務にするなら、出力形式の固定と比較のコード化ができるAPI経由のほうが再現性を取りやすくなります。
複数ページの納品書はどう渡すか
ページごとに画像を送り、各画像の前に「納品書1枚目:」「納品書2枚目:」のラベルを置きます。指示文に「全ページの行を1つの配列にまとめる」と書けば、1回の書き起こしで済みます。