你用同一句描述做出第一張海報,效果很好;隔天只想換成橫幅,罐子比例、品牌色與中文字卻一起漂走。問題通常不是你少背了一句「神奇咒語」,而是那份需求沒有可檢查的欄位。GPT-Image 2 Prompt as Code 的目的,就是把散文提示詞改造成可以驗證、比較與留下紀錄的視覺契約。
這個方法正在受到注意。2026 年 8 月 26 日,同一個 awesome-gpt-image-2 固定版本約整理了 530 個案例;GitHub Trending 當時顯示的快取星數,還和稍後的 REST 快照不同。這只能證明開發者關注,不能證明 JSON 會讓圖片更好。
這篇專為第一次把生圖流程放進專案的人寫。我會用一個完全虛構、文字與規格均為自有範例的飲料品牌,帶你建立最小 JSON Schema、產生四個只改一項的變體、接上官方 Image API,再用五道 gate 驗收。你不必先懂後端;照著檔名與指令做,就能留下下一輪接得上的版本。
先說結論:可重跑不是同一張圖,而是同一場實驗
🧩 Prompt as Code = 結構化 Brief + 固定參數 + 版本紀錄 + 可重複驗收
- 結構化 Brief:主體、鏡頭、光線、材質、版面與文案各有自己的欄位。
- 固定參數:端點、模型 snapshot、尺寸、品質、格式與背景都明寫。
- 版本紀錄:輸入、prompt hash、輸出 hash、素材權利與挑選理由一起保存。
- 可重複驗收:每次都用同一份主體、文字、階層、色彩與跨尺寸 rubric 檢查。
換句話說,這套流程讓你知道「改了什麼、得到什麼、為何選它」,不保證重跑會得到相同像素。
GPT-Image 2 Prompt as Code 是什麼?先拆掉兩個誤會
第一,它不是 OpenAI 新增的一種 API 模式。官方 GPT Image 2 模型頁把 Structured Outputs 標為不支援;Image API 的 prompt 仍是字串。我們是在自己的專案先用 JSON Schema 驗證物件,再把通過的 JSON 序列化成 prompt 字串。
第二,JSON 不是畫質加速器。OpenAI 的 官方生圖提示指南說,極短文字、段落、JSON-like 或指令式格式都能工作;生產流程更應優先選容易維護與掃讀的模板。JSON 的優勢是表單化、可 diff,不是模型偏愛大括號。

Step 0:先建一個不會把素材與成品混在一起的資料夾
visual-prompt/
├── schema/visual-prompt.schema.json
├── briefs/base.json
├── variants/
│ ├── v0-baseline.json
│ ├── v1-camera.json
│ ├── v2-lighting.json
│ └── v3-layout.json
├── materialized/
├── outputs/
├── runs/
├── evals/
└── rights/assets.json
briefs 是不變的品牌事實,variants 只放這一輪想測的差異,materialized 是兩者合併後真正送出的完整設定。rights 則記錄素材擁有人、來源網址、授權或許可、取用日與檔案 hash。這次範例沒有搬用案例庫的圖、文案或 logo,避免把「看得到」誤當成「可商用」。
Step 1:用六個創意欄位,建立最小 JSON Schema
如果所有要求都擠在一段話裡,少寫品牌色或 CTA 時,程式不會提醒你。解法是把創意拆成六格:subject、camera、lighting、materials、layout、copy;再加上 palette、constraints 與 output 三個操作層。JSON Schema 就像出貨前的勾選表,先擋掉缺欄位與拼錯 key 的請求。
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"type": "object",
"additionalProperties": false,
"required": [
"subject", "camera", "lighting", "materials",
"layout", "copy", "palette", "constraints", "output"
],
"properties": {
"subject": { "type": "object" },
"camera": { "type": "object" },
"lighting": { "type": "object" },
"materials": {
"type": "array",
"minItems": 1,
"items": { "type": "string" }
},
"layout": { "type": "object" },
"copy": {
"type": "object",
"required": ["locale", "headline", "subheadline", "cta"],
"properties": {
"locale": { "const": "zh-Hant" },
"headline": { "type": "string", "minLength": 1 },
"subheadline": { "type": "string", "minLength": 1 },
"cta": { "type": "string", "minLength": 1 }
}
},
"palette": { "type": "array", "minItems": 2 },
"constraints": { "type": "array", "minItems": 1 },
"output": {
"type": "object",
"required": ["size", "quality", "format", "background"]
}
}
}
把它存成 schema/visual-prompt.schema.json。這是能上手的最小版;正式專案可再對 HEX 格式、允許尺寸、每個巢狀欄位與 additionalProperties 加限制。JSON Schema Draft 2020-12的角色是描述 JSON 結構,並不會描述「一張好看的圖」。
Step 2:把自有品牌 Brief 寫成可以被驗證的基準版
範例品牌叫「潮汐茶房」,產品是虛構的「白桃烏龍氣泡茶」。痛點不是缺形容詞,而是「產品長怎樣、文字是什麼、哪些不能動」沒有分開。以下基準版把三段繁中列成 literal copy,也把四個主體特徵鎖住:
{
"subject": {
"primary": "一罐虛構品牌「潮汐茶房」的 330 mL 白桃烏龍氣泡茶",
"locked_traits": [
"霧面米白鋁罐",
"正面有深墨綠圓形浪紋",
"罐身比例纖長",
"罐頂與底圈為原色鋁"
]
},
"camera": {
"shot": "單一產品的三分之二身景",
"angle": "與罐身等高的三分之四角度",
"lens": "70mm 商品攝影視角,輕微景深"
},
"lighting": {
"key": "左上大型柔光",
"fill": "正面低強度中性補光",
"accent": "右後方淡桃色輪廓光"
},
"materials": ["霧面鋁罐", "少量凝結水珠", "淺色白橡木桌面", "切半白桃"],
"layout": {
"reading_order": ["產品", "標題", "副標", "行動文字"],
"subject_zone": "產品位於左側 42% 區域",
"copy_zone": "文字位於右側 50% 區域並左對齊",
"safe_area": "四邊保留 8%,文字與產品不重疊"
},
"copy": {
"locale": "zh-Hant",
"headline": "白桃烏龍氣泡茶",
"subheadline": "一口,回到夏天",
"cta": "立即預購"
},
"palette": [
{ "name": "墨綠", "hex": "#173F35" },
{ "name": "米白", "hex": "#F3EBDD" },
{ "name": "白桃", "hex": "#F29A8A" }
],
"constraints": [
"只顯示 copy 欄位內的三段繁體中文",
"不得新增其他商標、徽章或價格",
"保留鋁罐比例與四項 locked_traits"
],
"output": {
"size": "1536x1024",
"quality": "high",
"format": "png",
"background": "opaque"
}
}
HEX 在這裡是目標色,不是像素保證;鏡頭規格也是構圖線索,不是物理相機模擬。這兩句先寫清楚,後面才不會把「接近」包裝成「精準還原」。
Step 3:做四個受控變體,每次只動一個創意欄位
一次改鏡頭、光線、文案與版面,看到差異也不知道由誰造成。解法是以 baseline 為 V0,另外三個 patch 分別只替換 camera、lighting、layout。識別碼與說明可以變,但創意欄位只改一組:
// v0-baseline.json
{}
// v1-camera.json
{
"camera": {
"shot": "單一產品近景",
"angle": "略低於罐身中線的正面角度",
"lens": "50mm 商品攝影視角,背景清楚可辨"
}
}
// v2-lighting.json
{
"lighting": {
"key": "正上方狹長柔光,形成俐落高光",
"fill": "左前方低強度冷色補光",
"accent": "右後方淡桃色輪廓光"
}
}
// v3-layout.json
{
"layout": {
"reading_order": ["標題", "產品", "副標", "行動文字"],
"subject_zone": "產品位於中央下方 44% 區域",
"copy_zone": "文字位於上方 38% 區域並置中",
"safe_area": "四邊保留 8%,文字與產品不重疊"
}
}
合併時用 { ...base, ...patch },讓 patch 替換整個頂層物件,再把四份完整 JSON 寫進 materialized:
import { readFile, mkdir, writeFile } from "node:fs/promises";
const base = JSON.parse(await readFile("briefs/base.json", "utf8"));
const files = [
"v0-baseline.json",
"v1-camera.json",
"v2-lighting.json",
"v3-layout.json"
];
await mkdir("materialized", { recursive: true });
for (const file of files) {
const patch = JSON.parse(
await readFile("variants/" + file, "utf8")
);
const merged = { ...base, ...patch };
await writeFile(
"materialized/" + file,
JSON.stringify(merged, null, 2) + "\n"
);
}
接著依 Ajv CLI 官方用法驗證四份完整設定:
node scripts/build-variants.mjs
for file in materialized/*.json; do
npx --yes ajv-cli@5.0.0 validate --spec=draft2020 -s schema/visual-prompt.schema.json -d "$file"
done
AlphaLab 在 2026 年 8 月 26 日實際跑過這個驗證流程,四份 materialized JSON 都回傳 valid,建置腳本與生圖腳本也通過 Node 語法檢查。這證明契約與合併流程可執行;因本次沒有呼叫付費生圖 API,本文不捏造四張輸出或優勝分數。
Step 4:把通過驗證的 JSON 送進 GPT Image 2
最短路徑是直接用 Image API。不要把 gpt-image-2 當成 Responses API 的主模型;若走 Responses,架構會是另一個主線模型加 image_generation 工具,而且工具可能改寫 prompt。這個受控比較只用同一個 /v1/images/generations 端點。
npm install openai@7.5.0
export OPENAI_API_KEY="你的 API key"
node scripts/generate.mjs materialized/v0-baseline.json
import OpenAI from "openai";
import { readFile, writeFile } from "node:fs/promises";
const spec = JSON.parse(await readFile(process.argv[2], "utf8"));
const prompt = [
"用途:品牌社群主視覺。請依下列已驗證的視覺契約產圖。",
"所有 copy 必須逐字使用,不要自行改寫。",
JSON.stringify(spec, null, 2)
].join("\n\n").normalize("NFC");
const client = new OpenAI();
const result = await client.images.generate({
model: "gpt-image-2-2026-04-21",
prompt,
n: 1,
size: spec.output.size,
quality: spec.output.quality,
output_format: spec.output.format,
background: spec.output.background,
moderation: "auto"
});
await writeFile(
"output.png",
Buffer.from(result.data[0].b64_json, "base64")
);
這裡有一個容易踩的坑:寫在 JSON 裡的 quality 本身不會設定 API;是程式把它取出,再放進真正的 quality 參數。官方 Image Generation Guide目前列出的主要輸出控制包括 size、quality、format、compression 與 background;PNG 不需要 compression。
Step 5:每次生圖都存一份 run manifest
只把勝出的 PNG 拖到桌面,三天後就無法回答「它用哪版 prompt?」每次呼叫後,至少保存 endpoint、模型 snapshot、SDK 版本、prompt hash、明示參數、request ID、輸入素材 hash、原始輸出 hash、權利紀錄與挑選理由:
{
"endpoint": "/v1/images/generations",
"model": "gpt-image-2-2026-04-21",
"sdk": { "package": "openai", "version": "7.5.0" },
"input_file": "materialized/v0-baseline.json",
"prompt_unicode_normalization": "NFC",
"prompt_sha256": "實際計算值",
"parameters": {
"n": 1,
"size": "1536x1024",
"quality": "high",
"output_format": "png",
"background": "opaque",
"moderation": "auto"
},
"request_id": "實際回傳值",
"output_sha256": "實際計算值",
"rights_record": "rights/assets.json",
"selection_reason": null
}
最後才把 selection_reason 填成具體理由,例如「三段文字逐字正確、四項主體特徵都保留、CTA 沒有碰撞」。不要寫「比較有感覺」;那無法讓下一位編輯複查。
Step 6:用五道 gate 驗收,不用「我覺得好看」投票
每個變體若只產一張,只能叫四個示範案例,不能證明哪種設定更穩。若要宣稱「改善」,每個條件要重複生成、保留全部樣本、先寫選圖規則,再報告樣本數。初學者可先用以下 0/1/2 rubric,但不要杜撰還沒跑出的分數:
- 主體一致性:四項 locked traits 是否逐項保留?0 是身分改變,1 是有可修漂移,2 是全部可辨。
- 繁中可讀性:人工逐字轉錄 headline、subheadline、CTA;記錄漏字、錯字、繁簡誤換與順序,不只看 OCR。
- 版面階層:第一眼是否先看到指定主角?文字是否落在預定區域、有無遮擋與碰撞?
- 品牌色:HEX 只作目標;在事先指定的純色區域取樣,保存實測值,不從整張圖挑最接近的一顆像素。
- 跨尺寸穩定性:勝出方案再跑 1024×1024、1536×1024、1024×1536,檢查不變量是否保留。不同長寬比容許重排,不要求相同構圖。

Prompt as Code 的 7 個坑:版本化不等於自動正確
- 把 JSON 當魔法語法:它改善維護性,不保證提升畫質。
- 一輪改四件事:diff 很熱鬧,因果卻不可判讀;一次只改一個創意欄位。
- 只存最後一張:沒有 prompt、參數與 hash,就無法追溯淘汰原因。
- 把 HEX 當硬色票:光影、材質與壓縮都會改變像素;用預定取樣區驗收。
- 用四張圖下穩定結論:單次輸出只足以示範;比較級需要重複樣本與固定選圖規則。
- 把 snapshot 當像素鎖:固定
gpt-image-2-2026-04-21有助於控制模型版本,仍不是相同像素保證。截至 2026 年 8 月 26 日,官方 generation request schema 未列seed;本文也不自行添加。 - 整包複製案例庫:該 repo 的 MIT 授權不會自動替個別匯入案例清權;要回到每項素材的原作者與授權。
官方也明列現行限制:文字位置或清晰度、跨次生成的品牌元素一致性,以及精密版面仍可能失敗。因此 rubric 不是額外文書,而是生圖流程的一部分。
什麼時候用一般 prompt,什麼時候升級 Prompt as Code?
- 一次性靈感草圖:一般 prompt 已足夠,先追求方向,不必建立整套目錄。
- 兩張以上同系列素材:開始拆 subject、copy 與 palette,避免每張重寫品牌事實。
- 多人交接、定期活動、跨尺寸投放:使用完整 Schema、manifest、rights ledger 與 eval rubric。
- 需要精準文字或 logo:生圖只做背景或產品素材,文字與官方 logo 交給可控的排版工具;不要要求模型仿造品牌標誌。
若你想先理解「規則如何約束 Agent」,可從 AI Agent Harness補概念;要把視覺流程做成可交接的圖表,則可接著讀 Diagram Design SVG/PNG 交付教學。
GPT-Image 2 Prompt as Code 常見問題(FAQ)
Q1:Prompt as Code 是 OpenAI 官方功能嗎?
不是。這是應用層的工作方法;OpenAI API 收到的仍是 prompt 字串。
Q2:改成 JSON,圖片一定比較好嗎?
不一定。JSON 的直接收益是欄位完整、容易 diff 與自動驗證;輸出品質仍要看內容與評測。
Q3:同一份 JSON 會得到同一張圖嗎?
不會承諾。版本化讓實驗條件可追溯,不代表像素級 deterministic。
Q4:完全不會寫程式也能用嗎?
可以先用。先以 JSON 當表單填六個欄位;要自動驗證、合併與存 hash,再照本文三段指令執行。
Q5:GPT Image 2 能保證繁體中文零錯字嗎?
不能保證。把 literal copy 列清楚有助於溝通,但每張仍要人工逐字驗收;正式稿可在排版工具重上文字。
Q6:一定要用 Responses API 嗎?
不用。本文要控制同一端點與 prompt,所以直接用 Image API;多輪對話式修改才考慮 Responses 的 image generation tool。
Q7:GitHub 案例庫的圖片與 prompt 可以直接商用嗎?
不能一概而論。專案根目錄授權與個別匯入素材的權利是兩件事;逐項確認來源與許可,最簡單的教學路線是用自有或已授權內容。
Q8:最高分圖片就能直接當品牌最終稿嗎?
不建議。rubric 是篩選工具,不是法律、品牌與印刷終審;商標、權利、文字、色彩與實際尺寸仍要由人確認。
給新手的 6 個重點
- 先把品牌不變量寫成欄位,再開始堆形容詞。
- Schema 驗證輸入結構,rubric 驗證圖片輸出,兩者不能互相代替。
- 四個變體要各自從同一 baseline 出發,不要累積修改。
- 模型 snapshot、端點與所有參數要跟 prompt 一起版本化。
- 保存全部樣本與挑選理由,別只留下最好看的一張。
- 使用自有或已授權素材,正式稿再做文字、品牌與權利終審。
接著閱讀
左右滑動查看更多推薦
結語:先版本化一次差異,不要先追求完美模板
第一次實作只做一件事:把你現有的一段視覺 prompt 拆成六個創意欄位,建立 V0,再只改 camera 做 V1。驗證、生成、填完五道 gate,最後把選擇理由寫進 manifest。你已經完成一個最小但可交接的回圈。
回到本文的錨點:Prompt as Code = 結構化 Brief + 固定參數 + 版本紀錄 + 可重複驗收。真正被版本化的不是「漂亮」,而是你對漂亮做了哪些可檢查的決定。想繼續追蹤 AI 創作方法,可到 AlphaLab AI 專區;要把這種規格化思考延伸到完整工程工作流,也可查看 AlphaLab 線上課程。






