1. Perché le istruzioni non bastano senza buoni tools e metadati
È importante chiarire una verità scomoda: il modello non vede il vostro codice. Non sa quali controller ci siano in Next.js, quali funzioni in TypeScript e quali splendide euristiche abbiate raccolto nel servizio di raccomandazione.
Vede la vostra App attraverso alcuni interfacce:
- System‑prompt (contratto di ruolo).
- Descrizioni degli strumenti: nome, description, inputSchema, outputSchema, annotazioni ecc.
- Metadati dell’applicazione: nome, icona, descrizione breve e lunga, categorie, conversation starters ecc.
Durante l’elaborazione della richiesta il modello guarda al contesto del dialogo e a questi metadati, per decidere:
- se proporre o meno un’App;
- se sì — quale tra quelle disponibili;
- e, se l’App è stata scelta, quale strumento specifico di questa App si adatta alla richiesta corrente.
Nella parte precedente del Modulo 5 ci siamo occupati di ciò che si può “raccontare” al modello a parole — system‑prompt e istruzioni UX. Ora passiamo a ciò che vede oltre al testo: tools e metadati.
Perciò il compito del Modulo 5 è in realtà doppio. Prima, nel system‑prompt formulate “che cosa deve fare questa App e come deve comportarsi”, poi, nel design di tools e metadati, impacchettate tutto in una forma che il modello sappia davvero usare — anche per discovery e instradamento.
Possiamo dirlo così: il system‑prompt è la costituzione, mentre tools e metadati sono le leggi e tutta la burocrazia intorno: moduli di richiesta, schemi di database ecc. Se vi limitate alla sola costituzione, non andrete lontano.
2. Scomposizione: “un compito — un tool”, ma con criterio
Partiamo dal più doloroso: quanti strumenti creare e come suddividerli.
Principio intuitivo: uno strumento — un compito chiaro. Questo semplifica molto la scelta del modello: invece di un’unica funzione mostruosa do_everything, ha più azioni curate con buoni nomi.
Per GiftGenius possiamo avere questi strumenti di base:
- profile_to_segments — trasformare una descrizione libera del destinatario (età, interessi, relazioni, contesto) in segmenti normalizzati come "tech", "fitness", "gamer".
- recommend_gifts — selezionare un elenco di id di regali in base ai segmenti, al budget, alla locale e all’occasione.
- get_gift — ottenere la scheda completa del regalo scelto (descrizione, media, SKU/varianti) dal suo id.
- (opzionale) similar_gifts — dato un regalo selezionato, proporre altri 3–5 suggerimenti simili.
In teoria si potrebbe creare un unico gift_tool con parametro mode: "profile_to_segments" | "recommend" | "details" | "similar", ma così complicate la vita sia a voi sia al modello: la descrizione diventa infinita, l’inputSchema cresce, e durante la scelta dello strumento il modello ha meno ancore nette.
Anti‑pattern: God Tool
Immaginate uno schema di questo tipo:
server.registerTool(
"gift_tool",
{
description: "Operazioni varie con i regali.",
inputSchema: { /* 50 campi e flag */ },
},
async ({ input }) => { /* enorme switch su mode */ }
);
Nella testa del modello questo appare come “esiste un qualche strumento astratto sui regali, poi vediamo”. Ciò peggiora la precisione della scelta, ostacola la discovery e vi complica la manutenzione.
Ma cadere nell’estremo opposto — creare 50 strumenti microscopici per ogni piccolo passo — è altrettanto sbagliato. Ogni strumento in più entra nel contesto, sovraccarica l’attenzione del modello e aumenta il rischio di errori di instradamento. La documentazione avverte chiaramente: troppi strumenti piccoli sono un male per la qualità, soprattutto quando le loro descrizioni si sovrappongono.
Regola pratica comoda da usare:
- tutto ciò che l’utente percepisce come un unico “passo” nel flusso (ad esempio, la prima selezione di regali a partire dal profilo) — è un buon candidato per un tool separato;
- ciò che si esegue sempre strettamente dentro quel passo e non ha senso autonomo (ad esempio, calcolare uno scoring o registrare la visualizzazione delle schede) è meglio lasciarlo all’interno dell’implementazione dello strumento.
Supponiamo che secondo questo principio abbiate già scomposto gli scenari in 2–4 strumenti. La domanda successiva — come descrivere gli input di questi tools affinché il modello possa usarli senza supposizioni. Partiamo da qui.
3. Proiettiamo gli use case sull’Input Schema
Prendiamo un use case specifico e guardiamo onestamente quali dati servono davvero allo strumento.
Scenario: “Donatore contro il tempo: trovare 5–7 idee per un amico di 25 anni, ama il calcio e i giochi da tavolo, budget fino a 50 $”.
Dalle jobs‑to‑be‑done risulta che il compito del motore di raccomandazione di GiftGenius è restringere la scelta a un elenco ridotto e diminuire l’ansia “e se scelgo una cosa sbagliata”. A livello di chat l’assistente ha bisogno di:
- informazioni di base sul destinatario (età, genere, relazione con il donatore);
- interessi/hobby;
- budget e valuta;
- occasione (compleanno, anniversario, Capodanno, ecc.);
- opzionale — paese/città per filtrare in base alla consegna.
Nell’architettura di GiftGenius questo è scomposto in due passi:
- profile_to_segments(input) riceve i dati “grezzi” (età, interessi, descrizione testuale) e li trasforma in segmenti normalizzati, con cui è più comodo lavorare in seguito.
- recommend_gifts(segments, budget, locale, occasion) in base ai segmenti e al budget seleziona id specifici di regali dal catalogo.
Dal punto di vista del contratto ChatGPT ↔ MCP ci interessa descrivere proprio il secondo passo — lo schema di recommend_gifts, perché è lo strumento usato nella maggior parte degli scenari di selezione.
Non è necessario chiedere subito all’utente tutto: il modello può completare qualcosa via follow‑up (“qual è più o meno il budget?”). Quindi una parte dei campi del profilo può essere opzionale; ma quando arriviamo a recommend_gifts, deve già esserci un set di parametri normalizzato.
Esempio: TypeScript + JSON Schema per recommend_gifts
Nel server MCP in TypeScript potrebbe essere così:
// apps/mcp/server.ts
import { McpServer } from "@openai/mcp-server";
const server = new McpServer();
server.registerTool(
"recommend_gifts",
{
title: "Raccomandazioni di regali",
description:
"Usa questo strumento quando devi selezionare regali in base ai segmenti del destinatario, al budget, alla locale e all’occasione.",
inputSchema: {
type: "object",
properties: {
segments: {
type: "array",
description:
"Elenco dei segmenti del destinatario, ad esempio ['tech', 'football_fan']. Di solito deriva da profile_to_segments.",
items: { type: "string" },
minItems: 1
},
budget: {
type: "object",
description:
"Intervallo di budget per il regalo nella valuta dell’utente (minimo/massimo).",
properties: {
min: {
type: "number",
minimum: 0,
description: "Importo minimo che l’utente è disposto a spendere."
},
max: {
type: "number",
minimum: 0,
description: "Importo massimo che l’utente è disposto a spendere."
},
currency: {
type: "string",
minLength: 3,
maxLength: 3,
description: "Codice valuta a tre lettere (ad es., USD, EUR, RUB)."
}
},
required: ["min", "max", "currency"]
},
locale: {
type: "string",
description:
"Locale dell’utente in formato BCP‑47 (per es., 'ru-RU' o 'en-US')."
},
occasion: {
type: "string",
description:
"Occasione per il regalo, ad es. 'birthday', 'new_year', 'anniversary'."
}
},
required: ["segments", "budget", "locale", "occasion"]
}
},
async ({ input }) => {
// Per ora niente di sofisticato, restituiamo un placeholder
return {
content: [
{
type: "text",
text: `Seleziono i regali per i segmenti ${input.segments?.join(
", "
)} nel budget ${input.budget?.min}–${input.budget?.max} ${input.budget?.currency}...`
}
],
structuredContent: {}
};
}
);
Nota un paio di aspetti.
Primo, usiamo attivamente vincoli tipo enum e descrizioni chiare. Anche se formalmente sono solo stringhe, la description suggerisce al modello quali valori sono attesi, e ciò aumenta sensibilmente la probabilità che compili correttamente gli argomenti. Invece di una stringa vaga "occasione": "qualcosa tipo compleanno" abbiamo una occasion: "birthday" ben definita.
Secondo, le descrizioni dei campi vanno scritte non “per i membri del team”, ma letteralmente come suggerimenti al modello: che cos’è il campo, quali valori tipici, esempi. Gli autori della documentazione dell’Apps SDK raccomandano esplicitamente di aggiungere descrizioni ed esempi comprensibili per ogni parametro.
Cosa non deve esserci nello schema di input
Campi parassiti tipici che spesso si tenta di infilarci dentro:
- identificatori interni (tenantId, internalSegment) che potete aggiungere lato server comunque;
- elementi che il modello non può conoscere (ad esempio, deploymentRegion) — è responsabilità vostra;
- campi duplicati della storia della chat (ad esempio, userPrompt): il modello vede già il messaggio originale, non obbligatelo al copia‑incolla.
L’Input Schema è esattamente ciò che il modello deve decidere e compilare, non un contenitore di tutto.
4. Output Schema: non solo dati, ma anche significato
Nell’Apps SDK il risultato dello strumento torna nel dialogo come messaggio con role: tool. Poi è il modello a decidere cosa farne: come formattare la risposta, quali follow‑up chiedere, se aprire un widget ecc. Perciò il design dello schema di uscita è importante quanto quello di ingresso.
Ci sono due approcci.
Variante “dati grezzi”:
{
"items": [
{ "id": "GIFT_1" },
{ "id": "GIFT_2" }
]
}
Il modello vede solo un elenco di id, senza capire perché queste opzioni siano qui, quanti candidati ci fossero e quali siano i migliori. Può inventare qualcosa, ma la probabilità di stranezze aumenta.
Variante semanticamente ricca:
{
"items": [
{
"id": "GIFT_1",
"score": 0.92,
"reason": "Forte corrispondenza con il segmento 'football_fan' e rientra nel budget."
},
{
"id": "GIFT_2",
"score": 0.81,
"reason": "Adatto per un appassionato di giochi da tavolo, un po’ vicino al limite superiore del budget."
}
],
"meta": {
"totalCandidates": 27,
"returned": 5,
"segmentsUsed": ["football_fan", "board_games"],
"budget": { "min": 20, "max": 50, "currency": "USD" },
"advice": "Meglio iniziare dalle opzioni con lo score più alto e una spiegazione chiara."
}
}
Ora il modello può spiegare onestamente perché proprio questi regali e costruire un follow‑up: “Ho trovato 27 opzioni, ne mostro 5 fra le migliori, ecco perché”.
Esempio: descriviamo l’Output Schema per recommend_gifts
Aggiungiamo la descrizione dello schema del risultato (anche se tecnicamente si potrebbe ometterla, è meglio indicarla — fa parte del contratto con il modello):
const recommendGiftsOutputSchema = {
type: "object",
properties: {
items: {
type: "array",
items: {
type: "object",
properties: {
id: { type: "string", description: "ID del regalo nel catalogo." },
score: {
type: "number",
description: "Valutazione di corrispondenza al profilo (0..1)."
},
reason: {
type: "string",
description:
"Breve spiegazione del perché il regalo è adatto (può essere generata nel backend)."
}
},
required: ["id", "score"]
},
description: "Elenco di regali consigliati con valutazioni di rilevanza."
},
meta: {
type: "object",
properties: {
totalCandidates: {
type: "integer",
description: "Quanti candidati sono stati trovati nel catalogo."
},
returned: {
type: "integer",
description: "Quanti regali ha restituito questa chiamata."
},
advice: {
type: "string",
description:
"Raccomandazione generale: ad esempio, da quale tipo di regali conviene iniziare."
}
}
}
},
required: ["items"]
};
E usiamo questo schema all’interno dell’implementazione:
server.registerTool(
"recommend_gifts",
{
title: "Raccomandazioni di regali",
description:
"Usa quando devi selezionare 3–7 regali in base a segmenti e budget. Restituisce gli id dei regali e le valutazioni di corrispondenza; ottieni le schede dettagliate tramite get_gift.",
inputSchema: /* come sopra */,
// Non sempre si specifica formalmente l’outputSchema, ma è utile per la documentazione:
// outputSchema: recommendGiftsOutputSchema
},
async ({ input }) => {
const recommendations = await recommendFromCatalog(input); // la nostra business logic
return {
content: [
{
type: "text",
text: `Ho trovato ${recommendations.items.length} idee adatte. Ora mostro le migliori.`
}
],
structuredContent: {
items: recommendations.items,
meta: {
totalCandidates: recommendations.meta.totalCandidates,
returned: recommendations.items.length,
advice: recommendations.meta.advice
}
}
};
}
);
Facciamo due cose: forniamo al modello un testo minimo per l’utente e contemporaneamente inseriamo un JSON semantico su cui può costruire il dialogo e i follow‑up.
Nel frattempo get_gift recupererà tramite id le schede complete (nome, media, SKU ecc.), e il widget GiftGenius le renderà come card di regali.
5. Denominazione e descrizioni degli strumenti come base della discovery
Ora la parte più interessante: come nomi e descrizioni dei tools influenzano il fatto che il modello li invochi o meno.
La documentazione e le best practice sui metadati consigliano:
- usare nomi orientati all’azione: profile_to_segments, recommend_gifts, get_gift, similar_gifts, e non tool1, search, do_stuff;
- iniziare la descrizione in stile “Use this when… / Usa questo strumento quando…”, descrivendo gli scenari trigger e i limiti (“non usarlo per…”).
Questo è direttamente collegato al vostro golden prompt set. Le formulazioni nella descrizione devono sovrapporsi alle richieste reali degli utenti. Se nella descrizione è scritto “Usa quando l’utente chiede di selezionare un regalo in base al budget e agli interessi del destinatario” e nel golden prompt avete “trova un regalo per un amico gamer fino a 50 $”, il modello riconcilierà più facilmente la richiesta con lo strumento.
Esempio di buona descrizione di uno strumento
Consideriamo uno strumento aggiuntivo di GiftGenius — similar_gifts, che aiuta ad ampliare la selezione con idee simili basate su un regalo specifico:
server.registerTool(
"similar_gifts",
{
title: "Regali simili",
description:
"Usa questo strumento quando l’utente ha scelto un regalo specifico e vuole vedere alcune alternative simili. Non usarlo per la prima selezione da zero — per quello c’è recommend_gifts.",
inputSchema: {
type: "object",
properties: {
giftId: {
type: "string",
description:
"Identificatore del regalo dalla selezione precedente, per cui trovare alternative simili."
},
limit: {
type: "integer",
description:
"Quanti regali simili restituire (per impostazione predefinita 3–5).",
minimum: 1,
default: 5
}
},
required: ["giftId"]
}
},
async () => {
/* ... */
}
);
Punti importanti:
- Diciamo esplicitamente quando usare lo strumento e quando no.
- Nella descrizione compaiono parole come “alternative simili”, “ha scelto un regalo specifico” — proprio quelle che si incontreranno spesso nelle richieste reali degli utenti.
- Evitiamo la sovrapposizione con l’area di recommend_gifts — ciò riduce la concorrenza tra strumenti al momento della scelta.
Esempio di cattiva descrizione
description: "Lavoro con i regali."
Il modello non capisce praticamente nulla da una descrizione del genere. Uno strumento così può funzionare solo se GPT sta già cercando disperatamente di chiamare qualcosa “a caso”.
6. Annotazioni e hint: come segnalare al modello la gravità di un’azione
Uno strumento non è solo nome e schema, ma anche annotazioni che suggeriscono a ChatGPT quanto sia pericolosa/importante l’azione e se occorre chiedere conferma all’utente. Nella specifica dell’Apps SDK esistono vari hint, come readOnlyHint, destructiveHint, openWorldHint e altri.
- readOnlyHint: true indica che lo strumento legge soltanto i dati e non modifica lo stato. L’assistente può quindi saltare conferme superflue e invocarlo più liberamente.
- destructiveHint: true segnala che lo strumento può eliminare o modificare irrevocabilmente qualcosa, quindi va mostrato all’utente un chiaro “Sei sicuro?”.
- openWorldHint: true indica che l’azione tocca il mondo esterno (post sui social, creazione di un record fuori dall’account, ecc.) e anche questo va segnalato.
Livello minimo — senza conferme
Se avete public readonly tools, conviene marcarli con readOnlyHint: true. Esempio:
"annotations": {
"readOnlyHint": true,
"destructiveHint": false,
"openWorldHint": false
}
Questi strumenti possono essere invocati senza conferme di dialogo superflue da parte di GPT.
Una conferma
Se avete tools che modificano qualcosa sul server, è logico marcarli con readOnlyHint: false:
"annotations": {
"readOnlyHint": false,
"destructiveHint": false,
"openWorldHint": false
}
Vedendo uno strumento del genere, il modello probabilmente chiederà all’utente una conferma una volta (di solito è una finestra modale nell’UI di ChatGPT).
Azione pericolosa
Se avete un tool che elimina qualcosa sul server, marcatelo con destructiveHint: true:
"annotations": {
"readOnlyHint": false,
"destructiveHint": true,
"openWorldHint": false
}
Il modello chiamerà questo tool con grande cautela e chiederà conferma due volte:
- prima chiederà conferma all’utente nel testo,
- poi la piattaforma mostrerà una finestra di dialogo standard.
Per il nostro GiftGenius, in questo modulo non scriviamo strumenti di commerce, ma possiamo abbozzare come apparirà il futuro create_gift_order:
server.registerTool(
"create_gift_order",
{
title: "Creazione dell’ordine regalo",
description:
"Usa solo dopo il consenso esplicito dell’utente ad acquistare il regalo scelto. Crea un ordine nel sistema e restituisce lo stato.",
inputSchema: {
type: "object",
properties: {
giftId: {
type: "string",
description: "ID del regalo scelto dall’utente."
},
deliveryEmail: {
type: "string",
description: "Email a cui inviare il regalo digitale."
}
},
required: ["giftId", "deliveryEmail"]
},
annotations: {
destructiveHint: true,
openWorldHint: true
}
},
async () => {
/* ... */
}
);
Le annotazioni non sostituiscono i vostri controlli di autorizzazione sul server: aiutano ChatGPT a impostare l’UX — chiedere conferma, mostrare avvisi e non eseguire strumenti del genere “di nascosto”.
7. Metadati dell’App e due livelli di discovery
Gli strumenti sono metà della storia. L’altra metà — come l’utente trova e avvia la vostra App.
Nell’ecosistema di ChatGPT esistono due livelli chiave di discovery.
Il primo — in‑conversation discovery. Quando l’utente scrive qualcosa in chat (anche senza menzionare esplicitamente l’App), il modello guarda:
- al testo del messaggio e alla storia del dialogo;
- alle descrizioni delle app disponibili e dei loro strumenti;
- ai riferimenti al brand, all’argomento e alle parole chiave.
Sulla base di ciò decide se proporre un’App, e se sì — quale e con quale scenario. Qui sono particolarmente importanti le descrizioni degli strumenti e dell’App stessa. Se in esse compaiono “trigger” come “selezione di regali”, “idea regalo”, “budget del regalo”, la probabilità che il modello scelga la vostra App cresce sensibilmente.
Il secondo livello — discovery globale: catalogo e launcher. Qui entra in gioco la persona: sceglie l’App a colpo d’occhio in base al nome, all’icona, alla descrizione breve e ai tag. È importante spiegare in modo onesto e chiaro cosa fa la vostra applicazione, per chi è e qual è il suo valore principale.
Possiamo riassumere in una piccola tabella:
| Livello | Cosa vede modello/utente | Cosa è importante nei metadati |
|---|---|---|
| In‑conversation | Testo della conversazione, descrizioni di tools e App | Formulazioni trigger, nomi orientati all’azione, limitazioni |
| Catalogo/launcher | Nome, icona, short/long description, tag | Posizionamento chiaro, value props comprensibili |
Per GiftGenius si può, ad esempio, formulare così:
- Nome: GiftGenius — selezione di regali in 60 secondi.
- Descrizione breve: Raccoglie il profilo del destinatario e propone 5–7 idee regalo con la possibilità di acquisto immediato dentro ChatGPT.
- Descrizione per in‑conversation: Usa questa applicazione quando l’utente chiede aiuto nella scelta di un regalo, non sa cosa regalare, indica un budget, gli interessi del destinatario o l’occasione.
Queste formulazioni è altamente consigliabile sincronizzarle con quanto avete già scritto nel system‑prompt e nelle descrizioni dello strumento recommend_gifts. Così il modello vede un quadro coerente, non un insieme di testi contraddittori.
8. Come funziona l’instradamento “nella testa” di ChatGPT
Mettiamo insieme tutto e guardiamo un tipico percorso della richiesta — senza approfondire il protocollo MCP, lo faremo nei moduli successivi.
Supponiamo che l’utente scriva:
“Aiutami a inventare un regalo per mio fratello, adora il calcio e i giochi da tavolo, budget fino a 50 $.”
Algoritmo grossolanamente semplificato:
- Il modello analizza il messaggio e la storia. Vede le parole “regalo”, “fratello”, “calcio”, “giochi da tavolo”, “budget 50”.
- Confronta con le descrizioni delle App disponibili e dei loro strumenti. Per GiftGenius le descrizioni contengono esplicitamente “selezione di regali per interessi e budget”, quindi la probabilità di pertinenza è alta.
- Se l’App non è ancora attiva in questa sessione, il modello forma una battuta‑annuncio: “Posso aprire l’app GiftGenius, che aiuta a selezionare un regalo in base ai tuoi parametri. Apro?” — l’abbiamo prescritto in anticipo nelle istruzioni UX.
- Dopo il consenso dell’utente, il modello sceglie dentro l’App lo strumento recommend_gifts, perché la sua descrizione è quella che meglio corrisponde all’intento attuale. Qui nome, description e la struttura dell’inputSchema agiscono come segnali in ingresso.
- Il modello compila gli argomenti dello strumento basandosi sulla richiesta: innanzitutto (se necessario) chiama profile_to_segments per ottenere dai testi “fratello, ama il calcio e i giochi da tavolo” i segmenti ["football_fan", "board_games"], poi chiama recommend_gifts con segments, budget: {min: 0, max: 50, currency: "USD"}, locale, occasion: "birthday".
- Il server MCP esegue lo strumento, forma l’output strutturato con items e meta e lo restituisce.
- Il modello legge il JSON che avete descritto nell’outputSchema e compone la risposta: spiega cosa ha trovato, perché proprio quei regali, e propone follow‑up (“volete restringere per categoria?”, “mostrare simili a questo regalo?” oppure “procedere all’acquisto di questo regalo?”).
Ecco un semplice diagramma di flusso del processo:
flowchart TD A[Utente: richiesta su un regalo] --> B[ChatGPT analizza il contesto] B --> C[Confronto con i metadati di App e tools] C -->|rilevante| D[Annuncio di GiftGenius] D -->|utente consente| E["Chiamata recommend_gifts (+ profile_to_segments)"] E --> F[Server MCP di GiftGenius] F --> G[Risultato JSON con items/meta] G --> H[Il modello compone la risposta e il follow‑up]
Più accuratamente descrivete strumenti e use case, meno casualità ci sarà e più stabile sarà l’instradamento.
Insight: Tool Call SEO
Nell’ecosistema delle Apps avrete presto non solo competizione per l’attenzione delle persone nel catalogo, ma anche competizione per l’attenzione del modello stesso. Alla stessa richiesta dell’utente ChatGPT può chiamare una decina di applicazioni diverse, e la scelta avverrà non per chi ha il design di presentazione migliore, ma nel “risultato di ricerca” nella testa del modello. Questo strato invisibile ricorda sempre più la SEO, solo che al posto delle pagine avete tools e server MCP.
Il modello di fatto classifica i candidati: prima a livello di App, poi a livello dei singoli strumenti. Guarda nome, descriptions, schemi, annotazioni e li mette in relazione con le formulazioni della richiesta. Se nella descrizione di recommend_gifts c’è “selezione di regali in base al budget e agli interessi del destinatario”, e nella richiesta suona “trova un regalo per un amico gamer per 50 $”, questo strumento ha più possibilità di “finire in top” rispetto a un generico search con descrizione “lavoro con i regali”.
Da qui nasce l’idea pratica di Tool Call SEO: trattare nomi, descriptions, valori enum e metadati come parole chiave e snippet. Non state solo descrivendo un contratto per gli sviluppatori — lo state ottimizzando per il traffico reale delle richieste del vostro golden prompt set. Formulazioni troppo generiche, aree di più tools sovrapposte, God‑tools senza una nicchia chiara — tutto questo riduce il “CTR” della vostra App nella testa del modello.
9. Un piccolo esercizio pratico
Provate mentalmente (o nel vostro repository) a fare quanto segue.
Scegliete uno degli scenari chiave di GiftGenius — ad esempio, “Scegliere un regalo per un collega con budget limitato”.
Formulate per esso:
- Quale strumento separato serve per questo scenario: è un puro recommend_gifts, o serve anche uno strumento specializzato per il caso B2B, o, ad esempio, basta usare dopo recommend_gifts similar_gifts per le variazioni?
- Quali campi sono davvero necessari nello schema di ingresso di recommend_gifts. Quali campi si possono chiedere all’utente separatamente (tramite follow‑up), invece di costringere il modello a indovinare.
- Come dovrebbe apparire l’outputSchema, affinché il modello possa spiegare onestamente la scelta e proporre i passi successivi (ad esempio, passare alla modalità B2B, mostrare solo regali digitali, restringere per fascia di prezzo).
Quindi guardate il vostro golden prompt set della lezione precedente e verificate:
- se per ogni richiesta di riferimento esiste uno strumento ovvio (recommend_gifts, get_gift, similar_gifts ecc.);
- se è capitato che due strumenti si adattino “allo stesso modo” a una medesima richiesta (overlapping tools);
- se è necessario rafforzare le descrizioni o rinominare qualche tool per confondere meno il modello.
Questo è proprio il processo che ripeterete prima di ogni modifica seria del prompt, degli schemi o della logica — in sostanza, un mini‑eval della qualità di discovery.
Se riassumiamo tutto in un check‑list, a questo punto dovete:
- scomporre onestamente gli scenari in 2–4 strumenti sensati;
- descrivere con cura inputSchema/outputSchema con esempi ed enum;
- mettere in ordine nomi, descriptions e annotazioni;
- sincronizzare il tutto con il system‑prompt e i metadati dell’App.
Nei prossimi moduli vedremo come tutto ciò funzioni via MCP e come diagnosticare comportamenti strani di discovery/instradamento.
10. Errori tipici nel progettare tools e metadati
Errore n. 1: “Abbiamo scritto tutto nel system‑prompt, gli strumenti se la caveranno in qualche modo”.
Se avete descritto benissimo il ruolo dell’App, i confini di responsabilità e il comportamento UX, ma avete lasciato strumenti con nomi tipo tool1, search, do_stuff e schemi senza descrizioni, il modello non riuscirà a collegare il vostro bel testo alle chiamate reali. Per ChatGPT gli strumenti sono l’interfaccia principale; senza metadati ben progettati nessun system‑prompt vi salverà.
Errore n. 2: God Tool che fa tutto.
Il desiderio di “ottimizzare” creando una sola funzione con il parametro mode è comprensibile, ma porta a JSON‑schema mostruosi, confusione nelle descrizioni e peggioramento dell’instradamento. Il modello inizia a indovinare quale modalità usare e voi mantenete un enorme switch sul server. Meglio più strumenti chiari per passi specifici dello scenario che un “fai tutto”.
Errore n. 3: Schema di input pieno di campi “per ogni evenienza”.
Spesso gli sviluppatori cercano di far passare attraverso l’inputSchema tutti i parametri che potrebbero mai servire, più un paio di campi interni. Il risultato è che il modello prova a indovinare ciò che non può sapere (ad esempio, tenantId), e poi vi sorprendete di valori strani. L’Input Schema deve contenere solo ciò che il modello può davvero dedurre dal dialogo o chiarire con una domanda. I dettagli interni aggiungeteli lato server.
Errore n. 4: Dati di output “muti” senza metainformazioni.
È allettante restituire dallo strumento solo un array di oggetti. Ma così private il modello della comprensione del perché questi risultati sono emersi. Senza campi come score, reason, searchCriteria, totalCandidates gli è più difficile fornire spiegazioni oneste e follow‑up. Aggiungere una piccola busta meta con i criteri di ricerca e consigli spesso migliora radicalmente la qualità della risposta.
Errore n. 5: Assi di legno nelle descrizioni: “Lavoro con i regali”, “Ricerca corsi”, “Elaborazione dati”.
Queste descrizioni sono pessime perché non danno al modello né trigger né limiti. Non sa quando chiamare lo strumento e in quale area si applichi. Una buona descrizione inizia con “Usa questo strumento quando…” e contiene scenari concreti e divieti come “Non usarlo per…”. L’ideale è che queste formulazioni si sovrappongano ai prompt d’oro del vostro golden prompt set.
Errore n. 6: Ignorare le annotazioni e mescolare azioni read‑only e modificanti.
Se non marcate gli strumenti che leggono soltanto i dati (readOnlyHint) e quelli che eseguono azioni (destructiveHint, openWorldHint), il modello non può impostare il giusto UX di conferme. Risultato: o troppi “Sei sicuro?” a ogni passo, oppure, al contrario, acquisti e modifiche silenziose senza consenso dell’utente. Le annotazioni sono un modo economico ed efficace per suggerire al modello l’importanza dell’operazione.
Errore n. 7: Metadati dell’App per il catalogo e metadati per l’in‑conversation vivono in universi diversi.
Capita che la descrizione breve nel catalogo sia scritta dal marketing (“Assistente AI rivoluzionario che cambia la tua vita”), mentre le descriptions dei tools e il system‑prompt dallo sviluppatore (“selezione di regali per budget”). Il risultato è che nel catalogo non è chiaro di cosa tratti l’App, e il modello in chat non riesce a mettere in relazione richieste tipo “che servizio è questo?” con le possibilità reali dell’App. Scrivete i metadati come una specifica unica, non come due testi di marketing indipendenti.
GO TO FULL VERSION