CodeGym /課程 /ChatGPT Apps /ChatGPT App 的 syste...

ChatGPT App 的 system‑prompt 與「角色契約」

ChatGPT Apps
等級 5 , 課堂 0
開放

1. 將 system‑prompt 視為契約,而不是漂亮的文案

在先前的模組中,我們從架構角度看過 ChatGPT App:小工具、tools 與 MCP 伺服器。這一講我們切換到另一個焦點:我們用什麼話來說明模型的角色——它能做什麼、不能做什麼,以及如何使用工具。本質上,我們要把 system‑prompt 設計成你與模型之間的契約。

在一般與 ChatGPT 的對話中,你也許習慣使用像「想像你是個開朗的海盜助理」或「把所有事情講得像對五歲小孩」這類提示。這些都屬於人設與風格。在 ChatGPT App 的語境裡,system‑prompt 這個詞有著完全不同的意義

這裡的 system‑prompt 是對使用者隱藏的第一則 system 角色訊息,它會告訴模型:

  • 你在這個 App 裡是誰;
  • 你聚焦於哪種任務;
  • 你不負責哪些事情;
  • 你應該如何、何時呼叫應用程式的工具。

本質上它就是行為規格,與正式契約非常接近。如果雙方約定清楚——模型會努力遵守;若沒有——它就會像一般的「通用」ChatGPT 那樣行事,而你精心設計的 App 可能被晾在一旁。

重點在於,對 ChatGPT App 而言,這個 system‑prompt

  • 綁定到應用程式本身,而不是綁定到某一段對話;
  • 同時為小工具的使用與 tools 的呼叫設下邊界;
  • 其生命週期與 App 的工作階段一致(只要使用者還在與你的應用互動,它就存在)。

簡化來說,約定是這樣:你提供工具並描述模型的角色——它是哪種助理、做什麼、不做什麼、如何使用工具、如何對待使用者資料。模型則回應:會盡量依此行事。

2. system‑prompt 在架構中的位置

為了避免把它想像成某種魔法般的存在,看看簡圖會很有幫助。

sequenceDiagram
    participant User as 使用者
    participant ChatGPT as ChatGPT + 模型
    participant App as 你的 ChatGPT App
    participant MCP as MCP/Backend

    Note over ChatGPT: 在初始化 App 時
模型會收到 system‑prompt User->>ChatGPT: "幫我為朋友挑一個 50 美元以內的禮物" ChatGPT->>ChatGPT: 套用 system‑prompt + tools 的描述 ChatGPT->>App: callTool recommend_gifts(...) App->>MCP: HTTP /tools/recommend_gifts MCP-->>App: 禮物清單 App-->>ChatGPT: Tool result (JSON) ChatGPT-->>User: 說明文字 + 指示顯示卡片小工具

system‑prompt 會在 App 初始化時傳給模型,當 ChatGPT 決定把你的應用「接上」對話後即可。接著,每一次 ChatGPT 的決策——是否呼叫 tool、是否提出小工具、當資料不足時要說什麼——都會以這份契約為準。

在 Apps SDK 的程式碼角度,這通常就是一段字串,放在 App 的設定附近,例如:

// app/config/systemPrompt.ts
export const giftGeniusSystemPrompt = `
你是 GiftGenius,我們服務的禮物推薦助理...
`;

接著這段字串會傳到你的應用與 ChatGPT 連結的地方。技術「包裝」可能各不相同,但對你而言重要的是:system‑prompt 與工具的 schema 或 React 元件一樣,都是程式碼產物,需要同樣謹慎地設計與保存。

既然已經了解 system‑prompt 在架構中的位置與傳遞方式,接下來更重要的是——放入哪些內容,才能讓它成為契約,而不是單純的「可愛人設」描述。

3. App 的角色與責任邊界

任何正常的 system‑prompt 的第一大段,都是在定義:你是誰、你負責什麼

「人設」與「App 契約」的差異很簡單:說「你是海盜,用水手的口吻說話」——是語氣;說「你是我們禮物目錄的介面,負責挑選禮物,不處理其他主題」——那就是契約。

對我們這個禮物推薦教學應用 GiftGenius 而言,角色核心可以長這樣:

角色:
- 你是 GiftGenius,我們服務的禮物推薦助理。
- 你的任務是只使用我們的目錄,協助使用者挑選合適的禮物。
- 你不提供醫療、法律或財務方面的建議。

注意重點。

首先,我們明確縮小領域:只在我們服務的框架內做禮物挑選。這能避免模型開始「講量子物理」而不是開啟你的 App,也能避免它替你拼湊出對其他應用的奇怪 workflow。

其次,我們明確列出App 不做的事。例如:

  • 不提供與禮物與購物無關的建議;
  • 不捏造目錄裡沒有的禮物;
  • 不替使用者做決定,只負責提供選項並給出理由。

這類負面限制往往比正面指示更重要:模型本來就「什麼都能做」,你在 system‑prompt 裡做的,就是削掉不必要的能力。

在更複雜的環境中,如果同一位開發者有多個 App(例如「禮物推薦」與「訂單配送追蹤」),在 system‑prompt 中明寫:在這個 App 你只處理禮物挑選,不負責訂單與物流,也不啟動其他應用。這能降低模型對「誰的職責」的混淆風險。

4. 什麼時候要呼叫 App,什麼時候自己回答

下一個關鍵區塊:工具使用規則

如果不把規則寫清楚,常見會落入兩種極端:

  • 模型幾乎從不呼叫你的 App,因為直接「憑印象」回答更簡單、更便宜;
  • 或相反地,對任何小事都呼叫工具,連純理論問題也不例外。

在 App 的 system‑prompt 中,需要相當明確地規定:

  • 在哪些情況下必須使用工具;
  • 在哪些情況下應該自行回答、不要用 tools
  • 當使用者明確要求「不要啟動應用」時該怎麼做。

針對 GiftGenius 的文字片段範例:

工具使用:
- 當需要從目錄取得事實性資料(禮物清單、價格、商品類型、配送與折扣是否可用),請使用 App 的工具。
- 若問題是理論性的且不需要存取目錄(例如 "喬遷時一般會送哪些禮物"),請自行回答。
- 如果使用者明確要求 "不要開啟應用" 或 "不要用小工具",請尊重並不要呼叫工具。

這裡有幾件重要的事。

首先,我們把呼叫 tools 綁定到請求類型:需要事實/目錄資料 → 用工具;一般性的原理 → 模型自己答。

其次,我們明確說明對使用者意圖的尊重:若使用者寫「不要啟動任何東西,只要解釋就好」,模型不應該忽視這個訊號。

第三,我們因此能管理 App 的使用頻率。好的 system‑prompt 能幫助模型取得平衡:需要時才用 App,而不是變成任何時刻都跳出的惱人小視窗。

之後在下一講(UX 指示)我們會另外談,模型該如何宣告啟動小工具,以及在情境結束後該說些什麼。這一節我們只關注決策規則:該不該用 App。

5. 安全地使用 tools 與處理使用者資料

接下來談安全與常識。

你的 App 工具有各種型態:

  • 存取公開資料的(禮物目錄、商品可用性、配送條件);
  • 處理個人資料與/或代表使用者執行動作的(建立訂單、扣款、變更設定)。

system‑prompt 中需要標明模型對這些差異的態度。

典型的規則組合:

安全與隱私:
- 未經使用者在聊天中明確確認,不要執行需要同意的動作(購買、開啟訂閱、變更個人資料)。
- 不要把多餘的資料傳入工具(資料最小化)。
- 若請求涉及敏感資料(健康、財務、兒童),請先確認使用者是否同意把這些資料傳給應用。

這同時解決了幾件事。

首先,保護使用者免於意外行為:即使你提供了相關工具,模型不得自行購買禮物或建立訂單。先取得文字確認,再呼叫工具。

其次,降低多餘資料外洩的風險:模型往往傾向把「看到的全部」都丟進工具的參數;你要明確要求只提供最必要的欄位。

第三,我們特別強調敏感領域,即便沒有金流工具,也可能涉及法律/倫理風險。

一個好做法是:對危險工具在其描述(description)中註明會改變狀態或進行付款,並在 system‑prompt 層重申。如此就有雙重防線:契約層與具體工具描述層。

6. system‑prompt 的格式與風格:用規格書的方式撰寫

最常見的錯誤之一,是把 system‑prompt 寫成行銷文案:「你是創新且超智慧的助理,讓世界更美好……」。雖然漂亮,但對模型沒有幫助。它在意的是:

  • 我是誰;
  • 要做什麼;
  • 不要做什麼;
  • 如何使用工具;
  • 如何對待資料與其他 App。

因此最好把 system‑prompt 視為規格書

  • 切成邏輯區塊:「角色」、「任務」、「邊界」、「工具使用」、「安全性」;
  • 區塊內使用短而明確的句子;
  • 清楚區分「該做」與「禁止做」(是的,在提示本身用清單很合適)。

GiftGenius 的結構化提示片段可如下:

角色:
- 你是 GiftGenius,我們服務的禮物推薦助理。

任務:
- 依使用者目標、收禮者興趣與預算,協助挑選禮物。
- 以淺白語言說明每個選項的優缺點。

不要做:
- 不要捏造目錄中不存在的禮物。
- 不要承諾服務沒有的功能(例如目錄顯示需付費配送時,別承諾免運)。

風格宜中性、精準:「這不是銷售文案,而是契約」。越少歧義,行為越穩定。

另一個重要實務:system‑prompt 與程式碼一起版控與保存。提示也有版本,變更它會像改 TypeScript 邏輯一樣影響行為。你會比較樂於在 PR review 看到這樣的 diff:

- 不要捏造商品目錄中不存在的禮物。
+ 不要捏造商品目錄中不存在的禮物,即使使用者明確要求 "隨便編一個"。

總比事後回想「你在介面上隨手調了措辭」要好得多。

7. 我們教學 App 的完整 system‑prompt 範例

把上面所有內容組合起來,為教學用的 GiftGenius 寫一份乾淨的 system‑prompt。我們把它分段,方便閱讀與調整。

先描述角色與任務:

角色:
- 你是 GiftGenius,我們服務的禮物推薦助理。
- 與使用者互動時請禮貌、商務化;若使用者不使用俚語與玩笑,你也不要主動使用。

任務:
- 依據提供的參數(收禮者輪廓、興趣、場合、預算)協助挑選禮物。
- 用簡單易懂的語言說明為何推薦這些選項。

再來寫明邊界與限制:

責任邊界:
- 僅使用我們的禮物目錄與其後設資料。
- 不要捏造目錄或工具回應中不存在的禮物、活動與折扣。
- 不提供醫療、法律或財務建議。
- 不對其他應用或網站負責;若使用者詢問相關內容,請說明你無法協助。

加入工具使用規則:

工具使用:
- 當需要把收禮者的自由描述轉成興趣分群時,使用 tool `profile_to_segments`。
- 當需要依使用者參數(分群、預算、場合、在地化)搜尋或過濾禮物時,使用 tool `recommend_gifts`。
- 當使用者需要特定禮物的詳細資訊(描述、類型、價格、配送限制)時,使用 tool `get_gift`。
- 呼叫工具之前,若缺少關鍵參數(收禮者年齡、預算、場合)會讓結果失去意義,請先詢問補齊。
- 若請求是理論性的(例如 "整體來說,第一次結婚週年應怎麼選禮物"),請自行回答,不要呼叫工具。

接著是安全與代表使用者行動的規範:

安全性:
- 未經使用者在聊天中明確確認,不要進行購買、訂閱或寄送禮物。
- 若工具需要個人資料(收禮者 e‑mail、配送地址、姓名),請先向使用者說明用途並徵得確認。
- 不要把多餘的資料傳入工具(例如,若只需要年齡、興趣與預算,就不要傳送整段訊息)。

以及整體語氣/全域規則:

一般規則:
- 若工具回傳為空,請如實說明,並建議放寬條件(調整預算、禮物類型、分類或場合)。
- 如果使用者要求 "不要開啟應用" 或 "不用小工具",請尊重並僅以文字回覆,不呼叫 tools。
- 若請求與禮物或購物無關,請像基礎版 ChatGPT 那樣回答,且不要使用 GiftGenius 的工具。

最終這個結構與進階教材中的範例很像:有「角色」、「任務」、「可做/不可做」、「工具使用」、「安全性」、「一般規則」等章節。

在 Next.js 程式碼中,你可以把它整理成獨立模組:

// app/config/giftGeniusPrompt.ts
export const giftGeniusSystemPrompt = `
角色:
- 你是 GiftGenius,我們服務的禮物推薦助理。
...

一般規則:
- 若請求與禮物無關,請像基礎版 ChatGPT 那樣回答,且不要使用 GiftGenius 的工具。
`;

然後在 App 設定中引用這個常數(具體寫法取決於 Apps SDK 版本,但核心概念相同:在 App 對話初始化時,把這段文字放進 system 角色)。

8. 在 system‑prompt 中加入動態情境

有時候 system‑prompt 需要一點「動態」:例如當前日期、在地化、使用者身分(新/舊客)、訂閱狀態等等。

例如,如果你的禮物目錄與價格會因地區而異,你可以把當前地區傳入 system‑prompt

export function buildSystemPrompt(locale: string) {
  return `
角色:
- 你是 GiftGenius,負責地區 ${locale} 的禮物推薦助理。

邊界:
- 僅使用地區 ${locale} 可用的禮物與價格。
...
`;
}

Apps SDK 在 App 初始化時可能會提供 _meta["openai/locale"],你可以據此產生需要的提示版本。我們稍後會詳細談在地化,但現在先知道:system‑prompt 不一定是完全靜態的。

重點是:不要把它變成一鍋「義大利麵」式的條件堆疊。如果邏輯太複雜,最好拆分 App,或把條件下放到 tools(例如讓 MCP 伺服器根據 locale 自行選擇資料來源),而把 system‑prompt 保持在高階規則層。

9. system‑prompttools 描述及 UX 指示之間的關係

本講聚焦於 system‑prompt,但在實際 App 中它不是單獨存在。你還會有工具的描述(descriptioninputSchema)與你將在後續主題中加入的 follow‑up 範例。這些共同構成一組完整的指示系統。

關於 tools 呼叫控制:

  • system‑prompt 設定整體哲學:「工具只用於事實資料」、「不要捏造禮物」、「未經確認不要購買」。
  • tools 的 descriptions 會細化 recommend_gifts 的功能、需要的參數與呼叫時機;
  • follow‑up 句型決定工具呼叫後的對話風格:如何如實告知查無結果、如何建議調整請求、如何總結結果。

若這三個層次彼此一致,模型會表現可預期:

  • 在真正需要時才呼叫 App;
  • 不會捏造目錄外的禮物/商品;
  • 清楚向使用者解釋發生了什麼(找到/找不到/需要更多資訊)。

若不一致——你將得到混亂的行為,並陷入漫長的「神秘提示調校」循環,令人身心俱疲。

10. 在 system‑promptChatGPT App 上常見的錯誤

錯誤 1:把 system‑prompt 寫成「好看」而非契約。
開發者常只寫一些籠統的句子,比如「盡力幫助使用者解決問題」、「要友善」。這並不會讓模型更清楚何時要呼叫 App、責任邊界在哪裡、能不能捏造資料、工具出錯時要怎麼辦。結果是:一半邏輯散落在多個程式堆疊與作者腦中,而不是明確寫進契約。

錯誤 2:角色過於寬泛(「萬事通」)。
如果你在角色描述中寫「你是能幫助使用者解決所有問題的助理」,模型就會非常開心地去做所有事,而且不一定會想起你的 AppApp 會變成不太重要、很少被用到的選項,因為模型覺得自己就能處理。最好明確指出利基:禮物挑選、操作禮物目錄、特定領域的協助。

錯誤 3:沒有規定何時呼叫工具。
像「視需要使用工具」之類的說法太模糊。模型可能完全忽略 tools,也可能在明明可以「憑印象」回答時仍頻繁呼叫。需要明確區分情境:事實資料 → 工具;背景解說 → 模型自己答;使用者明確拒絕 App → 僅文字回覆。

錯誤 4:想靠一句「不要捏造」就治好幻覺。
「不要產生幻覺」本身幫助有限。要明確描述禁止捏造的內容(目錄外的商品/禮物、沒有 ID 的項目、不存在的折扣),以及在空結果時該怎麼做(誠實說明找不到)。若沒有這些,模型仍會為了「討好」而虛構選項。你需要一整套做法:在 system‑prompt 中的全域禁令、在 tools 描述中的限制、以及「查無結果」的回答模板。

錯誤 5:忽視安全與使用者同意。
如果在 system‑prompt 中沒有寫明購買、預訂或變更個資需要明確確認,模型可能出於「善意」自行呼叫工具。從 UX 的角度看這是災難。務必寫清楚:任何涉及金流或帳戶的動作都只在聊天中取得明確同意後才執行。

錯誤 6:沒有考慮到其他 App 與工具的存在。
在一個帳號有多個 App、而且工具眾多的世界裡,不能指望模型「自己猜到」該用哪個應用。如果 system‑prompt 沒有牢固定義這就是「選禮物」的 App 並且只做這件事,模型可能會在不同 App 間不可預期地切換,或把工具用錯地方。

錯誤 7:在沒有版本控管與測試的前提下「熱修」 system‑prompt
很容易手癢去設定檔改一行,並相信「只會更好」。實務上,任何提示的微調都可能破壞其他情境的行為。若不把 system‑prompt 放在版本庫中、檢視 diff、以及跑一組測試請求(golden prompt set——我們會在本模組中談到),你可能會追著回歸問題跑好幾週。

留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION