本日核心價值 (Core Focus): 把 ChatGPT 從「對話產生程式碼」改成可驗證、可持久化的開發 Workflow:固定輸入、工具執行、測試驗證、寫回 repo。後續 29 天都建立在這條管線上。
概念說明與實戰情境 (Overview)
純聊天能快速吐出程式碼,但輸出無法驗證、無法進入 CI、也無法穩定重跑。開發者真正需要的是可重複 Workflow:固定輸入、呼叫工具、驗證結果、把產物寫回 repo。ChatGPT 負責計畫與結構化輸出,Codex 在 Sandbox 執行測試,通過後才允許 commit。本文先對齊這條四階段管線,作為後續 29 天的共同骨架。
關鍵操作與範例 (Implementation & Example)
聊天視窗與 Workflow 的差異,不在模型能力,而在「輸出有沒有契約、有沒有工具、有沒有驗證閘門」。把同一件後端任務(例如為訂單服務加上折扣計算)丟進兩種模式,結果會完全不同:前者給你一段看起來合理的 C#;後者強制先產出計畫 JSON,再讓 Codex 在 Sandbox 跑測試,最後才允許 commit。
| 面向 | Chat(純聊天) | Workflow(本系列) |
|---|---|---|
| 輸入 | 口語需求、片段貼上 | Prompt 模組 + repo Context(檔案樹、介面、失敗測試) |
| 輸出 | 自由文字、可選程式碼 | 先 JSON 計畫,再最小 diff |
| 驗證 | 人工肉眼 | Codex Sandbox 執行 dotnet test / pytest |
| 持久化 | 對話紀錄 | commit、PR、CI artifact |
| 失敗處理 | 再問一次 | fail closed:計畫無效或測試紅燈就不寫入 |
| 可重跑 | 低(Context 漂移) | 高(同一 Prompt、同一 Schema、同一測試指令) |
四階段管線固定如下。Day 02 調 Prompt 與 Context,Day 03 把輸出鎖成 JSON Schema,Day 04 把指令拆成可複用模組,Day 05 把驗證交給 Codex Sandbox。不要跳過「計畫」直接要程式碼。
flowchart LR
A[Prompt module] --> B[Structured output]
B --> C[Codex sandbox verify]
C --> D[commit]
CodeChangePlan JSON(要改哪些檔、風險、測試指令、是否需要 SQL),通過 Schema 才進入寫碼。workspace-write 產生最小變更,跑測試;網路預設關閉。測試失敗就修,修到綠燈或明確失敗退出。git add / git commit。.git 在 Sandbox 內仍是 read-only,commit 由人(或明確授權的外層腳本)執行。以下 Starter Prompt 可直接貼到 Chat Completions 或 ChatGPT。它強迫模型「先 JSON、後程式碼」:沒有合法計畫就不准開始改檔。把 {{...}} 換成真實 Context。
You are a senior backend engineer working in a C# / PostgreSQL repo.
ROLE
- Plan first. Do not emit source code until the plan is accepted.
TASK
- Implement the following change with the smallest possible diff:
{{TASK}}
CONTEXT (do not invent files)
- File tree:
{{FILE_TREE}}
- Public interface:
{{INTERFACE}}
- Failing test (must pass after the change):
{{FAILING_TEST}}
CONSTRAINTS
- Do not rewrite unrelated modules.
- Do not add new NuGet packages unless the plan sets "new_dependency": true.
- If SQL is required, emit PostgreSQL only, and put it under "sql" in the plan.
- If information is missing, set "blocked": true and list questions. Do not guess.
OUTPUT CONTRACT
Return ONLY valid JSON (no markdown fences) matching:
{
"summary": "string",
"blocked": false,
"questions": ["string"],
"files": [{"path": "string", "action": "create|modify|delete", "reason": "string"}],
"risk": "low|medium|high",
"test_command": "string",
"sql_needed": false,
"sql": "string or empty"
}
After I reply with {"plan_accepted": true}, you may output a unified diff.
If I reply with {"plan_accepted": false, "reason": "..."}, revise the JSON plan only.
把 Workflow 接到 API 時,第一個閘門就是「解析失敗 = 中止」。下面這段 Python 示範最小編排:送出計畫 Prompt,解析 JSON,失敗則 fail closed,不呼叫 Codex。
import json
import os
from openai import OpenAI
client = OpenAI()
MODEL = os.getenv("OPENAI_MODEL", "gpt-4o") # 可換成團隊現用模型
SYSTEM = "Return only JSON. No markdown. No code until the plan is accepted."
def request_plan(prompt: str) -> dict:
resp = client.chat.completions.create(
model=MODEL,
messages=[
{"role": "system", "content": SYSTEM},
{"role": "user", "content": prompt},
],
response_format={"type": "json_object"},
temperature=0,
)
raw = resp.choices[0].message.content
try:
plan = json.loads(raw)
except json.JSONDecodeError as exc:
raise SystemExit(f"fail closed: invalid JSON ({exc})") from exc
required = {"summary", "files", "risk", "test_command", "sql_needed"}
missing = required - plan.keys()
if missing:
raise SystemExit(f"fail closed: missing keys {sorted(missing)}")
if plan.get("blocked"):
raise SystemExit(f"fail closed: blocked {plan.get('questions')}")
return plan
if __name__ == "__main__":
with open("prompt.txt", encoding="utf-8") as f:
plan = request_plan(f.read())
print(json.dumps(plan, ensure_ascii=False, indent=2))
# 下一步(Day 05):codex exec --sandbox workspace-write "..."
實務順序建議固定為:寫 Prompt 模組 → 取得 JSON 計畫 → 人工或規則審核風險(high 必須人審)→ Codex 改檔並跑 test_command → 綠燈才 commit。聊天可以當草稿區,但進 repo 的路徑只能走 Workflow。
以「訂單折扣」走完一輪,團隊節奏會變清楚。第一階段用固定 Prompt 描述驗收:GetTotal 必須把 discountRate 套到小計,且既有失敗測試要變綠。第二階段只收 JSON:files 指向 OrderService.cs,risk=low,sql_needed=false,test_command 寫死可執行指令。第三階段才允許 Codex 在 workspace-write 寫入最小 diff 並跑測試。第四階段由人看 diff 後 commit。若第二階段缺 test_command 或 JSON 解析失敗,腳本直接結束:不消耗 Codex 配額,也不留下半成品分支。
這條管線的價值是失敗可定位。Prompt 資訊不足會得到 blocked 與 questions;Schema 不合會在解析器失敗;實作錯誤會在 Sandbox 紅燈;只有四段都通過才進 git。純聊天把這四種失敗混成「再問一次」,所以無法進 CI,也無法做成本統計。從 Day 02 起,每一天只強化其中一段,不再回頭把聊天當正式入口。團隊若仍用聊天視窗交作業,先把四段做成開 PR 檢查清單:沒有 JSON 計畫、沒有測試指令、沒有 Sandbox 結果,就不開 PR。
注意事項與常見失敗 (Pitfalls)
json.loads 直接爆掉。修法:系統訊息寫死 Return ONLY valid JSON,並用 response_format;程式碼必須等 plan_accepted: true。test_command 的計畫直接拒絕;Codex 必須實際執行測試。workspace-write,.git 仍是 read-only。修法:commit 留在外層腳本或人工;不要開 danger-full-access 只為了 git commit。本日總結 (Takeaways)
blocked: true 就 fail closed。test_command,不能只帶「看起來對」的程式碼。明日預告 (Next)
明日進入 Day 02 Prompt Engineering 工作流:給開發者的精準 Prompt 調校與 Context 設計,把今天的 Starter Prompt 拆成 Role / Task / Context / Constraints / Output contract,並示範如何打包 repo Context 而不是整檔傾倒。
你把純聊天和 Workflow 的差距切得很明確,尤其是先出 CodeChangePlan JSON、再進 Codex Sandbox 跑 dotnet test,最後才允許 commit,整條路徑一旦紅燈就停住,這種 fail closed 的節奏很有感。那張「聊天 vs Workflow」表也很直白,從自由文字到最小 diff、從對話紀錄到 commit artifact,讀起來就像把 AI 開發真正接上可驗證的管線。我手邊有多的 Lovable 額度想送給有緣人,有興趣可從連結看看我的系列。 https://ithelp.ithome.com.tw/articles/10401174