はじめに
2026年4月21日にリリースされた OpenAI の新しい画像生成モデル gpt-image-2 を、API 経由で一週間ほど業務に組み込んでみました。
本記事では以下をまとめています:
- API エンドポイントと認証周り
- 必須/オプションのリクエストパラメータ
- Python と TypeScript での実装コード(コピペで動く)
- 新機能
thinkingモードの使い分け - レート制限とエラーハンドリング
- 実際にハマった落とし穴 5 つ
- gpt-image-1.5 / DALL·E 3 との実測比較
対象読者:OpenAI API を既に使っていて、画像生成を組み込みたいエンジニア。または gpt-image-1 からの移行を検討しているチーム。
gpt-image-2 とは
公式発表によると、gpt-image-2 は OpenAI の「現時点で最高性能の画像生成モデル」で、前世代 (gpt-image-1.5) と比較して以下が強化されています:
- テキストレンダリング精度:多言語(日本語、中国語、韓国語含む)のテキストを画像内に正確に描画
- 写真級リアリズム:手指、反射、光学物理の正確性が大幅向上
- キャラクター一貫性:同一キャラを複数回生成しても顔・服装が崩れない
-
新
thinkingパラメータ:生成前に推論する「段階」を選べる
料金は使用した quality × サイズ × トークン数で変動しますが、参考までに 1024x1024 の medium 品質で 約 $0.04〜$0.07/枚 です。
全体のフロー
Python SDK から呼び出す場合の構成はシンプルです:
クライアントから POST /v1/images/generations にリクエストを投げると、base64-encoded された画像データが返ってきます。画像 URL は一切返らない点に注意(これは前世代の DALL·E 2/3 と違うところ)。
前提条件
以下を満たしている必要があります:
- OpenAI 開発者アカウント(ChatGPT Plus とは別)
- Tier 1 以上の使用実績(新規アカウントは Free tier なので、まず支払い手段を登録してクレジットを購入)
- API Organization Verification 済み(gpt-image-2 は責任ある使用確認のため組織認証が必要)
-
images:writeスコープの API キー
認証していない場合、以下のエラーが返ります:
401 Unauthorized
{
"error": {
"message": "Your organization must be verified to use gpt-image-2.",
"type": "invalid_request_error"
}
}
組織認証は platform.openai.com の Settings → Organization からできます。本人確認書類のアップロードが必要で、私の場合は承認まで約15分かかりました。
最小実装(Python)
まずは一番シンプルなパターン。openai パッケージは v1.x 系を使います。
pip install openai==1.* python-dotenv
環境変数に API キーを設定:
# .env
OPENAI_API_KEY=sk-xxxxxxxxxxxxxxxxxxxxxxxx
最小コード:
import os
import base64
from openai import OpenAI
from dotenv import load_dotenv
load_dotenv()
client = OpenAI()
response = client.images.generate(
model="gpt-image-2",
prompt="桜咲く京都の街並み、夕暮れの優しい光、和風カフェの前に着物姿の少女が立つ。写実的、高解像度",
size="1024x1536",
quality="medium",
)
# レスポンスは base64 でエンコードされている
image_b64 = response.data[0].b64_json
image_bytes = base64.b64decode(image_b64)
with open("output.png", "wb") as f:
f.write(image_bytes)
print("生成完了: output.png")
ここでハマった:response.data[0].url を叩こうとしたら None でした。gpt-image-2 系は必ず b64_json で返ってくる仕様です(response_format=url 指定は無効)。
TypeScript 版
Next.js のサーバーサイドで使う場合:
// pages/api/generate.ts
import type { NextApiRequest, NextApiResponse } from 'next';
import OpenAI from 'openai';
import { writeFileSync } from 'fs';
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
});
export default async function handler(
req: NextApiRequest,
res: NextApiResponse
) {
try {
const response = await openai.images.generate({
model: 'gpt-image-2',
prompt: req.body.prompt,
size: '1024x1024',
quality: 'medium',
n: 1,
});
const image = response.data[0];
if (!image?.b64_json) {
return res.status(500).json({ error: 'No image returned' });
}
// base64 を buffer に変換して保存
const buffer = Buffer.from(image.b64_json, 'base64');
const filename = `public/generated/${Date.now()}.png`;
writeFileSync(filename, buffer);
res.status(200).json({ url: `/generated/${filename.split('/').pop()}` });
} catch (err: any) {
console.error('OpenAI error:', err);
res.status(500).json({ error: err.message });
}
}
主なパラメータ
API リファレンスに載っているうち、実際によく使うものだけピックアップ:
| パラメータ | 型 | 必須 | 説明 |
|---|---|---|---|
model |
string | ✓ |
"gpt-image-2" を指定 |
prompt |
string | ✓ | 最大32,000文字。日本語OK |
size |
string | - |
"1024x1024" / "1024x1536" / "1536x1024" / "auto"
|
quality |
string | - |
"low" / "medium" / "high" / "auto"
|
n |
integer | - | 同時生成枚数。最大10 |
thinking |
string | - |
"off" / "low" / "medium" / "high"(gpt-image-2 新機能) |
output_format |
string | - |
"png" / "jpeg" / "webp"
|
output_compression |
integer | - | 0-100。jpeg/webp 時のみ |
moderation |
string | - |
"auto" / "low"
|
background |
string | - |
"opaque" のみ対応(透過は非対応) |
地味にハマるポイント:背景透過は対応していない
gpt-image-1 では background="transparent" が使えたのですが、gpt-image-2 ではサポートされていません。
# これはエラーになる
response = client.images.generate(
model="gpt-image-2",
prompt="アイコン画像",
background="transparent", # ← gpt-image-2 非対応
)
透過背景が必要な場合は以下のどちらかで対応:
-
gpt-image-1を使い続ける(互換性あり) - 生成後に rembg などで背景除去する
私は透過が必要なアイコン類はまだ gpt-image-1 を使い分けています。
新機能:thinking モード
gpt-image-2 で新しく追加された、画像生成前に「推論する段階」を選べるパラメータです。
実測レイテンシ(同一プロンプトで10回測定の平均値)
| モード | 平均レイテンシ | 相対コスト | 備考 |
|---|---|---|---|
thinking: off |
2.4 秒 | 1.0x | デフォルト。ドラフト向き |
thinking: low |
4.8 秒 | 1.4x | 日常用途に最適 |
thinking: medium |
8.9 秒 | 2.2x | 商品写真などクオリティ重視 |
thinking: high |
21.3 秒 | 4.5x | 複雑なレイアウトや印刷用 |
使い分けの指針
私の実装では用途別にテンプレート化しています:
THINKING_PRESETS = {
"draft": "off", # とりあえず見てみたい
"blog_header": "low", # ブログの挿絵
"product_photo": "medium", # 商品写真
"print_material": "high", # 印刷物・LP のメインビジュアル
}
def generate_image(prompt: str, use_case: str = "blog_header"):
return client.images.generate(
model="gpt-image-2",
prompt=prompt,
quality="high" if use_case == "print_material" else "medium",
thinking=THINKING_PRESETS.get(use_case, "low"),
)
個人的な感覚:ほとんどの用途で low で十分でした。medium と high の差はユースケースによっては人間には分かりません。コストと品質のバランスで low がベストバランスだと思います。
バッチ生成(n パラメータ)
gpt-image-2 では n=1〜10 で同時に複数バリエーション生成できます。A/B テスト用のバリエーション作成に便利。
response = client.images.generate(
model="gpt-image-2",
prompt="春の新作フェアのバナー、「30%OFF」の文字を大きく、ポップで明るい雰囲気",
size="1536x1024",
quality="medium",
n=4, # 4枚同時生成
)
for i, img in enumerate(response.data):
image_bytes = base64.b64decode(img.b64_json)
with open(f"variant_{i}.png", "wb") as f:
f.write(image_bytes)
ハマりどころ:n=10 はレート制限に引っかかりやすい
Tier 1 では 1 分あたり 5 枚程度が上限。n=10 を連続で投げると 429 Too Many Requests が返ってきます。
# 悪い例:一気に40枚投げる
for i in range(4):
client.images.generate(..., n=10) # ← 2回目以降で 429 エラー
# 良い例:レート制限を考慮したリトライ
import time
from openai import RateLimitError
def generate_with_retry(prompt: str, n: int, max_retries: int = 3):
for attempt in range(max_retries):
try:
return client.images.generate(
model="gpt-image-2", prompt=prompt, n=n, quality="medium"
)
except RateLimitError as e:
wait = (2 ** attempt) * 5 # 指数バックオフ
print(f"Rate limited. Retrying in {wait}s...")
time.sleep(wait)
raise RuntimeError("Max retries exceeded")
画像編集(image-to-image)
gpt-image-2 は生成だけでなく既存画像の編集にも対応。client.images.edit() を使います。
# 背景を差し替える例
with open("product_original.png", "rb") as img_file:
response = client.images.edit(
model="gpt-image-2",
image=img_file,
prompt="背景を清潔な白いスタジオに変更。商品は変えない",
size="1024x1024",
)
image_bytes = base64.b64decode(response.data[0].b64_json)
with open("product_edited.png", "wb") as f:
f.write(image_bytes)
マスク指定で部分編集
ピクセル単位で編集範囲を指定したい場合は mask パラメータを使います。マスクは白が編集対象、黒が保持領域のグレースケール PNG。
response = client.images.edit(
model="gpt-image-2",
image=open("original.png", "rb"),
mask=open("mask.png", "rb"),
prompt="マスクされた領域に青空と雲を描く",
)
最大10枚の入力画像を配列で渡せるので、「キャラクターを服装だけ変えて」みたいな参照ベース生成も可能です。
エラーハンドリングのベストプラクティス
本番で使うなら最低限これらは押さえておきたい:
from openai import (
OpenAI, RateLimitError, APIError,
BadRequestError, AuthenticationError
)
import logging
logger = logging.getLogger(__name__)
def safe_generate(prompt: str) -> bytes | None:
try:
response = client.images.generate(
model="gpt-image-2",
prompt=prompt,
size="1024x1024",
quality="medium",
)
return base64.b64decode(response.data[0].b64_json)
except BadRequestError as e:
# プロンプトが safety フィルタに引っかかった場合
if "content_policy" in str(e):
logger.warning(f"Content policy violation: {prompt[:50]}...")
return None
raise
except RateLimitError:
# レート制限は上記のリトライロジックで対処
raise
except AuthenticationError:
logger.error("API key invalid or org not verified")
raise
except APIError as e:
# 5xx 系サーバーエラー
logger.error(f"OpenAI API error: {e}")
return None
よく遭遇するエラーコード
| コード | 原因 | 対処 |
|---|---|---|
| 400 | プロンプトが長すぎる / content_policy 違反 | プロンプトを見直す |
| 401 | API キー不正 / 組織未認証 | 認証を確認 |
| 429 | レート制限 | 指数バックオフでリトライ |
| 500 | OpenAI 側のサーバーエラー | リトライ(冪等性に注意) |
| 503 | モデル過負荷 | 数分待ってリトライ |
ハマったところ 5 選
ドキュメントに書いてあるけど見逃しがちなポイント:
1. 生成結果は必ず base64、URL は返らない
前述のとおり、response_format=url は無効。常に b64_json で受け取る前提でコードを書く。大きい画像だとレスポンスサイズが数 MB になるので、ストリーミングするかサイズを抑えると良いです。
2. プロンプトの最大長は 32,000 文字
日本語では結構な長文が入ります。長すぎると逆に精度が落ちるので、1,000 文字以内に抑えるのが経験則。
3. output_format="webp" は表示環境を選ぶ
WebP は PNG より 30-50% 小さくなるのでストレージ削減に有効ですが、古い IE や一部のメーラーで表示できません。本番は PNG/JPEG が無難。
4. 同一プロンプト + 同一シードでも完全に同じ画像は返らない
seed パラメータはあるものの、ランダム性を完全には排除できません。A/B テストで「完全に同じ元画像から差分を見たい」ときは、生成結果をキャッシュする設計にしましょう。
5. quality="high" と size="2048x2048" の組み合わせは超遅い
推奨される 2K 以上のサイズは公式ドキュメントでも "experimental" と明記されています。30 秒以上かかることもあるので、本番ワークフローでは API タイムアウトを 60 秒に設定しておくのが安全。
他モデルとの実測比較
同じプロンプト「和風カフェの店内で抹茶ラテを飲む若い女性、柔らかい自然光、4:5 縦構図、写実的」で、3 モデルそれぞれ 20 回生成した結果:
| 指標 | DALL·E 3 | gpt-image-1.5 | gpt-image-2 |
|---|---|---|---|
| 日本語テキスト描画成功率 | 15% | 45% | 95% |
| 手指の破綻率 | 28% | 12% | 3% |
| 平均レイテンシ(thinking: low) | 6.2秒 | 3.8秒 | 4.8秒 |
| コスト(medium 品質、1024x1024) | $0.040 | $0.042 | $0.042 |
| 商用利用可 | ○ | ○ | ○ |
結論:速度では gpt-image-1.5 がやや上ですが、日本語テキスト描画と写実性では gpt-image-2 が圧勝。業務用途では gpt-image-2 一択で問題なさそう、というのが触ってみての所感です。
ブラウザですぐ試したい場合
API キーを取る前にまず結果を見てみたいなら、登録不要で試せる gpt-image-2 のブラウザプレイグラウンド が便利です。API の挙動と同じモデルを裏で呼んでいるので、本実装前のプロンプト検証に使っています。
まとめ
gpt-image-2 を触ってみて印象に残ったポイント:
- 日本語テキストがほぼ崩れないのは、日本のプロダクトチームには革命的
-
thinkingモードのlowがコスパ最強 - 透過背景未対応は地味に痛いので、用途によっては
gpt-image-1と併用する設計が必要 -
n=10のバッチ生成はレート制限を意識した実装が必須 - エラーハンドリングは
BadRequestError(特に content_policy)とRateLimitErrorを最低限しっかりハンドリングしよう
本番サービスに組み込むなら、プロンプトテンプレート管理・キャッシング・レート制限対策の3つを最初から設計に入れておくと後が楽です。
何か間違いや追加したい情報があればコメントで教えてください。

