1. Il system‑prompt come contratto, non testo decorativo
Nei moduli precedenti abbiamo guardato a ChatGPT App dal punto di vista dell’architettura: widget, tools e server MCP. In questa lezione ci concentriamo su come, con le parole, spieghiamo al modello il suo ruolo: cosa può fare, cosa non deve fare e come usare gli strumenti. In sostanza, progetteremo il system‑prompt come un contratto tra voi e il modello.
Nel normale chat con ChatGPT forse siete abituati a prompt del tipo «Immagina di essere un assistente pirata allegro» oppure «Spiega tutto come se parlassi a un bambino di cinque anni». Tutto ciò riguarda persona e stile. Nel contesto di ChatGPT App il termine system‑prompt ha un significato ben diverso.
Qui il system‑prompt è il primo messaggio di ruolo system, nascosto all’utente, che definisce per il modello:
- chi è all’interno della tua App;
- su quale compito è focalizzato;
- di cosa NON si occupa;
- come e quando deve invocare gli strumenti della tua applicazione.
In sostanza è una specifica di comportamento, molto vicina a un contratto formale. Se c’è accordo — il modello cercherà di rispettarlo. Se non c’è accordo — agirà come un ChatGPT «generico» e tutta la tua splendida App resterà in disparte.
Importante: per ChatGPT App questo system‑prompt:
- è collegato all’applicazione stessa, non a un singolo dialogo;
- impone limiti sia all’uso del widget sia alle chiamate dei tools;
- vive finché vive la sessione dell’App (mentre l’utente interagisce con la tua applicazione).
Semplificando, il patto è questo: tu fornisci al modello gli strumenti e gli descrivi il ruolo — che tipo di assistente è, cosa fa, cosa non fa, come usa gli strumenti e come tratta i dati dell’utente. Il modello, a sua volta, cerca di comportarsi proprio così.
2. Dove vive il system‑prompt nell’architettura
Per evitare che sembri una sorta di entità magica, è utile vederlo in uno schema.
sequenceDiagram
participant User as Utente
participant ChatGPT as ChatGPT + modello
participant App as La tua ChatGPT App
participant MCP as MCP/Backend
Note over ChatGPT: All'inizializzazione dell'App
il modello riceve il system‑prompt
User->>ChatGPT: "Scegli un regalo per un amico fino a 50 $"
ChatGPT->>ChatGPT: Applica il system‑prompt + le descrizioni dei tools
ChatGPT->>App: callTool recommend_gifts(...)
App->>MCP: HTTP /tools/recommend_gifts
MCP-->>App: Elenco dei regali
App-->>ChatGPT: Tool result (JSON)
ChatGPT-->>User: Testo + indicazione del widget con le card
Il system‑prompt arriva al modello al momento dell’inizializzazione dell’App, quando ChatGPT decide di «collegare» la tua applicazione al dialogo. Successivamente ogni decisione di ChatGPT — se chiamare o meno un tool, se proporre un widget, cosa dire quando i dati non ci sono — passa attraverso il prisma di questo contratto.
Dal punto di vista del codice, nell’Apps SDK è di solito una semplice stringa, da qualche parte vicino alla configurazione dell’App, ad esempio:
// app/config/systemPrompt.ts
export const giftGeniusSystemPrompt = `
Sei GiftGenius, assistente per la selezione dei regali...
`;
Poi questa stringa finisce nel punto in cui la tua applicazione si collega a ChatGPT. La «colla» tecnica può variare, ma per te è importante: il system‑prompt è un artefatto del codice proprio come lo schema di uno strumento o un componente React, e va progettato e conservato con la stessa cura.
Ora che è chiaro dove il system‑prompt vive nell’architettura e come arriva al modello, la cosa più importante è — cosa inserirci per farne un contratto e non una semplice descrizione di una «personcina simpatica».
3. Ruolo dell’App e limiti di responsabilità
La prima e principale sezione di qualsiasi system‑prompt ben fatto è: chi sei e di cosa sei responsabile.
La differenza tra «persona» e «App‑contract» è semplice: dire «sei un pirata e parli come un marinaio» riguarda il tono; dire «sei un’interfaccia al nostro catalogo di regali, scegli i regali e non ti occupi di altri argomenti» è già un contratto.
Per la nostra app didattica GiftGenius, che seleziona i regali, il nucleo del ruolo può essere così:
Ruolo:
- Sei GiftGenius, l'assistente per la selezione dei regali del nostro servizio.
- Il tuo compito è aiutare l’utente a scegliere un regalo adatto usando solo il nostro catalogo.
- Non fornisci consigli medici, legali o finanziari.
Nota l’enfasi.
Primo, definiamo il dominio in modo stretto: solo selezione di regali nell’ambito del nostro servizio. Serve per evitare che il modello inizi a «spiegare la fisica quantistica» invece di aprire la tua App e per impedire che provi a costruire per te strani workflow attorno ad altre applicazioni.
Secondo, fissiamo esplicitamente ciò che l’App non fa. Per esempio:
- non dà consigli su temi non legati a regali e acquisti;
- non inventa regali che non sono nel catalogo;
- non decide al posto dell’utente, ma propone opzioni e argomenta.
Tali limitazioni negative spesso contano più delle istruzioni positive: il modello «sa fare tutto»; nel system‑prompt tagli via il superfluo.
Per ambienti più complessi, dove uno sviluppatore ha più App (ad esempio «selezione regali» e «tracciamento spedizioni degli ordini»), nel system‑prompt è utile scrivere chiaramente che in questa App ti occupi solo della selezione dei regali, non gestisci ordini e logistica e non avvii altre applicazioni. Questo riduce il rischio che il modello inizi a confondersi su «di chi sia la competenza».
4. Quando invocare l’App e quando rispondere da soli
Il blocco critico successivo del contratto: regole di utilizzo degli strumenti.
Se non le specifichi, di solito tutto scivola in uno dei due estremi:
- il modello quasi mai invoca la tua App, perché gli è più semplice ed economico rispondere «di testa propria»;
- oppure, al contrario, inizia a invocare gli strumenti per qualsiasi cosa, anche per le domande più teoriche.
Nel system‑prompt per l’App bisogna fissare con chiarezza:
- in quali casi bisogna usare gli strumenti;
- in quali casi bisogna rispondere da soli, senza tools;
- cosa fare se l’utente chiede esplicitamente di «non avviare l’app».
Esempio di frammento testuale per GiftGenius:
Uso degli strumenti:
- Usa gli strumenti dell’App quando servono dati fattuali dal catalogo (elenco dei regali, prezzi, tipi di prodotto, disponibilità di consegna e sconti).
- Rispondi in autonomia se la domanda è teorica e non richiede accesso al catalogo (per esempio, "quali regali si fanno di solito per un’inaugurazione della casa").
- Se l’utente chiede esplicitamente "non aprire l’applicazione" o "rispondere senza widget", rispetta la richiesta e non invocare gli strumenti.
Qui accadono varie cose importanti.
Primo, le chiamate ai tools vengono collegate al tipo di richiesta: dati fattuali/di catalogo → strumento; teoria generale → risponde il modello.
Secondo, dichiariamo esplicitamente il rispetto delle intenzioni dell’utente: se la persona scrive «non avviare nulla, spiegami e basta», il modello non deve ignorare quel segnale.
Terzo, gestiamo così la frequenza d’uso dell’App. Un buon system‑prompt aiuta il modello a trovare l’equilibrio: l’App si usa quando serve, senza diventare un pop‑up invadente che salta fuori sempre.
Più avanti, nella prossima lezione sulle istruzioni di UX, parleremo separatamente di come il modello debba annunciare l’avvio del widget e cosa dire alla fine dello scenario. Qui ci interessano proprio le regole decisionali: usare o no l’App.
5. Uso sicuro dei tools e gestione dei dati dell’utente
Ora — sicurezza e buon senso.
Gli strumenti della tua App possono essere di vario tipo:
- quelli che lavorano con dati pubblici (cataloghi dei regali, disponibilità dei prodotti, condizioni di consegna);
- quelli che lavorano con dati personali e/o effettuano azioni a nome dell’utente (creazione di un ordine, addebito, modifica impostazioni).
Nel system‑prompt bisogna indicare come il modello deve trattare queste differenze.
Set di regole tipico:
Sicurezza e riservatezza:
- Non eseguire azioni che richiedono il consenso dell’utente (acquisto, attivazione di un abbonamento, modifica di dati personali) senza un’esplicita conferma in chat.
- Non passare agli strumenti più dati del necessario per il loro funzionamento (minimizzazione dei dati).
- Se la richiesta riguarda dati sensibili (salute, finanze, bambini), prima verifica che l’utente confermi l’invio di tali dati nell’applicazione.
In questo modo risolviamo più problemi.
Primo, proteggiamo l’utente da attività inattese: il modello non ha il diritto di acquistare un regalo o effettuare un ordine di sua iniziativa, se gli hai dato un tool simile. Prima — conferma testuale, poi — chiamata dello strumento.
Secondo, riduciamo il rischio di perdite di dati superflue: il modello tende a «buttare dentro tutto ciò che vede» come argomenti dello strumento; tu invece chiedi esplicitamente di limitarsi ai campi strettamente necessari.
Terzo, evidenziamo domini sensibili dove, anche senza tool finanziari, possono emergere rischi legali/etici.
Buona pratica — aggiungere per gli strumenti pericolosi nella loro descrizione (description) che modificano lo stato o effettuano pagamenti, e duplicarlo a livello di system‑prompt. Così hai un doppio sbarramento: sia nel contratto sia nella descrizione del singolo tool.
6. Formato e stile del system‑prompt: scrivere come una specifica
Uno degli errori più comuni — scrivere il system‑prompt come un testo di marketing: «Sei un assistente innovativo e incredibilmente intelligente che rende il mondo migliore…». È bello, ma al modello non importa. A lui interessa:
- chi sono;
- cosa fare;
- cosa non fare;
- come usare gli strumenti;
- come trattare i dati e le altre App.
Perciò è meglio trattare il system‑prompt come una specifica:
- dividerlo in blocchi logici: «Ruolo», «Compiti», «Confini», «Uso degli strumenti», «Sicurezza»;
- all’interno dei blocchi scrivere frasi brevi e univoche;
- evidenziare esplicitamente «fare» e «non fare» (sì, elenchi puntati sono appropriati dentro il prompt stesso).
Un frammento di prompt strutturato per GiftGenius può essere così:
Ruolo:
- Sei GiftGenius, l'assistente per la selezione dei regali del nostro servizio.
Compiti:
- Aiuta l’utente a scegliere i regali in base al compito, agli interessi del destinatario e al budget.
- Spiega pro e contro di ogni opzione con linguaggio semplice.
Non fare:
- Non inventare regali che non sono nel catalogo.
- Non promettere funzionalità del servizio che non esistono (ad esempio, consegna gratuita se dal catalogo risulta a pagamento).
Conviene mantenere uno stile neutro e «asciutto»: non è un testo promozionale, ma un contratto. Meno ambiguità — più comportamento stabile.
Un’altra pratica importante: versionare e conservare il system‑prompt nel repository insieme al codice. Anche i prompt hanno versioni e le modifiche possono rompere il comportamento tanto quanto cambiare la logica TypeScript. È molto meglio vedere un diff in code review:
- Non inventare regali che non sono nel catalogo.
+ Non inventare regali che non sono nel catalogo, anche se l’utente chiede esplicitamente "inventati qualcosa".
piuttosto che cercare di ricordare che «hai ritoccato un po’ la formulazione direttamente nell’interfaccia».
7. Esempio completo di system‑prompt per la nostra App didattica
Mettiamo insieme tutto e scriviamo un system‑prompt pulito per la nostra GiftGenius didattica. Lo divideremo in parti per facilitarne lettura e modifica.
Per prima cosa descriviamo ruolo e compiti:
Ruolo:
- Sei GiftGenius, l'assistente per la selezione dei regali del nostro servizio.
- Comunichi con l’utente in modo educato e professionale, senza slang o battute, a meno che non li usi per primo l’utente.
Compiti:
- Aiuta a selezionare i regali in base ai parametri forniti (profilo del destinatario, interessi, occasione, budget).
- Spiega in modo semplice e comprensibile perché proponi proprio queste opzioni.
Ora definiamo confini e limitazioni:
Limiti di responsabilità:
- Lavori solo con il nostro catalogo di regali e i relativi metadati.
- Non inventare regali, promozioni o sconti che non sono nel catalogo o nella risposta degli strumenti.
- Non fornire consigli medici, legali o finanziari.
- Non sei responsabile del funzionamento di altre applicazioni o siti; se l’utente chiede su questo, dichiara che non puoi aiutare.
Aggiungiamo le regole di lavoro con gli strumenti:
Uso degli strumenti:
- Usa il tool `profile_to_segments` quando devi trasformare una descrizione libera del destinatario in segmenti di interesse.
- Usa il tool `recommend_gifts` quando devi trovare o filtrare regali in base ai parametri utente (segmenti, budget, occasione, localizzazione).
- Usa il tool `get_gift` quando all’utente servono dettagli su un regalo specifico (descrizione, tipo, prezzo, vincoli di consegna).
- Prima di invocare gli strumenti, prova a chiarire i parametri mancanti (età del destinatario, budget, occasione) se senza di essi il risultato sarebbe inutile.
- Se la richiesta è teorica (ad esempio, "come scegliere in generale i regali per il primo anniversario di matrimonio"), rispondi tu senza invocare strumenti.
Adesso — il blocco su sicurezza e azioni a nome dell’utente:
Sicurezza:
- Non effettuare acquisti, abbonamenti o invii di regali senza esplicita conferma dell’utente in chat.
- Se per il funzionamento dello strumento servono dati personali (e‑mail del destinatario, indirizzo di consegna, nome), spiega prima all’utente perché servono e chiedi conferma.
- Non passare agli strumenti più dati del necessario (ad esempio, non inviare l’intero messaggio se bastano età, interessi e budget).
E il tono/ragole generali:
Regole generali:
- Se gli strumenti restituiscono un risultato vuoto, dillo onestamente e proponi di allentare i vincoli (modificare budget, tipo di regalo, categoria o occasione).
- Se l’utente chiede "non aprire l’applicazione" o "fare a meno del widget", rispetta la richiesta e rispondi solo con testo, senza invocare tools.
- Se la richiesta non è legata a regali o acquisti, rispondi come ChatGPT di base e non usare gli strumenti di GiftGenius.
Alla fine, questa costruzione assomiglia molto all’esempio nei materiali aggiuntivi sul tema: ci sono le sezioni «Ruolo», «Compiti», «Fare/Non fare», «Uso degli strumenti», «Sicurezza», «Regole generali».
In Next.js puoi metterla in un modulo separato:
// app/config/giftGeniusPrompt.ts
export const giftGeniusSystemPrompt = `
Ruolo:
- Sei GiftGenius, l'assistente per la selezione dei regali del nostro servizio.
...
Regole generali:
- Se la richiesta non è legata ai regali, rispondi come ChatGPT di base e non usare gli strumenti di GiftGenius.
`;
Quindi usa questa costante nella configurazione dell’App (come esattamente — dipende dalla versione dell’Apps SDK, ma l’idea è la stessa: questo testo viene inserito come ruolo system all’inizializzazione del dialogo dell’App).
8. Contesto dinamico nel system‑prompt
A volte il system‑prompt va «condito» un po’ di dinamica: data corrente, localizzazione, tipo di utente (nuovo/di ritorno), stato dell’abbonamento, ecc.
Per esempio, se il tuo catalogo di regali e i prezzi differiscono per regioni, puoi passare al system‑prompt la regione attuale:
export function buildSystemPrompt(locale: string) {
return `
Ruolo:
- Sei GiftGenius, l'assistente per la selezione dei regali per la regione ${locale}.
Confini:
- Usa solo i regali e i prezzi disponibili nella regione ${locale}.
...
`;
}
L’Apps SDK, all’inizializzazione dell’App, può fornirti _meta["openai/locale"], e tu genererai la variante di prompt necessaria. Tratteremo la localizzazione più avanti, ma è già utile vedere che il system‑prompt non deve per forza essere statico.
La cosa fondamentale è non trasformarlo in «spaghetti» di condizioni. Se la logica diventa troppo complessa, è meglio separare l’App o trasferire le condizioni nei tools (ad esempio facendo scegliere al server MCP la fonte dati in base alla locale), e lasciare nel system‑prompt solo regole di alto livello.
9. Come il system‑prompt si collega alla descrizione dei tools e alle istruzioni UX
Questa lezione si concentra sul system‑prompt, ma in un’App reale non esiste da solo. Ci sono anche le descrizioni degli strumenti (description, inputSchema) e gli esempi di follow‑up che imposterai nelle lezioni successive. Tutto questo insieme forma un sistema unico di istruzioni.
Gestione della chiamata dei tools:
- il system‑prompt definisce la filosofia generale: «strumenti solo per dati fattuali», «non inventare regali», «non acquistare senza conferma»;
- le descriptions dei tools precisano cosa fa recommend_gifts, quali parametri servono e quando va chiamato;
- le frasi di follow‑up impostano lo stile del dialogo dopo la chiamata dello strumento: come dire onestamente che non è stato trovato nulla, come proporre di modificare la richiesta, come riassumere i risultati.
Se questi tre strati sono coerenti, il modello si comporta in modo prevedibile:
- invoca l’App quando serve davvero;
- non «allucina» regali/prodotti fuori base dati;
- spiega chiaramente all’utente cosa è successo (trovato / non trovato / servono più informazioni).
Se non lo sono — otterrai un comportamento caotico e lunghe sessioni di «magico tuning del prompt» che stancano tutti molto in fretta.
10. Errori tipici con il system‑prompt di ChatGPT App
Errore n. 1: scrivere il system‑prompt «per bellezza», non come contratto.
Spesso gli sviluppatori si limitano a frasi generiche come «Aiuta l’utente a risolvere i problemi come puoi» e «Sii amichevole». Questo non aiuta il modello a capire quando invocare l’App, dove stanno i confini di responsabilità, se può inventare dati e cosa fare in caso di errore dello strumento. Di conseguenza, metà della logica si sparpaglia tra gli stack di codice e la testa dell’autore, invece di essere incapsulata in un contratto esplicito.
Errore n. 2: ruolo troppo ampio («aiuta in tutto»).
Se nella sezione del ruolo scrivi «Sei un assistente che aiuta l’utente in qualsiasi questione», il modello inizierà felicemente a fare proprio questo e non sempre si ricorderà della tua App. L’App diventa un’opzione non necessaria, usata raramente, perché il modello pensa di farcela da solo. È meglio indicare esplicitamente la nicchia: selezione dei regali, lavoro con il catalogo dei regali, aiuto in un dominio specifico.
Errore n. 3: assenza di regole su quando invocare gli strumenti.
Formulazioni come «usa gli strumenti quando necessario» sono troppo vaghe. Il modello può o ignorare completamente i tools o chiamarli anche dove basterebbe rispondere «di testa propria». Bisogna separare chiaramente gli scenari: dati fattuali → tool, spiegazioni di background → risponde il modello, rifiuto esplicito dell’utente dell’App → solo testo.
Errore n. 4: cercare di curare le allucinazioni con la sola frase «non inventare».
La frase «non avere allucinazioni» di per sé serve a poco. È importante descrivere chiaramente cosa esattamente è vietato inventare (prodotti/regali fuori catalogo, posizioni senza ID, sconti inesistenti) e cosa fare quando il risultato è vuoto (dire onestamente che non è stato trovato nulla). Senza questo, il modello cercherà comunque di «far piacere», generando varianti inventate. Serve un set completo: divieto globale nel system‑prompt, limitazioni nelle descrizioni dei tools e modelli di risposta per i casi «non c’è nulla».
Errore n. 5: ignorare sicurezza e consenso dell’utente.
Se nel system‑prompt non è scritto che acquisto, prenotazione o modifica di dati personali richiedono conferma esplicita, il modello potrebbe, con «buone intenzioni», chiamare lo strumento da solo. Dal punto di vista UX è una catastrofe. Specifica sempre che le azioni che coinvolgono finanze o account si fanno solo dopo chiara conferma in chat.
Errore n. 6: non considerare l’esistenza di altre App e strumenti.
In un mondo in cui un account può avere più App e un mucchio di tools, non si può presumere che il modello «capisca da solo» quale applicazione usare. Se il system‑prompt non sancisce che questa è proprio l’App per la scelta dei regali e solo per quella, il modello può passare in modo imprevedibile tra diverse App o cercare di usare strumenti fuori contesto.
Errore n. 7: modificare «a caldo» il system‑prompt senza versionamento e test.
È allettante entrare nel config, cambiare una riga e credere che «sia solo meglio». In pratica qualsiasi modifica del prompt può rompere il comportamento di altri scenari. Se non conservi il system‑prompt nel repository, non guardi i diff e non esegui una batteria di richieste di test (golden prompt set — ci arriveremo in questo modulo), rincorrerai regressioni per settimane.
GO TO FULL VERSION