Last chance! 50% off DataCamp Premium
Sale ends in
Structured Query Language, of SQL (vaak uitgesproken als “sequel”), is een declaratieve programmeertaal die wordt gebruikt om data op te slaan, op te halen, te beheren en te manipuleren binnen een databasebeheersysteem.
Het werd begin jaren 70 ontwikkeld door IBM-onderzoekers Raymond Boyce en Donald Chamberlain, maar werd pas in 1979 commercieel beschikbaar toen Relational Software, Inc., dat nu is omgedoopt tot Oracle, zijn implementatie introduceerde.
Tegenwoordig wordt SQL algemeen geaccepteerd als de standaard relationele databasebeheersysteem (RDBMS) vanwege de eenvoud en het vermogen om grote datasets efficiënt te beheren en te analyseren. Dat maakt het onmisbaar in onze steeds meer datagedreven wereld.
Maar de datagedreven wereld evolueert.
Kunstmatige intelligentie wint razendsnel aan populariteit, en large language models zijn uitgegroeid tot extreem krachtige tools voor allerlei taken. Het enige probleem is dat de interactie met deze taalmodellen soms voelt alsof je een buitenaardse taal spreekt. Hier komt LMQL om de hoek kijken.
LMQL is ontwikkeld door het SRI Lab van ETH Zürich en fungeert als persoonlijke tolk tussen ontwikkelaars en hun taalmodellen. Concreet brengt LMQL de kracht van SQL naar het domein van taalmodellen, waardoor interacties soepeler, efficiënter en leuker worden.
In de rest van deze tutorial bespreken we:
LMQL, kort voor Language Models Query Language, is een innovatieve programmeertaal voor Large Language Models (LLM’s). Het combineert declaratieve, SQL-achtige elementen met een imperatieve scripttaal om op een meer gestructureerde en intuïtieve manier informatie uit LLM’s te halen of antwoorden te genereren.
Bovendien is LMQL een superset van Python, wat betekent dat het fungeert als een extensie die nieuwe functies introduceert en de mogelijkheden van Python uitbreidt. Hierdoor kunnen ontwikkelaars prompts in natuurlijke taal maken die tekst en code bevatten, wat de flexibiliteit en expressiviteit van queries vergroot.
Volgens de documentatie: “LMQL biedt een nieuwe manier om traditionele programmering te verweven met de mogelijkheid om LLM’s in je code aan te roepen. Het gaat verder dan traditionele templating-talen door LLM-interactie native te integreren op het niveau van je programmacode.”
De programmeertaal werd door de makers gepresenteerd in een onderzoeksartikel met de titel Prompting is Programming: A Query Lnague for Large Language Models als een oplossing om een fenomeen mogelijk te maken dat ze “LMP” noemden, oftewel Language Model Prompting.
Ter context: large language models hebben uitzonderlijke prestaties laten zien op meerdere taken, zoals vraagbeantwoording en codegeneratie. In de kern zijn LLM’s bedreven in het automatisch genereren van logische reeksen op basis van ingevoerde data met behulp van statistische waarschijnlijkheden.
Door deze capaciteit te benutten, kunnen gebruikers LLM’s aansturen met instructies in natuurlijke taal of voorbeelden om de uitvoering van verschillende downstream-taken te triggeren. Geavanceerde promptingtechnieken maken zelfs interacties mogelijk tussen gebruikers, het taalmodel en externe tools, zoals rekenmachines.
De uitdaging is het behalen van state-of-the-art prestaties of het afstemmen van LLM’s op specifieke taken, wat doorgaans vraagt om complexe, taakspecifieke programma’s die nog steeds afhankelijk kunnen zijn van ad-hocinteracties.
Prompting voor taalmodellen is een opkomende discipline die aan terrein wint om deze problemen aan te pakken. LMQL houdt zich aan de principes van LMP, waaronder het bieden van een intuïtieve combinatie van tekstprompting en scripting voor LLM’s, en het in staat stellen van gebruikers om beperkingen op de modeluitvoer te specificeren.
De recentere generatie taalmodellen kan conceptueel eenvoudig geprompt worden met voorbeelden of instructies. Maar om ze volledig te benutten en up-to-date te blijven wanneer nieuwe modellen verschijnen, heb je een grondig begrip nodig van hun interne werking en van leveranciersspecifieke libraries en implementaties.
Zo kan het beperken van het decodeerproces tot een lijst met geldige woorden of zinnen lastig zijn, omdat taalmodellen met tokens werken. Of je LLM’s nu lokaal gebruikt of via een API, ze zijn vrij kostbaar omdat het enorme netwerken zijn.
LMQL kan het aantal aanroepen naar het taalmodel (LM) verminderen door gebruik te maken van vooraf ingesteld gedrag en de zoekbeperking die wordt geïntroduceerd door constraints.
Een andere reden voor LMQL is dat veel promptingtechnieken heen-en-weercommunicatie vereisen tussen het taalmodel en de gebruiker (zoals we zien bij chatbots zoals ChatGPT) of sterk gespecialiseerde interfaces, zoals die voor rekenkundige berekeningen met externe besturingslogica.
Het implementeren van deze prompts vraagt veel handmatig werk en interactie met de decodeerprocedures van een model, wat de algemene toepasbaarheid van de resulterende implementaties beperkt. Tot slot: omdat een LM slechts één (subwoord)token tegelijk kan genereren, zijn er meerdere aanroepen nodig om af te ronden.
Bestaande LM’s bieden niet de functionaliteit om de output te begrenzen, wat cruciaal is als LM’s in productie worden ingezet. Stel bijvoorbeeld dat je een sentimentanalyse-applicatie bouwt om negatieve reviews te markeren. Het programma verwacht dat de LLM antwoordt met iets als “positief”, “negatief” of “neutraal”.
Maar vaak zegt de LLM iets als: “De sentiment voor de gegeven klantreview is positief,” wat lastig te verwerken is voor je API. Constraints zijn dus enorm nuttig.
Met LMQL kun je de output sturen met termen die voor mensen begrijpelijk zijn, in plaats van de tokens die de LM’s gebruiken.
LMQL kan lokaal worden geïnstalleerd of online worden gebruikt via de webgebaseerde Playground IDE. Let op: als je zelf-gehoste modellen wilt gebruiken via Transformers of llama.cpp, dan moet je LMQL lokaal installeren. Zo doe je dat:
LMQL lokaal installeren is vrij eenvoudig.
Het enige wat je hoeft te doen, is de volgende opdracht uitvoeren in een Python >= 3.10-omgeving:
pip install lmql
Als je modellen op een lokale GPU wilt draaien, moet je LMQL installeren in een omgeving met een GPU-enabled installatie van PyTorch >= 1.11.
Hier is de opdracht om LMQL met GPU-afhankelijkheden via pip te installeren:
pip install lmql[hf]
Let op: het installeren van dependencies in een virtuele omgeving is een goede gewoonte.
Na installatie heb je drie opties om LMQL-programma’s te draaien:
1. Playground
Je kunt een lokale instantie van de Playground IDE starten
lmql playground
Deze opdracht start een browsergebaseerde Playground IDE. Als deze niet automatisch opent, ga dan naar http://localhost:3000.
Let op: deze methode vereist een installatie van Node.js.
2. Command-line interface
Een alternatief voor de playground is de command-line tool. Deze kan worden gebruikt om lokale .lmql-bestanden uit te voeren. Voer hiervoor simpelweg de volgende opdracht uit:
lmql run
3. Python-integratie
Omdat het een superset is, kan LMQL rechtstreeks vanuit een Python-programma worden uitgevoerd. Je hoeft alleen het lmql-pakket te importeren. Alle querycode moet worden uitgevoerd via lmql.run of met de @lmql.query-decorator.
Wanneer je lokale Transformer-modellen gebruikt in de Playground IDE of de command-line tool, moet je eerst een instantie van de LMQL Inference API starten voor het betreffende model door het commando lmql serve-model uit te voeren.
Een LMQL-programma bestaat uit vijf fundamentele onderdelen, die elk een cruciale rol spelen bij het bepalen van het gedrag van een query. Deze componenten zijn:
Laten we elk onderdeel nader bekijken.
Het belangrijkste communicatiemiddel tussen het taalmodel en de gebruiker is het queryblok.
Hier is een basis- LMQL-query:
# Source: https://lmql.ai/docs/
"Say 'this is a test':[RESPONSE]" where len(TOKENS(RESPONSE)) < 25
—-- Model Output—--
"""
Say 'this is a test': RESPONSE This is a test
"""
Het queryblok behandelt elke string op het hoogste niveau als een directe query aan het taalmodel. Net als bij Python f-strings ondersteunen deze querystrings twee speciale geëscape subvelden.
Let op dat de uitdrukking die het taalmodel zal genereren wordt weergegeven met [varname]. Dit wordt ook wel een “hole” genoemd – op de where-clausule komen we zo terug.
Het ophalen van een variabelewaarde uit de huidige scope kan ook met {varname}.
Bijvoorbeeld:
# Source: https://lmql.ai/docs/language/overview.html
# review to be analyzed
review = """We had a great stay. Hiking in the mountains was fabulous and the food is really good."""
# use prompt statements to pass information to the model
"Review: {review}"
Verschillende decodeeralgoritmen die worden gebruikt om tekst te genereren uit de tokendistributie van een taalmodel, worden door LMQL ondersteund. Dit maakt het mogelijk om het decodeeralgoritme aan het begin van een query te specificeren.
Er zijn twee manieren om het te gebruiken decodeeralgoritme op te geven:
1. Als onderdeel van de query - hierbij specificeer je het algoritme en de parameters als onderdeel van de query. Volgens de LMQL-documentatie: “Dit kan bijzonder nuttig zijn als je keuze voor een decoder relevant is voor het concrete programma dat je schrijft.” Zo ziet dat er in code uit:
# Source: https://lmql.ai/docs/language/decoding.html
# use beam search with beam width 2 for
# the entire program
beam(n=2)
# uses beam search to generate RESPONSE
"This is a query with a specified decoder: [RESPONSE]"
2. Extern - hierbij worden het decodeeralgoritme en de parameters extern gespecificeerd, dus los van het eigenlijke programma. Let op: dit is alleen mogelijk wanneer LMQL vanuit een Python-context wordt gebruikt
# Source: https://lmql.ai/docs/language/decoding.htmlimport lmql
@lmql.query(model="openai/text-davinci-003", decoder="sample", temperature=1.8)
def tell_a_joke():
'''lmql
"""A list good dad joke. A indicates the punchline:
Q:[JOKE]
A:[PUNCHLINE]""" where STOPS_AT(JOKE, "?") and STOPS_AT(PUNCHLINE, "\n")
'''
tell_a_joke() # uses the decoder specified in @lmql.query(...)
tell_a_joke(decoder="beam", n=2) # uses a beam search decoder with n=2
LMQL wordt door de ontwikkelaars omschreven als een “high-level, front-end language for text generation”. Dat betekent dat het niet specifiek is voor één tekstgeneratiemodel. In plaats daarvan worden verschillende tekstgeneratiemodellen aan de achterkant ondersteund, zoals OpenAI model, llama.cpp en HuggingFace Transformers.
Modellen laden is vrij eenvoudig. Je kunt de functie lmql.model(...) gebruiken, die een lmql.LMM-object oplevert.
Zo ziet dat eruit:
# Source: https://lmql.ai/docs/models/
lmql.model("openai/gpt-3.5-turbo-instruct") # OpenAI API model
lmql.model("random", seed=123) # randomly sampling model
lmql.model("llama.cpp:<YOUR_WEIGHTS>.gguf") # llama.cpp model
lmql.model("local:gpt2") # load a `transformers` model in-process
lmql.model("local:gpt2", cuda=True, load_in_4bit=True) # load a `transformers` model in process with additional arguments
lmql.model("gpt2") # access a `transformers` model hosted via `lmql serve-model`
Zodra het lmql.LLM-object is aangemaakt, kun je het model op twee manieren aan het queryprogramma doorgeven:
1. Het model extern specificeren
# Source: https://lmql.ai/docs/models/
import lmql
# uses 'chatgpt' by default
@lmql.query(model="chatgpt")
def tell_a_joke():
'''lmql
"""A great good dad joke. A indicates the punchline
Q:[JOKE]
A:[PUNCHLINE]""" where STOPS_AT(JOKE, "?") and \
STOPS_AT(PUNCHLINE, "\n")
'''
tell_a_joke() # uses chatgpt
tell_a_joke(model=lmql.model("openai/text-davinci-003")) # uses text-davinci-003
2. Een query met de from-clausule gebruiken
# Source: https://lmql.ai/docs/models/
argmax
"This is a query with a specified 'from'-clause: [RESPONSE]"
from
"openai/text-ada-001"
Een van de grootste troeven van LMQL is het constraints-onderdeel. LMQL stelt gebruikers in staat om beperkingen op de modeluitvoer te specificeren. Dit helpt bij gescripte prompting door te garanderen dat de modeluitvoer stopt op het beoogde punt, en geeft gebruikers tijdens het decoderen controle over het model.
De ondersteunde constraints omvatten:
Bekijk de pagina Constraints in de LMQL-documentatie voor meer informatie.
De distribution-instructie is een sleutelonderdeel in LMQL. Het biedt controle over de opmaak en structuur van de output door te definiëren hoe de gegenereerde resultaten worden verdeeld en gepresenteerd.
Hier is een voorbeeld in actie:
# Source: https://lmql.ai/docs/language/overview.html
argmax
# review to be analyzed
review = """We had a great stay. Hiking in the mountains was fabulous and the food is really good."""
# use prompt statements to pass information to the model
"Review: {review}"
"Q: What is the underlying sentiment of this review and why?"
# template variables like [ANALYSIS] are used to generate text
"A:[ANALYSIS]" where not "\n" in ANALYSIS
# use constrained variable to produce a classification
"Based on this, the overall sentiment of the message can be considered to be[CLS]"
distribution
CLS in [" positive", " neutral", " negative"]
----- Model Output ------
Review: We had a great stay. Hiking in the mountains was fabulous and the food is really good.
Q: What is the underlying sentiment of this review and why?
A: ANALYSIS The underlying sentiment of this review is positive because the reviewer had a great stay, enjoyed the hiking and found the food to be good.
Based on this, the overall sentiment of the message can be considered to be CLS
Zoals bij alle technologieën zijn er enkele beperkingen bij LMQL. Bijvoorbeeld:
Hoewel dit struikelblokken kunnen zijn voor gebruikers die LMQL overwegen, is het belangrijk te benadrukken dat de bibliotheek nog vrij nieuw is en in ontwikkeling – deze beperkingen kunnen in latere versies worden opgelost.
LMQL is een SQL-achtige programmeertaal die ook een superset van Python is. Het vereenvoudigt het ophalen van informatie of genereren van antwoorden uit LLM’s door de declaratieve elementen te combineren met een imperatieve scripttaal. Ontwikkelaars kunnen met LMQL de tekstgeneratie effectief sturen, wat het tot een uiterst waardevol hulpmiddel maakt voor diverse toepassingen in de techsector.
Ga verder met leren via:
Begin vandaag nog aan je AI-reis!
Cursus
Cursus
Leerpad

blog
Adel Nehme
15 min