Wir haben viel über beliebte Techniken zur Optimierung der Leistung und Kosten von KI-Anwendungen gesprochen, z Antwort-Streaming oder sofortiges Caching. Heute möchte ich über etwas anderes, aber ebenso Wichtiges für die Entwicklung echter KI-Apps sprechen. Das heißt, strukturierte, maschinenlesbare Ausgaben.
Bisher haben wir uns in den meisten Beispielen, die ich geteilt habe, mit Freitextantworten eines KI-Modells befasst. Der Benutzer stellt eine Frage, das Modell antwortet in natürlicher Sprache und wir zeigen dem Benutzer diese Antwort einfach auf irgendeine Weise an. Ziemlich einfach und unkompliziert. Aber was passiert, wenn das Modell Daten in einem bestimmten Format (z. B. einem JSON-Objekt) zurückgeben muss, damit wir sie später programmgesteuert weiterverarbeiten können? Was wäre, wenn wir das Modell benötigen, um bestimmte Felder aus einem Textual content oder Bild zu extrahieren, einen Datenbankeintrag zu füllen oder basierend auf seiner Antwort eine Folgeaktion auszulösen? In solchen Fällen ist es nicht sehr praktisch, eine Textwand wiederherzustellen. 🤔
Glücklicherweise gibt es für dieses Downside mehrere Lösungen. Es gibt zwei Hauptansätze, um strukturierte, maschinenlesbare Ausgaben von einem LLM zu erhalten: JSON-Modus Und Funktionsaufruf (auch Werkzeuggebrauch genannt). Diese beiden werden oft miteinander verwechselt (was zu erwarten ist, da es sich bei beiden um strukturierte Ausgaben handelt), aber sie dienen ganz unterschiedlichen Zwecken. Darüber hinaus hat OpenAI eine strengere Variante des Funktionsaufrufs namens „Perform Calling“ eingeführt Strukturierte Ausgabenwas die Schemadurchsetzung, wie wir sehen werden, noch einen Schritt weiter bringt. In diesem Beitrag werfen wir einen genaueren Blick auf alle drei, verstehen, wie sie unter der Haube funktionieren, und finden heraus, wann sie jeweils zu verwenden sind.
Additionally schauen wir mal rein!
1. Was ist der JSON-Modus?
JSON-Modus ist der einfachere Ansatz, um maschinenlesbare Ausgaben eines LLM zu erzielen. Es handelt sich im Wesentlichen um einen Parameter, den Sie in einer API-Anfrage festlegen können, um das Modell anzuweisen stets Gibt ein gültiges JSON-Objekt zurück. Und das ist wirklich alles! Diese Einfachheit hat jedoch ihren Preis, da es keine Garantien für die Struktur oder das Schema des JSON gibt (denken Sie daran, dass wir kein Schema, keine Feldnamen, keine Typen oder ähnliches definiert haben), sondern lediglich dafür, dass es sich um ein gültiges, analysierbares JSON handelt.
Wenn wir beispielsweise die OpenAI-API in Python verwenden, können wir den JSON-Modus aktivieren, indem wir den Parameter hinzufügen response_format={"sort": "json_object"} zu unserem Aufruf zum Mannequin. Genauer gesagt würde es etwa so aussehen:
from openai import OpenAI
shopper = OpenAI(api_key="your_api_key")
response = shopper.chat.completions.create(
mannequin="gpt-4o-mini",
response_format={"sort": "json_object"},
messages=(
{
"function": "system",
"content material": "You're a useful assistant. All the time reply in JSON format."
},
{
"function": "person",
"content material": "Extract the identify, age, and metropolis from this textual content: 'Maria is 32 years previous and lives in Athens.'"
}
)
)
print(response.decisions(0).message.content material)
Und die Antwort würde in etwa so aussehen:
{
"identify": "Maria",
"age": 32,
"metropolis": "Athens"
}
Und voilà! ✨ Mit nur einer einfachen Parameteränderung erhalten wir jedes Mal ein gültiges JSON zurück. Kein String-Parsing oder seltsame Regex-Hacks erforderlich.
Allerdings gibt es einen Haken. Der JSON-Modus garantiert, dass die Ausgabe erfolgt gültiges JSONaber das tut es nicht eine bestimmte Struktur garantieren. Wenn wir dasselbe Beispiel mehrmals ausführen, erhalten wir möglicherweise jedes Mal leicht unterschiedliche Feldnamen oder eine leicht unterschiedliche Struktur. Beispielsweise könnte ein Lauf zurückkehren "identify" und noch eins "full_name". Das ist ein Downside, wenn wir versuchen, bestimmte Felder zuverlässig programmgesteuert zu extrahieren.
Eine andere Sache ist, dass sie jenseits der Einstellung liegt response_format={"sort": "json_object"}empfiehlt es sich, das Modell auch immer explizit anzuweisen, in JSON in der Systemeingabeaufforderung zu antworten. Beachten Sie, dass wir im obigen Beispiel auch hinzugefügt haben „Immer im JSON-Format antworten“ in der Systemaufforderung. Ohne dies gibt das Modell möglicherweise manchmal, aber nicht immer, einen gültigen JSON-Code zurück, da sein Verhalten möglicherweise unvorhersehbar wird.
2. Was ist Funktionsaufruf?
Funktionsaufruf (oder Werkzeugverwendung) ist ein fortgeschrittenerer Ansatz, um strukturierte, maschinenlesbare Ausgaben von einem LLM zu erhalten. Anstatt das Modell einfach aufzufordern, seine Antwort als JSON zu formatieren, definieren wir eine bestimmte Schema. Das heißt, wir definieren explizit eine formale Beschreibung der Struktur, der die Ausgabe folgen soll, und auf diese Weise ist das Modell stärker darauf beschränkt, Daten zurückzugeben, die genau diesem Schema entsprechen. Mit anderen Worten: Beim Funktionsaufruf definieren wir im Voraus, welche Felder wir erwarten, welche Typen diese Felder haben sollten, welche erforderlich sind und welche nicht und so weiter.
So würde das gleiche Extraktionsbeispiel mit Funktionsaufrufen aussehen:
from openai import OpenAI
import json
shopper = OpenAI(api_key="your_api_key")
# outline the schema of the output we anticipate
instruments = (
{
"sort": "operate",
"operate": {
"identify": "extract_person_info",
"description": "Extract private data from a textual content",
"parameters": {
"sort": "object",
"properties": {
"identify": {
"sort": "string",
"description": "The complete identify of the particular person"
},
"age": {
"sort": "integer",
"description": "The age of the particular person"
},
"metropolis": {
"sort": "string",
"description": "The town the particular person lives in"
}
},
"required": ("identify", "age", "metropolis")
}
}
}
)
response = shopper.chat.completions.create(
mannequin="gpt-4o-mini",
instruments=instruments,
tool_choice={"sort": "operate", "operate": {"identify": "extract_person_info"}},
messages=(
{
"function": "person",
"content material": "Extract the identify, age, and metropolis from this textual content: 'Maria is 32 years previous and lives in Athens.'"
}
)
)
# parse the structured output
tool_call = response.decisions(0).message.tool_calls(0)
end result = json.masses(tool_call.operate.arguments)
print(end result)
Und die Ausgabe würde so aussehen:
{
"identify": "Maria",
"age": 32,
"metropolis": "Athens"
}
Die Ausgabe für dieses Beispiel mit Funktionsaufrufen ist identisch mit der, die wir im JSON-Modus erhalten haben. Der Hauptunterschied besteht jedoch darin, dass die Ausgabe im Gegensatz zum JSON-Modus beim Funktionsaufruf konsistent ist. es wird stets Folgen Sie dem genau definierten Schema mit konsistenten Feldnamen, Typen und allen anderen Attributen, die wir darauf definieren.
🍨 DataCream ist ein Publication mit Geschichten und Tutorials zu KI, Daten und Technologie. Wenn Sie sich für diese Themen interessieren, Abonnieren Sie hier!
Bonus: Etwas mehr zum Funktionsaufruf
Bevor wir zu strukturierten Ausgaben übergehen, lohnt es sich, eine Pause einzulegen und die ursprüngliche Motivation und Verwendung des Funktionsaufrufs genauer zu erläutern, der weit über das bloße Erhalten strukturierter Ausgaben hinausgeht. Im Wesentlichen ist das Konzept des Funktionsaufrufs die Grundlage für Agenten-KI-Workflows. Genauer gesagt ist es in einem Agenten-Setup das LLM nicht nur antworten auf die Frage eines Benutzers, sondern es ist so entscheiden Welche Aktion als Nächstes ausgeführt werden soll, basierend auf der Eingabe des Benutzers.
Stellen wir uns zum Beispiel einen Kundendienstassistenten vor, der je nach den Fragen des Benutzers entweder eine Bestellung nachschlagen, eine Rückerstattung veranlassen oder an einen menschlichen Agenten eskalieren kann. Mit Funktionsaufrufen können wir alle drei dieser Kandidatenaktionen als „Werkzeuge“ (Funktionen) definieren, und die Ausgabe des Modells definiert basierend auf der Eingabe, welche aufgerufen werden soll und mit welchen Argumenten.
instruments = (
{
"sort": "operate",
"operate": {
"identify": "lookup_order",
"description": "Lookup the standing of a buyer order",
"parameters": {
"sort": "object",
"properties": {
"order_id": {"sort": "string", "description": "The order ID"}
},
"required": ("order_id")
}
}
},
{
"sort": "operate",
"operate": {
"identify": "issue_refund",
"description": "Concern a refund for a buyer order",
"parameters": {
"sort": "object",
"properties": {
"order_id": {"sort": "string"},
"purpose": {"sort": "string"}
},
"required": ("order_id", "purpose")
}
}
}
)
response = shopper.chat.completions.create(
mannequin="gpt-4o-mini",
instruments=instruments,
messages=(
{"function": "person", "content material": "I need a refund for order #12345, it arrived damaged."}
)
)
tool_call = response.decisions(0).message.tool_calls(0)
print(tool_call.operate.identify) # "issue_refund"
print(tool_call.operate.arguments) # '{"order_id": "12345", "purpose": "arrived damaged"}'
Das API-Antwortobjekt sieht additionally etwa so aus:
ChatCompletionMessage(
content material=None,
function='assistant',
tool_calls=(
ChatCompletionMessageToolCall(
id='call_abc123',
sort='operate',
operate=Perform(
identify='issue_refund',
arguments='{"order_id": "12345", "purpose": "arrived damaged"}'
)
)
)
)
Und die print-Anweisungen würden hypothetisch Folgendes ausgeben:
issue_refund
{"order_id": "12345", "purpose": "arrived damaged"}
Additionally, was passiert hier? Das Modell gibt a zurück tool_calls Objekt anstelle einer regulären Textantwort (sehen Sie sich an, wiecontent material Ist None). Im Inneren tool_calls Objekt können wir sehen, dass sich das Modell für den Aufruf entschieden hat issue_refund (nicht lookup_order) und füllte die Argumente selbstständig basierend auf den Aussagen des Benutzers aus. Anschließend analysieren wir diese Argumente und führen die eigentliche Rückerstattungslogik in unserem System aus.
Beachten Sie, dass das Modell nicht nur die angeforderten Daten zurückgegeben hat, sondern vielmehr entschieden Welche der Kandidatenaktionen am besten geeignet ist, trägt dann die entsprechenden Argumente in die Antwort ein. Auf diese Weise können wir diese Argumente dann nutzen und tatsächlich die entsprechende Aktion in unserem System ausführen. Darin liegt die wahre Stärke des Funktionsaufrufs und deshalb ist er eine so grundlegende Komponente in Agenten-KI-Anwendungen.
Aber kommen wir jetzt zurück zu den maschinenlesbaren Ausgaben und werden in einem anderen Beitrag mehr über agentische KI-Workflows und Funktionsaufrufe sprechen.
3. Was ist mit strukturierten Ausgaben?
Eine strengere Variante des Funktionsaufrufs ist Strukturierte Ausgaben. Auch wenn der Funktionsaufruf das Modell dazu anleitet, eine Ausgabe nach einem definierten Schema bereitzustellen, ist dies nicht der Fall Wirklich stark eingeschränkt. In der Praxis bedeutet dies, dass es dennoch zu einigen Abweichungen von diesem definierten Schema kommen kann. Solche Abweichungen können sein:
- Ein als erforderlich markiertes Feld, das tatsächlich weggelassen wird, wenn das Modell Schwierigkeiten hat, seinen Wert herauszufinden
- Zusätzliche Felder, die in unserem Schema nicht definiert sind, werden hinzugefügt
- Ein Feld definiert als
integerkommt als String zurück"32"anstatt32
…und so weiter.
Dies liegt daran, dass beim Funktionsaufruf das Modell vorhanden ist versuchen dem Schema zu folgen, aber dies ist immer noch eine Finest-Effort-Era. Wie bei jeder LLM-Ausgabe besteht die Ausgabe hier immer noch im Wesentlichen aus Token, die einzeln vorhergesagt werden, wobei das Schema nur ein starker Hinweis ist. Es besteht immer noch eine gute Likelihood, dass diese Token-für-Token-Generierung irgendwo auf der Route entgleist und Ausgaben erzeugt, die vom definierten Schema abweichen.
Strukturierte Ausgaben hingegen gehen beim Funktionsaufruf noch einen Schritt weiter, indem sie garantieren, dass jedes Feld im definierten Schema immer genau wie definiert in der Ausgabe erscheint, ohne Überraschungen, ohne fehlende oder zusätzliche Felder. Das Hauptunterscheidungsmerkmal ist, dass OpenAI verwendet wird eingeschränkte Dekodierung hinter den Kulissen. Dies bedeutet, dass das Modell bei jedem Token-Schritt nur Token generieren darf, die die Ausgabe gemäß dem Schema gültig halten. Mit anderen Worten: Das Schema wird auf Generierungsebene erzwungen, anstatt nur über die Systemeingabeaufforderung angefordert zu werden.
Die strukturierten Ausgänge von OpenAI können durch einfache Einstellung aktiviert werden strict: true in der Funktionsdefinition:
instruments = (
{
"sort": "operate",
"operate": {
"identify": "extract_person_info",
"strict": True, # allows Structured Outputs
"parameters": {
"sort": "object",
"properties": {
"identify": {"sort": "string"},
"age": {"sort": "integer"},
"metropolis": {"sort": "string"}
},
"required": ("identify", "age", "metropolis"),
"additionalProperties": False
}
}
}
)
Aber auch dies hat seinen Preis. Strukturierte Ausgaben sind auf GPT-4o und späteren Modellen verfügbar, wobei ältere Modelle auf den JSON-Modus zurückgreifen. Nicht jede JSON-Struktur wird unterstütztund es kann etwas langsamer sein, da OpenAI die Ergebnisse vorverarbeitet.
Dennoch ist es die strengste und sicherste Methode, ein bestimmtes Schema für die Modellausgaben ohne Spielraum für Abweichungen durchzusetzen. Für Produktionssysteme, bei denen Zuverlässigkeit und Konsistenz wirklich wichtig sind, ist dies im Allgemeinen die sicherste Choice.
Aber ist das nicht alles dasselbe?
Der JSON-Modus, Funktionsaufrufe und strukturierte Ausgaben scheinen möglicherweise dasselbe zu bewirken, da sie alle im Wesentlichen JSON aus dem Modell zurückerhalten. Dennoch unterscheiden sie sich, wie wir bereits gesehen haben, deutlich darin, was sie garantieren und wofür sie konzipiert sind. Insbesondere:
- Durchsetzung des Schemas: Der JSON-Modus gibt ein gültiges JSON zurück, jedoch ohne strukturelle Garantien. Funktionsaufrufe geben einen gültigen JSON-Code zurück, der einem definierten Schema entspricht und bestimmten Feldnamen, Typen und erforderlichen Feldern folgt. Abweichungen sind jedoch weiterhin möglich. Structured Outputs geht noch einen Schritt weiter und erzwingt dieses Schema auf Generierungsebene, wodurch Abweichungen unmöglich werden.
- Anwendungsfall: Der JSON-Modus ist für Fälle gedacht, in denen wir eine maschinenlesbare Antwort benötigen, aber mit einem variablen Format leben können. Funktionsaufrufe wurden in erster Linie für Fälle entwickelt, in denen das Modell eine Aktion auslösen oder Argumente an ein externes Instrument übergeben muss. Dies ist im Wesentlichen der allgemeine Fall maschinenlesbarer Ausgaben. Strukturierte Ausgaben sind Funktionsaufrufe mit einer Zuverlässigkeitsgarantie und eignen sich daher splendid für Produktionspipelines, bei denen wir Konsistenz bei den Ausgaben benötigen.
- Einfache Einrichtung: Der JSON-Modus ist die einfachste einzurichtende Choice. nur eine einzelne Parameteränderung ohne Schemadefinition. Auf der anderen Seite müssen wir für Funktionsaufrufe und strukturierte Ausgaben auch über das JSON-Schema nachdenken und es einrichten.
Allerdings OpenAI selbst empfiehlt, wann immer möglich, immer strukturierte Ausgaben anstelle des JSON-Modus zu verwendenals allgemeine Faustregel.

In meinen Gedanken
Das Erhalten maschinenlesbarer Ausgaben von LLMs und die Wahl des geeigneten Ansatzes dafür kann einen großen Unterschied in der Zuverlässigkeit und Wartbarkeit jeder KI-Anwendung machen. Freitext-Antworten eignen sich hervorragend für Konversationsschnittstellen, aber sobald unser LLM eine Komponente in einem größeren System ist (z. B. Daten weiterleiten, Aktionen auslösen, Datenbanken füllen usw.), sind strukturierte Antworten unerlässlich. JSON-Modus, Funktionsaufrufe und strukturierte Ausgaben können solche Ausgaben bereitstellen, jeweils mit unterschiedlicher Strenge. Wie bei vielen Entscheidungen in der KI-Technik hängt die richtige Wahl davon ab, was Sie bauen und wie viel Variabilität Sie tolerieren können.
Wenn du es bis hierher geschafft hast, Vielleicht finden Sie Pialgorithmen nützlich – eine von uns entwickelte Plattform, die Groups dabei hilft, organisatorisches Wissen sicher an einem Ort zu verwalten.
Hat Ihnen dieser Beitrag gefallen? Begleiten Sie mich 💌Unterstapel und 💼LinkedIn
Alle Bilder vom Autor, sofern nicht anders angegeben.
