1. Le system‑prompt comme contrat, pas comme joli texte
Dans les modules précédents, nous avons regardé ChatGPT App sous l’angle de l’architecture : widget, tools et serveur MCP. Dans cette leçon, nous allons nous concentrer sur la manière dont nous expliquons à la modèle son rôle : ce qu’elle peut faire, ce qu’elle ne doit pas faire et comment utiliser les outils. En substance, nous allons concevoir le system‑prompt comme un contrat entre vous et la modèle.
Dans un chat classique avec ChatGPT, vous êtes peut‑être habitué à des prompts du style « Imagine que tu es un assistant pirate jovial » ou « Explique tout comme à un enfant de cinq ans ». Tout cela concerne la persona et le style. Dans le contexte de ChatGPT App, le terme system‑prompt a un tout autre sens.
Ici, le system‑prompt est le premier message de rôle masqué à l’utilisateur du rôle system, qui indique à la modèle :
- qui elle est dans le cadre de votre App ;
- sur quelle tâche elle se concentre ;
- ce dont elle ne s’occupe PAS ;
- comment et quand elle doit appeler les outils de votre application.
En substance, c’est une spécification de comportement, très proche d’un contrat formel. Si vous vous êtes mis d’accord — la modèle s’efforce de s’y conformer. Sans accord — elle agira comme un ChatGPT « généraliste », et toute votre belle App restera en marge.
Important : pour ChatGPT App, ce system‑prompt :
- est rattaché à l’application elle‑même, et non à un seul dialogue concret ;
- impose des limites tant à l’utilisation du widget qu’aux appels des tools ;
- vit aussi longtemps que dure la session de l’App (tant que l’utilisateur interagit avec votre application).
Pour simplifier, l’accord est le suivant : vous donnez des outils à la modèle et vous lui décrivez son rôle : quel type d’assistant elle est, ce qu’elle fait, ce qu’elle ne fait pas, comment elle utilise les outils et comment elle traite les données de l’utilisateur. En retour, la modèle s’efforce d’agir exactement ainsi.
2. Où le system‑prompt vit‑il dans l’architecture
Pour éviter que cela ne paraisse être une entité magique, il est utile de le voir sur un schéma.
sequenceDiagram
participant User as Utilisateur
participant ChatGPT as ChatGPT + modèle
participant App as Votre ChatGPT App
participant MCP as MCP/Backend
Note over ChatGPT: Lors de l’initialisation de l’App
le modèle reçoit le system‑prompt
User->>ChatGPT: « Trouve un cadeau pour un ami jusqu’à 50 $ »
ChatGPT->>ChatGPT: Applique le system‑prompt + descriptions des tools
ChatGPT->>App: callTool recommend_gifts(...)
App->>MCP: HTTP /tools/recommend_gifts
MCP-->>App: Liste de cadeaux
App-->>ChatGPT: Tool result (JSON)
ChatGPT-->>User: Texte + indication d’un widget avec des cartes
Le system‑prompt parvient à la modèle au moment de l’initialisation de l’App, lorsque ChatGPT décide de « connecter » votre application au dialogue. Ensuite, chaque décision de ChatGPT — appeler un tool, proposer un widget, que dire en l’absence de données — passe à travers le prisme de ce contrat.
Du point de vue du code dans l’Apps SDK, c’est généralement une simple chaîne, située quelque part près de la configuration de l’App, par exemple :
// app/config/systemPrompt.ts
export const giftGeniusSystemPrompt = `
Tu es GiftGenius, assistant de sélection de cadeaux...
`;
Ensuite, cette chaîne est utilisée là où votre application se connecte à ChatGPT. Le « câblage » technique peut varier, mais l’essentiel pour vous est : le system‑prompt est un artefact de code à part entière, comme le schéma d’un outil ou un composant React, et il doit être conçu et stocké tout aussi soigneusement.
Maintenant que l’on comprend où le system‑prompt vit dans l’architecture et comment il parvient à la modèle, la question la plus importante est : que faut‑il y mettre pour qu’il s’agisse d’un contrat, et non d’une simple description d’une « persona sympathique ».
3. Rôle de l’App et périmètre de responsabilité
La première et principale section de tout system‑prompt bien conçu — qui tu es et de quoi tu es responsable.
La différence entre « persona » et « contrat d’App » est simple : dire « tu es un pirate et tu parles comme un marin » — c’est le ton ; dire « tu es une interface pour notre catalogue de cadeaux, tu sélectionnes des cadeaux et tu ne t’occupes pas d’autres sujets » — c’est un contrat.
Pour notre application pédagogique GiftGenius, qui sélectionne des cadeaux, le cœur du rôle peut ressembler à ceci :
Rôle :
- Tu es GiftGenius, assistant de sélection de cadeaux de notre service.
- Ta tâche est d’aider l’utilisateur à choisir un cadeau adapté en utilisant uniquement notre catalogue.
- Tu ne donnes pas de conseils médicaux, juridiques ou financiers.
Remarquez les accents mis.
Premièrement, nous définissons le domaine de manière étroite : uniquement la sélection de cadeaux dans le cadre de notre service. C’est nécessaire pour éviter que la modèle ne commence à « expliquer la physique quantique » au lieu d’ouvrir votre App, et pour qu’elle n’essaie pas de construire de curieux workflows autour d’autres applications.
Deuxièmement, nous fixons explicitement ce que l’App ne fait pas. Par exemple :
- ne donne pas de conseils sur des sujets sans lien avec les cadeaux et les achats ;
- n’invente pas des cadeaux qui n’existent pas dans le catalogue ;
- ne décide pas à la place de l’utilisateur ; elle propose seulement des options et les argumente.
De telles contraintes négatives sont souvent plus importantes que les instructions positives : la modèle sait déjà « tout faire », et vous utilisez le system‑prompt pour retirer le superflu.
Pour des environnements plus complexes, où un même développeur a plusieurs App (par exemple « sélection de cadeaux » et « suivi de livraison des commandes »), il est utile d’écrire directement dans le system‑prompt que, dans cette App, tu t’occupes uniquement de la sélection de cadeaux, que tu ne prends pas en charge la gestion des commandes et la logistique et que tu ne lances pas d’autres applications. Cela réduit le risque que la modèle commence à se tromper de « domaine de compétence ».
4. Quand appeler l’App et quand répondre soi‑même
Le bloc critique suivant du contrat : les règles d’utilisation des outils.
Si elles ne sont pas spécifiées, tout part généralement vers l’un des deux extrêmes :
- la modèle n’appelle presque jamais votre App, car il lui est plus simple et moins coûteux de répondre « de tête » ;
- ou, au contraire, elle commence à appeler les outils à tout propos, même pour les questions purement théoriques.
Dans le system‑prompt d’une App, il faut fixer assez clairement :
- dans quels cas il faut utiliser les outils ;
- dans quels cas il faut répondre soi‑même, sans tools ;
- que faire si l’utilisateur demande explicitement « de ne pas lancer l’application ».
Exemple de fragment textuel pour GiftGenius :
Utilisation des outils :
- Utilise les outils de l’App lorsqu’il faut obtenir des données factuelles du catalogue (liste de cadeaux, prix, types de produits, disponibilité de la livraison et remises).
- Réponds toi‑même si la question est théorique et ne nécessite pas d’accès au catalogue (par exemple : « quels cadeaux offre‑t‑on habituellement pour une pendaison de crémaillère »).
- Si l’utilisateur demande explicitement « ne pas ouvrir l’application » ou « répondre sans widget », respecte‑le et n’appelle pas les outils.
Il se passe ici plusieurs choses importantes.
Premièrement, nous relions l’appel des tools au type de requête : données factuelles/de catalogue → outil ; théorie générale → la modèle répond elle‑même.
Deuxièmement, nous parlons explicitement du respect des intentions de l’utilisateur : si quelqu’un écrit « n’en lance aucun, explique simplement », la modèle ne doit pas ignorer ce signal.
Troisièmement, nous gérons ainsi la fréquence d’utilisation de l’App. Un bon system‑prompt aide la modèle à trouver l’équilibre : l’App est utilisée quand c’est nécessaire, mais ne se transforme pas en pop‑up envahissant qui surgit tout le temps.
Plus tard, dans la prochaine leçon sur les instructions UX, nous parlerons séparément de la manière dont la modèle doit annoncer le lancement du widget et de ce qu’elle doit dire après la fin d’un scénario. Ici, ce qui nous intéresse, ce sont précisément les règles de décision : utiliser l’App ou non.
5. Utilisation sécurisée des tools et gestion des données utilisateur
Passons maintenant à la sécurité et au bon sens.
Les outils de votre App peuvent être de différents types :
- ceux qui fonctionnent avec des données publiques (catalogues de cadeaux, disponibilité des produits, conditions de livraison) ;
- ceux qui fonctionnent avec des données personnelles et/ou effectuent des actions au nom de l’utilisateur (création de commande, débit, modification de paramètres).
Dans le system‑prompt, il faut indiquer comment la modèle doit traiter ces différences.
Jeu de règles typique :
Sécurité et confidentialité :
- N’exécute pas d’actions nécessitant le consentement de l’utilisateur (achat, souscription, modification de données personnelles) sans confirmation explicite dans le chat.
- Ne transmets pas aux outils plus de données que nécessaire à leur fonctionnement (minimisation des données).
- Si la requête concerne des données sensibles (santé, finances, enfants), demande d’abord si l’utilisateur confirme la transmission de ces données à l’application.
Nous résolvons ici plusieurs problèmes à la fois.
Premièrement, nous protégeons l’utilisateur d’une activité inattendue : la modèle n’a pas le droit d’acheter un cadeau ou de passer une commande de sa propre initiative, si vous lui avez donné un tel tool. D’abord — une confirmation textuelle, ensuite — l’appel de l’outil.
Deuxièmement, nous réduisons le risque de fuite de données inutiles : la modèle a tendance à « tout embarquer » dans les arguments de l’outil ; vous demandez explicitement de vous limiter aux champs minimaux requis.
Troisièmement, nous mettons en lumière les domaines sensibles où, même sans tool financier, des risques juridiques/éthiques peuvent exister.
Une bonne pratique consiste à compléter, dans la description des outils dangereux (description), qu’ils modifient l’état ou effectuent un paiement, et à le dupliquer au niveau du system‑prompt. Vous obtenez ainsi une double barrière : à la fois dans le contrat et dans la description du tool concerné.
6. Format et style du system‑prompt : écrire comme une spécification
L’une des erreurs les plus courantes est d’écrire le system‑prompt comme un texte marketing : « Tu es un assistant innovant et incroyablement intelligent qui rend le monde meilleur… ». C’est joli, mais cela n’aide pas la modèle. Ce qui l’intéresse :
- qui je suis ;
- quoi faire ;
- quoi ne pas faire ;
- comment utiliser les outils ;
- comment traiter les données et les autres App.
Il vaut donc mieux considérer le system‑prompt comme une spécification :
- le découper en blocs logiques : « Rôle », « Tâches », « Périmètre », « Utilisation des outils », « Sécurité » ;
- écrire, au sein de chaque bloc, des phrases courtes et univoques ;
- mettre explicitement en évidence « à faire » et « à ne pas faire » (oui, des listes à puces à l’intérieur du prompt sont tout à fait appropriées).
Un fragment de prompt structuré pour GiftGenius peut ressembler à ceci :
Rôle :
- Tu es GiftGenius, assistant de sélection de cadeaux de notre service.
Tâches :
- Aide l’utilisateur à choisir des cadeaux selon l’objectif, les intérêts du destinataire et le budget.
- Explique les avantages et inconvénients de chaque option avec des mots simples.
À ne pas faire :
- N’invente pas des cadeaux qui n’existent pas dans le catalogue.
- Ne promets pas des fonctionnalités du service qui n’existent pas (par exemple, la livraison gratuite si, selon le catalogue, elle est payante).
Un style neutre et « sec » est approprié : ce n’est pas un texte commercial, mais un contrat. Moins il y a d’ambiguïtés — plus le comportement est stable.
Autre pratique importante : versionner et stocker le system‑prompt dans le dépôt avec le code. Les prompts ont, eux aussi, des versions, et les changements peuvent casser le comportement autant que des modifications de logique TypeScript. Il est bien plus agréable, lors de la revue d’une PR, de voir un diff :
- N’invente pas des cadeaux qui n’existent pas dans le catalogue.
+ N’invente pas des cadeaux qui n’existent pas dans le catalogue, même si l’utilisateur demande explicitement « d’imaginer quelque chose ».
plutôt que d’essayer de se rappeler que vous avez « légèrement retouché la formulation directement dans l’interface ».
7. Exemple complet de system‑prompt pour notre App pédagogique
Assemblons tout et écrivons un system‑prompt propre pour notre GiftGenius pédagogique. Découpons‑le en morceaux pour faciliter la lecture et les modifications.
Commençons par décrire le rôle et les tâches :
Rôle :
- Tu es GiftGenius, assistant de sélection de cadeaux de notre service.
- Tu échanges avec l’utilisateur poliment et de manière professionnelle, sans argot ni blagues, sauf si l’utilisateur en use lui‑même.
Tâches :
- Aide à choisir des cadeaux selon les paramètres donnés (profil du destinataire, ses centres d’intérêt, l’occasion, le budget).
- Explique, en termes simples et clairs, pourquoi tu proposes ces options précisément.
Définissons maintenant le périmètre et les limitations :
Périmètre de responsabilité :
- Tu travailles uniquement avec notre catalogue de cadeaux et ses métadonnées.
- N’invente pas des cadeaux, promotions ou remises absents du catalogue ou de la réponse des outils.
- Ne donne pas de conseils médicaux, juridiques ou financiers.
- Ne te porte pas garant du fonctionnement d’autres applications ou sites ; si l’utilisateur demande à ce sujet — dis que tu ne peux pas aider.
Ajoutons les règles d’utilisation des outils :
Utilisation des outils :
- Utilise l’outil `profile_to_segments` lorsqu’il faut transformer une description libre du destinataire en segments d’intérêt.
- Utilise l’outil `recommend_gifts` lorsqu’il faut trouver ou filtrer des cadeaux selon les paramètres de l’utilisateur (segments, budget, occasion, locale).
- Utilise l’outil `get_gift` lorsque l’utilisateur a besoin de détails sur un cadeau précis (description, type, prix, contraintes de livraison).
- Avant d’appeler les outils, essaie de préciser les paramètres manquants (âge du destinataire, budget, occasion) si, sans eux, le résultat sera inutile.
- Si la demande est théorique (par exemple : « comment choisir des cadeaux pour un premier anniversaire de mariage en général »), réponds toi‑même sans appeler d’outils.
Passons au bloc sur la sécurité et les actions au nom de l’utilisateur :
Sécurité :
- Ne finalise pas d’achat, d’abonnement ou d’envoi de cadeau sans confirmation explicite de l’utilisateur dans le chat.
- Si l’outil a besoin de données personnelles (e‑mail du destinataire, adresse de livraison, nom), explique d’abord à l’utilisateur pourquoi elles sont nécessaires et demande une confirmation.
- Ne transmets pas aux outils plus de données que nécessaire (par exemple, n’envoie pas le message complet s’il suffit de l’âge, des intérêts et du budget).
Et les règles globales/tonalité générale :
Règles générales :
- Si les outils retournent un résultat vide, dis‑le franchement et propose d’assouplir les conditions (modifier le budget, le type de cadeau, la catégorie ou l’occasion).
- Si l’utilisateur demande « ne pas ouvrir l’application » ou « se contenter du texte », respecte‑le et réponds uniquement par du texte, sans appel aux tools.
- Si la demande n’est pas liée aux cadeaux ou aux achats, réponds comme le ChatGPT de base et n’utilise pas les outils GiftGenius.
Au final, cette construction ressemble beaucoup à l’exemple des ressources supplémentaires sur le sujet : on y trouve les sections « Rôle », « Tâches », « À faire/À ne pas faire », « Utilisation des outils », « Sécurité », « Règles générales ».
Dans un projet Next.js, vous pouvez en faire un module séparé :
// app/config/giftGeniusPrompt.ts
export const giftGeniusSystemPrompt = `
Rôle :
- Tu es GiftGenius, assistant de sélection de cadeaux de notre service.
...
Règles générales :
- Si la demande n’est pas liée aux cadeaux, réponds comme le ChatGPT de base et n’utilise pas les outils GiftGenius.
`;
Puis utilisez cette constante dans la configuration de l’App (la manière exacte dépend de la version de l’Apps SDK, mais l’idée est la même : ce texte est envoyé dans le rôle system lors de l’initialisation du dialogue de l’App).
8. Contexte dynamique dans le system‑prompt
Parfois, le system‑prompt doit être légèrement « enrichi » de dynamique : date du jour, locale, type d’utilisateur (nouveau/ancien client), statut d’abonnement, etc.
Par exemple, si votre catalogue de cadeaux et vos prix varient selon les régions, vous pouvez transmettre la région actuelle dans le system‑prompt :
export function buildSystemPrompt(locale: string) {
return `
Rôle :
- Tu es GiftGenius, assistant de sélection de cadeaux pour la région ${locale}.
Périmètre :
- Utilise uniquement les cadeaux et prix disponibles dans la région ${locale}.
...
`;
}
L’Apps SDK, lors de l’initialisation de l’App, peut vous fournir _meta["openai/locale"], et vous générerez sur cette base la variante de prompt appropriée. Nous traiterons la localisation en détail plus tard, mais il est déjà utile de voir que le system‑prompt n’est pas forcément toujours statique.
L’essentiel — éviter de le transformer en « spaghetti » de conditions. Si la logique devient trop complexe, il vaut mieux scinder l’App ou déporter les conditions dans des tools (par exemple, pour que le serveur MCP choisisse lui‑même la bonne source de données selon la locale), et ne laisser dans le system‑prompt que les règles de haut niveau.
9. Lien entre le system‑prompt, la description des tools et les instructions UX
Cette leçon se concentre sur le system‑prompt, mais, dans une App réelle, il n’existe pas isolément. Il y a aussi les descriptions des outils (description, inputSchema) et des exemples de follow‑up que vous définirez dans les prochains sujets. Le tout forme un système d’instructions unifié.
Gestion de l’appel des tools :
- le system‑prompt définit la philosophie générale : « outils uniquement pour les données factuelles », « ne pas inventer des cadeaux », « ne pas acheter sans confirmation » ;
- les descriptions des tools précisent ce que fait exactement recommend_gifts, quels paramètres il requiert et quand il convient de l’appeler ;
- les phrases de follow‑up définissent le style de dialogue après l’appel de l’outil : comment dire honnêtement qu’on n’a rien trouvé, comment proposer de modifier la requête, comment résumer les résultats.
Si ces trois couches sont cohérentes, la modèle se comporte de manière prévisible :
- elle appelle l’App lorsque c’est réellement nécessaire ;
- elle n’hallucine pas des cadeaux/produits hors base ;
- elle explique clairement à l’utilisateur ce qui s’est passé (trouvé / pas trouvé / informations supplémentaires nécessaires).
Sinon — vous obtenez un comportement chaotique et de longues séances de « tuning magique de prompt », qui fatiguent très vite tout le monde.
10. Erreurs typiques avec le system‑prompt de la ChatGPT App
Erreur n°1 : écrire le system‑prompt « pour faire joli », et non comme un contrat.
Très souvent, les développeurs se limitent à des phrases générales du genre « Aide l’utilisateur à résoudre ses problèmes comme tu peux » et « Sois amical ». Cela n’aide pas la modèle à comprendre quand appeler l’App, où passent les frontières de responsabilité, s’il est permis d’inventer des données et que faire en cas d’erreur d’un outil. Au final, la moitié de la logique se disperse dans les piles de code et dans la tête de l’auteur, au lieu d’être ancrée dans un contrat explicite.
Erreur n°2 : rôle trop large (« aider pour tout »).
Si, dans la section « rôle », vous écrivez « Tu es un assistant qui aide l’utilisateur dans toutes ses questions », la modèle se mettra, très logiquement, à faire exactement cela, et n’aura pas toujours le réflexe de penser à votre App. L’App se transforme en option facultative, à peine utilisée, parce que la modèle estime pouvoir s’en sortir seule. Il vaut mieux préciser explicitement la niche : sélection de cadeaux, travail avec le catalogue de cadeaux, aide dans un domaine concret.
Erreur n°3 : absence de règles sur le moment d’appeler les outils.
Des formulations comme « utiliser les outils si nécessaire » sont trop vagues. La modèle peut soit ignorer totalement les tools, soit les appeler même là où une réponse « de tête » aurait suffi. Il faut clairement séparer les scénarios : données factuelles → tool, explications générales → réponse de la modèle, refus explicite de l’utilisateur d’utiliser l’App → texte seul.
Erreur n°4 : tenter de soigner les hallucinations avec la seule phrase « n’invente pas ».
La phrase « n’hallucine pas » aide peu à elle seule. Il est important de décrire explicitement ce qu’il est interdit d’inventer (produits/cadeaux hors catalogue, éléments sans ID, remises inexistantes) et quoi faire en cas de résultat vide (dire honnêtement que rien n’a été trouvé). Sans cela, la modèle cherchera quand même à « faire plaisir » et générera des variantes fictives. Il faut un ensemble complet : interdiction globale dans le system‑prompt, contraintes dans les descriptions des tools et modèles de réponses pour les cas « rien trouvé ».
Erreur n°5 : ignorer la sécurité et le consentement de l’utilisateur.
Si le system‑prompt ne stipule pas que l’achat, la réservation ou la modification de données personnelles exige une confirmation explicite, la modèle peut, avec les « meilleures intentions », appeler l’outil elle‑même. Du point de vue UX, c’est catastrophique. Indiquez toujours que toute action impliquant des finances ou le compte n’est effectuée qu’après consentement explicite dans le chat.
Erreur n°6 : ne pas tenir compte de l’existence d’autres App et outils.
Dans un monde où un même compte peut avoir plusieurs App et une multitude de tools, on ne peut pas compter sur le fait que la modèle « devinera d’elle‑même » quelle application utiliser. Si le system‑prompt ne verrouille pas le fait qu’il s’agit précisément de l’App de sélection de cadeaux — et seulement d’elle —, la modèle peut basculer de façon imprévisible entre différentes App ou tenter d’appliquer des outils à mauvais escient.
Erreur n°7 : modifier le system‑prompt « à chaud » sans versionnage ni tests.
La tentation est grande d’entrer dans la config, de changer une ligne et de croire que « cela n’a fait que s’améliorer ». En pratique, toute modification du prompt peut casser le comportement d’autres scénarios. Si vous ne stockez pas le system‑prompt dans le dépôt, ne regardez pas les diff et ne faites pas tourner un jeu de requêtes test (golden prompt set — nous y viendrons dans ce module), vous traquerez des régressions pendant des semaines.
GO TO FULL VERSION