CodeGym /Corsi /ChatGPT Apps /Voice / Realtime‑contesto: comportamento dell’App nelle c...

Voice / Realtime‑contesto: comportamento dell’App nelle conversazioni vocali

ChatGPT Apps
Livello 8 , Lezione 4
Disponibile

1. Contesto: cosa significa «modalità vocale» per ChatGPT App

Per cominciare, è importante capire che nell’ambito del ChatGPT Apps SDK non scrivete un vostro client audio, non controllate il microfono e non effettuate voi lo streaming audio. Se ne occupa il client di ChatGPT (app web o mobile).

Supponiamo che abbiate già una conoscenza di base del widget, di callTool e di GiftGenius dai moduli precedenti — qui osserviamo gli stessi elementi attraverso la lente della modalità vocale.

Dalla vostra prospettiva di sviluppatori dell’App tutto appare così:

  • L’utente parla nel microfono. Il client ChatGPT effettua il riconoscimento vocale e invia al modello già il testo.
  • Nel flusso «vedete» la stessa cosa che se l’utente digitasse un messaggio, solo che arrivano più rapidamente e in modo più «conversazionale».
  • Il modello risponde con testo, che il client vocalizza.
  • Contemporaneamente il modello può chiamare i vostri strumenti (callTool), cambiare il displayMode del widget, aggiornare il widgetState e proporre follow‑up — come nella modalità testuale.

La differenza chiave è che l’utente può quasi non guardare lo schermo, o dargli solo un’occhiata di sfuggita sul telefono. Il vostro UI quindi smette di essere il canale principale di interazione e diventa un complemento alla voce, non il contrario.

Ne derivano due conseguenze:

  • Tutto ciò che è davvero importante deve essere comprensibile «all’ascolto», tramite le battute del GPT.
  • Il widget deve essere «a colpo d’occhio» nel senso buono: con una rapida occhiata si vedono subito stato e opzioni chiave, senza leggere testo in piccolo.

Per il nostro GiftGenius questo suggerisce subito uno scenario: «sono in macchina, trova un regalo per la mamma» — non è solo una chat testuale. È un dialogo multimodale in cui guida la voce, e l’UI fa da rete di sicurezza.

2. In cosa lo scenario voice differisce da quello testuale

Per evitare la trappola del «è la stessa cosa, solo che l’utente parla», è utile confrontare modalità testuale e vocale su alcune dimensioni.

Aspetto Modalità testuale Modalità vocale
Attenzione dell’utente Guarda lo schermo, legge, scrolla Può non guardare affatto (hands‑free)
Forma delle richieste Più strutturata, l’utente modifica/edita Conversazionale, frasi spezzate, «mh‑mh», «ancora»
Tolleranza alle pause Ok 1–2 secondi di silenzio Il silenzio prolungato è percepito come fastidioso
Ruolo dell’UI Veicolo principale dei dettagli Ausiliario, «tabellone» con appigli visivi sintetici
Errori di input Refusi, ma il testo si vede Voce confusa, rumore, «sì/no» falsi positivi

Da qui alcuni importanti takeaway.

  • Non potete contare sul fatto che l’utente «leggerà nella scheda». Le cose critiche vanno dette: cosa avete capito, cosa intendete fare, quale risultato avete ottenuto.
  • L’UI deve reggere lo scenario «uno sguardo di 1 secondo». Stato, progresso, scelta principale — tutto deve essere in evidenza con caratteri grandi. I dettagli sono secondari.
  • Le pause vanno riempite. Mentre il vostro server MCP elabora una richiesta pesante, il modello dovrebbe dire a voce cosa sta succedendo, e il widget mostrare il progresso, per non dare la sensazione di un assistente bloccato.

Potete pensare alla modalità vocale come a un audiolibro con illustrazioni: avete un narratore (GPT) e delle immagini (il widget). Dovete sincronizzarli in modo che si completino, senza duplicarsi o contraddirsi.

3. Ruolo del widget in modalità vocale: da «pannello di controllo» a «tabellone»

Nello scenario testuale il widget è spesso un’interfaccia completa: form, tabelle, caroselli con filtri, pulsanti di azione. In modalità vocale il suo ruolo cambia. Le linee guida per interfacce multimodali e VUI mostrano che negli scenari vocali l’UI diventa piuttosto un tabellone informativo (glanceable UI): serve per verifiche rapide e conferme, non per un lavoro oculare intenso.

Per GiftGenius questo significa quanto segue.

Quando l’utente segue una procedura vocale guidata, a schermo nell’inline‑widget o a tutto schermo mostriamo:

  • Uno stato ben visibile: «Passo 2 di 3: budget e tipo di regalo».
  • Minimo testo ma etichette chiare: «Budget fino a 50 $», «Preferito regalo digitale».
  • Un paio di CTA grandi, se lo scenario vocale consente i clic: «Modifica budget», «Continua».
  • Una sola progress bar o uno stepper semplice, non dieci indicatori minuti.

Esempio di «tabellone» semplice in un inline‑widget per scenario vocale (TypeScript + React, molto semplificato):

type VoiceUiMode = "default" | "voiceGlance";

interface GiftStepProps {
  step: number;
  totalSteps: number;
  summary: string; // breve descrizione di ciò che è già stato raccolto
  uiMode: VoiceUiMode;
}

export function GiftVoiceStep(props: GiftStepProps) {
  const fontSize = props.uiMode === "voiceGlance" ? "text-lg" : "text-sm";

  return (
    <div className="rounded-xl border p-3 flex flex-col gap-2">
      <div className={`${fontSize} font-semibold`}>
        Passo {props.step} di {props.totalSteps}
      </div>
      <div className={`${fontSize} text-muted-foreground`}>
        {props.summary}
      </div>
    </div>
  );
}

Qui non c’è nulla di «vocale» in sé, ma l’idea è chiara: quando uiMode === "voiceGlance" rendiamo tutto più grande e semplice. Il segnale che indica la modalità vocale può arrivare da varie parti: da indizi indiretti fino a un flag esplicito che il modello imposta nel widgetState o nella risposta dello strumento.

4. Sincronizzazione delle modalità: cosa dice GPT e cosa mostra l’App

Il principio chiave della voice‑UX per le App è la sincronizzazione delle modalità: voce e UI visuale devono raccontare la stessa storia, ma con livelli di dettaglio diversi.

L’errore tipico è quando lo sviluppatore fa leggere al modello tutto ciò che è mostrato nel widget: liste lunghe di regali, strutture JSON con filtri, ecc. Diventa una tortura. Le raccomandazioni sono: la voce dà un breve sommario, l’UI mostra i dettagli.

Esempio di buona sincronizzazione per GiftGenius.

Utente: «Scegli un regalo per mia madre, le piace il giardinaggio, budget fino a 50 dollari».

Modello (a voce): «Ho trovato alcune opzioni. La migliore, a mio avviso, è un set di attrezzi da giardino a 45 dollari. Sullo schermo ho mostrato altri due simili. Vuoi che te li descriva meglio o passiamo direttamente alla scelta?»

Widget (inline): mostra tre schede con i regali, una breve descrizione e i pulsanti CTA «Seleziona» / «Mostra simili».

Rappresentazione dialogica in stile JSON di uno step (non è un protocollo reale, ma un’illustrazione di pensiero):

{
  "user": "Scegli un regalo per mia madre...",
  "assistant_text": "Ho trovato alcune opzioni...",
  "widget": {
    "displayMode": "inline",
    "state": {
      "view": "gift_list",
      "items": [
        { "id": "g1", "title": "Set di attrezzi da giardino", "price": 45 },
        { "id": "g2", "title": "Grembiule da giardiniere", "price": 30 },
        { "id": "g3", "title": "Set di semi di fiori", "price": 20 }
      ]
    }
  }
}

Dettaglio importante: nel system‑prompt potete scrivere esplicitamente come il modello deve parlare dell’UI, per non «leggere il JSON»: «Se mostri un elenco di alternative nel widget, non leggere ogni voce per intero. Descrivi brevemente l’opzione migliore e di’ che le altre sono visibili sullo schermo».

In futuro, quando lavorerete con la Realtime API e i vostri voice‑client, il principio resterà lo stesso: UI e flusso audio devono essere allineati. Avrete solo più controllo diretto sullo streaming.

5. Realtime e latenza: come evitare silenzi imbarazzanti

Tecnicamente i tool_calls in modalità vocale sono gli stessi che in quella testuale: il modello decide di chiamare uno strumento, voi restituite una risposta, il widget si aggiorna. Ma nella voce emerge un nuovo problema di UX — la latenza. Mentre il vostro server MCP chiama API esterne o calcola un report complesso, l’utente sente… nulla. E questo è percepito molto peggio rispetto all’attesa di testo in chat.

Qui ci sono due livelli di protezione: vocale e visivo.

  • A livello vocale il system‑prompt dovrebbe permettere (e incoraggiare) al modello di dire «sto lavorando» e porre domande aggiuntive mentre lo strumento sta ancora elaborando. Ad esempio: «Ora cerco i regali, ci vorranno alcuni secondi. Intanto dimmi se ci sono altri vincoli».
  • A livello visivo il vostro widget deve mostrare in modo molto evidente il progresso: loader, stato «Cerco opzioni…», step attuale. Senza questo l’utente penserà che tutto si sia bloccato e inizierà a parlare di nuovo, confondendo il flusso vocale.

Nella pratica è comodo risolverlo con un job differito: lo strumento restituisce subito lo stato "pending" e un jobId, mentre la ricerca prosegue in background. Il widget, vedendo "pending", mostra il progresso, e la voce indica che «sta lavorando».

Schema minimale di uno strumento server‑side che restituisce un «segnaposto» con job‑id invece di bloccarsi fino al risultato completo:

// Pseudocodice dello strumento server-side GiftGenius
export async function startGiftSearch(params: SearchParams) {
  const jobId = await createBackgroundJob(params); // mettiamo il job in coda

  return {
    status: "pending",
    jobId,
    message: "Ricerca dei regali avviata"
  };
}

Il widget, vedendo status: "pending", può passare l’UI in modalità progresso:

if (toolOutput.status === "pending") {
  return (
    <div className="p-4 rounded-xl border flex items-center gap-3">
      <Spinner />
      <div className="text-base">
        Sto cercando regali… Ci vorranno alcuni secondi.
      </div>
    </div>
  );
}

E il modello, in risposta allo stesso output dello strumento, secondo le istruzioni dirà a voce qualcosa di simile e magari farà una domanda di chiarimento. Più tardi, quando il job in background è terminato e, per esempio, tramite un MCP‑notification arriva job.completed, il widget si aggiorna con la lista dei regali e la voce ne annuncia il sommario.

Così otteniamo un comportamento il più vicino possibile al realtime, anche se il backend non è istantaneo.

6. Sicurezza e conferme nel parlato

L’interfaccia vocale è insidiosa quando si tratta di azioni critiche: pagamento, eliminazione dati, modifica impostazioni. Il riconoscimento vocale non è perfetto, gli utenti parlano «di corsa», e un «mh‑mh» può facilmente diventare «sì, compra». Perciò negli scenari vocali sono particolarmente importanti i flussi di conferma.

Ci sono due pattern di base.

  • Conferma vocale esplicita (Explicit Voice Confirmation). Per le azioni rischiose richiedete una frase specifica. Ad esempio: «Per confermare l’acquisto, dite: “Confermo l’acquisto”» — e nel system‑prompt vietate di eseguire il pagamento su «sì», «ok», «facciamo» vaghi.
  • Solo conferma visiva (Visual Confirmation Only). Il modello a voce guida l’utente all’azione («Ho preparato l’ordine, sullo schermo trovi l’importo finale e il contenuto del carrello»), ma il trigger effettivo è il clic sul pulsante «Paga» nel widget. È particolarmente rilevante negli scenari di commerce, e ci torneremo nel modulo 14.

Per GiftGenius può apparire così.

Modello: «Ho trovato un ottimo set per il giardinaggio a 45 dollari. Posso completare l’acquisto tramite ChatGPT. Sullo schermo trovi il prezzo finale e l’indirizzo di consegna. Per confermare a voce, dite “Confermo l’acquisto”, oppure premete il pulsante “Paga” sullo schermo.»

Widget (fullscreen): mostra l’ordine finale, mette in grassetto l’importo e l’indirizzo, e due pulsanti ben visibili: «Paga» e «Annulla».

All’interno del widget potete riflettere lo stato della conferma:

type CheckoutState = "review" | "waiting_voice_confirm" | "confirmed";

if (state.phase === "waiting_voice_confirm") {
  return (
    <div className="space-y-3">
      <h2 className="text-xl font-semibold">Quasi fatto</h2>
      <p className="text-base">
        Conferma l’acquisto a voce con la frase
        "Confermo l’acquisto" oppure premi il pulsante "Paga".
      </p>
      <Button variant="primary">Paga</Button>
      <Button variant="ghost">Annulla</Button>
    </div>
  );
}

In questo modo, se il modello ha interpretato male qualcosa nel parlato, all’utente resta uno strato visivo di «sicurezza».

7. Comandi vocali semplici e design degli strumenti

L’utente vocale non formulerà i comandi esattamente come le variabili del vostro strumento. Dirà «seleziona il primo», «mostra qualcosa di più economico», «senza tecnologia». Compito dello sviluppatore è progettare strumenti e system‑prompt affinché il modello mappi facilmente tali frasi sulle chiamate ai vostri strumenti (callTool).

Per GiftGenius si possono prevedere, ad esempio, queste azioni:

  • Selezione di una delle opzioni mostrate per indice o id.
  • Affinamento del budget: «più economico», «fino a 30 dollari».
  • Filtraggio per tipo: «solo regali digitali», «niente che debba essere spedito per posta».

È comodo esprimerlo tramite uno strumento con un semplice parametro enum action e campi aggiuntivi:

// Pseudoschema dello strumento in TypeScript
type VoiceActionInput =
  | { action: "select_item"; itemId: string }
  | { action: "refine_budget"; maxPrice: number }
  | { action: "filter_type"; type: "digital" | "physical" };

export function handleVoiceAction(input: VoiceActionInput) {
  switch (input.action) {
    case "select_item":
      // contrassegniamo il regalo come selezionato
      break;
    case "refine_budget":
      // ricalcoliamo la selezione per il nuovo budget
      break;
    case "filter_type":
      // filtriamo la lista esistente
      break;
  }
}

Nel system‑prompt descrivete come queste azioni corrispondono ai comandi vocali: «Se l’utente dice “seleziona la prima opzione”, chiama lo strumento gift.voiceAction con action="select_item" e l’identificatore del primo regalo a schermo» ecc.

Dal punto di vista dell’UX questo riduce il carico cognitivo: l’utente non deve inventare formulazioni precise tipo «Affina i filtri in modo che siano solo regali digitali fino a 30$». Parla in modo naturale e il modello traduce in una struttura dati.

8. Scenario vocale GiftGenius: tre step

Mettiamo insieme tutto e progettiamo uno scenario vocale completo per GiftGenius, senza approfondire per ora la Realtime API a basso livello.

Immaginiamo l’utente: sta guidando e avvia la modalità vocale di ChatGPT. Dice: «Per favore, trova un regalo per mia madre, ama il giardino, budget fino a 50 dollari».

Step 1. Raccolta informazioni a voce

Modello: «Perfetto, troviamo un regalo. Ti chiedo un paio di cose: per quando serve — nei prossimi giorni o più avanti? Ci sono vincoli, ad esempio niente di pesante o ingombrante?»

Widget (inline): per ora solo un pannellino con lo stato «Stiamo scegliendo un regalo per: mamma, giardinaggio, fino a 50 $». I font sono un po’ più grandi del solito, così si capisce con uno sguardo.

Il codice dello stato del widget può apparire così:

interface GiftSessionState {
  mode: "voice" | "text";
  step: 1 | 2 | 3;
  recipientSummary: string;
  budget?: number;
}

const [state, setState] = useState<GiftSessionState>({
  mode: "voice",
  step: 1,
  recipientSummary: "Mamma, ama il giardinaggio"
});

La parte server, man mano che arrivano le risposte dell’utente, aggiorna recipientSummary e budget, e il widget reagisce.

Step 2. Ricerca e attesa

Dopo che il modello ha raccolto informazioni sufficienti, chiama il vostro strumento di ricerca regali. Questo, a sua volta, può avviare un job in background, se la selezione è complessa, e restituire status: "pending". Mentre il job è in corso, il modello dice: «Ora cerco opzioni adatte, ci vorranno alcuni secondi. Intanto puoi dirmi se preferisce regali fisici o vanno bene certificati digitali».

Il widget passa a una modalità «tipo PiP» se l’utente va in un’altra parte dell’interfaccia, oppure resta inline con il progresso: «Cerco regali…» e un piccolo indicatore.

Step 3. Risultati e scelta

Quando i risultati sono pronti, il modello: «Ho trovato tre opzioni. La prima è un set di attrezzi da giardino a 45 dollari. La seconda è un grembiule da giardiniere a 30 dollari. Le ho mostrate sullo schermo. Di’ “seleziona la prima” oppure “mostra qualcosa di più economico”».

Il widget mostra tre schede grandi con prezzi e descrizioni brevi. Ogni scheda ha i CTA «Seleziona» e «Simili». In più un pulsante separato «Mostra altre opzioni».

Se l’utente dice: «Seleziona la seconda», il modello chiama il vostro strumento voiceAction con action="select_item" e id del secondo regalo. Il widget lo evidenzia come selezionato e il modello dice a voce: «Perfetto, selezionato il grembiule da giardiniere a 30 dollari».

Step 4 opzionale. Checkout

Se l’App è integrata con i pagamenti (nel futuro modulo 14), inizia il checkout. Il modello illustra le condizioni e chiede conferma a voce o con pulsante. Il widget passa a un wizard fullscreen con gli step «Verifica ordine» → «Indirizzo di consegna» → «Conferma».

È importante che a ogni step tutto ciò che è chiave venga detto a voce, mentre il widget funge da supporto visivo, soprattutto se l’utente si è fermato e guarda lo schermo.

9. Note pratiche di implementazione e limiti dell’Apps SDK

Tutti gli step descritti per GiftGenius si realizzano dentro una normale ChatGPT App — senza un client audio proprio e senza WebRTC. Qui è fondamentale ricordare i confini dello stack.

È facile «volare» verso temi come Realtime API, WebRTC, streaming audio e immaginare una vostra piattaforma vocale. Per questo c’è un modulo dedicato (20). In questa lezione è importante ricordare i confini della ChatGPT App dentro il client di ChatGPT.

Nell’architettura attuale:

  • Il flusso audio è gestito dal client ChatGPT. Non inviate né ricevete byte audio nel widget.
  • Nel backend vedete ancora le normali chiamate agli strumenti e messaggi testuali, ma il modello può essere in modalità vocale e le sue risposte verranno vocalizzate.
  • La piattaforma può trasmettere indizi indiretti che indicano la modalità voice (tramite user-agent o campi di ambiente). Ma non bisogna crearne una dipendenza rigida: le API possono cambiare, e la vostra App deve restare utile anche in modalità puramente testuale.

Perciò una buona strategia è questa. Prima progettate un’UX che funzioni bene sia per il testo sia per la voce: stati sintetici, CTA chiari, fasi di progresso comprensibili. Poi aggiungete alcune migliorie per la voce: font leggermente più grandi in modalità "voiceGlance", progresso più evidente, enfasi su stati come «Passo 2 di 3» e situazioni ovvie come «In attesa di conferma».

Inoltre nel system‑prompt descrivete il comportamento vocale del modello: come commenta lo stato del widget, quali frasi usa per le conferme, quali parole evita (ad esempio, non legge il JSON, non annuncia ogni minimo dettaglio in elenco).

Se in futuro realizzerete un vostro Custom Voice Client sulla Realtime API, tutte queste soluzioni di UX «migreranno» facilmente. La differenza sarà solo nel livello di accesso agli eventi e allo streaming, non nei principi.

10. Errori tipici nel lavoro con il contesto Voice / Realtime

Errore n. 1: «Leggere l’UI ad alta voce» invece del sommario.
A volte gli sviluppatori progettano strumenti tali che il modello inizi a leggere a voce tutto il contenuto della risposta JSON o l’elenco completo delle schede. In modalità vocale è un UX killer: l’utente perde il filo e voi sprecate token. Meglio che la voce esponga un breve riassunto, concentrandosi su una‑due opzioni, lasciando il resto sullo schermo.

Errore n. 2: Assenza totale di feedback visivo nella voce.
C’è la tentazione di pensare: «Se l’utente parla, allora ascolta, l’UI non serve». In pratica l’utente spesso dà un’occhiata allo schermo o ci torna dopo un minuto. Se in quel momento non ci sono stato, progresso o un risultato chiaro, concluderà che l’App è bloccata o non ha fatto nulla. Mostrate sempre «Sto pensando», «Passo 2 di 3», «Risultati pronti» e simili.

Errore n. 3: Azioni rischiose senza una conferma forte.
In modalità testuale è rischioso fare «Paga» con un solo clic, e in quella vocale è ancora più pericoloso eseguire un acquisto su un «mh‑mh» vago. Ignorare i flussi di conferma (vocali e/o visivi) porta ad acquisti sbagliati e a problemi di fiducia nell’App. Pensate a quali azioni richiedono doppia conferma e descrivetelo chiaramente in system‑prompt e UI.

Errore n. 4: Progettare solo per l’occhio, non per l’orecchio.
Talvolta l’App è progettata come se l’utente leggesse sempre: formulazioni troppo complesse, pulsanti troppo lunghi, descrizioni sovraccariche. In modalità vocale tutto questo va anche detto — ne esce una «minestra di parole». Cercate di far entrare il senso chiave in frasi brevi e semplici, facili da cogliere all’ascolto.

Errore n. 5: Confusione tra Apps SDK e un proprio voice‑client.
Alcuni studenti cercano nell’Apps SDK eventi del microfono, streaming audio, WebRTC, come nella Realtime API, e rimangono delusi perché «non c’è nulla di tutto ciò». È fondamentale capire: la ChatGPT App vive dentro il client di ChatGPT, e la voce è gestita dalla piattaforma. Lavorate con testo, chiamate agli strumenti e stato del widget, progettando l’UX affinché la modalità vocale «funzioni semplicemente bene». Se serve pieno controllo sulla voce, quello è un progetto a parte, più complesso, con la Realtime API.

Errore n. 6: Mancanza di una strategia per le latenze.
Se non pianificate cosa dice il modello e cosa mostra il widget durante le operazioni lunghe, l’utente interromperà, farà nuove domande e romperà il vostro flusso. Le latenze nella voce si percepiscono più che nel testo. Usate stati intermedi, elaborazione dei job in background e frasi vocali tipo «sto pensando, intanto raccontami…», in modo che il silenzio non sembri un bug.

1
Sondaggio/quiz
UX e interfacce, livello 8, lezione 4
Non disponibile
UX e interfacce
UX e interfacce (Inline, Fullscreen, Voice)
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION