|

画像生成で画像が返ってこないとき:まずレスポンスを確認してから再試行を。4ステップの判断で二重課金を防ぐ

画像生成で画像が返ってこないとき:まずレスポンスを確認してから再試行を。4ステップの判断で二重課金を防ぐ

著者より:画像生成APIを呼び出したとき、レスポンスに画像が含まれていなくても、リクエストが失敗したとは限りません。ましてや、課金されていないとも限りません。この記事では、「まずレスポンスを見て、それからリトライするかを決める」4ステップの判断法と、そのまま使えるPythonコードを紹介します。

画像生成APIを呼び出していると、こんな場面に出くわすことがあります。リクエストは送信され、APIからもレスポンスが返ってきたのに、結果の中に画像が見つからない。多くの人はまず「ネットワークが一瞬乱れたのかな」と考え、すぐにもう一度呼び出したり、ループで何度も連打したりしてしまいます。この記事では、まずレスポンスを確認し、それからリトライするかどうかを決めるという処理の順序を紹介します。画像が返ってこなかったときの正しい切り分け方が身につきます。

これは、よくある一般的なリトライ解説ではありません。従量課金(1回ごとの課金)の画像生成モデルでは、リクエストのたびに料金が発生する可能性があります。たとえば、2026-11-12 にAPIYIで提供が始まった gpt-image-2.6-all は1回あたり $0.025 の課金です。空のレスポンスを確認せずにそのままリトライすると、もう一度料金を支払うことになります。

この記事で得られること:画像が返ってこないときにまずどこを確認すべきか、どんな場合ならリトライしてよく、どんな場合は絶対にリトライしてはいけないのかが分かります。さらに、その判断をコードに落とし込んで、同じ画像に二重課金されるのを防ぐ方法も身につきます。

image-generation-no-image-check-response-before-retry-ja-image-0


画像生成で画像が返ってこないときの重要ポイント

まず結論からお伝えします。画像生成で画像が返ってこないとき、単なるネットワークの問題として片づけてはいけません。レスポンスの内容を決まった順番で確認する必要があります。次の表は、この判断方法の4つのステップをまとめたものです。

ステップ 確認内容 「いいえ」の場合の対応 価値
ステップ1 HTTPリクエストが成功したか ステータスコードに応じて対処し、以降の判断には進まない リクエスト層の失敗とコンテンツ層の問題を切り分ける
ステップ2 レスポンスに画像データまたは画像URLがあるか ステップ3へ進む 画像があればそこで終了し、誤ったリトライを防ぐ
ステップ3 レスポンスにエラー情報があるか エラーがあればエラーとして処理する 必ず失敗するリクエストに何度も課金されるのを避ける
ステップ4 画像もエラーもないことを確認 リトライは1回だけ 追加コストを予測可能な範囲に抑える

画像が返ってこなくても、すぐにリトライしてはいけない理由

画像生成リクエストは通常のテキスト対話と違って1回あたりのコストが高く、結果も「すべて成功かすべて失敗か」とは限りません。サーバー側ではすでに生成が完了していて、コードが正しいフィールドから画像を取り出せていないだけ、ということがあります。あるいはリクエスト自体が拒否されていて、レスポンスにその理由がはっきり書かれている場合もあります。どちらの場合も、すぐにリトライすると、前者では同じ画像に二重で支払うことになり、後者では失敗が決まっているリクエストに何度も支払うことになります。

gpt-image-2.6-all の従量課金 $0.025/回 で計算すると、盲目的なリトライが1回増えるごとに $0.025 余計にかかります。空のレスポンスをネットワークの一時的な揺らぎだと考えてループで連打し、3回リトライすれば $0.075 の追加です。しかも、そのお金で有効な画像が1枚も得られない可能性があります。つまり、画像が返ってこないときはリトライの前にレスポンスを確認するのが基本です。お金をかける前に、ほぼコストゼロでできるチェックを挟むということですね。

レスポンスを確認してからリトライするための判断ロジック

判断順序の設計方針は「外側から内側へ」です。HTTPステータスコードは最も外側のシグナルで、リクエストが正常に処理されたかどうかを教えてくれます。画像データは本当に欲しいものなので、その次に確認します。エラー情報はサーバーが自ら示した失敗理由なので、リトライよりも優先して扱う必要があります。ここまでの3層をすべて確認し、画像もなく、エラーの説明もないことがはっきりして初めて、リトライに意味が出てきます。

見落とされがちなポイントがあります。ステップ2で確認するのは「画像データまたは画像URL」だという点です。APIの形態によって画像が返される場所は異なります。data 配列の中の b64_json や url フィールドに入っている場合もあれば、対話メッセージの content テキストに画像リンクが書かれている場合もあります。パース処理がどちらか一方にしか対応していないと、画像が入っているレスポンスを空と誤判定してしまいます。これは誤ったリトライを引き起こす最も典型的な原因のひとつです。

image-generation-no-image-check-response-before-retry-ja-image-1


画像生成で画像が返ってこないときのレスポンスタイプ別の整理

「まずレスポンスを確認してから再試行する」ためには、そもそもレスポンスがどのような形で返ってくる可能性があるのかを把握しておく必要があります。以下の表に、よくあるレスポンスの種類と、それぞれの対処方法をまとめました。

レスポンスタイプ 典型的な特徴 画像は生成済みか 推奨される対処
リクエスト層の失敗 HTTPステータスコードが2xx以外 いいえ ステータスコードに応じて対処し、認証やパラメータの問題は修正してから再送する
正常に画像が返る(構造化) data に b64_json または url がある はい そのまま画像を取得する。再試行はしない
正常に画像が返る(テキスト埋め込み) メッセージの content に画像リンクが含まれている はい 正規表現でリンクを抽出する。再試行はしない
エラー情報を含む成功レスポンス HTTPは成功だが、レスポンスボディに error や拒否の説明がある いいえ エラーの原因を読み取り、プロンプトやパラメータを修正する
本当の空レスポンス HTTPは成功、画像もエラーもなし いいえ 生のレスポンスを記録したうえで、1回だけ再試行する
リクエストのタイムアウト クライアントがレスポンスを受け取れていない 確認できない 自動で再送せず、まずログと課金履歴を確認する

タイムアウトこそ「確認してから再試行」が必要な理由

タイムアウトは「ネットワークの一時的な揺らぎ」だと思われがちですが、実は最も慎重に扱うべきケースです。クライアント側のタイムアウトは「レスポンスを待ちきれなかった」ことを示すだけで、サーバー側で生成が完了していないことまでは意味しません。画像生成はもともと時間がかかる処理です。クライアントのタイムアウト設定が短すぎると、サーバー側では画像の生成と課金が済んでいるのに、プログラムのほうが先に待つのをやめてしまう、ということが十分に起こり得ます。

このような場合は、まずタイムアウト時間を適切に長めに設定します。そのうえで、タイムアウトが発生したらリクエスト時刻とパラメータを記録し、コンソールの呼び出しログでそのリクエストの実際の状態を確認しましょう。成功の記録がないことを確認してから手動で再送するほうが、プログラムに自動で連続リクエストさせるよりもずっと安全です。

エラー情報を含むレスポンスはエラーとして扱う

HTTPステータスは成功なのに、レスポンスボディにエラーオブジェクトが含まれていたり、モデルがテキストで生成できなかった理由を説明していたりすることがあります。たとえば、プロンプトがコンテンツ審査に引っかかったケースです。このようなレスポンスには画像こそありませんが、原因ははっきり書かれています。同じリクエストをそのまま再送しても、ほぼ確実に同じ結果になります。

正しい対処は、エラー情報を読み取り、パラメータの問題なのか、コンテンツの問題なのか、サーバー側の一時的な問題なのかを判断することです。パラメータやコンテンツの問題であれば、リクエストを修正してから再送します。エラー情報が一時的な障害をはっきり示している場合に限り、しばらく間隔を空けてからの再試行を検討してください。


画像生成で画像が返ってこないときは、再試行する前にレスポンスを確認:クイックスタート

ここでは Python を使って、この判断をコードに組み込む方法を紹介します。サンプルでは OpenAI 互換インターフェースを使い、モデルには gpt-image-2.6-all を例にしています。具体的なエンドポイントやレスポンス形式は、APIYI のドキュメントにあるこのモデルの説明を必ず確認してください。

最小限のサンプル:レスポンスを受け取ったら、まず画像の有無を確認する

いちばんシンプルな方法は、レスポンスを受け取ったあとで画像フィールドを確認することです。画像があればそこで終了し、なければ原因の調査に進みます。

from openai import OpenAI

client = OpenAI(
    api_key="YOUR_API_KEY",
    base_url="https://api.apiyi.com/v1",  # APIYI の OpenAI 互換インターフェース
)

resp = client.images.generate(
    model="gpt-image-2.6-all",
    prompt="一只坐在窗台上的橘猫,水彩风格",
)

item = resp.data[0] if resp.data else None
if item and (item.b64_json or item.url):
    print("已拿到图片,不要重试")
else:
    print("响应里没有图片,先打印原始响应再决定")
    print(resp.model_dump())

このコードはわずか十数行ですが、よくある失敗である「中身を見ずにもう一度リクエストを送ってしまう」ことを防げます。HTTP レベルの失敗は SDK が例外を送出します。そのため、外側で try を使って捕捉し、ステータスコードに応じて処理すれば、いきなりリトライループに入らずに済みます。

完全なサンプル:4ステップ判定+最大1回のリトライ

本番環境では、以下のより完全なバージョンをおすすめします。HTTPステータスの確認、2か所ある画像返却位置のパース、エラー情報の識別、タイムアウト時の自動再送の禁止、そして「画像がないと確認できた場合のみ最大1回リトライする」という制限をカバーしています。

import re
import requests

API_KEY = "YOUR_API_KEY"
BASE_URL = "https://api.apiyi.com/v1"  # APIYI の統一エンドポイント
MODEL = "gpt-image-2.6-all"
IMG_URL_RE = re.compile(r"https?://\S+?\.(?:png|jpe?g|webp)", re.I)


def find_images(body):
    """構造化された data フィールドと、対話の content 内にある画像リンクの両方をチェックする"""
    images = []
    for item in body.get("data") or []:
        if item.get("url"):
            images.append(item["url"])
        elif item.get("b64_json"):
            images.append("base64-image")
    for choice in body.get("choices") or []:
        content = (choice.get("message") or {}).get("content") or ""
        images += IMG_URL_RE.findall(content)
    return images


def generate_with_check(prompt, max_retry=1):
    for attempt in range(max_retry + 1):
        try:
            resp = requests.post(
                f"{BASE_URL}/images/generations",
                headers={"Authorization": f"Bearer {API_KEY}"},
                json={"model": MODEL, "prompt": prompt},
                timeout=300,
            )
        except requests.Timeout:
            # タイムアウト時はサーバー側で生成・課金済みかどうか確認できないため、自動で再送しない
            return {"status": "timeout", "action": "check_logs_first"}

        # ステップ1:HTTPが成功したか
        if resp.status_code != 200:
            return {"status": "http_error", "code": resp.status_code,
                    "detail": resp.text[:500]}

        try:
            body = resp.json()
        except ValueError:
            return {"status": "bad_json", "detail": resp.text[:500]}

        # ステップ2:レスポンスに画像データまたは画像URLがあるか
        images = find_images(body)
        if images:
            return {"status": "ok", "images": images}

        # ステップ3:エラー情報があればエラーとして処理し、リトライしない
        if body.get("error"):
            return {"status": "api_error", "error": body["error"]}

        # ステップ4:画像もエラーもないと確認できた場合のみ、元のレスポンスを記録したうえでリトライを許可する
        print(f"第 {attempt + 1} 次请求无图片,原始响应:{str(body)[:300]}")

    return {"status": "empty_after_retry", "action": "stop_and_report"}


result = generate_with_check("一只坐在窗台上的橘猫,水彩风格")
print(result)

このコードには、押さえておきたい設計上のポイントがいくつかあります。max_retry のデフォルトは 1 なので、1枚の画像で発生するリクエスト料金は最大2回分となり、コストの上限が見通せます。タイムアウト時はループを続けずにそのまま返しています。タイムアウトでは課金済みかどうか確認できないためです。また、空のレスポンスと判定するたびに元のレスポンスを出力するので、後から「パースの問題なのか、サーバー側が本当に画像を出力しなかったのか」を調べやすくなっています。

🚀 クイックスタート:まずテスト環境でこの判定ロジックを検証したい場合は、APIYI(apiyi.com)で無料のテスト枠を取得できます。同じAPIキーで gpt-image-2.6-all をはじめとする主要モデルを呼び出せるので、判定フローを動かして確認してから本番の業務に組み込みましょう。


画像生成で画像が返ってこないときの「盲目リトライ」コスト比較

判断ロジックをコードに書く前は、「とりあえず何回かリトライしておこう」のコストを実感しにくいものです。ここでは gpt-image-2.6-all の従量課金 $0.025/回 を例に、「やみくもに連打する」場合と「レスポンスを確認してからリトライする」場合とで、1枚あたりの追加支出を比べてみます。

処理方針 1枚あたりの最大リクエスト回数 最悪時の追加支出 リスクの説明
確認せず、失敗したら1回だけ再実行 2回 $0.025 すでに画像が生成されたリクエストに二重で課金される可能性がある
確認せず、ループで3回連打 4回 $0.075 必ず失敗するリクエストに何度も課金される
確認せず、画像が出るまでループ 不定 上限なし コンテンツ審査による拒否が続くと課金され続ける
レスポンスを確認し、画像なしと判断してから1回リトライ 2回 $0.025 本当に空のレスポンスだったときだけ追加コストが発生する

一見すると、「レスポンスを確認してからリトライ」と「失敗したら1回だけ再実行」は最悪時の追加支出が同じですが、発動する条件がまったく違います。前者は、画像もエラーメッセージもないことを確認できたときにだけ $0.025 を支払います。後者は、画像はすでに生成されているのにパースに失敗した場合や、コンテンツが拒否された場合にも同じ金額が発生し、しかも何の結果も得られません。

バッチで画像を生成するようになると、この差は何倍にも膨らみます。1枚ごとに余分に払う $0.025 に1日のリクエスト数を掛ければ、本来なら避けられた出費がかなりの額になります。

image-generation-no-image-check-response-before-retry-ja-image-2


画像生成でレスポンスに画像が返ってこないときの、インターフェースとモデルの参考情報

モデルやインターフェースの形態によって、画像が返ってくる位置はそれぞれ異なります。これは、ステップ 2 の判定が正確かどうかに直結します。下の表に、よくある返却形態とチェックのポイントをまとめました。ご自身の解析コードが画像を見落としていないか、確認する際にお役立てください。

返却形態 画像の位置 解析のポイント 利用可能なプラットフォーム
画像生成インターフェース(URL) data[].url リンクには有効期限がある場合があるため、取得したらできるだけ早くダウンロードして保存してください APIYI apiyi.com(モデルのドキュメントに準拠)
画像生成インターフェース(Base64) data[].b64_json デコードしてファイルに書き込みます。空文字列だと誤判定しないよう注意してください 同上
チャットインターフェースに埋め込まれた画像 choices[].message.content 正規表現で Markdown 形式の画像やリンクを抽出します 同上
ストリーミング返却 分割されたチャンクを連結した完全な内容 ストリームの終了を待ち、すべて連結してから画像の有無を判定する必要があります 同上

ストリーミング返却も、誤判定が起こりやすいポイントのひとつです。最初のチャンクを受け取った時点で画像を探しても、当然何も見つかりません。画像生成でレスポンスに画像が返ってこないときは、チェックしているのが途中の状態ではなく、完全なレスポンスであることを必ず確認してください。


よくある質問 FAQ

Q1:画像生成で画像が返ってこなかった場合、課金されていないと考えてよいですか?

必ずしもそうとは限りません。課金されるかどうかは、サーバー側がそのリクエストを処理したかどうかで決まります。コード側で画像を取得できたかどうかは関係ありません。解析するフィールド名の誤り、ストリーミングレスポンスを最後まで結合できていない、クライアント側が先にタイムアウトしたなどの理由で、「課金はされたのに画像は受け取れていない」状況が起こり得ます。そのため、「課金されていないはず」と決めつけてすぐに再送するのではなく、まずレスポンスを確認してから再試行するようにしましょう。

Q2:「レスポンスを確認してから再試行する」ことと、通常の指数バックオフによるリトライはどう違いますか?

指数バックオフが解決するのは「いつ再試行するか」という問題で、レート制限や一時的なサーバー障害に向いています。一方、レスポンスを確認してから再試行する方法が解決するのは「そもそも再試行すべきか」という問題です。1回ごとに課金される画像生成リクエストでは、まず4ステップの判断で再試行が本当に必要かを確認し、そのうえでバックオフ戦略を使って再試行のタイミングを決めます。この2つは代替関係ではなく、順番に使うものです。

Q3:gpt-image-2.6-all はいつリリースされましたか?料金はいくらですか?

gpt-image-2.6-all は 2026-11-12 に APIYI で提供が始まりました。料金は1回あたり $0.025 の従量課金です。リクエストごとに独立して課金されるため、空のレスポンスをそのまま再送すると、もう一度料金がかかります。これが、本記事で「レスポンスを確認してから再試行する」ことを強調している直接の理由です。

Q4:画像が返ってこなくても、絶対に再試行してはいけないのはどんな場合ですか?

主に次の3つのケースです。

– **レスポンスにエラー情報が含まれている場合**:プロンプトがコンテンツ審査に引っかかった、パラメータが不正だったなどのケースです。そのまま再送しても同じ結果になります。
– **リクエストがタイムアウトした場合**:サーバー側で画像が生成され課金されたかどうかを確認できないため、まずログを照合してください。
– **認証やクォータに関するHTTPエラーの場合**:再試行しても結果は変わりません。先にキーやクォータの問題を解消する必要があります。

Q5:自分の判断ロジックが正しいかどうかを、手早く検証するにはどうすればよいですか?

テスト環境で一通りの流れを動かしてみることをおすすめします。

1. APIYI apiyi.com でアカウントを登録し、APIキーと無料のテスト枠を取得します
2. 本記事の完全なサンプルにある `BASE_URL` を `https://api.apiyi.com/v1` に設定し、gpt-image-2.6-all を呼び出します
3. 通常のプロンプトと、拒否される可能性のあるプロンプトの両方でテストし、各分岐の戻り値を確認します

どのレスポンスも正しい分岐に振り分けられることを確認してから、本番の業務に組み込みましょう。

Q6:1回再試行しても画像が返ってこない場合は、どうすればよいですか?

自動リトライはそこで止め、2回分の元のレスポンス、リクエストパラメータ、時刻を記録しておきましょう。まず、解析コードが画像フィールドを取りこぼしていないかを確認し、そのうえでコンソールで2回分の呼び出し記録を照合します。サーバー側が連続して空の結果を返していると確認できた場合は、リクエスト時刻と元のレスポンスを添えて、APIYI apiyi.com のテクニカルサポートに問い合わせてください。課金を重ねて再送し続けるより、はるかに効果的です。

Q7:バッチで画像を生成するとき、リトライのコストはどう抑えればよいですか?

画像生成タスクごとに独立したリトライカウンターを持たせ、1タスクあたりのリトライ上限を1回に固定します。あわせて、タスク単位で「空レスポンス率」を集計することをおすすめします。あるバッチで空レスポンスが目立って多い場合は、リトライ回数を全体的に増やすのではなく、まずプロンプトと解析ロジックを調べてください。


画像生成で画像が返ってこないときは、リトライ前にレスポンスを確認しよう:重要ポイント Key Takeaways

  • 画像がない=課金されていない、とは限らない:リクエスト単位で課金される画像生成では、サーバー側で処理が行われた時点で、すでに課金されている可能性があります。
  • 判断の順序は固定:HTTPステータス → 画像データまたはURL → エラー情報 → 画像がないと確認できてからリトライ、の順で確認します。
  • リトライは1回だけ:画像もエラーもないと確認できた場合に限り、リトライは1回までにします。これでコストの上限を見積もれます。
  • タイムアウト時に自動で再送しない:タイムアウトでは生成状況を確認できないため、まずログを照合してから再送するかどうかを判断します。
  • 解析は複数の場所をカバーする:data フィールドと会話の content の両方をチェックし、空のレスポンスだと誤判定するのを防ぎます。
  • 盲目的なリトライには明確なコストがかかる:gpt-image-2.6-all の場合、盲目的にリトライするたびに $0.025 が余計にかかります。
  • まずテストクォータで検証する:APIYI(apiyi.com)の無料テストクォータで判断フローを一通り動かしてから、本番に導入できます。

まとめ

画像生成で画像が返ってこないときに、リトライ前にレスポンスを確認するポイントは次のとおりです。

  1. お金をかける前に原因を調べる:レスポンスの確認はほぼ無料ですが、盲目的なリトライは毎回課金されます。
  2. 4ステップの順序で判断する:HTTPが成功したか、画像があるか、エラーがあるかを確認し、画像がないと確定してから初めて1回だけリトライします。
  3. ルールをコードに組み込む:リトライ回数の制限、タイムアウト時の自動再送の禁止、生レスポンスの記録によって、コストを抑え、問題を追跡しやすくします。

リクエスト単位で課金される画像モデルを使う開発者にとって、この判断方法は難しいものではありません。それでも、同じ画像に対して二重に課金される事態を確実に防げます。まずテスト環境ですべての分岐を一通り試し、そのうえで画像生成呼び出しの標準ラッパーとして採用することをおすすめします。

この処理ロジックは、APIYI(apiyi.com)で手早く検証できます。プラットフォームはOpenAI互換インターフェースと無料テストクォータを提供しており、1つのキーで gpt-image-2.6-all をはじめとする主要モデルを呼び出せます。


📚 参考資料

  1. APIYI ドキュメントセンター:モデル呼び出し方法とレスポンス形式の説明
  2. リンク: docs.apiyi.com
  3. 説明: gpt-image-2.6-all の具体的な呼び出しエンドポイントとレスポンスフィールドを確認できます。内容はドキュメントを正としてください

  4. OpenAI Images API リファレンス:画像生成インターフェースの標準的なレスポンス構造

  5. リンク: platform.openai.com/docs/api-reference/images
  6. 説明: data 配列に含まれる url と b64_json フィールドの意味を確認できます

著者: APIYI 技術チーム
技術交流: APIYI のトップページからお気軽にお問い合わせください。接続に関するその他の資料は docs.apiyi.com のドキュメントセンターでご覧いただけます

関連記事

類似投稿