1. Comment le modèle « voit » vos outils
Commençons par rappeler que pour le modèle, un tool n’est pas « votre jolie fonction en TypeScript », mais une description structurelle du type :
- name : nom technique, par exemple "search_gifts" ;
- description : texte en langue naturelle qui explique quand et pourquoi utiliser cet outil ;
- inputSchema : JSON Schema avec des champs, chacun pouvant aussi avoir une description, un type, des contraintes.
Très schématiquement, le modèle fait à peu près ceci (pseudo‑code dans la tête de GPT) :
1. Lire la requête utilisateur (dans n'importe quelle langue).
2. Lire la liste des tools : name + description + descriptions des arguments.
3. Pour chaque tool, estimer s'il convient à la tâche.
4. Si un tool est nécessaire — générer du JSON avec les arguments selon le schéma.
5. Sinon — répondre en texte.
Deux conclusions importantes en découlent.
Premièrement, le champ description d’un outil n’est pas un commentaire pour les développeurs, mais l’interface entre le modèle et votre backend. Si la description de l’outil est vague, incomplète ou dans une langue qui ne correspond pas à celle de l’utilisateur, le modèle se trompera plus souvent : mauvais tool, mauvais arguments, réponse sans outil là où il en fallait un.
Deuxièmement, la description des champs dans le JSON Schema est tout aussi importante que la description de l’instrument. Le modèle lit réellement la description de chaque propriété et s’en sert pour décider dans quel champ placer « âge », dans lequel « budget », et où il doit y avoir un id.
Mini‑exemple pour GiftGenius
Prenons notre outil search_gifts. Dans sa version d’origine « EN seulement », il pouvait ressembler à ceci :
// 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"],
},
};
Si l’utilisateur écrit : « Il me faut un cadeau pour ma mère, elle a 60 ans, budget jusqu’à 3 000 roubles », le modèle doit :
- Comprendre que search_gifts est l’outil adapté.
- Comprendre que « 60 ans » doit aller dans recipient_age, et « 3 000 roubles » dans budget.
Tant que les descriptions ne sont qu’en anglais, GPT s’en sortira quand même, mais cela lui impose déjà une « traduction » interne supplémentaire. À l’échelle de plusieurs langues et avec des modèles plus faibles, la précision en pâtit.
2. Le problème des descriptions en anglais dans une app multilingue
Dans le module 9, nous avons déjà effleuré la « carte de localisation » générale : widget d’UI, catalogues, erreurs, textes commerce. Rétrécissons maintenant le focus et voyons ce qui se passe quand les descriptions des outils ne sont qu’en anglais et que l’utilisateur s’exprime, disons, en russe ou en espagnol — c’est là que commence un léger chaos.
Scénario typique :
- Utilisateur : « Choisis un cadeau pour un ami informaticien, budget jusqu’à 50 euros ».
- Le modèle regarde la liste des tools et ne voit que des descriptions en EN.
- Si la requête est aussi en EN — tout va bien.
- Si la requête est dans une autre langue, il doit :
- d’abord comprendre la requête,
- la faire correspondre mentalement aux descriptions anglaises,
- choisir l’outil,
- et ensuite extraire les arguments en JSON.
Avec des modèles puissants, cela peut encore passer, mais :
- la part des réponses sans appel de tools augmente — le modèle « pense » pouvoir s’en sortir seul ;
- le risque d’erreurs dans les arguments est plus élevé (surtout quand la devise, les unités de mesure ou les contraintes régionales sont importantes) ;
- la logique de routage entre plusieurs tools devient moins fiable (mauvais outil sélectionné).
Exemple d’erreur simple : dans le champ budget, on attend « dans la devise de l’utilisateur », mais la description ne le dit pas du tout. Le modèle décide que c’est l’USD par défaut et envoie au backend 50 dollars là où l’utilisateur voulait clairement 50 euros.
Et c’est là que la localisation des descriptions entre en jeu.
3. Approches de localisation : tools distincts vs descriptions multilingues
Il existe deux approches d’architecture de base, toutes deux valables.
Des outils distincts pour chaque langue
Dans cette variante, vous créez plusieurs tools avec des noms différents, chacun avec « sa » langue de description.
Pour GiftGenius, cela peut ressembler à ceci :
export const searchGiftsEn = {
name: "search_gifts_en",
description: "Search for gift ideas based on user preferences.",
// ...
};
export const searchGiftsRu = {
name: "search_gifts_ru",
description: "Sélection de cadeaux selon les préférences de l’utilisateur.",
// ...
};
Pour ChatGPT App, il est important que la liste des tools disponibles dépende de la locale. Si locale = "ru-RU", alors votre serveur MCP doit ne renvoyer que search_gifts_ru. Si locale = "en-US", — seulement search_gifts_en.
Avantages : des descriptions maximales « propres » et monolingues. Vous pouvez carrément considérer l’app comme plusieurs versions monolingues, chacune avec ses propres prompts et descriptions. C’est confortable quand il y a peu de langues et que les marchés diffèrent fortement.
Inconvénients : duplication de logique et complexité analytique. Côté backend, il y aura probablement le même handler, mais côté MCP/manifests — déjà deux outils différents. Il ne faut pas oublier de mettre à jour les deux descriptions à chaque modification.
Insight (données au 2025-12-01)
De manière expérimentale, aucun avantage notable n’a été constaté pour une description dans la langue de l’utilisateur/locale. Les outils étaient choisis avec une fréquence pratiquement identique, indépendamment de la langue de la description. S’il y avait 2 outils avec des descriptions proches (dans des langues différentes), cela embrouillait ChatGPT.
De plus, votre application devra passer un review lors de l’inscription dans le Store. Je recommande donc simplement d’écrire toutes les descriptions de tools et d’arguments en anglais.
Cependant, si à l’avenir ChatGPT compte des milliers d’applications et que la concurrence pour le « choix de l’outil » s’intensifie, il est possible qu’une description dans la locale de l’utilisateur prenne l’avantage. Attendons l’émergence du Tool Search Optimization.
Un seul outil avec des descriptions multilingues
Dans la deuxième variante, vous conservez un seul name (par exemple search_gifts), mais vous rendez sa description et les descriptions des champs du JSON Schema multilingues.
Il existe différents styles :
- Forme courte bilingue :
description: "Search gifts for a recipient. / RU: Recherche de cadeaux selon les préférences du destinataire.", - Blocs balisés par langue :
description: "[EN] Search for gifts based on user preferences. [RU] Recherche de cadeaux selon les préférences du destinataire.", - Champs distincts combinés en une chaîne (moins pratique) :
description: `EN: ${enDescription} RU: ${ruDescription}`,
Avantages : un seul tool, une source de vérité unique (single source of truth), plus simple de déployer une architecture avec MCP Gateway : vous exposez toujours la même interface à ChatGPT, quel que soit le langage de l’utilisateur.
Inconvénients : les descriptions deviennent plus longues. Si l’on « mélange » les langues sans soin, le modèle peut se tromper un peu — surtout quand l’anglais et le texte local sont entremêlés sans balises explicites [EN], [RU].
Pour un projet d’apprentissage comme GiftGenius, nous recommandons une approche hybride : garder des descriptions principalement en anglais, mais ajouter soigneusement un bref complément dans la langue locale, et faire transiter toute la vraie « sémantique » (quelle langue utiliser, comment s’adresser à l’utilisateur) via les arguments (locale) et le system‑prompt.
4. Localisation du JSON Schema : descriptions des champs
Allons plus loin : jusqu’aux arguments de l’outil eux‑mêmes.
Dans le JSON Schema, chaque champ peut (et doit) recevoir une description. Le modèle lit cette chaîne lorsqu’il génère le JSON pour appeler l’outil.
Pour GiftGenius, on peut faire ainsi :
export const searchGiftsTool = {
name: "search_gifts",
description:
"Search gifts based on user preferences (RU: sélection de cadeaux selon les préférences du destinataire).",
inputSchema: {
type: "object",
properties: {
recipient_age: {
type: "integer",
description:
"Recipient age in years. RU: âge du destinataire (entier).",
},
budget: {
type: "number",
description:
"Maximum budget in user's currency. RU: budget maximal dans la devise de l’utilisateur.",
},
locale: {
type: "string",
description:
"User locale (e.g. 'en-US', 'ru-RU'). RU: langue de l’interface et des réponses.",
},
},
required: ["budget", "locale"],
},
};
Quelques observations pratiques.
Premièrement, les noms des champs (recipient_age, budget, locale) restent généralement en anglais. Ce qui est traduit, c’est la description. C’est important pour que le format JSON ne change pas d’une langue à l’autre et pour éviter d’avoir à maintenir deux contrats différents.
Deuxièmement, dans la description, il est utile d’indiquer explicitement la devise, les unités de mesure et les contraintes importantes. Cela réduit fortement le nombre d’arguments « bancals ».
Troisièmement, si vous utilisez déjà un MCP Gateway, vous pouvez convenir qu’il propage automatiquement la locale dans les arguments de l’outil, de sorte que le modèle n’ait pas à la renseigner lui‑même. Même dans ce cas, garder la description de locale est utile : le modèle comprend mieux ce paramètre et sa raison d’être.
5. Choisir la langue des descriptions : stratégies pour une app réelle
La question pratique principale : quelle langue choisir comme langue de base pour les descriptions, et quand faut‑il les localiser complètement ?
Les recommandations et l’expérience montrent que les modèles GPT fonctionnent encore le mieux dans un contexte anglais, et beaucoup de développeurs laissent les descriptions en EN uniquement. Mais pour une app multilingue, cela peut être un compromis.
Voyons plusieurs stratégies.
Descriptions EN uniquement
La variante la plus simple : tout en anglais.
Avantages : une seule base de code, une seule langue à maintenir, plus facile d’écrire des formulations bonnes et précises. Le modèle est heureux quand tout est en anglais.
Inconvénients : pour les utilisateurs écrivant dans d’autres langues, la qualité du choix des outils et des arguments peut être moindre. Surtout pour des modèles « paresseux » ou des outils complexes avec de nombreux paramètres.
EN + court complément local
Approche de compromis : la description principale en EN et, à la fin, un court bloc dans la langue locale pour aider le modèle à faire correspondre les mots de l’utilisateur aux arguments.
Exemple :
description:
"Search for gifts based on user preferences. RU: l’outil sélectionne des cadeaux d’après la description du destinataire, son âge et son budget.",
Pour le JSON Schema :
description:
"Age of the recipient in years. RU: âge du destinataire (en années).",
Avantages : le modèle reste dans un « monde anglais », mais dispose d’un indice dans la langue de l’utilisateur.
Inconvénients : les descriptions deviennent plus longues, mais en général ce n’est pas critique.
Localisation complète des descriptions par locale
Approche la plus poussée : les descriptions des outils et des champs changent en fonction de la locale fournie par ChatGPT. Pour en-US, vous renvoyez des descriptions purement anglaises, pour ru-RU — purement russes, et pour de-DE — allemandes.
Ce n’est plus « un seul JSON Schema pour toujours », mais un ensemble de schémas que le MCP/Gateway choisit à la volée.
Au niveau MCP, cela ressemble à :
function getSearchGiftsToolDescription(locale: string) {
if (locale.startsWith("ru")) {
return {
name: "search_gifts",
description: "Sélection de cadeaux selon les préférences du destinataire.",
// ru‑schema...
};
}
return {
name: "search_gifts",
description: "Search for gifts based on user preferences.",
// en‑schema...
};
}
Avantages : le modèle voit une interface dans la même langue que celle de l’utilisateur. Confort maximal.
Inconvénients : maintenance et test plus complexes. Il faut un processus garantissant que toutes les variantes localisées des descriptions restent synchronisées sur le fond, et que vous n’oublierez pas de mettre à jour, disons, le schéma allemand lors de l’ajout d’un nouveau champ dans l’anglais.
6. Implémentation dans notre application GiftGenius
Passons au concret. Réalisons dans GiftGenius une variante hybride : un seul outil search_gifts, des descriptions principalement en EN, mais avec des explications en russe, plus l’argument locale.
Supposons que vous ayez un serveur MCP en TypeScript qui décrit les tools dans le style 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. RU: âge du destinataire (entier)."
),
budget: z
.number()
.describe(
"Maximum budget in user's currency. RU: budget maximal dans la devise de l’utilisateur."
),
locale: z
.string()
.describe(
"User locale (e.g. 'en-US', 'ru-RU'). RU: langue de l’interface et des réponses."
),
});
export const searchGiftsTool = {
name: "search_gifts",
description:
"Search for gifts based on user preferences (RU: sélection de cadeaux selon les préférences du destinataire).",
inputSchema: searchGiftsInputSchema,
// execute(...) ...
};
Important :
- locale est obligatoire. Si le widget la connaît (et nous la connaissons via _meta["openai/locale"]), il l’injectera soit lui‑même dans l’appel callTool, soit le MCP Gateway le fera automatiquement de son côté ;
- les descriptions contiennent déjà des mots‑clés en russe « âge », « budget », « langue de l’interface », ce qui facilite pour le modèle la correspondance entre ce que l’utilisateur écrit et l’endroit où le placer.
Côté Apps SDK, vous pouvez, par exemple, avoir une fonction qui appelle ce tool directement (si widgetAccessible est activé), en lui passant la locale issue du widget.
// 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;
}
Cet enchaînement renforce l’architecture : la locale vient de ChatGPT → arrive dans le tool → celui‑ci choisit le bon catalogue et les formats de prix, que vous afficherez ensuite joliment en frontend.
7. Expériences de comportement : mesurer l’impact de la localisation
La partie la plus intéressante : comment vérifier que la localisation des tools et des descriptions améliore réellement le comportement du modèle, et que vous n’avez pas perdu votre temps à traduire ?
Vous pouvez mener une petite « expérience scientifique » directement en Dev Mode sur GiftGenius.
Deux variantes d’app : base vs localisée
Préparez deux configurations de votre app :
- base — descriptions des outils et JSON Schema en EN uniquement ;
- localisée — descriptions EN+RU (ou des versions RU complètes si vous êtes prêt).
Laissez le reste (catalogues, UI, prompts) identique pour ne pas mélanger les effets.
Pour simplifier, vous pouvez :
- en Dev Mode (et a fortiori dans le Store) ne garder que la version localisée ;
- et lancer la base en local dans une branche séparée pour comparer les résultats sur un jeu de requêtes prédéfini.
Ce qu’il faut mesurer
Trois métriques clés.
Première — la fréquence des choix d’outil corrects. Pour un ensemble de requêtes de test en russe (et/ou dans une autre langue), vous regardez combien de fois le modèle :
- a décidé d’appeler un outil quand il le fallait ;
- a choisi précisément search_gifts et non un autre tool.
Deuxième — la correction des arguments. Vérifiez à quelle fréquence le JSON de l’appel correspond aux attentes : pas d’inversion de champs, budget dans la bonne devise, âge clairement entier, locale non perdue.
Troisième — le nombre d’appels étranges ou dénués de sens. Par exemple, le modèle appelle search_gifts pour la question « quelle heure est‑il ? » ou renseigne recipient_age : 3000 à la place du budget.
Les tests peuvent être faits à la main ou via les logs MCP/Agents — les logs vous serviront de toute façon plus tard, autant vous y habituer dès maintenant.
Comment organiser un jeu de test manuel
Vous pouvez constituer un petit « golden prompt set » pour la localisation :
1. "J’ai besoin d’un cadeau peu cher jusqu’à 30 €, pour une fille de 10 ans qui aime dessiner."
2. "Choisis un cadeau pour un collègue développeur, 35 ans, budget 100 $."
3. "Il faut un cadeau pour ma grand-mère pour son jubilé, 70 ans, budget jusqu’à 5 000 roubles."
Et les passer dans les deux versions de l’app (base et localisée), en observant :
- quels tools le modèle choisit ;
- quels arguments il renseigne ;
- comment le texte de la réponse change si l’outil n’a pas été appelé.
Astuce semi‑pro : vous pouvez écrire un simple script qui fera tourner ces requêtes via l’API ChatGPT, mais dans le cadre du cours le mode manuel en Dev Mode suffit. Une catégorie particulière de requêtes qu’il est utile d’inclure dans ce set — les messages en langues mixtes et les combinaisons étranges de locale. Nous leur consacrons un bloc à part.
Si vous développez une application commerciale sérieuse et que des millions de dollars sont en jeu, testez impérativement ces points spécifiquement pour votre application. Le module 20 est consacré au travail professionnel avec le « golden prompt set » — prenez le temps d’en maîtriser le sujet.
8. Langues mixtes et combinaisons de locale étranges
Rien n’amuse autant un développeur LLM qu’un utilisateur qui écrit dans deux langues à la fois. Par exemple :
"Besoin d’un cadeau for my friend, il aime Star Wars, budget 100 €"
Nous savons déjà que le modèle est multilingue et s’en sort le plus souvent. Mais avec des langues mixtes et des descriptions « anglaises », la probabilité d’erreur augmente.
Plusieurs situations typiques.
Première — l’utilisateur écrit en RU et les descriptions d’outils sont en EN. Le modèle peut comprendre, mais se trompe parfois, surtout sur la terminologie spécifique (noms de catégories, labels de champs rares).
Deuxième — locale = "ru-RU", mais l’utilisateur écrit en anglais. ChatGPT vous a envoyé des signaux indiquant que l’interface doit être en russe, mais la langue effective du texte est EN. Deux options :
- fournir quand même des descriptions russes, en considérant locale comme signal prioritaire ;
- ou implémenter une détection de langue du message comme signal supplémentaire et ajuster les descriptions à la langue effective.
Troisième — locale = "en", et l’utilisateur insère parfois des mots russes. Dans ce cas, les descriptions en anglais se portent en général très bien.
En pratique, il suffit de choisir une politique claire. Par exemple :
- si la locale commence par "ru" — vous ajoutez des fragments russes dans les descriptions ;
- sinon — descriptions purement en anglais.
Une règle claire a l’avantage de vous permettre de tester chaque branche, sans deviner pourquoi aujourd’hui les descriptions se retrouvent dans telle ou telle langue.
9. Documentation, processus et langue « canonique »
La localisation des descriptions n’est pas un acte ponctuel, mais un processus. Les utilisateurs aiment voir apparaître des fonctionnalités, et vous aimez quand rien de l’existant ne casse. Mieux vaut donc se mettre d’accord à l’avance :
- quelle langue considérer comme « canonique » pour réaliser toutes les traductions ;
- où stocker les descriptions localisées ;
- comment vérifier la cohérence.
En général, la langue canonique est l’anglais. Tous les nouveaux outils et champs sont d’abord décrits en EN, passent en review, puis sont localisés dans les autres langues. Dans la base de code, on peut l’exprimer ainsi :
- fichier tools.en.json avec la description complète name/description/champs ;
- fichiers tools.ru.json, tools.de.json comme « dérivés » pour des langues spécifiques ;
- un petit générateur qui compose les JSON Schema finaux pour le MCP à partir de ces dictionnaires.
Dans une version simple, on peut pour l’instant se contenter de chaînes dans le code, mais les structurer pour pouvoir facilement les déplacer plus tard dans des dictionnaires séparés.
Il est important de se souvenir que les descriptions sont aussi du texte produit. Elles méritent un review aussi strict que les textes de l’UI : vérifier la clarté, l’absence d’ambiguïtés et de « blabla » inutile. Surtout en multilingue, nous ne voulons pas qu’un complément russe contredise la partie anglaise des descriptions.
10. Schéma visuel : comment la langue traverse la stack
Pour tout rassembler, regardons un schéma simplifié du flux d’une requête en tenant compte de la localisation des tools.
flowchart TD
U[Utilisateur écrit en RU] --> C[ChatGPT UI]
C -->|"_meta.openai/locale = 'ru-RU'"| W[Widget GiftGenius]
W -->|"locale = 'ru-RU'"| T["Descriptions du tool (EN+RU)"]
T --> M[Modèle GPT]
M -->|callTool search_gifts| MCP[MCP / Gateway]
MCP -->|"locale = 'ru-RU'"| B[Backend / catalogues RU]
B --> MCP --> M2["Modèle GPT (réponse)"]
M2 --> C2[ChatGPT UI + widget RU]
Ici, la langue de l’utilisateur et la locale déterminent :
- la langue d’affichage du widget ;
- quelles descriptions d’outils et de champs le modèle voit ;
- quels catalogues et devises le backend choisit ;
- comment les réponses sont formatées (par le modèle et par le widget).
11. Erreurs typiques lors de la localisation des tools et des descriptions
Erreur n°1 : considérer le champ description comme « technique » et ne pas le localiser.
Cette approche fonctionne tant que vous n’avez que des utilisateurs anglophones. Dès que d’autres langues apparaissent, le modèle répond plus souvent sans tools ou transmet des arguments bancals selon les schémas. Vous avez traduit l’UI, mais l’app se comporte « en anglais ».
Erreur n°2 : changer les noms de champs JSON selon la langue.
La tentation peut être de faire age → vozrast, budjet, etc. Cela conduit à un cauchemar côté backend : schémas différents, formats différents, analyse de logs compliquée. Mieux vaut laisser le name des champs stable et ne localiser que les descriptions.
Erreur n°3 : mélanger les langues de manière chaotique dans les descriptions.
Des phrases comme « Recherche de gifts selon les préférences de user » n’aident ni le modèle ni l’humain. Si vous créez des descriptions multilingues, séparez les blocs explicitement : [EN] ... [RU] .... Le modèle voit alors une structure, pas une bouillie.
Erreur n°4 : ne pas transmettre la locale aux outils.
Même si vous avez localisé les descriptions, mais que vous ne transmettez pas locale au tool (ou que le MCP Gateway ne la propage pas), le backend ne sait pas quels catalogues et formats utiliser. Au final, le modèle tente d’être « multilingue », mais le serveur renvoie des données pour un seul marché.
Erreur n°5 : traduction automatique des descriptions sans review.
On pourrait croire qu’il suffit de passer les descriptions dans un traducteur automatique et de s’en réjouir. En pratique, ces traductions sont souvent imprécises, surtout sur la terminologie et les arguments. Le modèle peut alors interpréter de travers le sens d’un outil ou d’un champ. Mieux vaut un bon variant EN bien pensé et des versions localisées soignées que vingt langues « automatiques ».
Erreur n°6 : absence de tests/expériences pour différentes locales.
Si vous ne vérifiez pas le comportement de l’app au moins sur un set de requêtes de base pour chaque locale, tout peut « casser » pendant des mois, jusqu’à l’arrivée du premier utilisateur réel de cette langue. Un petit set de requêtes golden et des tests manuels en Dev Mode réduisent fortement ce risque.
Erreur n°7 : désynchronisation entre descriptions canoniques et localisées.
Vous avez ajouté un nouveau champ occasion (« motif » du cadeau) dans le schéma anglais, mais oublié de mettre à jour le russe. Résultat : en locale RU, le modèle ne connaît pas ce champ et ne le renseigne pas, alors que le backend l’attend. Par exemple, le serveur essaie de filtrer des cadeaux par motif, reçoit null et affiche une liste trop générale — en EN tout fonctionne, mais en RU le comportement « casse » discrètement. Par conséquent, toute modification des descriptions d’outils doit passer par un processus simple mais régulier : mettre à jour EN → mettre à jour les locales → exécuter rapidement les tests.
GO TO FULL VERSION