Come ho programmato il mio personale tutor di francese privato da ChatGPT

Ho creato un tutor di francese personale usando ChatGPT.

Guida passo-passo su come ho utilizzato i più recenti servizi di intelligenza artificiale per insegnarmi una nuova lingua, dall’architettura all’ingegneria delle prompt

Il codice del tutor di lingua straniera discusso può essere trovato nel repo companion sulla mia pagina GitHub e puoi utilizzarlo liberamente per qualsiasi utilizzo non commerciale.

Realizzato con Dall-E

Quindi, dopo averlo rimandato per un po’ di tempo, ho deciso di riprendere i miei studi di francese. Mentre mi iscrivevo al corso, mi è venuto in mente questo pensiero: e se potessi programmare ChatGPT per essere il mio tutor personale di francese? E se potessi parlargli e lui mi rispondesse? Essendo un Data Scientist che lavora con LLM, mi è sembrato qualcosa che valeva la pena costruire. Cioè, sì, posso semplicemente parlare con mia moglie, che è francese, ma non è così bello come progettare il mio tutor personale con ChatGPT. Ti amo, tesoro ❤️.

Ma scherzi a parte, questo progetto è un po’ più di un “altro codice interessante”. L’intelligenza artificiale generativa sta facendo progressi in ogni campo della nostra vita e i Large Language Models (LLM) sembrano essere in testa. Le possibilità di ciò che una singola persona può fare in questi giorni con accesso a questi modelli sono incredibili e ho deciso che questo progetto vale il mio tempo – e credo anche il tuo – per due motivi principali:

  • Utilizzare ChatGPT come strumento online ben noto è potente, ma integrare un LLM nel tuo codice è un’altra cosa. I LLM sono ancora in parte imprevedibili e quando il tuo prodotto si basa su un LLM – o su qualsiasi altro modello di intelligenza artificiale generativa – per il prodotto principale, devi imparare a controllare realmente l’intelligenza artificiale generativa. E non è così facile come sembra.
  • Ottenere una prima versione funzionante ha richiesto solo pochi giorni di lavoro. Prima dell’intelligenza artificiale generativa e dei LLM, ciò richiederebbe mesi e probabilmente richiederebbe più di una sola persona. Il potere di utilizzare questi strumenti per creare applicazioni potenti in modo rapido è qualcosa che devi provare tu stesso: è il futuro, almeno secondo me. Non stiamo tornando indietro.

Inoltre, questo progetto può davvero fare del bene. Mia madre vuole davvero qualcuno con cui esercitarsi in inglese. Ora può farlo e costa meno di 3 dollari al mese. La madre di mia moglie vuole iniziare a studiare il coreano. La stessa cosa, lo stesso costo. E ovviamente lo uso anche io! Questo progetto aiuta davvero le persone e costa meno di una piccola tazza di caffè. Questa è la vera rivoluzione dell’intelligenza artificiale generativa, secondo me.

Partendo da zero

Osservando questo progetto da una prospettiva di alto livello, ciò di cui avevo bisogno erano 4 elementi:

  • Speech-to-text, per trascrivere la mia voce in parole
  • Large-Language Model, preferibilmente un Chat-LLM, da cui posso fare domande e ottenere risposte
  • Text-to-speech, per trasformare le risposte del LLM in voce
  • Traduzione, per convertire qualsiasi testo in francese che non capisco completamente in inglese (o ebraico, la mia lingua madre)

Fortunatamente, siamo nel 2023 e tutti i suddetti elementi sono molto accessibili. Ho scelto anche di utilizzare servizi gestiti e API anziché eseguire tutto in locale, poiché l’inferenza sarà molto più veloce in questo modo. Inoltre, i prezzi ridotti di queste API per l’uso personale hanno reso questa decisione ovvia.

Dopo aver provato diverse alternative, ho scelto Whisper di OpenAI e ChatGPT come Speech-to-text e LLM, e Text-to-speech e Translate di Google come i moduli rimanenti. La creazione delle chiavi API e la configurazione di questi servizi è stata estremamente semplice e sono riuscito a comunicare con tutti loro tramite le loro librerie native di Python in pochi minuti.

Ciò che mi ha colpito davvero dopo aver testato tutti questi servizi è che il tutor che sto costruendo non è solo un insegnante di inglese-francese; poiché Whisper, ChatGPT e Google Translate & TTS supportano decine di lingue, può essere utilizzato per imparare praticamente qualsiasi lingua mentre si parla qualsiasi altra lingua. È incredibile!

Realizzato con Dall-E

Architettura e Thread

Prima di tutto, assicuriamoci di capire bene il flusso generale: (1) Iniziamo registrando la voce dell’utente, che viene (2) inviata all’API Whisper e restituita come testo. (3) Il testo viene aggiunto alla cronologia della chat e inviato a ChatGPT, che (4) restituisce una risposta scritta. La sua risposta viene (5) inviata a Google Text-to-speech, che restituisce un file audio che verrà (6) riprodotto come audio.

Architettura ad alto livello

Il mio primo passo pratico è stato scomporre questo in componenti e progettare l’architettura complessiva. Sapevo che avrei bisogno di un’interfaccia utente (UI), preferibilmente una UI Web poiché è più facile lanciare le app attraverso il browser al giorno d’oggi piuttosto che avere un eseguibile autonomo. Avrò anche bisogno di un “backend”, che sarà il codice Python effettivo, che comunica con tutti i diversi servizi. Ma per fornire un’esperienza di flusso in tempo reale, mi sono reso conto che dovrò suddividerlo in diversi thread.

Il thread principale eseguirà la maggior parte del codice: trascriverà la mia registrazione in testo (tramite Whisper), visualizzerà questo testo sullo schermo come parte della chat, e quindi visualizzerà anche la risposta scritta del tutor sulla schermata della chat (come ricevuta da ChatGPT). Ma dovrò spostare la sintesi vocale del tutor in un thread separato – altrimenti, avremo:

  • la voce del tutor verrà udita solo una volta che l’intero messaggio sarà ricevuto da ChatGPT, e la sua risposta potrebbe essere lunga
  • blocca l’utente dal rispondere mentre il tutor parla

questo non è il comportamento “fluido” che vorrei avere; vorrei che il tutor iniziasse a parlare mentre il suo messaggio viene scritto sullo schermo e sicuramente non blocchi l’utente e gli impedisca di rispondere solo perché l’audio sta ancora suonando.

Per fare ciò, la parte di sintesi vocale del progetto è stata suddivisa in altri due thread. Mentre la risposta del tutor veniva ricevuta da ChatGPT token per token, ogni frase completa creata veniva passata a un altro thread, da cui veniva inviata al servizio di sintesi vocale, convertendola in file audio. Vorrei sottolineare la parola “file” qui – poiché sto inviando il testo al servizio TTS frase per frase, ho anche più file audio, uno per ogni frase, che devono essere riprodotti nell’ordine corretto. Questi file audio vengono quindi riprodotti da un altro thread, assicurandosi che la riproduzione audio non blocchi il resto del programma in esecuzione.

Rendere tutto ciò funzionante, insieme a diversi altri problemi derivanti dalle interazioni UI-server, è stata la parte complicata di questo progetto. Sorprendente, vero? L’ingegneria del software è dove le cose diventano difficili.

Progettazione dell’UI

UI del progetto

Bene, sapevo di aver bisogno di un’interfaccia utente e sapevo anche più o meno come avrei voluto che apparisse, ma la codifica di un’interfaccia utente va oltre le mie conoscenze. Così ho deciso di provare un approccio innovativo: ho chiesto a ChatGPT di scrivere la mia interfaccia utente al posto mio.

Per questo ho usato il servizio ChatGPT effettivo (non l’API) e ho usato GPT-4 (sì, sono un orgoglioso cliente pagante!). Sorprendentemente, la mia richiesta iniziale:

Scrivi un'interfaccia utente web Python per un'applicazione di chatbot. La casella di testo in cui l'utente inserisce il suo prompt si trova in fondo allo schermo e tutti i messaggi precedenti vengono mantenuti sullo schermo

ha prodotto un risultato fantastico, ottenendo un backend Python-Flask, codice jQuery, HTML e CSS corrispondente. Ma questo riguardava solo l’80% di tutte le funzionalità che speravo di ottenere, quindi ho trascorso circa 10 ore andando avanti e indietro con GPT-4, ottimizzando e aggiornando la mia interfaccia utente, una richiesta alla volta.

Se ho reso tutto semplice, non voglio dire chiaramente che non lo fosse. Più richieste ho aggiunto, più GPT-4 si è confuso e ha fornito codice difettoso, che a un certo punto era più facile correggere manualmente che chiedergli di sistemarlo. E avevo molte richieste:

  • Aggiungi un’immagine del profilo accanto a ogni messaggio
  • Aggiungi un pulsante per riprodurre l’audio di ogni messaggio
  • Aggiungi un pulsante a ogni messaggio in francese che aggiungerà la sua traduzione sotto il testo originale
  • Aggiungi pulsanti per salvare e caricare sessioni
  • Aggiungi una modalità scura e fai in modo che scelga automaticamente la modalità corretta
  • Aggiungi un’icona “in lavorazione” quando si attende una risposta da un servizio
  • E molte altre…

Tuttavia, anche se di solito il codice di GPT non funzionava immediatamente, considerando il fatto che ho pochissime conoscenze nel campo del front-end, i risultati sono incredibili – e molto al di là di ciò che avrei potuto fare da solo semplicemente cercando su Google e StackOverflow. Ho anche fatto molti progressi nell’apprendimento di come creare prompt migliori. Pensandoci, forse dovrei scrivere un altro post sulle lezioni apprese dalla creazione letteralmente da zero di un prodotto insieme a un LLM… restate sintonizzati!

Ingegneria dei Prompt

In questa parte del post, assumerò che tu abbia una conoscenza di base di come avviene la comunicazione con un Chat LLM (come ChatGPT) tramite API. Se non l’hai, potresti sentirti un po’ perso.

Realizzato con Dall-E

Ultimo ma non meno importante: ho fatto in modo che GPT assumesse il ruolo di un tutor privato.

Come punto di partenza, ho aggiunto un Prompt di Sistema all’inizio della chat. Poiché la chat con un LLM è essenzialmente una lista di messaggi inviati dall’utente e dal bot l’uno all’altro, un Prompt di Sistema è di solito il primo messaggio della chat, che descrive al bot come dovrebbe comportarsi e cosa ci si aspetta da esso. Il mio sembrava qualcosa del genere (i parametri racchiusi tra parentesi graffe sono sostituiti da valori in tempo di esecuzione):

Sei un insegnante di {lingua} di nome {nome_insegnante}. Sei in una sessione 1-1 con il tuo studente, {nome_utente}. Il livello di {lingua} di {nome_utente} è: {livello}. Il tuo compito è aiutare il tuo studente a migliorare il suo {lingua}.* Quando inizia la sessione, offri una sessione adatta a {nome_utente}, a meno che non venga richiesto qualcos'altro.* La lingua madre di {nome_utente} è {lingua_utente}. {nome_utente} potrebbe rivolgersi a te nella propria lingua quando sente che il suo {lingua} non è sufficientemente buono. Quando ciò accade, traduci prima il loro messaggio in {lingua} e poi rispondi.* IMPORTANTE: se il tuo studente commette errori, sia di battitura che di grammatica, DEVI prima correggere il tuo studente e solo dopo rispondere.* Hai il permesso di parlare solo {lingua}.

In realtà questo dava risultati abbastanza buoni, ma sembrava che l’efficacia delle istruzioni comportamentali che ho dato al bot (“correggimi quando sbaglio”, “rispondi sempre in francese”) diminuisse man mano che la chat proseguiva.

Cercando di contrastare questo comportamento che svaniva, ho pensato a una soluzione interessante; ho manipolato i messaggi dell’utente prima di inviarli a GPT. Qualunque fosse il messaggio dell’utente, gli ho aggiunto del testo aggiuntivo:

[Qui va il messaggio dell'utente]---IMPORTANTE: * Se ho risposto in {lingua} e ho commesso errori (grammatica, errori di battitura, ecc.), devi correggermi prima di rispondere. * Devi mantenere il flusso della sessione, la tua risposta non può terminare la sessione. Cerca di evitare domande ampie come "cosa vorresti fare" e preferisci fornirmi domande ed esercizi correlati. * DEVI rispondere in {lingua}.

Aggiungendo queste frasi alla fine di ogni messaggio dell’utente, mi sono assicurato che l’LLM risponda esattamente come volevo. Vale la pena sottolineare che il lungo suffisso che ho aggiunto è scritto in inglese, mentre il messaggio dell’utente potrebbe non esserlo. Per questo motivo ho aggiunto un separatore esplicito tra il messaggio originale e la mia aggiunta (il ---), terminando il contesto del messaggio originale e iniziando un nuovo contesto. Nota anche che poiché questo suffisso è aggiunto al messaggio dell’utente, è scritto in prima persona (“io”, “me”, ecc…). Questo piccolo trucco ha migliorato notevolmente i risultati e il comportamento. Anche se potrebbe sembrare ovvio, potrebbe valere la pena sottolineare che questo suffisso non viene visualizzato nell’interfaccia della chat e l’utente non ha idea che venga aggiunto ai suoi messaggi. Viene inserito dietro le quinte, proprio prima di essere inviato con il resto della cronologia della chat a ChatGPT.

Un altro comportamento che volevo avere era fare in modo che il tutor parlasse per primo, il che significa che ChatGPT invierà il primo messaggio all’inizio della sessione, senza aspettare che l’utente avvii la sessione. Questo, apparentemente, non è qualcosa per cui ChatGPT è stato progettato.

Ciò che ho scoperto quando ho cercato di far sì che ChatGPT rispondesse su una cronologia dei messaggi che conteneva solo la System Prompt, è che ChatGPT “l’ha persa” e ha iniziato a creare una chat con se stesso, interpretando sia l’utente che il bot. Non importa cosa abbia provato, non sono riuscito a farlo avviare correttamente la sessione senza che l’utente dicesse qualcosa per primo.

E poi ho avuto un’idea. Quando la sessione è stata inizializzata, ho inviato a ChatGPT il seguente messaggio a nome dell’utente:

Salutami e suggerisci poi 3 argomenti opzionali per la nostra lezione adatti al mio livello. Devi rispondere in {lingua}.

Questa richiesta è stata progettata per far sì che la risposta di GPT sembrasse esattamente come pensavo che un’inizializzazione corretta della sessione da parte del bot dovesse essere. Poi ho rimosso il mio messaggio dalla chat e ho fatto sembrare che il bot avesse avviato la sessione da solo.

Sommario

Creato con Dall-E, modificato

Ciò che è iniziato come un piccolo capriccio divertente è diventato realtà in letteralmente poco tempo, fatto completamente durante il tempo libero di un solo uomo piuttosto impegnato. Il fatto che compiti come questi siano ora così semplici da creare non smette di stupirmi. Solo un anno fa, avere qualcosa come ChatGPT disponibile era fantascienza, e ora posso modellarlo dal mio personale laptop.

Questo è l’inizio del futuro, e qualunque cosa accada – almeno so che sarò pronto per essa con un’altra lingua straniera. Au revoir!