Sfruttare i modelli GPT per trasformare il linguaggio naturale in query SQL

Utilizzare i modelli GPT per convertire il linguaggio naturale in query SQL

 

Il Natural Language Processing – o NLP – è evoluto enormemente, e i modelli GPT sono all’avanguardia di questa rivoluzione.

Oggi i modelli LLM possono essere utilizzati in una vasta gamma di applicazioni. 

Per evitare compiti superflui e migliorare il mio flusso di lavoro, ho iniziato a esplorare la possibilità di addestrare GPT per formulare query SQL per me.

E qui è apparso un’idea brillante:

Utilizzare il potere dei modelli GPT nell’interpretazione del linguaggio naturale e trasformarlo in query SQL strutturate. 

Possibile?

Scopriamolo insieme!

Quindi iniziamo dall’inizio…

 

Il concetto di “Few Shot Prompting”

 

Alcuni di voi potrebbero già essere familiari con il concetto di few shot prompting, mentre altri potrebbero non averlo mai sentito prima.

Quindi… Che cos’è?

L’idea di base qui è utilizzare alcuni esempi espliciti – o shot – per guidare il LLM a rispondere in un modo specifico.

Ecco perché si chiama few shot prompting.

In parole semplici, mostrando alcuni esempi dell’input dell’utente – prompt di esempio – insieme all’output LLM desiderato, possiamo insegnare al modello a generare un output migliorato che segue le nostre preferenze.

In questo modo stiamo espandendo la conoscenza del modello in un determinato dominio per generare un output che si allinea meglio con il nostro obiettivo desiderato.

Esemplichiamo questo!

In tutto questo tutorial, userò una funzione predefinita chiamata chatgpt_call() per avviare il modello GPT. Se vuoi capirla meglio, puoi consultare l’articolo seguente.

Immagina che voglio che ChatGPT descriva il termine ottimismo. 

Se semplicemente chiedo a GPT di descriverlo, otterrò una descrizione seria e noiosa. 

## Blocco di codicerisposta = chatgpt_call("Insegnami dell'ottimismo. Sii breve.")print(response)

 

Con l’output corrispondente: 

  

Tuttavia, immagina che preferirei ottenere qualcosa di più poetico. Posso aggiungere alla mia richiesta ulteriori dettagli specificando che desidero una definizione poetica.

## Blocco di codicerisposta = chatgpt_call("Insegnami dell'ottimismo. Sii breve. Cerca di creare una definizione poetica.")print(response)

 

Ma questo secondo output sembra solo una poesia e non ha nulla a che fare con il mio output desiderato.

  

Cosa posso fare?

Potrei dettagliare ancora di più il prompt e iterare fino a ottenere un buon output. Tuttavia, ciò richiederebbe molto tempo.

Invece, posso mostrare al modello quale tipo di descrizione poetica preferisco progettando un esempio e mostrandolo al modello.

## Blocco di codiceprompt = """Il tuo compito è rispondere in uno stile coerente con il seguente stile: Insegnami dell'azione resilienza.: La resilienza è come un albero che si piega al vento ma non si spezza. È la capacità di riprendersi dalle avversità e andare sempre avanti.: Insegnami dell'ottimismo."""response = chatgpt_call(prompt)print(response)

 

E l’output è esattamente quello che stavo cercando.

  

Quindi… Come possiamo tradurre tutto ciò nel nostro caso specifico di query SQL?

 

Utilizzando l’NLP per la generazione di SQL

 

ChatGPT è già in grado di generare query SQL da prompt in linguaggio naturale. Non dobbiamo nemmeno mostrare al modello alcuna tabella, basta formulare un calcolo ipotetico e lo farà per noi.

## Blocco di codice
user_input = """Supponendo di avere sia il prodotto che le tabelle degli ordini, potresti generare una singola tabella che contenga tutte le informazioni di ogni prodotto insieme a quante volte è stato venduto?"""
prompt = f"""Dato il seguente prompt in linguaggio naturale, genera una query ipotetica che soddisfi il compito richiesto in SQL.{user_input}"""
response = chatgpt_call(prompt)
print(response)

 

Tuttavia, come già sai, più contesto forniamo al modello, migliori saranno gli output che genererà. 

  

In tutto questo tutorial, suddivido i prompt di input nella specifica richiesta dell’utente e nel comportamento generale previsto dal modello. Questa è una buona pratica per migliorare la nostra interazione con LLM e per essere più concisi nei nostri prompt. Puoi saperne di più nell’articolo seguente.

Immaginiamo quindi di lavorare con due tabelle principali: PRODUCT e ORDERS

  

Se chiedo a GPT una semplice query, il modello fornirà una soluzione immediatamente, proprio come ha fatto all’inizio, ma con tabelle specifiche per il mio caso.

## Blocco di codice
user_input = """Quale modello di TV è stato venduto di più nel negozio?"""
prompt = f"""Dato le seguenti tabelle SQL, il tuo compito è fornire le query SQL richieste per soddisfare qualsiasi richiesta dell'utente. Tabelle: <{sql_tables}>. Richiesta dell'utente: ```{user_input}```"""
response = chatgpt_call(prompt)
print(response)

 

Puoi trovare le sql_tables alla fine di questo articolo!

E l’output assomiglia a quanto segue!

  

Tuttavia, possiamo osservare alcuni problemi nell’output precedente.

  1. Il calcolo è parzialmente errato, poiché considera solo le TV che sono state già consegnate. E qualsiasi ordine emesso-deve essere consegnato o meno-dovrebbe essere considerato come una vendita.
  2. La query non è formattata come vorrei.

Quindi, prima concentriamoci su come far capire al modello come calcolare la query richiesta.

 

#1. Correggere alcune incomprensioni del modello

 

In questo primo caso, il modello considera solo quei prodotti che sono stati consegnati come venduti, ma questo non è vero. Possiamo semplicemente correggere questa incomprensione mostrando due esempi diversi in cui calcolo query simili.

## Esempi di few-shot
fewshot_examples = """-------------- PRIMO ESEMPIOUtente: Quale modello di TV è stato venduto di più nel negozio considerando tutti gli ordini emessi. Sistema: Prima devi unire le tabelle degli ordini e dei prodotti, filtrare solo gli ordini che corrispondono alle TV e contare il numero di ordini emessi: SELECT P.product_name AS modello_di_tv, COUNT(*) AS totale_vendutiFROM products AS PJOIN orders   AS O ON P.product_id = O.product_idWHERE P.product_type = 'TVs'GROUP BY P.product_nameORDER BY total_sold DESCLIMIT 1;-------------- SECONDO ESEMPIOUtente: Quale prodotto venduto è stato già consegnato di più?Sistema: Prima devi unire le tabelle degli ordini e dei prodotti, contare il numero di ordini già consegnati e mantenere solo il primo: SELECT P.product_name AS modello_di_tv, COUNT(*) AS totale_vendutiFROM products AS PJOIN orders   AS O ON P.product_id = O.product_idWHERE P.order_status = 'Delivered'GROUP BY P.product_nameORDER BY total_sold DESCLIMIT 1;"""

 

E ora, se interroghiamo di nuovo il modello e includiamo gli esempi precedenti, si può vedere che la query corrispondente non sarà solo corretta-la query precedente funzionava già-ma considererà anche le vendite come vogliamo! 

## Blocco di codice
user_input = """Quale modello di TV è stato venduto di più nel negozio?"""
prompt = f"""Dato le seguenti tabelle SQL, il tuo compito è fornire le tabelle SQL richieste per soddisfare qualsiasi richiesta dell'utente. Tabelle: <{sql_tables}>. Segui gli esempi per generare la risposta, prestare attenzione sia al modo di strutturare le query che al loro formato:<{fewshot_examples}>. Richiesta dell'utente: ```{user_input}```"""
response = chatgpt_call(prompt)
print(response)

 

Con l’output seguente:

 Screenshot del mio Jupyter Notebook. Utilizzando GPT. 

Adesso se controlliamo la query corrispondente…

## Blocco di codicepysqldf("""SELECT P.product_name AS modello_di_tv, COUNT(*) AS totale_vendutoFROM PRODOTTI AS PJOIN ORDINI AS O ON P.product_id = O.product_idWHERE P.product_type = 'TVs'GROUP BY P.product_nameORDER BY totale_venduto DESCLIMIT 1;""")

 

Funziona perfettamente!

 Screenshot del mio Jupyter Notebook. Utilizzando GPT.

 

#2. Formattazione delle Query SQL

 

Anche la promptizzazione few-shot può essere un modo per personalizzare il modello per il nostro scopo o stile.

Se torniamo agli esempi precedenti, le query non avevano alcun formato. E sappiamo tutti che ci sono alcune buone pratiche – insieme a alcune particolarità personali – che ci consentono di leggere meglio le query SQL.

Ecco perché possiamo utilizzare la promptizzazione few-shot per mostrare al modello il modo in cui ci piace effettuare le query – con le nostre buone pratiche o semplicemente con le nostre particolarità – e addestrare il modello per produrre le query SQL formattate secondo le nostre preferenze.

Quindi, adesso preparerò gli stessi esempi di prima, ma seguendo le mie preferenze di formato.

## Blocco di codicefewshot_examples = """---- ESEMPIO 1Utente: Qual è il modello di TV più venduto nel negozio considerando tutti gli ordini emessi. Sistema: Prima devi unire le tabelle degli ordini e dei prodotti, filtrare solo gli ordini che corrispondono alle TV e contare il numero degli ordini emessi: SELECT        P.product_name AS modello_di_tv,        COUNT(*)       AS totale_vendutoFROM products AS PJOIN orders   AS O  ON P.product_id = O.product_id  WHERE P.product_type = 'TVs'GROUP BY P.product_nameORDER BY totale_venduto DESCLIMIT 1;---- ESEMPIO 2Utente: Qual è l'ultimo ordine emesso?Sistema: Prima devi unire le tabelle degli ordini e dei prodotti e filtrare per la data e ora di creazione dell'ultimo ordine: SELECT       P.product_name AS modello_di_tvFROM products AS PJOIN orders AS O   ON P.product_id = O.product_id  WHERE O.order_creation = (SELECT MAX(order_creation) FROM orders)GROUP BY p.product_nameLIMIT 1;"""

 

Una volta definiti gli esempi, possiamo inserirli nel modello in modo che possa imitare lo stile mostrato.

Come puoi osservare nel seguente blocco di codice, dopo aver mostrato a GPT cosa ci aspettiamo da esso, esso replica lo stile degli esempi forniti per produrre qualsiasi nuovo output di conseguenza.

## Blocco di codiceuser_input = """Qual è il modello di prodotto più popolare del negozio?"""prompt = f"""Dati i seguenti tavoli SQL, il tuo compito è fornire le tabelle SQL richieste per soddisfare qualsiasi richiesta dell'utente.Tabelle: <{sql_tables}>. Segui questi esempi per generare la risposta, prestando attenzione sia al modo di strutturare le query che al loro formato:<{fewshot_examples}>Richiesta dell'utente: ```{user_input}```"""response = chatgpt_call(prompt)print(response)

 

E come puoi osservare nell’output seguente, ha funzionato!

 Screenshot del mio Jupyter Notebook. Prompting GPT.

 

#3. Addestramento del modello per calcolare alcune variabili specifiche.

 

Approfondiamo un caso illustrativo. Supponiamo di voler calcolare quale prodotto richiede più tempo per essere consegnato. Rivolgeremo questa domanda al modello in linguaggio naturale, aspettandoci una query SQL corretta. 

## Blocco di codiceuser_input = """Quale prodotto richiede più tempo per essere consegnato?"""prompt = f"""Dati i seguenti tavoli SQL, il tuo compito è fornire le tabelle SQL richieste per soddisfare qualsiasi richiesta dell'utente.Tabelle: <{sql_tables}>. Segui questi esempi per generare la risposta, prestando attenzione sia al modo di strutturare le query che al loro formato:<{fewshot_examples}>Richiesta dell'utente: ```{user_input}```"""response = chatgpt_call(prompt)print(response)

 

Tuttavia, la risposta che riceviamo è lontana dalla correttezza.

 Screenshot del mio Jupyter Notebook. Prompting GPT. 

Cosa è andato storto?

Il modello GPT cerca di calcolare direttamente la differenza tra due variabili datetime SQL. Questo calcolo è incompatibile con la maggior parte delle versioni di SQL, creando un problema, soprattutto per gli utenti di SQLite. 

Come risolvere questo problema? 

La soluzione è sotto il nostro naso – ricorriamo al few-shot prompting.

Dimostrando al modello come calcoliamo tipicamente le variabili di tempo – in questo caso, il tempo di consegna – lo addestriamo a replicare il processo ogni volta che si trova di fronte a tipi di variabili simili. 

Ad esempio, gli utenti di SQLite possono utilizzare la funzione julianday(). Questa funzione converte una qualsiasi data nel numero di giorni trascorsi dall’epoca iniziale nel calendario giuliano.

Questo potrebbe aiutare il modello GPT a gestire meglio le differenze di date nel database SQLite.

## Aggiungere un altro esempiofewshot_examples += """------ ESEMPIO 4Utente: Calcola il tempo che ci vuole per consegnare ogni prodotto?Sistema: Prima devi unire le tabelle degli ordini e dei prodotti, filtrare solo gli ordini consegnati e calcolare la differenza tra la data di creazione dell'ordine e la data di consegna.: SELECT     P.product_name AS prodotto_con_tempi_consegna_piu_lunghi,    julianday(O.delivery_date) - julianday(O.order_creation) AS TEMPO_DIFF    FROM     products AS PJOIN     orders AS O ON P.product_id = O.product_idWHERE     O.order_status = 'Consegnato';"""

 

Quando utilizziamo questo metodo come esempio per il modello, impara il nostro modo preferito di calcolare il tempo di consegna. Questo rende il modello più adatto a generare query SQL funzionali personalizzate per il nostro ambiente specifico.

Se utilizziamo il precedente esempio come input, il modello replicherà il modo in cui calcoliamo il tempo di consegna e fornirà query funzionali per il nostro ambiente concreto da ora in poi.

## Blocco di codiceuser_input = """Quale prodotto impiega più tempo per essere consegnato?"""prompt = f"""Dato le seguenti tabelle SQL, il tuo compito è fornire le tabelle SQL richieste per soddisfare qualsiasi richiesta dell'utente.Tabelle: <{sql_tables}>. Segui quegli esempi per generare la risposta, prestando attenzione sia al modo di strutturare le query che al suo formato:<{fewshot_examples}>Richiesta dell'utente: ```{user_input}```"""response = chatgpt_call(prompt)print(response)

 Screenshot del mio Jupyter Notebook. Prompting GPT.

 

Sommario

 

In conclusione, il modello GPT è un’ottima risorsa per convertire il linguaggio naturale in query SQL. 

Tuttavia, non è perfetto. 

Il modello potrebbe non essere in grado di comprendere query sensibili al contesto o operazioni specifiche senza un adeguato addestramento. 

Utilizzando il few-shot prompting, possiamo guidare il modello a comprendere il nostro stile di query e le nostre preferenze di calcolo. 

Questo ci consente di sfruttare appieno il potere del modello GPT nei nostri flussi di lavoro di data science, trasformando il modello in uno strumento potente che si adatta alle nostre esigenze uniche. 

Dalle query non formattate a query SQL perfettamente personalizzate, i modelli GPT portano la magia della personalizzazione a portata di mano!

Puoi andare a controllare il mio codice direttamente su GitHub.

## TABELLE SQLsql_tables = """CREATE TABLE PRODUCTS (    product_name VARCHAR(100),    price DECIMAL(10, 2),    discount DECIMAL(5, 2),    product_type VARCHAR(50),    rating DECIMAL(3, 1),    product_id VARCHAR(100));INSERT INTO PRODUCTS (product_name, price, discount, product_type, rating, product_id)VALUES    ('UltraView QLED TV', 2499.99, 15, 'TVs', 4.8, 'K5521'),    ('ViewTech Android TV', 799.99, 10, 'TVs', 4.6, 'K5522'),    ('SlimView OLED TV', 3499.99, 5, 'TVs', 4.9, 'K5523'),    ('PixelMaster Pro DSLR', 1999.99, 20, 'Cameras and Camcorders', 4.7, 'K5524'),    ('ActionX Waterproof Camera', 299.99, 15, 'Cameras and Camcorders', 4.4, 'K5525'),    ('SonicBlast Wireless Headphones', 149.99, 10, 'Audio and Headphones', 4.8, 'K5526'),    ('FotoSnap DSLR Camera', 599.99, 0, 'Cameras and Camcorders', 4.3, 'K5527'),    ('CineView 4K TV', 599.99, 10, 'TVs', 4.5, 'K5528'),    ('SoundMax Home Theater', 399.99, 5, 'Audio and Headphones', 4.2, 'K5529'),    ('GigaPhone 12X', 1199.99, 8, 'Smartphones and Accessories', 4.9, 'K5530');CREATE TABLE ORDERS (    order_number INT PRIMARY KEY,    order_creation DATE,    order_status VARCHAR(50),    product_id VARCHAR(100));INSERT INTO ORDERS (order_number, order_creation, order_status, delivery_date, product_id)VALUES    (123456, '2023-07-01', 'Spedito','', 'K5521'),    (789012, '2023-07-02', 'Consegnato','2023-07-06', 'K5524'),    (345678, '2023-07-03', 'In Elaborazione','', 'K5521'),    (901234, '2023-07-04', 'Spedito','', 'K5524'),    (567890, '2023-07-05', 'Consegnato','2023-07-15', 'K5521'),    (123789, '2023-07-06', 'In Elaborazione','', 'K5526'),    (456123, '2023-07-07', 'Spedito','', 'K5529'),    (890567, '2023-07-08', 'Consegnato','2023-07-12', 'K5522'),    (234901, '2023-07-09', 'In Elaborazione','', 'K5528'),    (678345, '2023-07-10', 'Spedito','', 'K5530');"""

  Josep Ferrer è un ingegnere analitico di Barcellona. Si è laureato in ingegneria fisica ed attualmente lavora nel campo della Data Science applicata alla mobilità umana. È un creatore di contenuti a tempo parziale focalizzato sulla data science e sulla tecnologia. Puoi contattarlo su LinkedIn, Twitter o VoAGI.