CodeGym /課程 /ChatGPT Apps /工具與 description 的本地化:對 GPT 的影響與行為實驗

工具與 description 的本地化:對 GPT 的影響與行為實驗

ChatGPT Apps
等級 9 , 課堂 3
開放

1. 模型如何「看見」你的工具

先說在前面,對模型而言,tool 並不是「你用 TypeScript 寫的漂亮函式」,而是如下風格的結構化說明:

  • name:技術名稱,例如 "search_gifts"
  • description:給人看的自然語言文字,解釋何時以及為什麼要使用此工具;
  • inputSchema:包含欄位的 JSON Schema,每個欄位也可以有 description、型別與限制。

非常簡化地說,模型大概會這樣做(GPT 腦中的偽代碼):


1. 讀取使用者請求(可為任何語言)。
2. 讀取工具清單:name + description + 參數說明。
3. 為每個 tool 估計是否適合這個任務。
4. 若需要 tool —— 依據 schema 產生帶參數的 JSON。
5. 否則 —— 以文字回覆。

這裡有兩個重點結論。

首先,工具的 description 並不是給開發者看的註解,而是模型與你後端之間的介面。如果描述含糊、資訊不全,或與使用者語言不一致,模型更容易出錯:挑錯 tool、填錯參數、該用工具時卻直接回文字等。

其次,JSON Schema 欄位裡的 description 同樣重要,不亞於工具本的描述。模型真的會讀每個屬性的 description,並據此判斷該把「年齡」放在哪個欄位、「預算」放哪裡,以及哪裡該是 id

GiftGenius 小範例

拿我們的工具 search_gifts 來說。在原始「僅 EN」版本中,它可能長這樣:

// server/tools/searchGifts.ts
export const searchGiftsTool = {
  name: "search_gifts",
  description: "Search for gift ideas based on user preferences.",
  inputSchema: {
    type: "object",
    properties: {
      recipient_age: {
        type: "integer",
        description: "Age of the recipient in years.",
      },
      budget: {
        type: "number",
        description: "Maximum budget in user's currency.",
      },
    },
    required: ["budget"],
  },
};

如果使用者寫:「需要一份送給媽媽的禮物,她 60 歲,預算不超過 3000 盧布」,模型應該:

  1. 判斷 search_gifts 是合適的工具。
  2. 了解「60 歲」要放在 recipient_age,而「3000 盧布」要放在 budget

當描述只有英文時,GPT 通常仍能處理,但它需要多做一步「內部翻譯」。在多語環境與較弱模型上,這會影響準確度。

2. 多語 App 中「英語描述」的問題

在模組 9 我們曾略談本地化的「全圖」:UI 小工具、目錄、錯誤、商務文案。現在聚焦當工具描述只有英文,但使用者以俄文或西文互動時會發生什麼——混亂就從這裡開始。

典型流程:

  1. 使用者:「幫我挑一份給 IT 朋友的禮物,預算 50 歐元以內」。
  2. 模型查看 tools 清單,發現描述只有 EN。
  3. 如果請求也是 EN —— 一切順利。
  4. 如果請求是其他語言,它必須:
    • 先理解請求,
    • 再把它在腦中對照英文描述,
    • 選出工具,
    • 還要把參數抽取成 JSON。

在強模型上尚可,但會出現:

  • 不調用工具的比例上升——模型「認為」自己能直接回答;
  • 參數錯誤機率變高(尤其是幣別、單位、地區限制等);
  • 在多工具間的路由邏輯更不穩定(選錯工具)。

一個簡單錯誤:budget 期望「以使用者幣別」表示,但描述完全沒說。模型就假設是預設 USD,於是把應該是 50 歐元的值當成 50 美元發到後端。

這時就輪到描述的本地化上場了。

3. 本地化作法:獨立工具 vs 多語描述

有兩個基本架構作法,兩者都可行。

每種語言各自的工具

這個作法是為不同語言建立多個 tools,各自擁有對應語言的描述。

在 GiftGenius 中可能會像這樣:

export const searchGiftsEn = {
  name: "search_gifts_en",
  description: "Search for gift ideas based on user preferences.",
  // ...
};

export const searchGiftsRu = {
  name: "search_gifts_ru",
  description: "根據使用者偏好挑選禮物。",
  // ...
};

對 ChatGPT App 來說,重要的是可用 tools 清單應取決於 locale。如果 locale = "ru-RU", 你的 MCP 伺服器就只應回傳 search_gifts_ru。如果 locale = "en-US", ——就只回傳 search_gifts_en

優點是 descriptions 最「乾淨」且單語。你甚至可以把 App 當成多個單語版本,各自擁有獨立 prompts 與描述。當語言數量少且市場差異大時,這很舒服。

缺點是邏輯重複與分析上的複雜度。在後端程式碼中多半仍是同一支處理器,但在 MCP/manifest 層就變成兩個不同工具。每次修改別忘了同步更新兩邊描述。

洞察(資料截至 2025-12-01)

實驗上沒有觀察到明顯的優勢來自於讓 description 使用者語言/locale。工具的被選頻率幾乎相同,與描述語言無關。如果同時存在兩個描述相近但語言不同的工具,反而會讓 ChatGPT 困惑。

此外,你的應用需要通過 Store 的審查。因此建議直接把所有 tool description 與 argument description 都寫成英文

然而,若未來 ChatGPT 中有成千上萬個應用、對「工具選擇」的競爭加劇,則有可能使用者 locale 的語言描述會取得優勢。拭目以待 Tool Search Optimization 的出現。

單一工具 + 多語描述

第二個作法是保留一個 name(例如 search_gifts),但讓它的 description 與 JSON Schema 欄位說明成為多語版本。

可以有不同寫法:

  1. 簡短雙語:
    description: "Search gifts for a recipient. / 根據收禮者偏好搜尋禮物。",
  2. 以語言區塊標示:
    description: "[EN] Search for gifts based on user preferences. [RU] 根據收禮者偏好挑選禮物。",
  3. 以獨立欄位組合為字串(較不方便):
    description: `EN: ${enDescription} RU: ${ruDescription}`,

優點:只需一個 tool、單一真實來源(single source of truth),更容易部署帶 MCP Gateway 的架構:不論使用者用什麼語言,你對 ChatGPT 暴露的介面都一致。

缺點:描述會變長。如果語言混用不夠清楚,模型可能有點混淆——特別是英文與在地語句子交錯、缺乏明確標記如 [EN][RU] 時。

像 GiftGenius 這樣的教學專案,我們建議採混合方案:以英文為主描述,但加上簡短的在地語補充;而真正的「語意」(用什麼語言、如何稱呼使用者)則透過參數(locale)與 system‑prompt 傳遞。

4. 在地化 JSON Schema:欄位說明

接著更深入到工具的參數本身。

在 JSON Schema 中,每個欄位都可以(也應該)提供 description。模型在產生工具呼叫的 JSON 時會讀取這段文字。

在 GiftGenius 中可這麼做:

export const searchGiftsTool = {
  name: "search_gifts",
  description:
    "Search gifts based on user preferences (RU: 根據收禮者偏好挑選禮物).",
  inputSchema: {
    type: "object",
    properties: {
      recipient_age: {
        type: "integer",
        description:
          "Recipient age in years. RU: 收禮者的年齡(整數)。",
      },
      budget: {
        type: "number",
        description:
          "Maximum budget in user's currency. RU: 以使用者幣別表示的最高預算。",
      },
      locale: {
        type: "string",
        description:
          "User locale (e.g. 'en-US', 'ru-RU'). RU: 介面與回覆的語言。",
      },
    },
    required: ["budget", "locale"],
  },
};

幾點實務觀察:

第一,欄位名稱(recipient_agebudgetlocale)通常保留英語。不翻譯名稱,只翻譯 description。如此可保證 JSON 格式不會因語言而改變,你也不用維護兩套不同契約。

第二,在 description 中明確寫出幣別、單位與重要限制很有幫助,能大幅降低「歪掉」的參數。

第三,若你已使用 MCP Gateway,可以約定它會自動把 locale 注入工具參數,讓模型不必自己補上。但即便如此,為 locale 寫清楚描述仍然有用:模型會更理解這個參數是什麼、為何需要。

5. 如何選擇描述語言:真實 App 的策略

關鍵的實務問題:描述以哪個語言為主?什麼時候要完全在地化?

建議與經驗顯示,GPT 模型在英語脈絡中仍然表現最佳,許多開發者因此只保留英文描述。但對多語 App 而言,這是個折衷。

以下幾種策略可參考。

僅 EN 描述

最簡單的做法——全用英文。

優點:單一程式碼基底、單語維護,較容易寫出精確的敘述。當一切皆為英文時,模型通常更「開心」。

缺點:對用其他語言輸入的使用者而言,工具選擇與參數品質可能較差。尤其在「偷懶型」模型或參數眾多的複雜工具中更明顯。

EN + 簡短在地語尾

折衷作法:主要描述用 EN,末尾加上一小段在地語,幫助模型把使用者的詞彙對齊到參數。

範例:

description:
  "Search for gifts based on user preferences. RU: 此工具會根據收禮者描述、年齡與預算來挑選禮物。",

對 JSON Schema:

description:
  "Age of the recipient in years. RU: 收禮者年齡(以年為單位)。",

優點:模型仍處在「英文世界」,但有在地語提示可對應使用者詞彙。

缺點:描述會變長,不過通常可接受。

依 locale 完整本地化描述

最徹底的做法:工具與欄位描述依你從 ChatGPT 得知的 locale 而變化。對 en-US 回純英文描述、對 ru-RU 回純俄文、對 de-DE 回德文。

這不再是「一份永遠不變的 JSON Schema」,而是 MCP/Gateway 會動態挑選的一組 schemas。

在 MCP 層大概像這樣:

function getSearchGiftsToolDescription(locale: string) {
  if (locale.startsWith("ru")) {
    return {
      name: "search_gifts",
      description: "根據收禮者偏好挑選禮物。",
      // ru‑schema...
    };
  }
  return {
    name: "search_gifts",
    description: "Search for gifts based on user preferences.",
    // en‑schema...
  };
}

優點:模型看到的介面語言與使用者一致,體驗最佳。

缺點:維護與測試更複雜。你需要流程確保所有在地化版本在語意上保持同步,別在英文新增欄位後忘了更新德文那份。

6. 在我們的 GiftGenius 中的實作

進入具體做法。我們在 GiftGenius 採混合方案:維持一個 search_gifts 工具,描述以 EN 為主但帶俄語提示,並加入參數 locale

假設你有一個使用 MCP SDK 描述工具的 TypeScript MCP 伺服器。

// mcp/tools/searchGifts.ts
import { z } from "zod";

export const searchGiftsInputSchema = z.object({
  recipient_age: z
    .number()
    .int()
    .describe(
      "Age of the recipient in years. RU: 收禮者的年齡(整數)。"
    ),
  budget: z
    .number()
    .describe(
      "Maximum budget in user's currency. RU: 以使用者幣別表示的最高預算。"
    ),
  locale: z
    .string()
    .describe(
      "User locale (e.g. 'en-US', 'ru-RU'). RU: 介面與回覆的語言。"
    ),
});

export const searchGiftsTool = {
  name: "search_gifts",
  description:
    "Search for gifts based on user preferences (RU: 根據收禮者偏好挑選禮物).",
  inputSchema: searchGiftsInputSchema,
  // execute(...) ...
};

重點在:

  • locale 是必填。如果小工具知道它(我們可從 _meta["openai/locale"] 得知),要嘛在呼叫 callTool 時自行帶上,要嘛由 MCP Gateway 在它那邊自動注入;
  • 描述已包含關鍵在地語詞「年齡」「預算」「介面語言」,模型更容易把使用者的文字對上對應欄位。

在 Apps SDK 端,例如可以寫個函式直接呼叫這個 tool(若開啟 widgetAccessible),把小工具的 locale 傳進去。

// widget/hooks/useSearchGifts.ts
export async function searchGiftsFromWidget(params: {
  recipientAge: number;
  budget: number;
  locale: string;
}) {
  const openai = (window as any).openai;
  const result = await openai.callTool("search_gifts", {
    recipient_age: params.recipientAge,
    budget: params.budget,
    locale: params.locale,
  });
  return result;
}

這條鏈路固化了架構:locale 由 ChatGPT 傳入 → 進入 tool → tool 選對目錄與價格格式,最後你在前端漂亮地渲染。

7. 行為實驗:如何衡量本地化的影響

最有趣的是:如何判斷工具與描述的本地化真的改善了模型行為,而不只是你白忙一場?

可以直接在 GiftGenius 的 Dev Mode 做個小「實驗」。

兩個版本:base vs localized

準備兩份 App 設定:

  • base —— 工具與 JSON Schema 描述只用 EN;
  • localized —— 描述為 EN+RU(或若你願意,也可做完整 ru 版本)。

其餘(目錄、UI、prompts)保持一致,以免混入其他變因。

為了簡化:

  • 在 Dev Mode(以及更進一步在 Store)只保留 localized 版本;
  • 把 base 在本機另開分支,對一組預先準備的請求做對比。

要量什麼

三個關鍵指標:

第一——工具選擇的正確率。對一組中文(與/或其他語言)的測試請求,觀察模型:

  • 在需要工具時是否有調用;
  • 是否選到正確的 search_gifts,而不是別的 tool。

第二——參數正確性。檢查呼叫 JSON 是否符合預期:欄位不混淆、預算幣別正確、年齡為整數、locale 未遺失。

第三——怪異或無意義呼叫的數量。例如對「現在幾點?」卻呼叫 search_gifts,或把 recipient_age 填成 3000(本該是預算)。

可以手動測,也可以透過 MCP/Agents 的日誌。反正日誌未來都用得上,愈早建立這類分析習慣愈好。

如何建立手動測試集

可以準備一個小型「golden prompt set」專測本地化:

1.「我需要一份不超過 30 歐元的平價禮物,送給 10 歲女孩,她喜歡畫畫。」
2.「幫我為 35 歲的同事(程式設計師)挑一份禮物,預算 100 美元。」
3.「需要一份送給奶奶的週年紀念禮物,70 歲,預算不超過 5000 盧布。」

然後把它們分別丟進 base 與 localized 兩個版本中觀察:

  • 模型選了哪些 tools;
  • 填了哪些參數;
  • 若未調用工具,文字回覆有何差異。

半專業小撇步:可寫個簡單腳本把這些請求用 ChatGPT API 來回跑。不過在本課程中,Dev Mode 的手動測就足夠了。特別值得納入的請求類型,是語言混雜的訊息與奇怪的 locale 組合;我們會在下一節專談。

若你正在開發嚴肅的商業應用、關係到數百萬美元,那就務必針對你的應用把這些點測清楚。模組 20 專門討論專業的「golden prompt set」——務必熟悉這個主題。

8. 語言混用與奇怪的 locale 組合

沒有什麼比同時混用兩種語言的使用者更能「娛樂」LLM 開發者了。例如:

「需要禮物 for my friend,他喜歡 Star Wars,budget 100€」

我們已知道模型是多語的,通常能處理。但在語言混用與「英文描述」並存時,出錯機率會上升。

幾個常見情境:

第一——使用者用中文輸入,但工具描述是 EN。模型能理解,但偶爾會混淆,尤其在專有詞(分類名稱、罕見的欄位標籤)上。

第二——locale = "ru-RU",但使用者偏偏用英文寫。ChatGPT 給了你用俄語建 UI 的信號,但實際文字是 EN。你可以:

  • 仍回傳俄語描述,把 locale 視為第一手真相;
  • 或加入訊息語言偵測作為額外信號,依實際語言調整描述。

第三——locale = "en",但使用者偶爾插入中文詞。通常英語描述在這種情況下也表現良好。

實務上選定一套明確政策就夠了。例如:

  • locale"ru" 開頭——你就在描述中加入俄語片段;
  • 否則——描述就維持純英文。

明確規則的好處是你能針對每條分支專門測試,而不是猜今天為什麼描述突然變成了某種語言。

9. 文件、流程與「正典」語言

描述本地化不是一次性工作,而是個流程。使用者希望功能持續推出,而你希望既有東西不要壞。所以要先跟自己約法三章:

  • 哪個語言是「正典」(canonical),其他語言都以它為準;
  • 在何處保存在地化後的描述;
  • 如何檢查一致性。

通常英語是正典語言。所有新工具與欄位先用 EN 描述、通過審查,之後再本地化到其他語言。程式碼庫中可以這樣做:

  • 一個 tools.en.json 檔,完整描述 name/description/欄位;
  • tools.ru.jsontools.de.json 等檔作為各語言的「衍生版」;
  • 一個小型產生器,基於這些字典組出給 MCP 用的最終 JSON Schema。

簡化版本可以先寫在程式碼字串裡,但要有結構,之後才能輕鬆抽離成獨立字典。

別忘了描述本身也是產品文字。審查要和 UI 文案一樣嚴格:易懂、無歧義、少廢話。特別是在多語版本中,我們不希望在地語尾巴與英文主體相互矛盾。

10. 視覺化:語言如何穿越整個堆疊

為了總結,來看一張簡化的請求流程圖,納入工具描述的本地化。

flowchart TD
    U[使用者以 RU 輸入] --> C[ChatGPT UI]
    C -->|"_meta.openai/locale = 'ru-RU'"| W[GiftGenius 小工具]
    W -->|"locale = 'ru-RU'"| T["工具描述(EN+RU)"]
    T --> M[GPT 模型]
    M -->|callTool search_gifts| MCP[MCP / Gateway]
    MCP -->|"locale = 'ru-RU'"| B[Backend / RU 目錄]
    B --> MCP --> M2["GPT 模型(回覆)"]
    M2 --> C2[ChatGPT UI + RU 小工具]

在這裡,使用者語言與 locale 會決定:

  • 小工具的 UI 用什麼語言呈現;
  • 模型看到的工具與欄位描述是什麼語言;
  • 後端選用哪些目錄與貨幣;
  • 回覆如何格式化(模型與小工具端)。

11. 本地化工具與描述時的常見錯誤

錯誤一:把 description 當成「技術註解」,完全不做本地化。
只有英語使用者時或許還行,但一旦出現其他語言,模型更常不調用工具,或按錯 schema 傳了奇怪參數。你把 UI 都翻好了,App 還是在「英語腦」裡行事。

錯誤二:依語言改動 JSON 欄位名稱。
有時會想把 agevozrastbudjet 等。這會讓後端變成噩夢:不同 schema、不同格式、日誌分析困難。最好把欄位 name 穩定不變,只在描述上做本地化。

錯誤三:在描述中無序混用語言。
像「以中文描述 Search gifts for user preferences」這類混搭,既不幫助模型也不幫助人。如果要做多語描述,請明確分區:[EN] ... [RU] ...。模型會看到結構,而不是一團混雜。

錯誤四:不把 locale 傳進工具。
即使你做了描述本地化,但沒有把 locale 傳給 tool(或 MCP Gateway 沒有代你傳),後端就不知道該用哪個目錄與格式。最後變成模型想「多語」,伺服器卻只回某一個市場的資料。

錯誤五:用機器翻譯直接產生描述、且不做審查。
看似把描述丟進機器翻譯就能收工。實務上這類翻譯常不準,尤其在術語與參數部分。模型可能因此誤解工具或欄位的意義。寧可有一份精心打磨的 EN 版本與少數精準的在地化版本,也不要二十種「機器譯」。

錯誤六:沒有為不同 locale 做測試/實驗。
如果你沒有至少針對每個 locale 做基本請求測試,有些問題可能要等到第一位真實使用者上門才會暴露。準備小型 golden 集合與 Dev Mode 的手動測,能大幅降低風險。

錯誤七:正典與在地化描述之間不同步。
你在英文 schema 新增了欄位 occasion(「送禮場合」),卻忘了更新俄語版本。於是 RU locale 下模型根本不知道這個欄位,也就不會填。後端想依場合過濾禮物,得到 null,只好回非常寬泛的清單——在 EN 下一切正常,在 RU 下則悄悄「壞掉」。因此任何工具描述變更都該經過簡單但固定的流程:先更新 EN → 再更新各語言 → 快速跑一輪測試。

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