1. Як модель «бачить» ваші інструменти
Почнімо з того, що для моделі tool — це зовсім не «ваша гарна функція на TypeScript», а структурований опис на кшталт:
- name: технічна назва, наприклад "search_gifts";
- description: текст людською мовою, який пояснює, коли й навіщо використовувати цей інструмент;
- inputSchema: JSON Schema з полями, у кожного з яких також може бути description, тип і обмеження.
Якщо дуже спростити, модель діє приблизно так (псевдокод у «голові» GPT):
1. Прочитати запит користувача (будь-якою мовою).
2. Прочитати список tools: name + description + описи аргументів.
3. Для кожного tool прикинути, чи підходить він до задачі.
4. Якщо потрібен tool — згенерувати JSON з аргументами за схемою.
5. Інакше — відповісти текстом.
Звідси випливають два важливі висновки.
По‑перше, поле description в інструмента — це не коментар для розробників, а інтерфейс між моделлю та вашим бекендом. Якщо опис інструмента розмитий, неповний або написаний мовою, що не збігається з мовою користувача, модель частіше помиляється: обирає не той tool, передає не ті аргументи або відповідає без інструментів там, де вони були потрібні.
По‑друге, description у полів у JSON Schema так само важливий, як і опис самого інструмента. Модель справді читає 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 років, бюджет до 3 000 гривень», модель має:
- Зрозуміти, що search_gifts — відповідний інструмент.
- Зрозуміти, що «60 років» потрібно покласти в recipient_age, а «3 000 гривень» — у budget.
Поки описи лише англійською, GPT зазвичай упорається. Але це вже вимагає від неї зайвого внутрішнього «перекладу». Коли зʼявляється кілька мов і/або слабші моделі, це бʼє по точності.
2. Проблема «англійських описів» у багатомовному застосунку
У модулі 9 ми вже побіжно обговорювали загальну «карту локалізації»: UI‑віджет, каталоги, помилки, commerce‑тексти. Тепер звузьмо фокус і подивімося, що відбувається, коли описи інструментів написані лише англійською, а користувач спілкується, скажімо, українською або іспанською. Саме тут і починається певний хаос.
Типовий сценарій:
- Користувач: «Підбери подарунок для друга‑айтішника, бюджет до 50 євро».
- Модель дивиться на список tools і бачить описи лише EN.
- Якщо запит теж англійською — усе добре.
- Якщо запит іншою мовою, моделі доводиться:
- спочатку зрозуміти запит,
- потім зіставити його з англійськими описами,
- підібрати інструмент,
- а далі ще й витягти аргументи в JSON.
У сильних моделях це ще якось працює, але:
- частіше зростає частка відповідей без виклику tools — модель «вважає», що впорається сама;
- збільшуються шанси помилок в аргументах (особливо коли важливі валюта, одиниці вимірювання, регіональні обмеження);
- логіка маршрутизації між кількома tools стає менш надійною (інструмент «пролітає повз касу»).
Простий приклад помилки: у полі budget очікується значення «у валюті користувача», а в описі про це взагалі не сказано. Модель вирішує, що це USD за замовчуванням, і надсилає в бекенд 50 доларів там, де користувач явно мав на увазі 50 євро.
І тут у гру вступає локалізація описів.
3. Підходи до локалізації: окремі tools vs багатомовні описи
Є два базові архітектурні підходи — і обидва цілком життєздатні.
Окремі інструменти для кожної мови
У цьому варіанті ви робите кілька tools із різними назвами, і кожен має «свою» мову описів.
Для GiftGenius це може виглядати так:
export const searchGiftsEn = {
name: "search_gifts_en",
description: "Search for gift ideas based on user preferences.",
// ...
};
export const searchGiftsUa = {
name: "search_gifts_uk",
description: "Підбір подарунків за вподобаннями користувача.",
// ...
};
Для застосунку ChatGPT при цьому важливо, щоб список доступних tools залежав від locale. Якщо locale = "uk-UA", то ваш MCP‑сервер має повернути тільки search_gifts_uk. Якщо locale = "en-US", — лише search_gifts_en.
Плюс такого підходу в тому, що описи виходять максимально «чистими» й одномовними. Ви можете мислити застосунок як набір одномовних версій: кожна — зі своїми prompts і описами. Це зручно, коли мов небагато, а ринки суттєво відрізняються.
Мінуси — дублювання логіки та складніша аналітика. У бекенд‑коді, найімовірніше, усе одно буде один і той самий обробник, а от на рівні MCP/маніфестів — уже два різні інструменти. Також важливо не забувати оновлювати описи в усіх варіантах після кожної зміни.
Спостереження (дані станом на 1 грудня 2025 р.)
Експериментально не виявлено помітних переваг у description мовою користувача/locale. Інструменти обиралися майже з однаковою частотою — незалежно від мови опису. Якщо було два інструменти зі схожими описами (різними мовами), це, навпаки, збивало ChatGPT з пантелику.
Крім того, вашому застосунку потрібно буде пройти ревʼю під час реєстрації в Store. Тож рекомендую просто писати усі tool description і argument description англійською.
Однак якщо в майбутньому в ChatGPT будуть тисячі застосунків і конкуренція за «вибір інструмента» зросте, можливо, description мовою locale користувача отримуватиме перевагу. Чекаємо на Tool Search Optimization.
Один інструмент із багатомовними descriptions
У другому варіанті ви лишаєте один name (наприклад, search_gifts), але його description й описи полів JSON Schema робите багатомовними.
Є різні стилі:
- Коротка двомовна форма:
description: "Search gifts for a recipient. / Пошук подарунків за вподобаннями отримувача.", - Марковані блоки за мовами:
description: "[EN] Search for gifts based on user preferences. [UK] Підбір подарунків за вподобаннями отримувача.", - Окремі поля, обʼєднані в рядок (менш зручно):
description: `EN: ${enDescription} UK: ${ukDescription}`,
Плюси — один tool, єдине джерело правди (single source of truth) і простіше розгортання архітектури з MCP Gateway: ви завжди експонуєте один і той самий інтерфейс для ChatGPT, незалежно від того, якою мовою спілкується користувач.
Мінуси: описи стають довшими. Якщо «міксувати» мови неакуратно, модель може трохи плутатися — особливо коли англійський і локальний текст ідуть упереміш, без явних позначок [EN], [UK].
Для навчального проєкту на кшталт 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 (UK: підбір подарунків за вподобаннями отримувача).",
inputSchema: {
type: "object",
properties: {
recipient_age: {
type: "integer",
description:
"Recipient age in years. UK: вік отримувача (ціле число).",
},
budget: {
type: "number",
description:
"Maximum budget in user's currency. UK: максимальний бюджет у валюті користувача.",
},
locale: {
type: "string",
description:
"User locale (e.g. 'en-US', 'uk-UA'). UK: мова інтерфейсу та відповідей.",
},
},
required: ["budget", "locale"],
},
};
Кілька практичних спостережень.
По‑перше, назви полів (recipient_age, budget, locale) зазвичай лишають англійською. Перекладається саме description. Це важливо, щоб JSON‑формат не змінювався від мови до мови — і вам не довелося підтримувати два різні контракти.
По‑друге, у description корисно явно вказувати валюту, одиниці вимірювання та важливі обмеження. Це суттєво знижує кількість «кривих» аргументів.
По‑третє, якщо ви вже використовуєте MCP Gateway, можна домовитися, що він автоматично прокидатиме locale в аргументи інструмента. Тоді модель не зобовʼязана підставляти його сама. Але навіть у цьому разі опис locale не зайвий: модель краще розуміє, що це за параметр і навіщо він потрібен.
5. Як обирати мову описів: стратегії для реального застосунку
Тепер головне практичне питання: яку мову зробити основною для описів і коли варто локалізувати їх повністю?
Рекомендації та реальний досвід показують, що GPT‑моделі досі найкраще працюють в англомовному контексті, і багато розробників лишають описи лише EN. Але для багатомовного застосунку це може бути компромісом.
Розберімо кілька стратегій.
Лише EN‑описи
Найпростіший варіант — усе англійською.
Плюси: одна кодова база, одна мова для підтримки, простіше писати гарні й точні формулювання. Моделі простіше, коли все довкола англійською.
Мінуси: для користувачів, які пишуть іншими мовами, якість вибору інструментів і аргументів може бути нижчою. Особливо на «ледачих» моделях або зі складними інструментами, де багато параметрів.
EN + короткий локальний «хвіст»
Компромісний підхід: основний опис англійською, а наприкінці — короткий блок локальною мовою, який допомагає моделі зіставляти слова користувача з аргументами.
Приклад:
description:
"Search for gifts based on user preferences. UK: інструмент підбирає подарунки за описом отримувача, його віком і бюджетом.",
Для JSON Schema:
description:
"Age of the recipient in years. UK: вік отримувача (у роках).",
Плюси: модель і далі в «англомовному» світі, але має підказку мовою користувача.
Мінуси: описи стають довшими, але зазвичай це не критично.
Повна локалізація описів за locale
Найсерйозніший підхід: описи інструментів і полів змінюються залежно від locale, яку ви знаєте з ChatGPT. Для en-US ви віддаєте суто англійські описи, для uk-UA — суто українські, а для de-DE — німецькі.
Це вже не «одна JSON Schema назавжди», а набір схем, які MCP/Gateway обирає на льоту.
На рівні MCP це виглядає так:
function getSearchGiftsToolDescription(locale: string) {
if (locale.startsWith("uk")) {
return {
name: "search_gifts",
description: "Підбір подарунків за вподобаннями отримувача.",
// uk‑schema...
};
}
return {
name: "search_gifts",
description: "Search for gifts based on user preferences.",
// en‑schema...
};
}
Плюси: модель бачить інтерфейс тією самою мовою, якою пише користувач. Це максимум зручності.
Мінуси: ускладнюється підтримка й тестування. Потрібно вибудувати процес, який гарантує, що всі локалізовані варіанти описів лишаються синхронізованими за змістом, і що ви не забудете оновити, скажімо, німецьку схему під час додавання нового поля в англійську.
6. Реалізація в нашому застосунку GiftGenius
Переходимо до конкретики. Зробімо в GiftGenius гібридний варіант: один інструмент search_gifts, описи переважно англійською, але з україномовними поясненнями, плюс аргумент locale.
Припустімо, у вас MCP‑сервер на TypeScript, який описує tools у стилі MCP SDK.
// 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. UK: вік отримувача (ціле число)."
),
budget: z
.number()
.describe(
"Maximum budget in user's currency. UK: максимальний бюджет у валюті користувача."
),
locale: z
.string()
.describe(
"User locale (e.g. 'en-US', 'uk-UA'). UK: мова інтерфейсу та відповідей."
),
});
export const searchGiftsTool = {
name: "search_gifts",
description:
"Search for gifts based on user preferences (UK: підбір подарунків за вподобаннями отримувача).",
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 → той обере правильний каталог і формати цін, які потім ви акуратно відмалюєте у фронтенді.
7. Експерименти з поведінкою: як вимірювати вплив локалізації
Тепер найцікавіше: як зрозуміти, що локалізація tools і описів справді покращує поведінку моделі, а ви не витратили час на переклад даремно?
Можна провести невеликий «науковий експеримент» прямо в режимі розробника (Dev Mode) у GiftGenius.
Два варіанти застосунку: base vs localized
Підготуйте дві конфігурації вашого застосунку:
- base — описи інструментів і JSON Schema лише EN;
- localized — описи з EN+UK (або повноцінні uk‑версії, якщо ви готові).
Решту (каталоги, UI, промпти) лишіть однаковими, щоб не змішувати ефекти.
Для простоти можна:
- у 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€"
Ми вже знаємо, що модель багатомовна й зазвичай упорається. Але за змішаних мов та «англійських» описів імовірність помилки зростає.
Є кілька типових ситуацій.
Перша — користувач пише українською, а описи інструментів англійською. Модель може зрозуміти запит, але іноді плутається — особливо у специфічній термінології (назви категорій, рідкісні мітки полів).
Друга — locale = "uk-UA", але користувач із якихось причин пише англійською. ChatGPT надіслав вам сигнали, що інтерфейс краще будувати українською, але фактична мова тексту — EN. Можна:
- усе одно віддавати українські описи, вважаючи locale первинним джерелом правди;
- або додати визначення мови повідомлення як додатковий сигнал і підлаштовувати описи під фактичну мову.
Третя — locale = "en", а користувач іноді вставляє українські слова. У цьому разі, як правило, англомовні описи чудово працюють.
На практиці достатньо обрати одну чітку політику. Наприклад:
- якщо locale починається з "uk" — ви додаєте українські фрагменти в описи;
- якщо ні — описи суто англійські.
Чітке правило корисне тим, що ви зможете цілеспрямовано тестувати кожну гілку, а не гадати, чому сьогодні описи опинилися тією чи іншою мовою.
9. Документація, процес і «канонічна» мова
Локалізація описів — це не одноразова дія, а процес. Користувачі люблять, коли фічі зʼявляються, а ви — коли не ламається нічого старого. Тому варто заздалегідь домовитися із самим собою:
- яку мову вважати «канонічною», відносно якої робити всі переклади;
- де зберігати локалізовані описи;
- як перевіряти узгодженість.
Зазвичай у ролі канонічної мови виступає англійська. Усі нові інструменти та поля спершу описуються англійською, проходять ревʼю, і тільки потім локалізуються іншими мовами. У кодовій базі це можна оформити так:
- файл tools.en.json із повним описом name/description/полів;
- файли tools.uk.json, tools.de.json як «похідні» для конкретних мов;
- невеликий генератор, який збирає фінальні JSON Schema для MCP на основі цих словників.
У простому варіанті можна поки обійтися рядками в коді, але структурувати їх так, щоб потім легко винести в окремі словники.
Важливо памʼятати, що описи — це теж продуктовий текст. Їх варто ревʼювати так само уважно, як тексти в UI: перевіряти на зрозумілість, відсутність двозначностей і зайвої «води». Особливо в багатомовному варіанті ми не хочемо, щоб український «хвіст» суперечив англійській частині описів.
10. Візуальна схема: як мова проходить крізь стек
Щоб усе скласти докупи, подивімося на спрощену схему потоку запиту з урахуванням локалізації tools.
flowchart TD
U[Користувач пише українською] --> C[ChatGPT UI]
C -->|"_meta.openai/locale = 'uk-UA'"| W[Віджет GiftGenius]
W -->|"locale = 'uk-UA'"| T["Опис інструментів (EN+UK)"]
T --> M[Модель GPT]
M -->|callTool search_gifts| MCP[MCP / Gateway]
MCP -->|"locale = 'uk-UA'"| B[Backend / каталоги UK]
B --> MCP --> M2["Модель GPT (відповідь)"]
M2 --> C2[ChatGPT UI + віджет UK]
Тут мова користувача і locale визначають:
- якою мовою віджет показує UI;
- які описи інструментів і полів бачить модель;
- які каталоги та валюти обирає бекенд;
- як форматуються відповіді (і моделлю, і віджетом).
11. Типові помилки під час локалізації tools і описів
Помилка №1: вважати поле description «технічним» і не локалізувати його взагалі.
Такий підхід працює, доки у вас лише англомовні користувачі. Щойно зʼявляються інші мови, модель частіше відповідає без tools або передає «криві» аргументи за схемами. Ви начебто переклали UI, а застосунок поводиться «по‑англійськи».
Помилка №2: змінювати назви полів у JSON залежно від мови.
Іноді виникає спокуса зробити age → vozrast, budjet тощо. Це перетворюється на кошмар на боці бекенда: різні схеми, різні формати, складний аналіз логів. Краще залишити name полів стабільними й локалізувати лише описи.
Помилка №3: хаотично змішувати мови в описах.
Фрази на кшталт «Пошук gifts за вподобаннями user» не допомагають ані моделі, ані людині. Якщо ви робите багатомовні описи, розділяйте блоки явно: [EN] ... [UK] .... Тоді модель бачить структуру, а не кашу.
Помилка №4: не передавати locale в інструменти.
Навіть якщо ви локалізували описи, але не передаєте locale у tool (або MCP Gateway не прокидає її), бекенд не знає, які каталоги та формати використовувати. У підсумку модель намагається бути «багатомовною», а сервер повертає дані лише для одного ринку.
Помилка №5: автопереклад описів через машинний перекладач без ревʼю.
Здається, що можна прогнати описи через автоматичний перекладач і радіти життю. На практиці такі переклади часто неточні, особливо в частині термінів і аргументів. У результаті модель може неправильно інтерпретувати зміст інструмента або поля. Краще мати один добре продуманий EN‑варіант і акуратно локалізовані версії, ніж двадцять «автоматичних» мов.
Помилка №6: відсутність тестів/експериментів для різних локалей.
Якщо ви не перевіряєте поведінку застосунку хоча б на базовому наборі запитів для кожної локалі, усе може «ламатися» місяцями — аж доки до вас не прийде перший реальний користувач із цією мовою. Невеликий golden‑набір запитів і ручні тести в Dev Mode значно знижують цей ризик.
Помилка №7: розсинхрон між канонічними та локалізованими описами.
Ви додали нове поле occasion («привід» подарунка) в англійську схему, але забули оновити українську. У результаті на UK‑локалі модель узагалі не знає про це поле й не заповнює його, хоча бекенд уже очікує. Наприклад, сервер намагається відфільтрувати подарунки за приводом, отримує null і показує надто загальний список — на EN усе працює, а на UK поведінка «ламається» непомітно. Тому будь‑які зміни описів інструментів мають проходити через простий, але регулярний процес: оновити EN → оновити локалі → коротко прогнати тести.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ