- Antworten lokaler Modelle können an ein JSON Schema gebunden werden, wodurch sich der Aufwand für nachträgliches Parsing verringert und die Ergebnisse bei der Datenextraktion konsistenter werden
- Nutzer können in cURL, Python und JavaScript über den Parameter
format ein Schema übergeben und so auf dieselbe Weise strukturierte Ausgaben anfordern
- In Python mit Pydantic und in JavaScript mit Zod lässt sich die Schemadefinition leicht mit der Antwortvalidierung auf Code-Ebene verknüpfen
- Die Beispiele geben Länderinformationen, Texte zu Haustieren und Bildanalyse-Ergebnisse von
llama3.2-vision in festgelegten JSON-Feldern zurück und validieren sie
- Wenn stabile Ergebnisse wichtig sind, wird empfohlen, im Prompt „return as JSON“ zu ergänzen und die temperature auf 0 zu setzen
Modellantworten mit JSON Schema einschränken
- Ollama unterstützt strukturierte Ausgaben, mit denen sich die Modellausgabe auf ein bestimmtes JSON-Schema beschränken lässt
- Auch die Python- und JavaScript-Bibliotheken von Ollama wurden aktualisiert, um strukturierte Ausgaben zu unterstützen
- Diese Funktion kann für folgende Aufgaben genutzt werden
- Daten aus Dokumenten parsen
- Daten aus Bildern extrahieren
- Antworten von Sprachmodellen strukturieren
- Höhere Zuverlässigkeit und Konsistenz als im JSON-Modus erreichen
Installation und Aufruf
- Es muss die neueste Version von Ollama heruntergeladen werden
- Die Python-Bibliothek wird mit folgendem Befehl auf die neueste Version aktualisiert
pip install -U ollama
- Die JavaScript-Bibliothek wird mit folgendem Befehl installiert
npm i ollama
- Um strukturierte Ausgaben anzufordern, wird das Schema in cURL-Anfragen oder in den Python- bzw. JavaScript-Bibliotheken über den Parameter
format übergeben
JSON Schema per cURL übergeben
- Das cURL-Beispiel sendet eine Anfrage an
http://localhost:11434/api/chat, setzt model auf llama3.1 und stream auf false
- In
format wird ein Objektschema mit name, capital und languages übergeben
name: Zeichenkette
capital: Zeichenkette
languages: Array von Zeichenketten
- Alle drei Felder sind als
required markiert
- Die Antwort wird im Format des in der Anfrage enthaltenen JSON-Schemas zurückgegeben
{
"capital": "Ottawa",
"languages": [
"English",
"French"
],
"name": "Canada"
}
Verwendung der Python- und JavaScript-Bibliotheken
-
Python
- Die Ollama Python library übergibt das Schema als JSON-Objekt an den Parameter
format
- Das Schema kann als
dict übergeben werden; empfohlen wird die Serialisierung mit model_json_schema() aus Pydantic
- Im Beispiel definiert das Modell
Country die Felder name, capital und languages, und die Antwort wird mit Country.model_validate_json() validiert
country = Country.model_validate_json(response.message.content)
- Die Beispielausgabe gibt
Canada, Ottawa, English und French passend zu den definierten Feldern zurück
-
JavaScript
- Die Ollama JavaScript library übergibt das Schema als JSON-Objekt an den Parameter
format
- Das Schema kann als
object übergeben werden; empfohlen wird die Verwendung von Zod zusammen mit zodToJsonSchema()
- Im Beispiel wird das Schema
Country als Zod-Objekt definiert, der Antworttext mit JSON.parse() verarbeitet und anschließend mit Country.parse() validiert
const country = Country.parse(JSON.parse(response.message.content));
Daten aus Texten und Bildern extrahieren
-
Extraktion aus Haustiertexten
- Strukturierte Ausgaben können verwendet werden, um benötigte Informationen aus Texten zu extrahieren
- Das Beispiel definiert die Pydantic-Modelle
Pet und PetList und gibt Informationen zu Haustieren in einer JSON-Struktur zurück
Pet: name, animal, age, color, favorite_toy
PetList: Array pets
- Der Eingabetext enthält Informationen zu zwei Katzen
- Luna: 5 Jahre alt, graues Fell, mag yarn
- Loki: 2 Jahre alt, schwarz, mag tennis balls
- Die Ausgabe wird gemäß dem definierten Schema als Liste von
Pet-Objekten validiert
-
Bildbeschreibung mit Vision-Modell
- Strukturierte Ausgaben können zusammen mit Vision-Modellen verwendet werden
- Das Beispiel analysiert ein Bild mit
llama3.2-vision und gibt ein Ergebnis zurück, das dem Schema ImageDescription entspricht
- Das Schema enthält die folgenden Felder
summary
objects
scene
colors
time_of_day
setting
text_content
- Die Beispielanfrage weist an, Objekte, Szene, Farben und erkennbaren Text im Bild zu analysieren
- In den Optionen wird
temperature auf 0 gesetzt, um eine deterministischere Ausgabe zu erhalten
- Die Beispielausgabe fasst eine Szene mit Palmen am Strand zusammen und gibt strukturierte Felder für
tree und beach, Farben, Tageszeit und Outdoor-Umgebung zurück
Verwendung der OpenAI-kompatiblen API
- Das OpenAI-kompatible Beispiel konfiguriert den
OpenAI-Client mit base_url="http://localhost:11434/v1" und api_key="ollama"
- Mit
client.beta.chat.completions.parse() wird im response_format das Pydantic-Modell PetList übergeben
- In der Antwort wird
completion.choices[0].message geprüft; falls parsed vorhanden ist, wird das geparste Ergebnis ausgegeben
- Falls
refusal vorhanden ist, wird eine Ablehnungsantwort ausgegeben; openai.LengthFinishReasonError wird als Fall behandelt, in dem zu viele Tokens erzeugt wurden
Einstellungen für stabile Ausgaben und künftige Pläne
- Für die Definition des Antwortschemas wird die Verwendung von Pydantic in Python oder Zod in JavaScript empfohlen
- Es ist sinnvoll, dem Prompt „return as JSON“ hinzuzufügen, damit das Modell die Anforderung versteht
- Für deterministischere Ausgaben sollte temperature auf 0 gesetzt werden
- Für die Zukunft sind folgende Punkte geplant
- Logits-Freigabe für kontrollierte Generierung
- Verbesserungen bei Leistung und Genauigkeit strukturierter Ausgaben
- GPU-Beschleunigung für Sampling
- Unterstützung weiterer Formate über JSON Schema hinaus
1 Kommentare
Hacker-News-Kommentare
Wenn stärkere Ausgabebeschränkungen nötig sind, unterstützt llama.cpp GBNF
https://github.com/ggerganov/llama.cpp/blob/master/grammars/...
Rein intuitiv würde ich denken, dass Modelle JSON besser erzeugen als andere Formate, weil sie davon deutlich mehr gesehen haben
Gute Nachricht
Beim Erzeugen von CSV-Daten habe ich mich gefragt, wie man einen normalen Prompt so formulieren soll, dass keine unnötigen Phrasen wie "Here is your data" oder "Please note blah blah" davor oder danach erscheinen; deshalb freut es mich, dass man jetzt das gewünschte Rückgabeformat exakt definieren und die strukturierte Ausgabe direkt als CSV erhalten kann
Sonst kann zwar technisch gesehen CSV herauskommen, aber ohne sinnvolle Bedeutung. Das Modell wollte möglicherweise eigentlich eine Antwort in Absatzform schreiben, und der Token-Sampler hat dann nur Tokens mit niedriger Wahrscheinlichkeit gewählt, die das Modell gar nicht besonders ausgeben wollte
\n vorab füllt und beistoppen lässtFunktioniert. Ich habe gemma2:2b den folgenden Satz gegeben und das gewünschte JSON erhalten
You have spent 190 at Fresh Mart. Current balance: 5098Das Ergebnis war
{"amount": 190, "balance": 5098, "category": "Shopping", "place": "Fresh Mart"}Wirklich erstaunlich. Das war tatsächlich eine der Funktionen, die ich mir gewünscht habe
Der Reiz von ollama liegt darin, dass es sich anfühlt, als würde man ein LLM wie ein anderes UNIX-Programm verwenden, und als gehöre ein LLM ganz natürlich in UNIX hinein
Mich würde allerdings interessieren, ob es jemand gut auf einer AMD GPU zum Laufen gebracht hat. Ich habe gehört, dass es schwieriger ist, würde aber beim nächsten Kartenkauf nächstes Jahr gern den Wettbewerber unterstützen
Auf einem Mini-PC mit 780M lief es ziemlich gut, nachdem ich im BIOS 16 GB Shared Memory zugewiesen hatte
Ich frage mich, welche Auswirkungen solche Beschränkungen auf die Qualität der LLM-Ausgabe haben
In manchen Fällen würde ich lieber Markdown oder Klartext parsen, wenn die Ausgabequalität dann höher ist
Im ersten Durchlauf lässt man ein größeres Modell mit natürlicher Sprache die Schlussfolgerung in Markdown-Abschnitten behandeln und die endgültige Antwort in natürlicher Sprache liefern. Wenn möglich, klar mit Markdown-Überschriften beschriften
Im zweiten Durchlauf wandelt ein günstigeres und schnelleres Modell diese Antwort in ein strukturiertes Ausgabeformat um, das vom nicht-LLM-Teil der Pipeline konsumiert wird
Im Grunde nutzt man den JSON-Schema-Modus, um saubere Grenzen um mehrdeutige Teile natürlicher Sprache zu ziehen, und lässt das LLM wie einen Vorverarbeiter arbeiten, der seine eigene Ausgabe in ein nützliches Format überführt
Außerdem muss man dem Modell das Schema mitteilen. Wenn man das nicht tut, treten eher seltsame Tokenisierungsprobleme auf
Wenn das Schema zum Beispiel den JSON-Key
"foobarbaz"erwartet und die Standard-BPE-Tokenisierung["foobar", "baz"]ist, dann können die Token-Masken, die heutige Libraries für constrained output erzeugen, dem Modell erlauben, zwischen"f","foo"und"foobar"zu wählen. Wenn das Modell"foo"wählt, erzwingt die Beschränkung als nächstes Token etwa"bar"und"baz". Dann sieht das Modell["foo", "bar", "baz"]statt["foobar", "baz"], was es verwirrt [0]Wenn das Modell im Prompt weiß, dass
"foobarbaz"einer der Schema-Keys ist, bevorzugt es im Allgemeinen"foobar"gegenüber"foo"[0] Bei neueren Modellen sind diese Tokens durch Normalisierung zwar verwandt, aber nicht identisch
Es hängt stark davon ab, ob das LLM und der Prompt überhaupt von sich aus wahrscheinlich eine JSON-Antwort erzeugen würden. Je stärker man das LLM in eine Richtung zwingt, desto geringer die Chance, dass es eine normale Eingabe erzeugt
Bei kleinen Modellen erreicht man schneller den Rand des Bereichs, in dem noch sinnvolle Vorhersagekraft vorhanden ist, und die Ausgabe beginnt eher wie zufälliges Rauschen zu wirken
Das ist keine strenge Messung, sondern ein Bauchgefühl nach viel Zeit in verschiedenen LLM-Projekten. Diese konkreten Werkzeuge habe ich noch nicht benutzt, aber ollama konnte früher schon auf eine ähnlich wirkende Weise JSON-Ausgabe garantieren, und ich habe mit einem Partner auch an etwas JSONformer-Ähnlichem für oobabooga gearbeitet, ein weiteres LLM-Runtime-Tool
Ich hoffe, dass sich mit solchen Änderungen irgendwann auch allgemeine strukturierte Generierung ermöglichen lässt, nicht nur JSON
Man kann leicht viele Tokens verbrauchen, aber wenn der Anwendungsfall die Kosten rechtfertigt, lässt sich damit ziemlich viel erzwingen. Auch wenn es nicht die absolut höchste Qualität ist, lohnt sich ein Werkzeug, das ohne großen Aufwand 95 % erreicht, auf jeden Fall für den Werkzeugkasten
Ich frage mich, ob man das mit jedem unterstützten Modell verwenden kann
Auf meiner Hardware kann ich nur 1B- bis 3B-Modelle stabil betreiben, deshalb frage ich
Bei kleinen Modellen können die Ergebnisse schwanken, aber die Bitte, „x als JSON zurückzugeben“, hat tendenziell bei der Genauigkeit geholfen
Der PR für diese Funktion war fast ein Jahr lang offen
Etwas schade, dass die Maintainer so still waren
Hoffentlich schaffen wir es nächstes Jahr, Community-PRs besser zu begleiten und zusammenzuführen
Ich nutze immer noch oobabooga. Dank exlv2 ist auf einer Dual-3090 deutlich effizientere Inferenz möglich.
Soweit ich mich erinnere, war exl2 zwar schneller, aber insbesondere bei geringer Bittiefe schien die gptq-Quantisierung bei der Genauigkeit besser zu sein.
Ich frage mich, welchen Mehrwert es im Vergleich zu
outlinesgibt.https://www.souzatharsis.com/tamingLLMs/notebooks/structured...
Auf Grundlage der aktuellen Forschung zu outlines/xgrammar hoffe ich, das Sampling so aktualisieren zu können, dass mehr Formate unterstützt, die Genauigkeit erhöht und die Performance verbessert werden.
Ich frage mich, ob es eine beste Methode gibt, dem LLM strukturierte Eingaben zu geben.
Zum Beispiel, wenn man 100 Sätze eingibt und jeden davon auf mehrere Arten klassifizieren lassen will. Strukturierte Daten zu empfangen ist einfach, aber meine Methode, Zeilennummern voranzustellen, wirkt unbeholfen.
In diesem Fall ist es aber am besten, die Sätze einzeln zu geben, damit das Modell nicht durcheinanderkommt.
Wenn du den Prompt als
"Klassifiziere den folgenden Satz. Die Regeln sind ..."+ Satz aufbaust, kannst du Prefix-Caching nutzen, wodurch die Performance sogar besser sein kann als bei einer Sammelanfrage.Das funktioniert natürlich nur, wenn Prefix-Caching verfügbar ist und nicht pro Eingabetoken abgerechnet wird. Die meisten Anbieter ermöglichen inzwischen geringere Kosten, wenn man angibt, dass man Prefix-Caching nutzen möchte.