Antwort und Nutzung
Auf dieser Seite
Verstehen, was die API zurückgibt
Die meisten Entwickler, die neu bei der API sind, lesen nur eine einzige Zeile der Antwort – den generierten Text – und ignorieren alles andere. Das ist ein Fehler. Jeder Aufruf von /v1/chat/completions gibt ein reichhaltiges JSON-Objekt zurück. Hier finden Sie die Daten, die Sie benötigen, um Kosten zu verfolgen, eine abgeschnittene Antwort zu erkennen, bevor sie den Nutzer erreicht, und einen bestimmten Aufruf zu lokalisieren, wenn Sie einen Support-Ticket eröffnen.
Vollständige Anatomie der Antwort
Beginnen wir mit den Metadaten. Dies sind die Felder, die Sie selten überprüfen, aber am Tag eines Vorfalls dankbar sein werden, sie protokolliert zu haben:
from mistralai.client import Mistral
import os
client = Mistral(api_key=os.getenv("MISTRAL_API_KEY"))
response = client.chat.complete(
model="mistral-large-latest",
messages=[{"role": "user", "content": "Was ist maschinelles Lernen?"}],
max_tokens=500
)
# Zugriff auf Metadaten
print(f"Request ID : {response.id}")
print(f"Modell verwendet : {response.model}")
print(f"Erstellt am : {response.created}")
Das Feld id ist eine eindeutige Kennzeichnung, die jedem Aufruf zugewiesen wird. Dies ist der Verweis, den Sie dem technischen Support geben, und derjenige, der es ermöglicht, eine Beschwerde eines Nutzers mit einem spezifischen Aufruf in Ihren Protokollen zu verknüpfen. Das Feld model bestätigt, welches Modell tatsächlich verwendet wurde. Dies ist wichtiger, als Sie vielleicht denken, wenn Sie einen -latest-Alias aufrufen und sich das Verhalten über Nacht ändert, ohne dass sich Ihr Code ändert.
Das Array choices
Das Herzstück der Antwort liegt in choices. Standardmäßig enthält dieses Array ein einziges Element. Daraus extrahieren Sie sowohl den Text als auch das Urteil darüber, wie die Generierung beendet wurde:
choice = response.choices[0]
# Die generierte Nachricht
print(choice.message.role) # "assistant"
print(choice.message.content) # Der Antworttext
# Der Index dieser Antwort im Array
print(choice.index) # 0
# Der Beendigungsgrund
print(choice.finish_reason) # "stop", "length" oder "tool_calls"
Wenn Sie mehrere Antworten mit dem Parameter n anfordern, den wir in Lektion 15 behandeln werden, enthält choices mehrere Elemente, und der Index wird wieder bedeutsam.
Werte für finish_reason
Dieses Feld bestimmt die Zuverlässigkeit Ihrer Anwendung. Es gibt drei mögliche Werte. stop signalisiert, dass das Modell seine Antwort natürlich beendet hat. Dies ist der Normalfall, bei dem Sie den Inhalt uneingeschränkt anzeigen können. length bedeutet, dass die Generierung durch max_tokens abgeschnitten wurde, sodass die Antwort potenziell unvollständig ist – eine Zusammenfassung, die ihren Schluss verpasst, oder eine Liste, die beim siebten Element abbricht. Schließlich zeigt tool_calls an, dass das Modell die Ausführung eines externen Tools als Teil des Funktionsaufrufs anfordert, und nun liegt die Verantwortung bei Ihnen.
Jeder dieser Fälle erfordert eine spezifische Behandlung, die Sie einmal und für alle Zeiten schreiben sollten:
response = client.chat.complete(
model="mistral-large-latest",
messages=[{"role": "user", "content": "Schreiben Sie einen detaillierten Bericht."}],
max_tokens=200
)
choice = response.choices[0]
if choice.finish_reason == "stop":
# Vollständige Antwort – normale Verarbeitung
result = choice.message.content
elif choice.finish_reason == "length":
# Abgeschnittene Antwort – erneut versuchen mit mehr Tokens oder den Nutzer warnen
print("Warnung: Die Antwort wurde abgeschnitten.")
# Option: Erneut versuchen mit einem höheren max_tokens-Limit
# Option: Das Modell bitten, fortzufahren
elif choice.finish_reason == "tool_calls":
# Das Modell fordert einen Tool-Aufruf an
for tool_call in choice.message.tool_calls:
print(f"Angefordertes Tool: {tool_call.function.name}")
Beachten Sie, dass der Zweig für length den Text nicht einfach durchlässt. Sie müssen entweder erneut versuchen, mit einem höheren Limit, das Modell bitten, fortzufahren, oder den Nutzer warnen. Was Sie niemals tun dürfen, ist abgeschnittenen Text so anzuzeigen, als wäre er vollständig.
Das Objekt usage – Verfolgen Sie Ihre Kosten
Das Feld usage zählt die vom Aufruf verbrauchten Tokens und trennt Eingabe von Ausgabe:
usage = response.usage
print(f"Eingabetokens : {usage.prompt_tokens}")
print(f"Ausgabetokens : {usage.completion_tokens}")
print(f"Insgesamt : {usage.total_tokens}")
Dieser Unterschied ist nicht kosmetisch. Mistral-Modelle haben unterschiedliche Sätze für Eingabe und Ausgabe. Eine Funktion, die einen langen Kontext sendet, um drei Wörter zurückzuerhalten, hat ein völlig anderes Kostenprofil als ein langer Entwurf, der aus einer kurzen Aufforderung generiert wird. Die Berechnung dauert nur wenige Zeilen:
# Hypothetische Sätze pro Million Tokens (aktuelle Preise prüfen)
RATE_INPUT = 2.0 # $/M Tokens Eingabe
RATE_OUTPUT = 6.0 # $/M Tokens Ausgabe
cost_input = (usage.prompt_tokens / 1_000_000) * RATE_INPUT
cost_output = (usage.completion_tokens / 1_000_000) * RATE_OUTPUT
cost_total = cost_input + cost_output
print(f"Kosten dieses Aufrufs: ${cost_total:.6f}")
Ein einzelner Aufruf kostet Bruchteile eines Zent, was fälschlicherweise beruhigend wirkt. Multiplizieren Sie dies mit dem tatsächlichen Verkehr einer Anwendung, und die Frage lautet: Welche Funktion verbraucht was? Um dies zu beantworten, aggregieren Sie Nutzungsdaten ab Ihrer allerersten Bereitstellung. Protokollieren Sie jeden Aufruf zusammen mit dem Namen der Funktion, die ihn ausgelöst hat:
import json
from datetime import datetime
def log_usage(response, endpoint_name: str):
"""Protokolliert Nutzungsdaten für jeden API-Aufruf."""
log_entry = {
"timestamp": datetime.utcnow().isoformat(),
"endpoint": endpoint_name,
"model": response.model,
"prompt_tokens": response.usage.prompt_tokens,
"completion_tokens": response.usage.completion_tokens,
"total_tokens": response.usage.total_tokens,
"finish_reason": response.choices[0].finish_reason,
"request_id": response.id
}
with open("api_usage.jsonl", "a") as f:
f.write(json.dumps(log_entry) + "\n")
# Nutzung
response = client.chat.complete(
model="mistral-large-latest",
messages=[{"role": "user", "content": "Hallo"}]
)
log_usage(response, "main_chatbot")
Eine JSONL-Datei wie diese, die nach zwei Wochen überprüft wird, wird Ihnen ohne Ambiguität sagen, welches Bildschirm in Ihrem Produkt am schwersten auf die Rechnung wiegt – und wie viele Aufrufe mit length enden.
Antwortinhalt
Das Feld content der Nachricht des Assistenten kann zwei Formen annehmen, genau wie auf der Anforderungsseite:
# Einfache Form – String
content = response.choices[0].message.content
# "Maschinelles Lernen ist ein Zweig der künstlichen Intelligenz..."
# Strukturierte Form – Liste von Blöcken (selten in Standard-Chat)
# [{"type": "text", "text": "..."}]
In der Praxis ist content bei Standard-Aufrufen für Chat Completions immer ein String. Die strukturierte Form ist für multimodale Antworten vorbehalten.
In die Praxis umsetzen
Bringen wir dies alles in einer Hilfsfunktion zusammen – derjenigen, die Sie von Projekt zu Projekt kopieren werden. Sie montiert die Nachrichten, führt den Aufruf durch und gibt ein Dictionary zurück, das sowohl Metriken als auch Text offenlegt:
from mistralai.client import Mistral
def chat_complete(
client: Mistral,
prompt: str,
system: str = "",
model: str = "mistral-large-latest",
max_tokens: int = 1000
) -> dict:
"""Chat Completions-Aufruf mit Fehlerbehandlung und Metriken."""
messages = []
if system:
messages.append({"role": "system", "content": system})
messages.append({"role": "user", "content": prompt})
response = client.chat.complete(
model=model,
messages=messages,
max_tokens=max_tokens
)
return {
"content": response.choices[0].message.content,
"finish_reason": response.choices[0].finish_reason,
"tokens_in": response.usage.prompt_tokens,
"tokens_out": response.usage.completion_tokens,
"model": response.model,
"id": response.id
}
Der entscheidende Punkt ist, was die Funktion zurückgibt: niemals nur den Text. Indem Sie finish_reason, Token-Zahlen und die Anforderungs-ID an den Aufrufer weitergeben, machen Sie den häufigsten Fehler unmöglich – eine abgeschnittene Antwort als gültige zu behandeln.
Kernaussagen
- Die Antwort enthält
choices(Inhalt),usage(Tokens) und Metadaten (id,model) - Immer
finish_reasonüberprüfen –lengthbedeutet eine unvollständige Antwort usagezählt Eingabe- und Ausgabetokens separat für eine präzise Kostenverfolgung- Richten Sie Metrik-Protokollierung ab Ihrer allerersten Produktionsbereitigung ein
- Das Feld
idist für die Fehlerbehebung und den technischen Support unerlässlich