Erstaunlich viel von dem, was „Dokumenten-KI" heißt, ist schlicht ein Bild an ein Chat-Modell zu schicken und zu lesen, was es zurückgibt. Ein Beleg, ein Dashboard-Screenshot, eine gescannte PDF-Seite, das Foto eines Whiteboards — moderne Claude- und Gemini-Modelle lesen all das nativ, ganz ohne separate OCR-Engine. Der Haken ist meist die Verkabelung: Jeder Anbieter hat seine eigene Art, ein Bild anzuhängen, und Code von einem zum anderen zu portieren ist lästig.
Über Brievio nutzt du eine Request-Form — das content-Array der OpenAI Chat Completions mit einem image_url-Teil — und sie funktioniert identisch gegen Claude Opus 4.7, Sonnet 4.6, Haiku 4.5 sowie Gemini 2.5 Pro / Flash. Das sind die echten First-Party-Modelle mit nativer Vision-Unterstützung, also liest Claude dasselbe JPEG, das Claude gut lesen kann, auch wirklich selbst. Dieser Beitrag behandelt Bild-Input (Verständnis), nicht Bildgenerierung: URLs, base64, Multi-Image-Prompts und die OCR- / Chart- / Scan-Muster, die in echter Arbeit auftauchen.
Der einfachste Fall: ein Bild per URL
Wenn dein Bild bereits unter einer öffentlichen HTTPS-URL liegt, hänge es als image_url-Teil neben deinen Text. Tausche claude-sonnet-4-6 gegen gemini-2.5-pro, und der Request-Body ändert sich nicht — genau diese Portabilität ist der ganze Sinn:
# Ein Bild per URL senden. Gleiche OpenAI-Chat-Form, gegen das echte Modell.
from openai import OpenAI
client = OpenAI(
api_key="sk-brievio-...",
base_url="https://api.brievio.com/v1",
)
resp = client.chat.completions.create(
model="claude-sonnet-4-6", # oder gemini-2.5-pro — gleiche Request-Form
max_tokens=500,
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "What does this chart show? Give the trend in one sentence."},
{
"type": "image_url",
"image_url": {"url": "https://example.com/q3-revenue.png"},
},
],
}
],
)
print(resp.choices[0].message.content)
# Bilder werden als INPUT-Tokens abgerechnet — lies resp.usage.prompt_tokens für die Kosten.Eins solltest du früh verinnerlichen: Bilder kosten Input-Tokens. Ein Modell sieht Pixel nicht gratis — es kachelt das Bild, und jede Kachel rechnet wie Text ab. Brievio meldet ehrliche Token-Zahlen, also taucht der Bildpreis in resp.usage.prompt_tokens genau so auf, wie der vorgelagerte Anbieter ihn berechnet. Ein Vollbild-Screenshot kann je nach Auflösung ein paar Hundert bis ein paar Tausend Input-Tokens kosten. Plane dafür so wie für einen Absatz Kontext, nicht als Gratiszugabe.
Base64: der Fall, den du tatsächlich nutzt
In Produktion ist das Bild selten eine öffentliche URL — es ist eine Datei, die ein Nutzer gerade hochgeladen hat, ein Buffer aus einem Scanner, ein privates S3-Objekt. Für die inline die Bytes als base64-data:-URL. Das Modell merkt keinen Unterschied; deine Bytes müssen nie öffentlich erreichbar sein:
# Die meisten Produktiv-Bilder sind keine öffentlichen URLs. Inline sie als base64-Daten-URLs.
import base64
from openai import OpenAI
client = OpenAI(api_key="sk-brievio-...", base_url="https://api.brievio.com/v1")
def data_url(path: str, media_type: str = "image/png") -> str:
with open(path, "rb") as f:
b64 = base64.standard_b64encode(f.read()).decode("utf-8")
return f"data:{media_type};base64,{b64}"
resp = client.chat.completions.create(
model="gemini-2.5-flash", # günstig + schnell für OCR / Belege
max_tokens=800,
messages=[
{
"role": "user",
"content": [
{"type": "text", "text": "Extract every line item and total as JSON. Keys: items[], total."},
{"type": "image_url", "image_url": {"url": data_url("receipt.jpg", "image/jpeg")}},
],
}
],
)
print(resp.choices[0].message.content)
# Tipp: Daten-URLs blähen den Request-Body um ~33% gegenüber der Rohdatei auf. Halte Bilder
# angemessen klein — ein 2-3-MP-Screenshot reicht für Text völlig; 12 MP brauchst du selten.Zwei praktische Vorbehalte. Erstens fügt base64 deinem Request-Body rund 33% Overhead hinzu, und es gibt Größenlimits pro Bild (Anthropic deckelt einzelne Bilder über die API bei rund 5 MB; Gemini hat seine eigene Obergrenze). Wirft ein großer Scan einen 413, skaliere ihn herunter — Text bleibt bei weit niedrigerer Auflösung lesbar, als du vermuten würdest. Zweitens: Sende den korrekten media_type (image/png, image/jpeg, image/webp); ein nicht passender Typ ist eine häufige Ursache für ein stilles Decode-Fehlschlagen. Wenn ein Request mit einem 4xx oder 5xx auf Brievio doch fehlschlägt, wird er dir nicht berechnet — fehlgeschlagene Calls sind kostenlos, du kannst ein herunterskaliertes Bild also erneut senden, ohne doppelt zu zahlen.
Multi-Image-Prompts und gescannte Dokumente
Das content-Array nimmt so viele image_url-Teile, wie du willst, verschachtelt mit Text. Das schaltet die wirklich nützlichen Workflows frei: einen Vorher-/Nachher-Screenshot vergleichen, ein mehrseitig gescanntes Dokument lesen oder eine Reihe von Charts einspeisen und nach dem roten Faden fragen. Der Trick, der sich bei beiden Modellfamilien auszahlt: jedes Bild mit einem kleinen Text-Anker zu beschriften, damit das Modell es zitieren kann:
# Mehrere Bilder in einem Prompt — zwei Screenshots vergleichen oder einen 4-seitigen Scan lesen.
content = [
{"type": "text", "text": "These are pages 1-3 of a scanned contract. Summarize the parties, term, and termination clause. Cite the page number for each."},
]
for i, path in enumerate(["page1.png", "page2.png", "page3.png"], start=1):
content.append({"type": "text", "text": f"--- Page {i} ---"})
content.append({"type": "image_url", "image_url": {"url": data_url(path)}})
resp = client.chat.completions.create(
model="claude-opus-4-7", # stärkstes Reasoning über dichte Dokumente
max_tokens=1200,
messages=[{"role": "user", "content": content}],
)
print(resp.choices[0].message.content)
# Ein Text-Label vor jedem Bild ("--- Page 2 ---") gibt dem Modell einen Anker zum Zitieren
# und verbessert das Multi-Image-Grounding bei beiden Familien spürbar.Bei langen Dokumenten gibt es einen Trade-off bei der Modellwahl. Gemini 2.5 Flash ist günstig und schnell und ein hervorragender Standard für OCR, Belege und Formularextraktion in hoher Stückzahl. Claude Opus 4.7 denkt härter über dichtes, mehrseitiges Material nach — Verträge, Finanzberichte, alles, wo es mehrere Seiten im Blick halten und querverweisen muss. Sonnet 4.6 und Gemini 2.5 Pro liegen dazwischen. Du kannst pro Aufgabe routen, ohne irgendeinen Code außer dem model-String zu ändern; die Live-Liste findest du unter /models.
Worin diese Modelle gut sind (und worin nicht)
Native Vision bewältigt eine breite Palette echter Aufgaben gut:
- OCR und Transkription — gedruckter Text und überraschend ordentliche Handschrift. Keine Tesseract-Pipeline zu pflegen.
- Charts und Dashboards — Werte von Balken-/Linien-Charts ablesen, einen Trend zusammenfassen, eine Kennzahl in einem Screenshot plausibilisieren.
- Strukturierte Extraktion — Belege, Rechnungen, Formulare, Ausweise nach JSON. Kombiniere das mit einem strikten Schema in deinem Prompt für sauberen Output.
- UI- und Diagramm-Verständnis — einen Screen beschreiben, einen Fehlerdialog lesen, ein Architekturdiagramm erklären.
Und ein paar ehrliche Grenzen. Modelle verlesen sich gelegentlich noch bei einer einzelnen Ziffer oder einer dichten Tabellenzelle; bei allem, wo eine falsche Zahl teuer wird, validiere also gegen ein Schema oder eine Prüfsumme (z. B. sollten sich Posten zur ausgewiesenen Summe addieren). Winziger Text in einem niedrig aufgelösten Bild ist der häufigste Fehler — gib ihm einen höher aufgelösten Ausschnitt. Und das Verhalten unterscheidet sich pro Modell tatsächlich: ein Layout, das ein Modell trifft, kann ein anderes ins Stolpern bringen — genau deshalb ist die Fähigkeit, Modelle hinter einer API zu tauschen und sie auf deinen eigenen Dokumenten gegeneinander zu testen, mehr wert als jeder einzelne Benchmark.
Noch weiter: Vision plus Tools
Vision lässt sich mit dem Rest der API kombinieren. Du kannst dem Modell ein Bild und einen Satz Tools übergeben, sodass es einen Screenshot liest und dann eine Funktion mit dem Extrahierten aufruft — „lies diese Rechnung, dann ruf create_expense(amount, vendor, date) auf". Diese Tool-Call-Ebene ist über Brievio ebenfalls einheitlich über Claude und Gemini; der Tool-Use-Guide behandelt die gemeinsame Form. Kombiniert mit Vision ist das fast die ganze Dokumentenverarbeitungs-Pipeline in einem einzigen Request.
Das Fazit
Für Bildverständnis brauchst du keinen separaten OCR-Service und keine anbieterspezifischen SDKs. Hänge einen image_url-Teil — URL oder base64-Daten-URL — an deinen normalen Chat-Request, beschrifte mehrere Bilder, damit das Modell sie zitieren kann, und route zu dem Modell, das zur Aufgabe passt: Gemini Flash für günstige Reads in hoher Stückzahl, Claude Opus für schwere Dokumente. Denk daran, dass Bilder als Input-Tokens abrechnen (ehrlich ausgewiesen in usage), halte die Auflösung vernünftig, validiere extrahierte Zahlen und verlass dich auf kostenlose Retries bei fehlgeschlagenen Calls, wenn ein großer Scan abprallt. Die vollständige Request-Referenz und die Limits pro Modell stehen in den Docs — fang dort an, und du hast Dokumente in einem Nachmittag durch Claude oder Gemini fließen.