Blog
Durchsetzung und Validierung der LLM-Ausgabe mit Pydantic

Einführung
Große Sprachmodelle (Large Language Models, LLMs) sind hervorragend in der Generierung von Text, haben aber oft Schwierigkeiten, strukturierte Ausgaben zu erzeugen. Durch den Einsatz der Typvalidierung und des Prompt-Engineering von Pydantic können wir die von LLMs erzeugte Ausgabe erzwingen und validieren.
Alle Codebeispiele in diesem Blogbeitrag sind in Python geschrieben. Der verwendete LLM ist der gpt-3.5-Turbo von OpenAI.
Abfrage des LLM
Um den LLM abzufragen, verwenden wir die folgende Funktion:
import openai
def query(prompt: str) -> str:
"""Query the LLM with the given prompt."""
completion = openai.ChatCompletion.create(
model="gpt-3.5-turbo",
messages=[
{
"role": "user",
"content": prompt,
}
],
temperature=0.0,
)
return completion.choices[0].message.content
Wir rufen die Funktion dann mit einer einfachen Frage auf:
response = query("What is the largest planet in our solar system?")
print(response)
'The largest planet in our solar system is Jupiter.'
JSON-Ausgabe mit einer Eingabeaufforderung erzwingen
In unserer Eingabeaufforderung können wir den LLM auffordern, in einem bestimmten Format zu antworten:
prompt = """
I will ask you questions and you will respond. Your response should be in the following format:
```json
{
"thought": "How you think about the question",
"answer": "The answer to the question"
}
```
"""
Dann fragen wir das Modell ab:
question = "What is the largest planet in our solar system?"
response = query(prompt + question)
print(response)
'{
"thought": "This is a factual question that can be answered with scientific knowledge.",
"answer": "The largest planet in our solar system is Jupiter."
}'
Das ist großartig, denn so können wir die strukturierte Ausgabe leicht parsen:
import json
parsed_response = json.loads(response)
print(parsed_response["answer"])
'The largest planet in our solar system is Jupiter.'
Validierung der Ausgabe
from pydantic import BaseModel
class ThoughtAnswerResponse(BaseModel):
thought: str
answer: str
raw_response = query(prompt)
# Note: When you are using pydantic<2.0, use parse_raw instead of model_validate_json
validated_response = ThoughtAnswerResponse.model_validate_json(raw_response)
print(validated_response)
thought='This is a factual question that can be answered with scientific knowledge.' answer='The largest planet in our solar system is Jupiter.'
print(type(validated_response))
<class 'ThoughtAnswerResponse'>
Verwendung des pydantischen Modells in der Eingabeaufforderung
Im Moment beschreiben wir unser Antwortformat an zwei Stellen:
- eine JSON-Beschreibung in unserer Eingabeaufforderung
- ein entsprechendes pydantisches Modell
Wenn wir das Antwortformat aktualisieren möchten, müssen wir sowohl die Eingabeaufforderung als auch das Pydantic-Modell ändern. Dies kann zu Inkonsistenzen führen.
Wir können dieses Problem lösen, indem wir das Pydantic-Modell in ein JSON-Schema exportieren und das Schema zur Eingabeaufforderung hinzufügen. Dadurch werden die Antwort und das Pydantic-Modell konsistent.
response_schema_dict = ThoughtAnswerResponse.model_json_schema()
response_schema_json = json.dumps(response_schema_dict, indent=2)
prompt = f"""
I will ask you questions, and you will respond.
Your response should be in the following format:
```json
{response_schema_json}
```
"""
Die Eingabeaufforderung sieht nun wie folgt aus:
I will ask you questions, and you will respond. Your response should be in the following format:
```json
{
"properties": {
"thought": { "title": "Thought", "type": "string" },
"answer": { "title": "Answer", "type": "string" }
},
"required": ["thought", "answer"],
"title": "ThoughtAnswerResponse",
"type": "object"
}
Die Antwort sieht dann so aus:
{
"thought": "The largest planet in our solar system is Jupiter.",
"answer": "Jupiter"
}
Wenn Sie nun das Pydantic-Modell ändern, wird das entsprechende Schema in der Eingabeaufforderung angezeigt. Beachten Sie, dass das Schema komplexer geworden ist als zuvor. Ein Vorteil ist, dass wir nun genauer festlegen können, welche Antworten wir benötigen.
Fehlerbehandlung
Der LLM kann immer noch Ergebnisse liefern, die nicht mit unserem Modell übereinstimmen. Wir können etwas Code hinzufügen, um dies abzufangen:
from pydantic import ValidationError
try:
validated_response = ThoughtAnswerResponse.model_validate_json(raw_response)
except ValidationError as e:
print("Unable to validate LLM response.")
# Add your own error handling here
raise e
Bestimmte Werte mit Hilfe eines Literal erzwingen
Manchmal möchten Sie die Verwendung von bestimmten Werten für ein bestimmtes Feld erzwingen. Wir fügen das Feld "difficulty" zu unserem Antwortobjekt hinzu. Der LLM sollte es verwenden, um Informationen über den Schwierigkeitsgrad der Frage bereitzustellen. Bei einer normalen Eingabeaufforderung würden wir wie folgt vorgehen:
prompt = """Your response should be in the following format:
```json
{
"thought": "How you think about the question",
"answer": "The answer to the question",
"difficulty": "How difficult the question was. One of easy, medium or hard"
}
```
"""
Natürlich könnte das Modell auch andere Werte verwenden. Um sie zu validieren, müssten wir eigenen Code schreiben.
Mit Pydantic ist das sehr viel einfacher. Wir erstellen einen neuen Typ namens Difficulty unter Verwendung eines Literal. Mit einem Literal können wir die Verwendung einer Auswahlliste von Werten festlegen. Wir fügen dem Feld difficulty in unserem Pydantic-Modell einen Hinweis auf den Typ Difficulty hinzu:
from typing import Literal
from pydantic import BaseModel
# We create a new type
Difficulty = Literal["easy", "medium", "hard"]
class ThoughtAnswerResponse(BaseModel):
thought: str
answer: str
difficulty: Difficulty
Der LLM antwortet möglicherweise mit einem Wert, den wir nicht zulassen:
{
"thought": "The largest planet in our solar system is Jupiter.",
"answer": "Jupiter",
"difficulty": "Unknown"
}
Wenn wir dieses Ergebnis parsen, überprüft Pydantic die Werte für das Feld difficulty. Unknown stimmt nicht mit einem der Werte überein, die in dem von uns definierten Literal-Typ angegeben sind. Daher erhalten wir die folgende Fehlermeldung:
validated_response = ThoughtAnswerResponse.model_validate_json(response)
ValidationError: 1 validation error for ThoughtAnswerResponse
difficulty
Input should be 'easy', 'medium' or 'hard' [type=literal_error, input_value='Unknown', input_type=str]
Fazit
Durch den Einsatz von Pydantic und Prompt Engineering können Sie die Ausgabe von LLMs erzwingen und validieren. Dadurch erhalten Sie eine bessere Kontrolle über die LLM-Ausgabe und können robustere KI-Systeme entwickeln.
Foto von Andrew Ridley auf Unsplash
Verfasst von
Timo Uelen
Timo Uelen is a Machine Learning Engineer at Xebia.
Unsere Ideen
Weitere Blogs
Contact



