1. 為什麼沒有良好的 tools 與後設資料,僅靠指令是不夠的
得先承認一個不太舒服的事實:模型看不到你的程式碼。它不知道 Next.js 有哪些控制器、TypeScript 有哪些函式,也不了解你在推薦服務裡堆了哪些厲害的啟發式。
它是透過幾個介面來「看見」你的 App:
- System‑prompt(角色契約)。
- 工具的描述:名稱,description,inputSchema,outputSchema,註解等。
- 應用本身的後設資料:名稱、圖示、短/長描述、類別、conversation starters 等等。
在處理請求時,模型會查看對話上下文與這些後設資料,以決定:
- 是否需要建議某個 App;
- 若需要 — 在可用的 App 中該選哪一個;
- 若已選定 App — 該用此 App 的哪個工具來對應目前的請求。
在模組 5 的上一部分,我們處理了能用文字「告訴」模型的內容 — system‑prompt 與 UX 指令。現在轉向它在文字之外能看見的東西:tools 與後設資料。
因此,模組 5 的任務其實是雙重的。你先在 system‑prompt 中定義「這個 App 應該做什麼、如何行為」,然後在 tools 與後設資料的設計中,把它包裝成模型真正能使用的形式 — 包含 discovery 與路由。
可以這樣理解:system‑prompt 是「憲法」,而 tools 與後設資料就是「法律與官僚體系」:申請表、資料庫綱要等。只靠憲法是走不遠的。
2. 拆解:「一個任務 — 一個 tool」,但要拿捏分寸
先談最棘手的:到底要做多少工具、怎麼切。
直覺的原則是:一個工具對應一個清楚的任務。這能大幅降低模型的選擇難度:它面對的不是一個巨大的函式 do_everything,而是幾個命名良好的小動作。
以 GiftGenius 為例,可能的基礎工具有:
- profile_to_segments — 把對收禮者的自由描述(年齡、興趣、關係、情境)轉成標準化的分段,如 "tech"、"fitness"、"gamer"。
- recommend_gifts — 依分段、預算、在地化與場合挑選禮物的 id 清單。
- get_gift — 依禮物 id 取得完整卡片(描述、媒體、SKU/變體)。
- (可選) similar_gifts — 針對已選禮物,再提供 3–5 個相似選項。
理論上也能做成一個 gift_tool,用參數 mode: "profile_to_segments" | "recommend" | "details" | "similar" 來切換,但那會讓你和模型都更痛苦:描述會變成長篇大論,inputSchema 會膨脹,而模型在挑工具時少了清楚的錨點。
反模式:God Tool
想像如下:
server.registerTool(
"gift_tool",
{
description: "與禮物相關的各種操作。",
inputSchema: { /* 50 個欄位與旗標 */ },
},
async ({ input }) => { /* 依據 mode 的巨大 switch */ }
);
在模型看來,這就像是「有個關於禮物的抽象工具,之後再想辦法」。這會降低選擇的精準度、妨礙 discovery,也增加你的維護成本。
但走到另一個極端 — 為每個小動作做 50 個微型工具 — 也不好。每多一個工具就會進入上下文、佔用模型注意力,並提高路由出錯的風險。文件也明說:太多細碎且描述互相重疊的工具會降低品質。
實用規則:
- 凡是使用者感知為流程中的單一步驟(例如依個人檔案做第一次禮物挑選),都是獨立 tool 的好候選;
- 而那些一定在此步驟內部執行、沒有獨立意義的事(例如計算評分、記錄檢視卡片),最好留在工具的實作裡。
假設你依此原則把情境切成 2–4 個工具。下一個重要問題是 — 如何描述這些工具的輸入,讓模型不必猜。先從這裡開始。
3. 把 use‑cases 投影到 Input Schema
接著挑一個具體的 use‑case,老實看看這個工具實際需要哪些資料。
情境:「送禮者時間緊迫:為 25 歲、愛足球和桌遊的朋友,在 50 美元預算內挑出 5–7 個點子」。
從 jobs‑to‑be‑done 的角度,GiftGenius 的推薦核心任務是把選項縮小到少量清單,並降低「萬一我選錯」的焦慮。在聊天層面,助理需要:
- 收禮者的基本資訊(年齡、性別、與送禮者的關係);
- 興趣/嗜好;
- 預算與貨幣;
- 場合(生日、週年、新年等);
- 可選 — 國家/城市,用於配送篩選。
在 GiftGenius 的架構中,這被拆成兩步:
- profile_to_segments(input) 接受「原始」資料(年齡、興趣、文字描述),並轉為標準化的分段,便於後續處理。
- recommend_gifts(segments, budget, locale, occasion) 依分段與預算,從目錄中挑選具體的 id 禮物。
就 ChatGPT ↔ MCP 的契約而言,重要的是描述第二步 — recommend_gifts 的綱要,因為大多數挑選情境都會用到這個工具。
同時不必一開始就向使用者要求所有資訊:模型可以透過追問補齊(例如「大概的預算是多少?」)。因此個人檔案中的部分欄位可以是選填;但當我們走到 recommend_gifts 時,參數就應該已經正規化。
範例:TypeScript + JSON Schema 用於 recommend_gifts
在 TypeScript 的 MCP 伺服器中,可能長這樣:
// apps/mcp/server.ts
import { McpServer } from "@openai/mcp-server";
const server = new McpServer();
server.registerTool(
"recommend_gifts",
{
title: "禮物推薦",
description:
"當需要根據收禮者分段、預算、在地化與場合來挑選禮物時,使用此工具。",
inputSchema: {
type: "object",
properties: {
segments: {
type: "array",
description:
"收禮者的分段清單,例如 ['tech', 'football_fan']。通常來自 profile_to_segments。",
items: { type: "string" },
minItems: 1
},
budget: {
type: "object",
description:
"以使用者貨幣表示的禮物預算範圍(最小/最大)。",
properties: {
min: {
type: "number",
minimum: 0,
description: "使用者願意花費的最小金額。"
},
max: {
type: "number",
minimum: 0,
description: "使用者願意花費的最大金額."
},
currency: {
type: "string",
minLength: 3,
maxLength: 3,
description: "三個字母的貨幣代碼(例如 USD、EUR、RUB)。"
}
},
required: ["min", "max", "currency"]
},
locale: {
type: "string",
description:
"使用者的在地化,BCP‑47 格式(例如 'ru-RU' 或 'en-US')。"
},
occasion: {
type: "string",
description:
"送禮場合,例如 'birthday', 'new_year', 'anniversary'."
}
},
required: ["segments", "budget", "locale", "occasion"]
}
},
async ({ input }) => {
// 這裡先不聰明,先回傳假資料
return {
content: [
{
type: "text",
text: `正在依據分段 ${input.segments?.join(
", "
)} 與預算 ${input.budget?.min}–${input.budget?.max} ${input.budget?.currency} 挑選禮物…`
}
],
structuredContent: {}
};
}
);
注意幾點。
首先,積極使用類 enum 的限制與清楚的描述。就算形式上只是字串,description 也能暗示模型期望的值,顯著提升它正確填入參數的機率。相比於含糊的字串 "場合": "大概像是生日之類",我們有清楚的 occasion: "birthday"。
其次,欄位描述不是「寫給團隊的人看」,而是要當成給模型的提示:這是什麼欄位、典型值、是否有範例。Apps SDK 的作者明確建議為每個參數加入易懂的 descriptions 與範例。
輸入綱要中不該出現的東西
常見但不該塞入的雜訊欄位:
- 內部識別碼(tenantId、internalSegment),這些可在伺服器端自行補上;
- 模型不可能知道的東西(例如 deploymentRegion)— 這是你的責任範圍;
- 與聊天記錄重複的欄位(例如 userPrompt):模型本來就看得到原始訊息,不要逼它複製貼上。
Input Schema 描述的是模型需要 決定並填入 的東西,而不是萬用大雜燴。
4. Output Schema:不只資料,也要語意
在 Apps SDK 中,工具的結果會以訊息 role: tool 回到對話。接著由模型決定如何處理:如何整理回答、要問哪些追問、是否開啟小工具等。因此,輸出綱要的設計一點也不比輸入差。
有兩種做法。
做法一:回傳「原始資料」:
{
"items": [
{ "id": "GIFT_1" },
{ "id": "GIFT_2" }
]
}
模型只看到 id 清單,理解不到為什麼會有這些選項、總共有多少候選、哪些是最好的。它可能會自己腦補,但出錯的機率更高。
做法二:語意更豐富:
{
"items": [
{
"id": "GIFT_1",
"score": 0.92,
"reason": "與 'football_fan' 分段高度匹配,並且符合預算。"
},
{
"id": "GIFT_2",
"score": 0.81,
"reason": "適合桌遊愛好者,價格稍接近預算上限."
}
],
"meta": {
"totalCandidates": 27,
"returned": 5,
"segmentsUsed": ["football_fan", "board_games"],
"budget": { "min": 20, "max": 50, "currency": "USD" },
"advice": "建議先從分數最高且理由清楚的選項開始。"
}
}
如此一來,模型就能坦率解釋為什麼是這些禮物,並繼續走後續互動:「我找到 27 個候選,先展示 5 個最佳,原因如下」。
範例:為 recommend_gifts 描述 Output Schema
把結果綱要也補進工具描述裡(即便技術上可以不填,最好也寫清楚 — 這是與模型的契約的一部分):
const recommendGiftsOutputSchema = {
type: "object",
properties: {
items: {
type: "array",
items: {
type: "object",
properties: {
id: { type: "string", description: "目錄中的禮物 ID。" },
score: {
type: "number",
description: "與個人檔案的符合度評分(0..1)。"
},
reason: {
type: "string",
description:
"為什麼適合的簡短解釋(可由後端產生)。"
}
},
required: ["id", "score"]
},
description: "帶有相符度評分的推薦禮物列表。"
},
meta: {
type: "object",
properties: {
totalCandidates: {
type: "integer",
description: "目錄中總共找到幾個候選。"
},
returned: {
type: "integer",
description: "本次呼叫回傳了幾個禮物。"
},
advice: {
type: "string",
description:
"一般建議:例如建議先從哪種禮物開始。"
}
}
}
},
required: ["items"]
};
接著在實作中使用此綱要:
server.registerTool(
"recommend_gifts",
{
title: "禮物推薦",
description:
"在需要依分段與預算挑出 3–7 個禮物時使用。回傳禮物 id 與符合度評分;詳細卡片請透過 get_gift。",
inputSchema: /* 如上 */,
// 不一定都會正式填寫 outputSchema,但作為文件很有幫助:
// outputSchema: recommendGiftsOutputSchema
},
async ({ input }) => {
const recommendations = await recommendFromCatalog(input); // 我們的商業邏輯
return {
content: [
{
type: "text",
text: `我找到了 ${recommendations.items.length} 個合適的點子。現在先展示最好的。`
}
],
structuredContent: {
items: recommendations.items,
meta: {
totalCandidates: recommendations.meta.totalCandidates,
returned: recommendations.items.length,
advice: recommendations.meta.advice
}
}
};
}
);
我們同時做兩件事:給模型一段最小的使用者可讀文字,並提供語意化的 JSON,讓它能依此推進對話與追問。
同時, get_gift 會依 id 取得完整卡片(名稱、媒體、SKU 等),而 GiftGenius 的小工具會把它們渲染成禮物卡片。
5. 工具的命名與描述是 discovery 的根基
接著是重點:工具的名稱與描述會如何影響模型是否會呼叫它。
文件與最佳實務建議:
- 使用動作導向的名稱:profile_to_segments、recommend_gifts、get_gift、similar_gifts,而不是 tool1、search、do_stuff;
- 用「Use this when… / 當…時使用此工具」開頭,描述觸發情境與限制(「不要用於…」)。
這與你的 golden prompt set 直接相關。描述中的文字應該和真實的使用者請求重疊。若你在描述中寫著「當使用者要求依預算與收禮者興趣挑選禮物時使用」,而在 golden prompt 中有「幫我在 50 美元內為喜歡電玩的朋友挑禮物」,模型會更容易把請求對應到工具。
範例:好的工具描述
以 GiftGenius 的另一個工具 — similar_gifts — 為例,它能根據特定禮物擴充推薦清單:
server.registerTool(
"similar_gifts",
{
title: "相似禮物",
description:
"當使用者已選定某個禮物,並希望再看到幾個相似選項時,使用此工具。不要用於從零開始的第一次挑選 — 那請使用 recommend_gifts。",
inputSchema: {
type: "object",
properties: {
giftId: {
type: "string",
description:
"前一次挑選中的禮物識別碼,用來尋找相似選項。"
},
limit: {
type: "integer",
description:
"要回傳多少個相似禮物(預設 3–5)。",
minimum: 1,
default: 5
}
},
required: ["giftId"]
}
},
async () => {
/* ... */
}
);
重點:
- 明確說清楚什麼時候使用、什麼時候不該使用。
- 描述中包含「相似選項」、「選定了某個禮物」等詞彙 — 這些正是使用者請求中常見的用語。
- 避免與 recommend_gifts 的領域重疊 — 可降低工具之間在選擇時的競爭。
範例:不良的描述
description: "處理禮物."
模型幾乎無法從這種描述獲得資訊。這類工具只有在 GPT 已經「盲打」的情況下才可能被觸發。
6. 註解與 hints:如何讓模型理解動作的嚴重性
工具不只是名稱與綱要,還有能提示 ChatGPT 行為風險/重要性的註解,告訴它是否需要向使用者確認。在 Apps SDK 規格中有多種 hints,例如 readOnlyHint、destructiveHint、openWorldHint 等。
- readOnlyHint: true 表示工具只讀、不改變狀態。助理可以省略多餘確認並更自由地呼叫。
- destructiveHint: true 表示工具可能刪除或不可逆地修改東西,因此要向使用者顯示「你確定嗎?」。
- openWorldHint: true 表示這個動作會觸及外部世界(例如發社群貼文、在帳號之外建立資料),也要提醒使用者。
最低等級 — 不需額外確認
若你有 public readonly tools,建議標記為 readOnlyHint: true。例如:
"annotations": {
"readOnlyHint": true,
"destructiveHint": false,
"openWorldHint": false
}
這類工具可以在 GPT 端少掉多餘的對話式確認,較為自由地呼叫。
一次確認
若你的工具會改變伺服器端狀態,建議標記為 readOnlyHint: false:
"annotations": {
"readOnlyHint": false,
"destructiveHint": false,
"openWorldHint": false
}
模型看見這種工具,多半會向使用者要求一次確認(通常是 ChatGPT UI 中的模態對話框)。
危險操作
若有工具會刪除伺服器上的東西,請標記為 destructiveHint: true:
"annotations": {
"readOnlyHint": false,
"destructiveHint": true,
"openWorldHint": false
}
模型會非常謹慎地呼叫,並進行兩次確認:
- 先在文字中向使用者確認,
- 然後平台會顯示標準的對話框。
在本模組的 GiftGenius 裡,我們暫不撰寫 commerce‑工具,但可以先勾勒未來的 create_gift_order:
server.registerTool(
"create_gift_order",
{
title: "建立禮物訂單",
description:
"僅在使用者明確同意購買所選禮物後才使用。會在系統中建立訂單並回傳狀態。",
inputSchema: {
type: "object",
properties: {
giftId: {
type: "string",
description: "使用者選定的禮物 ID。"
},
deliveryEmail: {
type: "string",
description: "要傳送數位禮物的電子郵件地址。"
}
},
required: ["giftId", "deliveryEmail"]
},
annotations: {
destructiveHint: true,
openWorldHint: true
}
},
async () => {
/* ... */
}
);
註解不能替代你在伺服器端的權限檢查;它們只是協助 ChatGPT 設計 UX:詢問確認、顯示警告,並避免「背地裡」執行這類工具。
7. App 後設資料與兩個層級 discovery
工具只佔一半。另一半是使用者要如何找到並啟動你的 App。
在 ChatGPT 生態中有兩個關鍵的 discovery 層級。
第一 — in‑conversation discovery。當使用者在聊天中輸入內容(即便沒有明確提到 App),模型會看:
- 訊息文字與對話歷史;
- 可用應用與其工具的描述;
- 品牌提及、主題與關鍵詞。
基於此,模型決定是否要推薦某個 App,若要 — 推薦哪個、用什麼情境。此處尤其仰賴工具與 App 的描述。若其中包含「挑選禮物」、「禮物點子」、「禮物預算」等觸發字眼,模型選中你 App 的機率會大增.
第二層 — 全球 discovery:目錄與 launcher。這裡由人來選:他會依名稱、圖示、短描述與標籤來挑 App。因此你要誠實、清楚地說明你的應用做什麼、面向誰、核心價值是什麼。
可以整理成一個小表格:
| 層級 | 模型/使用者看到什麼 | 後設資料的重點 |
|---|---|---|
| In‑conversation | 對話文字、tools 與 App 的描述 | 觸發式措辭、動作導向命名、限制條件 |
| 目錄/launcher | 名稱、圖示、short/long description、標籤 | 清楚定位、易懂的價值主張 |
以 GiftGenius 為例,可這樣表述:
- 名稱:GiftGenius — 60 秒內挑選禮物。
- 簡短描述:蒐集收禮者的個人檔案,提供 5–7 個禮物點子,並可在 ChatGPT 內即時購買。
- 對話中描述(in‑conversation):當使用者請你幫忙挑選禮物、不知道要送什麼、提出預算、收禮者興趣或場合時,使用此應用。
這些表述最好與你在 system‑prompt 和工具 recommend_gifts 的描述保持一致。如此模型才能看到一個整體,而非互相矛盾的片段。
8. ChatGPT「腦中」的路由是怎麼運作的
把以上彙整起來,看一個典型流程 — 不深入 MCP 協定,該部分留到後續模組。
假設使用者輸入:
「幫我想一個送給弟弟的禮物,他超愛足球和桌遊,預算 50 美元以內。」
大致簡化的流程:
- 模型分析訊息與歷史。辨識出詞彙:「禮物」、「弟弟」、「足球」、「桌遊」、「預算 50」。
- 拿這些與可用 App 及其工具的描述比對。對 GiftGenius 而言,描述明確包含「依興趣與預算挑選禮物」,因此相當吻合。
- 若該 App 尚未在此工作階段啟用,模型會給一段引言:「我可以開啟 GiftGenius,幫你依參數挑選禮物。要開啟嗎?」— 這在我們的 UX 指令中已預先規劃。
- 在使用者同意後,模型會在 App 內選擇工具 recommend_gifts,因為它的名稱、description 與 inputSchema 最符合當前意圖。
- 模型依請求填入工具參數:必要時先呼叫 profile_to_segments,將文字「弟弟、喜歡足球和桌遊」轉成分段 ["football_fan", "board_games"],再用 segments、budget: {min: 0, max: 50, currency: "USD"}、locale、occasion: "birthday" 呼叫 recommend_gifts。
- MCP 伺服器執行工具,產生含 items 與 meta 的結構化輸出並回傳。
- 模型讀取你在 outputSchema 描述的 JSON,組織回覆:解釋找到什麼、為何是這些,並提出追問(「要不要依類別縮小?」「要不要顯示這個禮物的相似項?」或「要不要為這個禮物下單?」)。
以下是一張簡單的流程圖:
flowchart TD A[User:關於禮物的請求] --> B[ChatGPT 分析脈絡] B --> C[與 App 與 tools 的後設資料比對] C -->|相關| D[GiftGenius 引言] D -->|使用者同意| E["呼叫 recommend_gifts(+ profile_to_segments)"] E --> F[GiftGenius 的 MCP 伺服器] F --> G[含 items/meta 的 JSON 結果] G --> H[模型組織回覆並提出後續問題]
工具與 use‑case 描述得愈好,這裡的隨機性就愈小,路由就愈穩定。
洞見:Tool Call SEO
在 Apps 生態中,你很快不僅要爭取人類在目錄中的注意,還要爭取 模型本身的注意。對同一個使用者請求,ChatGPT 可能會考慮好幾個應用;選擇不是看誰的簡報設計好,而是在模型腦中的「搜尋結果」。這個隱形層越來越像 SEO,只是頁面換成了 tools 與 MCP 伺服器。
模型其實在做排序:先在 App 層級,再在各工具層級。它查看名稱、descriptions、綱要、註解,並與請求的措辭比對。若在 recommend_gifts 的描述裡有「依預算與收禮者興趣挑選禮物」,而請求是「幫我替電玩迷在 50 美元內選禮物」,它就比抽象的 search(描述為「處理禮物」)更可能排到「前幾名」。
由此產生實務上的想法 Tool Call SEO:把名稱、descriptions、enum 值與後設資料當作關鍵字與摘要。你不只是寫給開發者看的契約 — 你也在為自己的 golden prompt 流量做優化。過度籠統的表述、領域重疊的多個工具、沒有明確定位的 God 工具 — 都會降低你在模型腦中的「CTR」。
9. 小型實作練習
試著在腦中(或在你的儲存庫)做做看。
先選一個 GiftGenius 的關鍵情境 — 例如,「在有限預算下,替同事挑禮物」。
為它定義:
- 這需要哪個獨立工具:是單用 recommend_gifts 就好,還是需要 B2B 專用工具?或者在 recommend_gifts 之後用 similar_gifts 來產生變化即可?
- recommend_gifts 的輸入綱要裡,哪些欄位真的必要?哪些可以透過追問向使用者取得,而不是讓模型去猜。
- outputSchema 應該長怎樣,才能讓模型坦率解釋選擇並提出下一步(例如切到 B2B 模式、只顯示數位禮物、或縮小價格範圍)。
接著回看你在上一堂課整理的 golden prompt set 並檢查:
- 每個基準請求是否都有對應明確的工具(recommend_gifts、get_gift、similar_gifts 等);
- 是否出現兩個工具同樣「適用」於同一請求(overlapping tools);
- 是否該強化描述或重新命名某個 tool,以降低模型混淆。
每次你對 prompt、綱要或邏輯做重大變更前,都要重複這個流程 — 本質上是一個關於 discovery 品質的迷你評估。
若把以上濃縮為清單,此階段你需要:
- 把情境誠實地切成 2–4 個有意義的工具;
- 細緻描述 inputSchema/outputSchema,附上範例與 enum;
- 整理好名稱、descriptions 與註解;
- 與 system‑prompt 與 App 後設資料保持一致。
在後續模組中,我們會看這一切如何透過 MCP 運作,以及如何診斷 discovery/路由的怪異行為。
10. 設計 tools 與後設資料的常見錯誤
錯誤 #1:「我們都寫在 system‑prompt 了,工具自己會搞定」。
就算你把 App 的角色、責任邊界與 UX 行為寫得再好,但工具名稱仍是 tool1、search、do_stuff,綱要沒有描述,模型也無法把你漂亮的文字連到實際呼叫。對 ChatGPT 而言,工具才是主要介面;沒有良好的後設資料,再強的 system‑prompt 也救不了。
錯誤 #2:包山包海的 God Tool。
想要「優化」成一個帶參數 mode 的函式可以理解,但會導致巨無霸 JSON 綱要、描述混亂、路由變差。模型開始猜要用哪個模式,而你得在伺服器維護一個巨大的 switch。與其如此,不如針對情境中的特定步驟切成幾個明確工具。
錯誤 #3:輸入綱要塞滿了「以防萬一」的欄位。
開發者常想一次把所有可能用到的參數都塞進 inputSchema,再加幾個內部欄位。結果模型試圖猜它不可能知道的東西(例如 tenantId),然後你對奇怪數值感到困惑。Input Schema 只能包含模型可從對話推得或可透過追問取得的內容。內部細節請在伺服器端補上。
錯誤 #4:啞巴式輸出資料,沒有中介資訊。
只回傳陣列很誘人。但這讓模型失去對 為什麼 這些結果會出現的理解。沒有像 score、reason、searchCriteria、totalCandidates 之類的欄位,它更難做出坦率的說明與追問。加上一點 meta 包裝(搜尋條件與建議)經常能大幅提升答案品質。
錯誤 #5:千篇一律的描述:「處理禮物」、「搜尋課程」、「資料處理」。
這類描述的問題在於既沒有觸發點,也沒有邊界。模型不知道何時該呼叫工具、或它適用的領域。好的描述以「當…時使用此工具」開頭,包含具體情境與禁止用法。最好這些措辭能與你的 golden prompt set 中的黃金請求相呼應。
錯誤 #6:忽略註解,將唯讀與改變狀態的動作混在一起。
如果你不標記只讀工具(readOnlyHint)與會執行動作的工具(destructiveHint、openWorldHint),模型無法建立正確的確認 UX。結果不是每一步都在問「你確定嗎?」、就是反過來,悄悄地下單或修改。註解是便宜又有效的方式,能提示模型操作的重要性。
錯誤 #7:用於目錄的 App 後設資料與對話內的後設資料各過各的。
有時目錄裡的短描述由行銷撰寫(「革命性的 AI 助理,改變你的生活」),而 descriptions tools 與 system‑prompt 由工程師撰寫(「依預算挑選禮物」)。結果是目錄看不出 App 在做什麼,而模型在聊天中也難以把像「這是什麼服務?」的請求與 App 的實際能力對上。請把後設資料當作一份統一規格來寫,而不是兩份互不相干的行銷文本。
GO TO FULL VERSION