Skip to main content
Ein Dokument zu lesen ist einfach. Aus jedem Dokument dieselben Felder herauszubekommen, in einer Form, auf die sich dein Code verlassen kann, ist die eigentliche Arbeit. Es gibt zwei Wege von einer Datei zu einem Datensatz. Du kannst den Text extrahieren und einem Modell übergeben, oder du kannst die Seite einem Modell zeigen, das sehen kann. Welcher Weg der richtige ist, hängt davon ab, wie die Datei erzeugt wurde, und ein PDF sagt dir beim Ansehen nicht, welche Art es ist. Dieses Tutorial baut beide und lässt die API zwischen ihnen entscheiden:
Dabei werden wir:
  1. Den Text aus einem PDF mit /augment/text-parser herausziehen
  2. Den gewünschten Datensatz als JSON-Schema beschreiben
  3. Ihn extrahieren, wobei das Schema erzwungen und nicht nur angefragt wird
  4. Mit der Datei umgehen, die gar keinen Text enthält
  5. Vergleichen, was die beiden Wege aus derselben Seite produzieren

Setup

Du brauchst Python 3.9 oder neuer, das requests-Paket und einen Venice-API-Schlüssel. Siehe API-Schlüssel erzeugen, falls du noch keinen hast.
Wir verwenden ein öffentliches Paper als Beispieldokument, damit du mit derselben Datei mitmachen kannst:
Erstelle extract.py:
Beachte, dass AUTH und JSON_HEADERS getrennt sind. Der Parser nimmt einen Multipart-Upload entgegen, und wenn du Content-Type bei einer Multipart-Anfrage selbst setzt, hindert das requests daran, den Boundary hinzuzufügen, was auf eine lästig zu diagnostizierende Weise fehlschlägt.

1. Den Text herausbekommen

/augment/text-parser nimmt eine PDF-, DOCX-, XLSX- oder reine Textdatei von bis zu 25 MB entgegen und gibt den Text zusammen mit einer Token-Zahl zurück. Dokumente werden im Speicher verarbeitet, und der Inhalt wird nicht aufbewahrt.
Der tokens-Wert ist der nützliche Teil dieser Antwort. Er sagt dir, was dich das Dokument in der nächsten Anfrage kosten wird, bevor du sie stellst, was wichtig ist, weil ein langes PDF leicht über das hinauswachsen kann, was du ausgeben wolltest.

2. Den gewünschten Datensatz beschreiben

Ein Modell nach JSON zu fragen bringt dir JSON, das ungefähr so geformt ist, wie du gefragt hast. Ein Schema zu übergeben bringt dir JSON, das passt, denn das Schema schränkt die Generierung ein, statt sie nur zu empfehlen.
additionalProperties: False lohnt sich auf jeder Ebene. Ohne das kann ein Modell, das etwas Interessantes findet, einen Schlüssel hinzufügen, den du nie eingeplant hast, und der Code, der das Ergebnis liest, wird ihn nicht erwarten.

3. Extrahieren

Ein Aufruf, wobei response_format das Schema trägt und strict eingeschaltet ist:
Jede Extraktion in diesem Tutorial läuft durch einen kleinen Reader, weil die zwei Arten, wie dieser Aufruf fehlschlagen kann, beide als HTTP 200 ankommen:
Sieh dir den letzten Autor an. Das Paper nennt keine Affiliation für Illia Polosukhin, und das Schema sagt, affiliation sei erforderlich, also hat das Modell einen leeren String zurückgegeben, statt das Feld wegzulassen. Genau das tut das Schema, was du ihm gesagt hast.
Ein leerer String und ein fehlender Wert sind unterschiedliche Fakten, und required wirft sie in einen Topf. Wenn du „das Dokument sagt es nicht” von „das Dokument sagt hier nichts” unterscheiden musst, typisiere das Feld als {"type": ["string", "null"]} und bitte im System-Prompt um null. Der Strict-Modus akzeptiert die Union, und du bekommst null statt "".

Das Denken abschalten

disable_thinking ist die Zeile in dieser Anfrage, über die es sich zu streiten lohnt, hier also das Argument. Das Standard-Textmodell reasoniert, bevor es antwortet, und Reasoning wird aus demselben Completion-Budget gezogen wie das JSON. Führ dieselbe Extraktion viermal aus und beobachte, was das Modell ausgibt: Das Budget zu erhöhen behebt das erste Problem nicht, es hebt nur die Decke an, gegen die das Modell stoßen darf. Der Lauf, der 4003 Tokens ausgegeben hat, kam mit finish_reason length und einem leeren String zurück. Das Denken abzuschalten hat diese Extraktion fünfmal günstiger gemacht und, was nützlicher ist, jedes Mal gleich. Das Schema erledigt schon die Arbeit, die das Reasoning täte, nämlich zu entscheiden, welche Form die Antwort annimmt.
Wenn das Budget doch ausgeht, hat das Modell meist schon etwas JSON geschrieben, du bekommst also ein abgeschnittenes Objekt statt eines Fehlers. json.loads scheitert dann irgendwo in der Mitte an einem unbeendeten String, was wie ein Parsing-Bug aussieht und keiner ist. read_record prüft finish_reason zuerst, sodass die Nachricht sagt, was wirklich passiert ist.

4. Wenn es keinen Text zu holen gibt

Ein PDF, das von einem Scanner erzeugt wurde, enthält Bilder von Seiten, keinen Text. Nichts am Dateinamen sagt das, und nichts an der Dateigröße verrät es. Du musst es nicht selbst erkennen, denn der Parser tut das:
Das kommt als HTTP 400 an, und es ist ein Routing-Signal, kein Fehlschlag. Der Textweg ist für diese Datei nicht verfügbar, nimm also den anderen: Rendere die Seite und lass ein Modell hinschauen.
Jetzt lassen sich die beiden Wege zusammenschalten, wobei der Fehler des Parsers selbst zwischen ihnen entscheidet:
Der Fallback liest eine Seite. Das ist für ein Formular, eine Rechnung oder eine Titelseite in Ordnung und für alles Längere falsch, weil der Rest des Dokuments stillschweigend nicht existiert. Rendere jede Seite und schick sie als mehrere Bilder, wenn die Antwort vielleicht nicht auf Seite eins steht.

5. Worin die beiden Wege sich uneinig sind

Führ beide gegen dieselbe erste Seite aus und die Datensätze kommen fast identisch zurück. „Fast” ist der interessante Teil: Der Textweg hat das Ł erhalten. Der Vision-Weg hat ein ASCII-L zurückgegeben, weil er Buchstabenformen liest statt Zeichencodes, und ein diakritisches Zeichen ist ein kleines visuelles Detail, das schlecht überlebt. Wenn du extrahierte Namen gegen eine Datenbank abgleichst, entscheidet dieser Unterschied, ob die Zeile gefunden wird. Der achte Autor ist wichtiger. Die Seite gibt keine Affiliation für Illia Polosukhin an, und der Textweg berichtet das jedes Mal getreu als leeren String. Der Vision-Weg hat in manchen Läufen das Feld mit einem plausiblen Nachbarn von derselben Seite gefüllt. Pixel zu lesen lässt mehr Raum zum Ableiten als Zeichen zu lesen, und ein erforderliches Feld ist eine Einladung, es zu füllen. Wenn du die Ausgabe nicht von Hand prüfen kannst, ist das ein Grund, den geparsten Text zu bevorzugen, wo immer das Dokument ihn anbietet. Die Kosten liegen näher beieinander, als es aussieht. Mit ausgeschaltetem Denken auf beiden Seiten liefen die beiden Wege auf dieser Seite mit etwa gleicher Prompt-Größe: Das Bild hatte 923.732 Zeichen Base64, und für nichts davon zahlst du. Bilder werden nach Größe tokenisiert, nicht nach der Länge ihrer Kodierung, sodass ein großes PNG nicht das kostet, wonach es aussieht. Bevorzuge geparsten Text, wenn das Dokument Text hat. Er behält die exakten Zeichen, es kostet nichts extra, über Seite eins hinauszureichen, und es ist ihm egal, wie die Seite gelayoutet wurde. Greif zu Vision, wenn der Parser sagt, es gebe nichts zu lesen, oder wenn die Bedeutung im Layout steckt, wie in einem Diagramm, einem Stempel oder einer Unterschrift.

Etwas anderes extrahieren

Nichts oben ist paperspezifisch. Tausch das Schema und den System-Prompt, und die Pipeline extrahiert Rechnungen:
Die description-Felder leisten echte Arbeit. Ein Datum ist erst dann eindeutig, wenn du gesagt hast, welches Format du willst, und 03/04/2026 bedeutet zwei verschiedene Tage, je nachdem, wer es geschrieben hat.

Nächste Schritte

  • Validiere das Ergebnis mit pydantic oder jsonschema gegen das Schema, damit ein fehlerhafter Datensatz an der Grenze scheitert und nicht drei Funktionen später.
  • Speichere den extrahierten Text mit Embeddings, um über Dokumente hinweg zu suchen, statt sie neu zu extrahieren.
  • Häng Dokumente direkt an eine Chat-Completion mit File Inputs an, wenn du Antworten statt Datensätzen möchtest.
  • Gib den Extraktor einem Agenten als Werkzeug mit Einen tool-nutzenden Agenten mit Function Calling bauen.

Document Processing

Referenz für den text-parser-Endpunkt.

Strukturierte Antworten

Wie json_schema eine Completion einschränkt.

Vision

Bilder an ein Chat-Modell senden.

File Inputs

Ein Dokument anhängen, ohne es selbst zu parsen.