Fa parlare di sé LMQL, un linguaggio di interrogazione open source sviluppato da ETH Zürich per i large language models (LLMs). Ecco come funziona.
Si chiama LMQL il linguaggio di interrogazione per il prompt engineering messo a punto da ETH Zürich, il Politecnico Federale di Zurigo. Pensato in modo specifico per la gestione dei large language models (LLMs), LMQL risponde all’obiettivo di superare alcuni limiti intrinseci ai prompt di solo testo. Di seguito spieghiamo qual è il fondamento concettuale del nuovo linguaggio e ne illustriamo, in pratica, il funzionamento.
Se sei interessato al prompt engineering, ti ricordiamo che ce ne siamo occupati anche in altri articoli: uno dedicato a chain-of-thought (CoT) prompting e reprompting, l’altro alle pratiche di looping per GPT.
Interrogare è come programmare
La premessa è quasi filosofica. I sostantivi inglesi prompt e query sono in apparenza sinonimi. In italiano, potremmo rendere entrambi con il termine richiesta. Dove sta la differenza? Diciamo che il prompt è una richiesta formulata in linguaggio naturale (per esempio: «visualizza la lista in ordine alfabetico per cognome e – in caso di cognome identico – esegui l’ordinamento in base al nome»), mentre la query è un’espressione formale e strutturata (la richiesta formulata in linguaggio naturale nell’esempio precedente corrisponde alla query SQL «ORDER BY COGNOME ASC, NOME DESC»).
Ora, il mondo del LLMs ci sta abituando a interfacce – come ChatGPT o Midjourney – che ci permettono di interrogare il modello utilizzando il linguaggio naturale. Alla base, vi è la capacità dell’intelligenza artificiale generativa di completare la sequenza in input – ovvero la nostra richiesta – svolgendo un’operazione di tipo statistico. Il modello fornisce in output la sequenza più probabile.
Sappiamo che, a seconda del modello e del compito ad esso richiesto, il prompt deve essere opportunamente aggiustato. Il prompt engineering altro non è che la pratica di generare gli input più adeguati rispetto al compito che il modello deve assolvere.
Le buone pratiche
Ecco perché, tanto per cominciare, dobbiamo saper riconoscere fra diverse categorie di prompt. Schematizzando un po’, potremmo dire che un prompt risponde di volta in volta a uno dei seguenti scopi:
- Ottenere una determinata informazione
- Chiedere l’esecuzione di uno specifico compito
- Fornire al modello un contesto di interpretazione, per consentirgli di produrre output più puntuali
- Istituire un confronto fra diverse opzioni
- Cercare un’opinione (ricordiamo che l’intelligenza artificiale non ha opinioni, ma si limita a calcolare le probabilità che una determinata opinione – fra tutte quelle su cui è stata addestrata – sia corretta)
- Fare in modo che il modello assuma un ruolo e ce ne fornisca il punto di vista
L’osservazione e l’esperienza suggeriscono una serie di buone pratiche da seguire, quando si interagisce con un LLM:
- Essere chiari
- Fornire esempi e informazioni di contesto
- Fissare limiti e vincoli, per non ottenere risposte troppo generiche
- Spezzare le richieste troppo lunghe
- Iterare le richieste, riformulandole
- Rendere evidenti le informazioni più importanti
- Chiedere al modello di procedere passo dopo passo
- Mettere il modello di fronte a eventuali contraddizioni nelle sue risposte
Metodi avanzati di prompting possono persino implicare l’interazione tra il modello linguistico, l’utente e strumenti esterni come computer o robot.
Se il gioco si fa duro, arriva il LMP
Eppure, non sempre tutto questo è sufficiente. Per elevare la qualità delle risposte o per adattare i modelli linguistici all’esecuzione di compiti peculiari, talvolta è necessario implementare programmi ad hoc, ossia disegnati per uno specifico compito e modello.
Partendo da questa intuizione, i ricercatori dell’ETH hanno sviluppato l’idea di una programmabilità del modello linguistico (LMP, language model programming). Si tratta di passare da un approccio basato su prompt di puro testo a una combinazione intuitiva di prompt e script. L’LMP postula la possibilità di controllare meglio gi output del modello e di adattare il modello stesso all’esecuzione di molti compiti, attraverso la messa a punto di vincoli più specifici di quelli che si possono introdurre mediante prompt meramente testuali. A tale scopo l’LMP implementa una semantica di alto livello che astrae dalle peculiarità dei singoli modelli.
Da LMP a LMQL il passo è breve. L’LMQL (abbreviazione di Language Model Query Language) è un linguaggio di interrogazione open source che sfrutta i vincoli e il flusso di controllo di un prompt «misto», come sopra descritto, per generare una procedura di inferenza efficiente. Il suo impiego contribuisce a minimizzare il numero di chiamate al modello linguistico sottostante. Secondo i ricercatori di Zurigo, l’uso di LMQL consente di mantenere o aumentare l’accuratezza di diversi compiti a valle, riducendo al contempo in modo significativo la quantità di calcolo o il costo richiesto nel caso di API a pagamento.
La sintassi è quella di Python
In sostanza, LMQL combina elementi dichiarativi simili a SQL con una sintassi di scripting imperativa. Sfruttando un runtime sottostante che si integra perfettamente con i modelli di linguaggio esistenti, attuando modifiche minime della logica di decodifica. Sfruttando la sua natura dichiarativa, è possibile controllare e guidare efficacemente la generazione del testo. Ciò rende LMQL uno strumento prezioso per diverse applicazioni.
I programmi scritti in LMQL adottano la sintassi di Python, con l’aggiunta di alcune funzioni proprie e immodificabili (built-in), e si compongono di cinque parti:
Decoder – Specificato come stringa, determina la procedura di decodifica utilizzata durante la generazione del testo, ovvero il modo in cui l’output del modello viene trasformato in risultati significativi. La scelta del decodificatore è decisiva per la qualità, la diversità e le prestazioni complessive del testo generato.
Query – È il meccanismo centrale di interazione con il modello linguistico. Assomiglia al corpo di una funzione Python, anche se con alcune restrizioni e aggiunte. Le dichiarazioni di funzioni interne non sono ammesse, ma è possibile includere le importazioni. Ogni stringa di primo livello all’interno del blocco di query viene trattata come un’interrogazione diretta al modello linguistico. Queste stringhe di query supportano due speciali sottocampi di escape, simili alle stringhe f di Python.
Clausola from – Specifica qual è il modello interrogato.
Clausola where – Specifica i vincoli.
Distribute – Contiene le istruzioni di distribuzione, ovvero definisce il modo in cui i risultati generati vengono distribuiti e presentati, offrendo un controllo sul formato e sulla struttura dei risultati.
La query viene eseguita alla stregua di un programma in Python. Un quadro completo sul funzionamento di LMQL è disponibile nel paper di Luca Beurer-Kellner, Marc Fischer e Martin Vechev, Prompting Is Programming: A Query Language for Large Language Models, 30 maggio 2023 (3a revisione): https://arxiv.org/abs/2212.06094.