For the complete documentation index, see llms.txt. Markdown versions of documentation pages are available by appending .md to the page URL.
主要導覽
2026年2月4日 Apps SDK

打造 ChatGPT 應用程式的 15 個心得

以及我們如何將這些心得融入 Codex 技能,協助你以 10 倍速度打造 ChatGPT 應用程式。

作者: Nikolay Rodionov (Co-founder, Alpic)

打造 ChatGPT 應用程式的 15 個心得

Alpic,我們相信下一代產品與服務將圍繞 以 AI 為核心的體驗打造。在這樣的介面中,使用者與模型協作,而不是按照傳統 UI 預先設定的工作流程操作。

OpenAI 推出 Apps SDK 後,我們立即開始用它開發。在三個月內,我們開發了 24 個 ChatGPT 應用程式,供內部使用,也服務 旅遊、零售和 SaaS 等 B2B 與 B2C 領域的客戶。

我們很早就發現, 打造 ChatGPT 應用程式,與開發傳統網頁或行動應用程式有根本上的不同。在網頁上行之有效的模式,例如需要時才擷取資料、由 UI 驅動狀態、讓使用者明確設定選項等,到了智慧體環境中往往行不通,甚至會損害使用體驗。

本文整理了我們在打造實際使用的 ChatGPT 應用程式時,學到的 最重要的 15 個心得 ,接著介紹我們如何將這些心得融入為社群打造的開源框架 Skybridge 與一項 Codex 技能,協助開發人員大幅加快構思、開發、測試及推出應用程式的速度。

三體問題

傳統網頁應用程式的情況很簡單:只有 使用者UI。但在 ChatGPT 應用程式中,系統多了第三個角色: 模型

為 ChatGPT 開發時,最困難的事情之一就是管理這三者之間的資訊流動。如果使用者在小工具中按下「選取」按鈕,UI 的畫面會更新,但作為對話大腦的模型並不知情,除非你明確將這些上下文傳遞給它。如果使用者接著問: 「請提供這項產品的更多詳細資訊。」 模型根本不知道使用者正在看什麼。

我們將這種情況稱為 上下文不對稱 :每個角色都只知道系統的部分資訊,沒有任何一方掌握全貌。打造好的 ChatGPT 應用程式,重點不在於讓所有資訊保持同步,而在於決定應該分享 哪些 資訊、 何時 分享,以及 需要知道。能否解決這個問題,決定了應用程式是操作不順,還是能提供流暢的智慧體體驗。

1. 並非所有上下文都應該分享

我們最初的直覺是「把所有資訊分享到所有地方就好」。結果,這成了我們最早犯的錯誤之一。

實務上,ChatGPT App 的不同部分往往需要針對同一個狀態, 刻意呈現不同的資訊 。為什麼?

  • 效能考量: UI 小工具所需的資料量,通常遠超過模型應該需要的範圍。例如,旅遊預訂應用程式可能需要圖片、不同價格方案,以及預先載入的選項。將這些資料全部傳送給模型,會增加 Token 用量、延遲,以及干擾理解的雜訊。
  • 邏輯考量: 有些資訊在設計上就必須保持不對稱。在我們最早開發的應用程式之一,也就是 Murder in the Valleys 推理遊戲中,模型需要知道誰是兇手,才能正確扮演角色,但 UI 和使用者都不能知道。在 Time’s Up 類型的遊戲中,情況則相反:UI 會向使用者顯示謎底詞語,但模型必須毫不知情。

我們學到的不是「隨時同步所有資訊」,而是: 明確決定誰需要知道什麼。我們透過不同的 工具輸出 欄位,將這個原則落實下來:

欄位用途可見對象
structuredContent供小工具和模型使用的具型別資料小工具與模型皆可見(透過 toolOutput 和 callTool 函式)
_meta回應中繼資料僅小工具可見,對模型隱藏

例如,在 Time’s Up 遊戲中,我們只透過 _meta 欄位將謎底詞語傳給小工具,讓模型根據使用者的提示猜出詞語。

2. 延遲載入不太適合 AI 應用程式

由於過去從事網頁開發,我們習慣採用延遲載入:等使用者點擊時才擷取資料、按需載入詳細資訊,並盡量減少初次載入的資料量。

但在 ChatGPT 中,情況恰好相反:工具呼叫會帶來延遲,而且因為安全沙盒和模型推理的緣故,往往需要數秒才能完成。

實務上,我們學會了盡可能提前載入資料:在初次工具回應中傳送盡可能多的資料,並透過 window.openai.toolOutput 將資料填入小工具。這幾乎總能帶來更快速、反應更靈敏的體驗。

當然,如果小工具可以安全地從公開 API 端點擷取資料,而且不需要與模型分享資訊,你仍然可以在小工具內使用傳統的 XHR 呼叫。但大多數時候,你會希望模型能夠自主呼叫工具,讓使用者持續以對話方式操作。

3. 模型需要掌握介面狀態

當使用者與小工具互動,例如在清單中選取某項產品,接著在對話中提問時,就會出現一個不易察覺卻很關鍵的問題。如果模型不知道使用者指的是 UI 的哪個部分,就無法正確回答。

為此,我們使用了 window.openai.setWidgetState(state)。它能儲存特定的狀態資料,並在使用者下次與模型互動時,將這些資料加入模型的上下文。

隨著應用程式變得更複雜,我們發現自己在許多地方加入了 setWidgetState,好讓模型掌握使用者的導覽動向。因此,我們決定引入宣告式的方式來描述 UI 上下文。我們不再於每次互動時以命令式方式更新模型,而是直接在元件上附加 data-llm 屬性:

<div
  data-llm={
    selectedTab === "details"
      ? "User is viewing product details"
      : "User is viewing reviews"
  }
>

為了讓這套機制在幕後自動運作,我們開發了一個 Vite 外掛程式,擷取這些屬性並自動更新 widgetState。對模型而言,它只會在適當的時機收到相關 UI 上下文,開發人員不必再為每次互動手動同步資訊。

你可以在我們為了與社群分享心得而建立的開源框架中,找到這個 Vite 外掛程式,以及本文分享的許多其他技巧。

4. 不同互動需要不同的 API

ChatGPT 應用程式的小工具、伺服器和模型之間,有多條互動路徑。這些路徑無法互相替代:每條路徑都是為了支援不同類型的互動而存在。

打造 ChatGPT 應用程式的一項重要心得,就是明確定義這些通訊路徑,並仔細決定由哪個機制負責體驗中的哪個部分。

將這些路徑畫出來,大致如下:

小工具、伺服器和模型之間各種互動的示意圖

這些心得確立了 ChatGPT App 的基礎:如何分享上下文、如何讓模型掌握資訊,以及不同互動如何在系統中傳遞。下一節將以此為基礎,探討這些做法對 UI 設計的影響。

為 AI 重新設計 UI

ChatGPT 應用程式是一個全新的環境,因此我們很快就學會放下對 UI 的既有想法,充分運用新的能力。本節將介紹為了打造實用的應用程式,我們需要學習,以及需要放下的介面設計觀念。

5. UI 必須適應多種顯示模式及其限制

ChatGPT 應用程式並不局限於單一版面配置。視啟用的方式與時機而定,同一個小工具可以透過三種不同的顯示模式呈現。

應用程式可以 內嵌 在對話中、以 子母畫面(PiP) 懸浮於對話上方,或在需要更多空間時以 全螢幕 顯示。PiP 和全螢幕雖然能呈現更豐富的介面,卻也會帶來小工具無法控制的 UI 覆蓋元素。設計時必須考慮各裝置的安全顯示區域,例如為行動裝置上固定顯示的關閉按鈕預留空間,才能避免內容遭到裁切,並改善互動體驗。

隨著經驗累積,我們歸納出各種顯示模式的特點與適用時機:

呈現方式使用時機
內嵌預設顯示模式。小工具會保留在對話記錄中。適合快速互動
全螢幕小工具佔滿整個螢幕,對話列位於底部。小工具較複雜且需要大量空間時,例如地圖
子母畫面尺寸與內嵌模式相同,但小工具會持續懸浮於對話上方小工具產生後,在後續對話中仍會用到時

6. 在嵌入式環境中,UI 一致性很重要

一開始,我們不確定 ChatGPT App 的視覺設計應該有多大的自由度。對使用者而言,這是全新的介面,卻仍需要讓人感到熟悉且一致,不僅我們自己的各個應用程式要保持一致,也要與周圍的 ChatGPT 生態系統協調。小工具與獨立產品不同,它存在於既有的介面之中,任何視覺上的不一致都會立刻顯得突兀。

幸好,OpenAI Apps SDK UI Kit 為我們提供了明確的基準。

它以 Tailwind CSS 為基礎,提供符合 ChatGPT 設計系統的現成元件、圖示與設計 Token。使用這套工具讓我們能快速開發,同時確保小工具自然融入周圍介面,維持一致的視覺風格;即使開發自訂元件(例如整合 Mapbox 所需的元件)也是如此。

7. 以自然語言為主的篩選方式

傳統儀表板的側邊欄充滿核取方塊與範圍滑桿。但在智慧體式 UI 中,這往往反而是一種退步。當使用者可以直接以自然語言表達意圖,例如「預算低於 $200、陽光充足的歐洲目的地」,卻仍被迫操作多個 UI 控制項,只會增加操作阻力。他們應該只要說出需求就好。

因此,我們決定讓大多數應用程式採用「不設篩選器」的做法。我們不在側邊欄提供篩選與排序選項,而是向模型提供工具參數的 值清單(LOV)

這讓模型能直接以使用者的訊息作為輸入,不必「猜測」有哪些可用選項。換句話說,模型可以將自然語言直接對應到後端 API 的要求。如果使用者說「陽光充足」,模型就知道要以 weather="sunny" 呼叫工具。

8. 檔案能帶來更豐富的互動

隨著我們開發的應用程式日益複雜,我們體會到不該把檔案當作次要輸入。在 ChatGPT 應用程式中,檔案能帶來新的互動方式。使用體驗不必從表單或篩選器開始,也可以從使用者手邊已有的東西開始。

例如,在電子商務應用程式中,使用者可以在對話中上傳商品照片,讓模型辨識,再直接於小工具中尋找相符商品或探索其他商品。

要做到這一點,關鍵是讓檔案能在系統的兩端流通。在模型端,工具可以透過 openai/fileParams 直接使用對話中上傳的檔案,讓模型針對圖片或使用者提供的其他素材進行推理。在 UI 端,小工具也能透過 window.openai.uploadFilewindow.openai.getFileDownloadUrl 直接處理檔案,在 UI 流程中要求使用者上傳檔案,或產生可供使用者下載並重複使用的檔案。

邁向正式環境

接著,當應用程式不再只在本機開發時,就需要考量安全性、組態與工具等不同面向的問題。這正是第三組經驗要談的內容。

9. CSP 成了新一代的 CORS 課題

基於安全性考量,OpenAI 會在雙層巢狀 iframe 中呈現應用程式。內容安全性政策(CSP)是 iframe 隔離的原生機制,而這種架構會嚴格執行政策,因此經常出現典型的「本機能跑,正式環境卻出問題」現象。

在傳統網頁開發中,寬鬆的政策或許還能應付,但 Apps SDK 要求你精確設定。

這表示你必須在應用程式資訊清單中,仔細宣告每種互動類型允許使用哪些網域:

欄位用途範例常見錯誤
connectDomainsAPI 與 XHR 請求https://api.weather.com忘了區分預備環境與正式環境的 API。
resourceDomains圖片、字型、指令碼https://cdn.jsdelivr.net使用 delivr.net 等通用 CDN,卻未將其加入允許清單
frameDomains嵌入 iframehttps://www.youtube.com嵌入 YouTube 影片或 Mapbox 執行個體,卻未將其加入允許清單。
redirectDomains開啟時不顯示警告的外部連結https://app.alpic.ai遺漏結帳或 OAuth 回呼的網域。

從一開始就重視 CSP 組態,讓我們後來省下了大量在正式環境中除錯的時間。

10. 小工具旗標雖小,影響卻很大

除了 CSP 之外,還有少數小工具層級的設定,會決定小工具、模型與主機環境之間如何分配控制權。這些旗標很容易被忽略,卻界定了導覽、工具存取與發布的重要邊界。

主機與導覽的邊界

  • 提交時必須提供 widgetDomain 。它定義了全螢幕模式下「在 <App> 中開啟」按鈕的預設目標位置,也用於來源允許清單,因為小工具是在 <widgetDomain>.web-sandbox.oaiusercontent.com 下呈現。我們使用 setOpenInAppUrl,根據上下文將使用者導向適當路徑。

模型與工具的邊界

  • 工具註解 必須遵循發布準則。readOnlydestructiveHintopenWorldHint 等旗標是必填項目,提交時也會進行驗證。
  • 工具可見性 很重要:不應讓模型呼叫的工具,必須明確標記為私有。

小工具執行的邊界

  • widgetAccessible 控制小工具是否能自行透過 callTool 呼叫工具。

這些設定單看都是小細節,但合在一起,就決定了應用程式發布後能否正確運作。

為快速迭代做好準備

Apps SDK 正快速演進,能在它持續發展的同時投入開發,讓我們相當興奮。為了讓開發工作流程更順暢、更有效率,我們決定開發自己的開源框架,並分享給社群。以下是我們整理的一些經驗,幫助大家避開我們初期遇到的開發體驗問題。

11. 快速迭代需要熱重載

迭代速度是我們最先著手改善的問題之一。資源快取的 TTL 很長,加上資源透過 JSON-RPC 轉送,使得 Vite 或 Next.js 中常見的標準模組熱重載,無法直接用於 ChatGPT 應用程式。

我們花了不少時間了解 Vite 的內部運作後,開發了一個 Vite 外掛程式,讓小工具能直接在 ChatGPT 內即時重新載入。這個外掛程式會攔截送往 MCP 伺服器的資源請求,並將即時更新注入 ChatGPT 的 iframe。在 IDE 中做出的變更能立刻反映在 ChatGPT 裡,大幅縮短了我們取得回饋的時間。

展示熱重載實際運作的 GIF 動畫

12. 並非所有測試都需要在 ChatGPT 中進行

在 ChatGPT 上測試是最可靠的標準,但在最初幾輪迭代中,本機模擬器能幫助你更快推進,尤其是在修改工具定義、需要於開發人員模式中重新載入應用程式時。

為了加快初期迭代,我們打造了一個輕量的本機模擬器,用來模擬 ChatGPT 主機環境,並配備除錯工具與應用程式專用記錄。這讓我們能以毫秒級的速度反覆調整 React 狀態與版面配置,再到真正的 ChatGPT 環境中驗證模型互動與邊界情況。

13. 行動裝置測試需要專門支援

行動裝置測試帶來了另一個挑戰:在 ChatGPT 中測試時,必須為本機伺服器建立通道連線,但 Vite 預設使用 localhost,導致其他裝置無法存取同一個 URL。

我們擴充了 Vite 外掛程式,讓它支援通道連接埠上的網域轉送,藉此解決問題。這讓我們能在 iOS 與 Android 裝置上測試,也讓行動裝置驗證成為日常工作流程的一部分。

14. 熟悉的抽象介面(例如 React 掛勾)能加快前端開發

Apps SDK 提供了強大的能力,但主要透過低階 JavaScript API 開放使用。身為長期使用 React 的開發者,我們希望能透過已經熟悉的概念來使用這些能力。

因此,我們加入了一些適合 React 的抽象介面,包括 useCallTooluseWidgetStateuseLocale 等掛勾,以及以 Zustand 為基礎、用來處理複雜資料流程的 createStore 等進階狀態管理工具。重新引入熟悉的前端模式,減少了樣板程式碼,也讓小工具開發更接近現代網頁開發的工作流程。

將經驗轉化為 Codex 技能

15. 將經驗轉化為可重複使用的工具

當這些模式在多個應用程式中反覆出現,我們逐漸意識到,一再重新摸索相同做法正在拖慢開發速度。為了讓 ChatGPT App 開發更快速、過程更可預期,我們決定將這些經驗直接融入工具中,不僅供自己使用,也分享給社群。

這促成了兩項相輔相成的成果:

  1. Skybridge Framework 這個開源 React 框架將本文介紹的許多模式封裝成可重複使用的構件,包括我們的掛勾(useCallTooluseToolInfo)、開發工具(HMR 和本機模擬器),以及 data-llm 屬性。
  2. chatgpt-apps-builder Codex 技能 我們在框架的基礎上打造了專用的 Codex 技能,支援應用程式的完整生命週期:
    • 構思: 腦力激盪,思考如何讓應用程式具備智慧體特性,而不只是移植網頁應用程式。
    • 程式碼生成: 同時編寫 React 前端與 MCP 伺服器後端,並預先套用所有合適的 UX 與 UI 模式。
    • 本機測試: 啟動開發伺服器,將本機應用程式連接至 ChatGPT,透過熱重載即時反覆調整。
    • 品質工程與發布: 依照 OpenAI 的提交指南進行有系統的檢查,包括 CSP 驗證、安全區域考量,以及正式環境測試。
    • 應用程式部署: 協助完成應用程式上線與後續改進所需的最後步驟。

若要安裝並使用這項技能,只需使用以下指令:

npx skills add alpic-ai/skybridge

結語

打造 ChatGPT 應用程式,需要重新思考上下文如何傳遞、介面如何運作,以及使用者與模型如何協作。本文的許多經驗,都來自熟悉的網頁開發模式與智慧體系統實際運作之間的落差。

我們分享這些經驗,並將它們融入開源框架與 Codex 技能,希望能讓團隊少花時間重複摸索相同問題,多花時間探索這種新互動模式帶來的可能性。最吸引人的 ChatGPT 應用程式不會只是現有產品的簡單移植,而是從這種以 AI 為優先的全新體驗出發,精心設計而成。