iT邦幫忙

2026 iThome 鐵人賽

DAY 27
0
Claude AI

從零開始 Claude Code:30 天打造 AI 任務管理 Web App系列 第 27 篇

[Day 27] 調整 Prompt:讓 AI 不只格式正確,內容也更符合需求

  • 分享至 

  • xImage
  •  

Day 26 已經把 AI 的輸出從自由文字改成結構化 JSON。

目前流程是:

大型目標
↓
Groq API
↓
openai/gpt-oss-20b
↓
Structured Outputs
↓
JSON Schema
↓
Python 解析
↓
title / description

格式這一塊已經穩定很多。

但真正測下去後,我發現另一個問題:

格式正確,不代表內容一定真的符合使用者的意思。

例如我之前輸入:

我要在三個月內學會 Python 基礎、Flask、MySQL,
最後做出一個可以展示的專題

AI 曾經自己補出:

實作並部署專題到線上平台

甚至提到:

Heroku
Render

但我原本只說:

可以展示的專題

並沒有要求:

一定要部署到線上

這代表 Day 26 雖然把 JSON 格式處理穩定了,但內容本身還是可能出現:

AI 自行延伸
AI 自己補條件
AI 猜使用者沒說的事情

所以 Day 27 的重點,就是調整 system prompt。


今天只改 Prompt

這次我刻意把修改範圍壓得很小。

只修改:

groq_api_test.py

而且只改:

SYSTEM_PROMPT

其他都不動。

這樣做有一個好處:

如果結果變好或變差,我比較知道原因真的來自 Prompt,而不是其他設定一起被改掉。


Day 26 的 Prompt 太簡單

Day 26 的 Prompt 主要只有幾個要求:

使用繁體中文
拆成 5~8 個可執行任務
每筆有 title 和 description
只回傳符合格式的資料

這些規則主要是在處理:

格式

但沒有明確處理:

不要亂猜
不要自行增加工具
不要自行增加平台
不要自行增加日期
資訊不足時怎麼辦
description 不要重複 title
任務彼此不要重複
順序要合理

所以這次要把規則補完整。


我一開始整理出的 9 條規則

最初我先整理成:

1. 使用繁體中文。
2. 把使用者目標拆成 5~8 個可執行任務。
3. 任務按照合理順序排列。
4. 不要自行加入使用者沒有明確提到的:
   - 平台
   - 工具
   - 日期
   - 限制
   - 成果形式
5. 如果資訊不足,採用保守、通用的拆解,不要亂猜。
6. 每個 title 要簡短明確。
7. description 要補充具體行動,不要只是重複 title。
8. 任務之間要有明確差異,不要只是換句話說。
9. 只回傳符合 JSON Schema 的資料。

這 9 條是要給:

openai/gpt-oss-20b

不是給 Claude Code 本身。

Claude Code 的角色只是幫我把這些規則寫進:

groq_api_test.py 的 SYSTEM_PROMPT

先讓 Claude Code 做 Plan

我沒有直接自己改 Prompt。

而是先讓 Claude Code 分析:

目前 Prompt 缺什麼?
哪些規則該保留?
哪些規則可以合併?
哪些地方可能互相衝突?

Claude Code 最後把 9 條整理成 6 條。

其中有一個調整我覺得很重要。

原本我寫:

title 要以動作開頭

後來改成:

title 要簡短明確,以具體行動為主

因為中文任務名稱不一定每次都要硬性要求第一個詞是動詞。

像:

專題需求整理

其實也可以是一個清楚的任務名稱。

真正想避免的是:

Python 能力提升
英文進步
專題成功

這種太抽象、很難直接執行的標題。


最後採用的新 System Prompt

最後整理後的 Prompt 大概是:

你是任務拆解助手。使用者會給你一個大型目標,
請用繁體中文把它拆成 5~8 個可執行的小任務,
並依合理的執行順序排列。

規則:
1. 只根據使用者提供的資訊拆解。
   使用者沒有明確提到的平台、工具、日期、限制或成果形式,
   不要自行加入,也不要把目標延伸到使用者沒提到的階段。

2. 資訊不足時,採用保守、通用的拆解,
   不要猜測使用者未提供的細節。

3. 每個任務都應是具體、可實際執行的行動,
   彼此目的明確不同,不要只是換句話說。

4. title 要簡短明確,以具體行動為主。

5. description 用一到兩句補充具體做法或要完成的內容,
   不要只是重複或改寫 title。

6. 只回傳符合指定格式的資料,
   不要加入其他多餘文字。

這次我刻意沒有把:

Heroku
Render
TOEIC
IELTS

直接寫進 Prompt。

因為如果在 Prompt 裡一直提這些詞,反而可能產生:

反向引導

也就是原本模型沒有想到,看到 Prompt 後反而被提示到。


Prompt 不是越長越好

這次也讓我更清楚一件事。

Prompt 並不是:

規則越多
=
效果一定越好

如果寫太多:

要精準
要專業
要完整
要合理
要最佳化
要高品質

這些其實很抽象。

真正有用的是:

不要自行加入沒提到的平台
資訊不足時不要亂猜
description 不要只是重複 title
任務之間不要只是換句話說

這些規則比較能直接對應到實際問題。


今天不是只測一次

AI 的輸出本來就不是每次完全一樣。

所以如果改完 Prompt 後只測一次:

這次看起來不錯

其實不能證明真的改善。

這次我準備了 9 個測試案例:

1. 我要準備期末專題
2. 我要做一個可以展示的專題
3. 學英文
4. 我要三個月內學會 Python
5. 我要用 Flask 做一個部落格
6. 我要做網站並部署到 Vercel
7. 整理房間
8. 存錢
9. Plan a birthday party

這 9 個案例分別測不同問題。


測「不要亂加東西」

例如:

我要做一個可以展示的專題

這個案例主要看:

AI 還會不會自己加入部署
上線
雲端平台

舊 Prompt 的 3 次測試裡,有 1 次出現:

上線與推廣
部署至伺服器

新 Prompt 的 3 次:

0/3 出現明確部署

這算是明顯改善。

不過新 Prompt 還是有一些輕微延伸,例如:

上傳或呈現
整合至展示平台

所以不是完全沒有推測,只是程度有下降。


測「學英文」這種模糊輸入

另一個重要案例是:

學英文

因為這句話沒有提供:

學習目的
目前程度
期限
考試
用途

這種情況下,我希望 AI 採用保守、通用的拆解。

不要自己硬補成:

準備 TOEIC
準備 IELTS
三個月完成
每天兩小時
商務英文

實測後,新的 Prompt 並沒有明顯完全解決這個問題。

雖然沒有出現 TOEIC/IELTS,但還是曾出現:

每天至少 15~30 分鐘
餐飲
商務
旅遊

也就是 AI 還是會偶爾自行補細節。

這次我沒有繼續瘋狂加規則。

因為如果 Prompt 壓得太死,也可能讓模型連合理的拆解都不敢做。


也要防止「修過頭」

Prompt 加入:

不要自己加日期
不要自己加平台
不要自己加工具

之後,也有另一個風險:

AI 會不會連使用者明確講的東西也忽略?

所以我另外測:

我要三個月內學會 Python

這裡「三個月」是使用者自己提供的。

所以應該保留。

還有:

我要用 Flask 做一個部落格

這裡:

Flask

也是使用者明確指定的。

以及:

我要做網站並部署到 Vercel

這次部署不是 AI 亂加的。

因為使用者自己就要求:

部署到 Vercel

所以新的 Prompt 不能把它刪掉。


防過度修正的結果

這部分結果還不錯。

新舊 Prompt 都能保留:

Flask
Vercel 部署

「三個月」大部分也有保留。

也就是新的 Prompt 雖然限制 AI 不要亂加東西,但沒有嚴重壓掉使用者真正提供的資訊。

這一點很重要。

因為 Prompt 的目標不是:

讓 AI 什麼都不敢補

而是:

使用者說過的要保留
使用者沒說的不要過度延伸

測小目標:整理房間

我也測:

整理房間

原本有一個問題:

既然系統規定一定要 5~8 筆,
會不會為了湊數產生很多重複任務?

但目前:

SYSTEM_PROMPT
+
parse_tasks()

都要求至少 5 筆。

所以今天不能把:

硬湊到 5 筆

當成失敗。

因為這是我們自己要求它一定要做到的。

這次真正看的改成:

每筆任務有沒有不同目的
有沒有明顯重複
有沒有只是換句話說

新版分別產生:

6 筆
5 筆
7 筆

任務之間大多有差異,沒有明顯重複。

不過還是有一些稍微像在湊內容的項目,例如:

檢查燈具與電器
清理窗簾與窗戶

這也提醒我:

強迫所有目標一定拆成 5~8 筆,本身就是一個產品規則。

未來如果真的要改善小目標,可能要重新思考:

是不是每個目標都一定要 5~8 筆?

但今天不處理這件事。


前後總共測了 54 次

這次不是只憑感覺比較。

9 個案例:

9

舊 Prompt 和新 Prompt:

× 2

每一組各跑 3 次:

× 3

最後就是:

9 × 2 × 3 = 54 次 API 呼叫

兩邊都使用完全相同的:

model
reasoning_effort
max_completion_tokens
JSON Schema

唯一改變的是:

SYSTEM_PROMPT

這樣比較才有意義。


自動檢查不能完全取代人工閱讀

這次還有做一些自動檢查。

例如:

有沒有出現部署
有沒有出現 TOEIC / IELTS
有沒有保留 Flask
有沒有保留 Vercel
title 是否太相似
description 是否太像 title

但很快就發現:

關鍵字檢查只能當第一層。

例如如果 AI 回:

不需要進行部署,只要準備展示內容

自動檢查只看到:

部署

可能就會判定失敗。

但人工一看就知道:

它其實沒有要求部署

所以最後還是要:

自動檢查
+
人工閱讀

一起判斷。


新 Prompt 有沒有真的變好?

這次不能說:

完全解決

比較準確的說法是:

有小幅改善

目前觀察到:

展示專題明確變成部署
→ 有下降

任務 title 重複
→ 有改善

使用者明確提供的 Flask / Vercel
→ 還是有保留

description 重複 title
→ 新舊這批測試都沒明顯發生

模糊輸入自行補細節
→ 仍然存在

可執行性
→ 新舊差距不算很大

所以 Prompt Engineering 並不是:

多寫幾條規則
↓
問題全部消失

而比較像:

找到問題
↓
加一條更精準的限制
↓
測試
↓
比較
↓
看有沒有副作用
↓
再決定要不要繼續調

測試時突然出現 HTTP 400

這次大量測試時,還遇到了一個原本沒預期到的問題。

54 次比較測試裡,曾出現:

HTTP 400

一開始不知道原因。

而且新舊 Prompt 都有發生:

舊 Prompt:有
新 Prompt:也有

所以不能直接說:

新 Prompt 害 API 壞掉

我決定先停下 Prompt 調整,回頭查 400 的真正原因。


原因是 json_validate_failed

Groq 回傳:

HTTP status: 400

type:
invalid_request_error

code:
json_validate_failed

錯誤訊息大意是:

模型產生的 JSON 驗證失敗

也就是問題發生在:

模型生成
↓
Groq 驗證
↓
JSON 不合法
↓
直接 HTTP 400

甚至還沒有進到我的:

json.loads()
parse_tasks()

模型到底產生了什麼錯誤?

這次 Groq 的錯誤內容裡有:

failed_generation

也就是模型那一次實際產生的文字。

把內容拿出來檢查後,發現其中一筆大概變成:

{"title","建立 GitHub 版控與持續整合流程", ...}

正常 JSON 應該是:

{
  "title": "建立 GitHub 版控與持續整合流程"
}

但模型當次生成的是:

"title","建立 GitHub 版控與持續整合流程"

title 後面應該是:

:

結果卻變成:

,

所以 JSON 本身有語法錯誤。


strict: true 不代表每次 API 都一定成功

這次我學到一個很重要的差別。

Day 26 使用:

strict: true

我原本很容易理解成:

AI 每一次一定會成功回傳合法 JSON

但這次實際測試後,更準確的理解是:

如果 Structured Output 成功產生並被 Groq 接受
→ 回傳資料會符合指定格式

如果模型生成過程本身失敗
→ Groq 可能直接回 API error

這次就是:

模型產出錯誤 JSON
↓
Groq strict 驗證失敗
↓
json_validate_failed
↓
HTTP 400

所以 Structured Outputs 可以提高格式可靠性,但不代表 API 呼叫永遠不會失敗。


這次 400 到底多常發生?

這次整個測試過程累計:

88 次 API 呼叫

其中觀察到:

4 次 HTTP 400

如果只算這批樣本,大約是:

4.5%

但這個數字不能直接寫成:

Groq 有 4.5% 失敗率

原因是:

樣本太小
只有其中 1 次保留完整錯誤資訊
另外 3 次當時沒有記錄完整 error body

所以目前只能說:

在這次 Day 27 的大量測試中,觀察到少量 HTTP 400,其中至少一次確認是 json_validate_failed。

不能把它當成平台的固定失敗率。


為什麼今天不直接加 retry?

查到原因後,其實很容易想到:

json_validate_failed
↓
自動重試一次

但我今天沒有做。

因為 Day 27 一開始就設定:

只調 system prompt

如果現在加入:

retry
特殊錯誤處理
HTTP 400 判斷

就已經變成另一個主題:

API 錯誤恢復機制

所以目前只記錄:

json_validate_failed

不修改程式處理流程。

等之後真的把 AI API 接進 Web App,再來決定:

要不要自動 retry
retry 幾次
失敗時怎麼提示使用者
要不要記錄錯誤

Day 27 的實際結果

最後可以整理成:

System Prompt 調整完成                         ✓

新舊 Prompt 54 次比較完成                      ✓

「可展示的專題」明確延伸成部署的情況下降        ✓

使用者明確指定 Flask / Vercel 仍有保留           ✓

任務 title 重複情況有改善                       ✓

模糊輸入仍可能自行補充細節                      △

description 品質沒有明顯退步                    ✓

Prompt 改善不是 100% 保證                       ○

HTTP 400 原因進一步追查                         ✓

至少 1 次確認為 json_validate_failed             ✓

目前沒有加入 retry                              ○

沒有修改 Web App / MySQL / Task model            ✓

今天最大的收穫

Day 25 我學到:

AI API 要怎麼成功呼叫。

Day 26 我學到:

AI 回傳資料要怎麼固定成程式可以處理的格式。

Day 27 則讓我看到:

格式穩定之後,內容品質還是需要另外調整。

而且 Prompt 並不是像一般程式:

if 寫對
→ 每次一定同樣結果

AI 的輸出本來就有變動。

所以 Prompt 調整比較像:

提出規則
↓
實際測試
↓
觀察問題
↓
比較新舊
↓
找副作用
↓
決定是否值得繼續調

不是一直加規則,直到某幾個測試案例看起來完美。


不要為測試案例過度調 Prompt

這次「學英文」仍然偶爾會多補一些細節。

如果我現在一直針對:

學英文
展示專題
整理房間

加入更多限制,很容易變成:

Prompt 專門為這幾個測試題最佳化

但真正使用者之後輸入其他目標時,結果不一定更好。

所以這次我選擇停在:

有明顯改善
但還不是完美

先保留目前版本。

這反而更符合實際 AI 功能開發。


下一步:Day 28

做到 Day 27,目前 AI 這條路已經有:

Groq API
↓
GPT-OSS
↓
Prompt
↓
Structured Outputs
↓
JSON Schema
↓
Python 驗證

前面幾天一路加功能,也留下了一些:

測試程式
暫時邏輯
註解
已知問題
重複內容

所以 Day 28 不急著繼續加新功能。

下一步要開始:

整理目前專案,把 AI 功能和原本 Web App 的程式碼重新檢查一次。

包含:

哪些測試程式該保留
哪些註解可以整理
哪些已知問題要記錄
requirements 是否一致
CLAUDE.md 是否跟目前狀態同步
Git working tree 是否乾淨

先把目前累積的東西整理好,再準備最後幾天的完整測試。


上一篇
[Day 26] 把 AI 回傳內容變成真正可用的結構化任務
下一篇
[Day 28] 功能先停一下:整理專案、清掉暫時程式與確認目前狀態
系列文
從零開始 Claude Code:30 天打造 AI 任務管理 Web App 共 30 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言