Rechnungen mit Strom analysieren
Ein schneller und günstiger Weg, strukturierte Daten aus Rechnungs-PDFs zu extrahieren.
Einige unserer Nutzer setzen Strom ein, um ihre Dokumente besser zu verstehen:
- E-Mails und PDFs in Kategorien einordnen (z. B. ist diese E-Mail eine Kündigung eines Abos?)
- Bestimmte Daten in Dokumenten und Bildern extrahieren und prüfen (z. B. wurde der richtige Mehrwertsteuersatz angewendet?)
Weil dieses Problem so häufig vorkommt, haben wir eine Pipeline gebaut, die Daten aus Rechnungen extrahiert. Ihr könnt sie hier ausprobieren.
Der Rest dieses Beitrags erklärt, wie der Extraktor im Inneren funktioniert, und zeigt, wie man Strom effektiv für die Verarbeitung großer Datenmengen einsetzt.
TL;DR
So sieht der Ablauf von Anfang bis Ende aus:
- Der Nutzer lädt Rechnungs-PDF(s) hoch
- Text aus dem PDF extrahieren (nicht digitale PDFs brauchen zusätzlich OCR)
- PDF-Seiten in Bilder umwandeln
- Bilder und extrahierten PDF-Text an Strom senden
- Antwort bereinigen und logisch prüfen
Wo Strom ins Spiel kommt
Der interessante Schritt oben ist die Anfrage an Strom. Die Grundidee ist diese:
"Hey Strom, dieses PDF hat 200 Zeilen. Welche davon ist das Fälligkeitsdatum der Rechnung?"
Da Entscheidungsmodelle keinen Text generieren können, formulieren wir die Aufgabe also als eine Reihe von Multiple-Choice-Fragen.
So sieht eine Beispielanfrage an Strom aus:
POST https://api.uprelic.com/v1/systemone
{
"model": "strom-1.0.7",
"state": "The lines below are every text line of an invoice PDF....
L1 (page 1, x=393, y=108): INVOICE
L2 (page 1, x=85, y=138): Tobacco Merchants Association, Inc.
...
L44 (page 1, x=83, y=728): All payments to TMA are due in U.S. Dollars
",
"questions": {
"supplier": {
"type": "choice",
"criteria": {"L1": null, "L2": null, "…": null, "L45": null, "none": "No line contains it"},
"instructions": "Which line contains the name of the supplier, the company that issued the invoice?"
},
"due_date": { "…": "Which line contains the payment due date?" },
"gross_total": { "…": "Which line contains the total amount including VAT?" }
...
},
"media": [
{"type": "image", "url": "data:image/png;base64,iVBORw0KGgo…"}
]
}
Was an der Anfrage auffällt:
- Die Anfrage enthält sowohl die Seitenbilder (in
media) als auch den PDF-Text (instate). Man könnte argumentieren, dass Bilder und Text dieselben Daten doppelt enthalten, aber wir haben festgestellt, dass beides zusammen Vorteile bringt:- Bild: Zeigt Strom, wo der Text optisch steht. Ohne Bild hat ein Text wie "200€" zum Beispiel keine Bedeutung. Steht er aber unten unter einer Tabelle mit den Rechnungspositionen, ist das ein starker Hinweis darauf, dass es der Bruttobetrag der Rechnung ist. Unten seht ihr ein Beispielbild, das wir Strom zeigen.
- Text: Eigentlich sollte das Bild reichen, damit Strom uns sagt, dass z. B. Zeile 5 der Bruttobetrag ist. Bilder können aber eine niedrige Auflösung haben, und Text und Beschriftungen im Bild können sich überlappen.
- Jedes Rechnungsfeld wird zu einer Frage. Wir stellen 12 solcher Fragen, dazu eine für die Währung der Rechnung. Jede Frage ist vom Typ "Choice", und jede Zeile des PDFs ist eine Option, aus der Strom wählen kann. Außerdem hat jede Frage die Option "none", falls das Feld in der Rechnung gar nicht vorkommt. Die USt-IdNr. kann im PDF zum Beispiel fehlen, und Strom braucht eine Möglichkeit, das auszudrücken.
So sieht die Antwort aus:
{
"model": "strom-1.0.7",
"answers": {
"supplier": {
"type": "choice",
"choice": "L2",
"confidence": 0.9677762475508005,
"probabilities": {
"L1": 0.004401314928251427,
"L2": 0.9785174983672003,
...
"L45": 9.183572895225142e-05,
"none": 0.0011083225443333591
}
},
"invoice_number": {
"type": "choice",
"choice": "L7",
...
}
},
"usage": ...
"metadata": ...
}
Stärken dieses Ansatzes
Keine Halluzinationen: Strom wählt die Zeile, die seiner Einschätzung nach das Fälligkeitsdatum enthält. Es kann also keine Werte erfinden, was bei klassischen LLMs ein großes Problem ist.
Geschwindigkeit: Eine typische Rechnung mit 2 Seiten dauert für den gesamten Ablauf etwa 500 ms, ohne Netzwerklatenz.
Kosten: Eine typische Rechnung kostet etwa 0,00049 $. Für 1 $ lassen sich also rund 2.000 Rechnungen verarbeiten.
Konfidenzwerte: Jedes Feld kommt mit einem Konfidenzwert. So lassen sich Rechnungen herausfiltern, die mehr Aufmerksamkeit brauchen: eine manuelle Prüfung oder die Weitergabe an ein intelligenteres, aber teureres LLM.
Schwächen
Intelligenz: Strom ist ein Entscheidungsmodell und denkt nicht nach wie die meisten großen LLMs. Es macht daher mehr Fehler bei der Auswahl der Felder, vor allem bei Rechnungen, die stark vom üblichen Aufbau abweichen.
Kann keinen Text generieren: Entscheidungsmodelle können konstruktionsbedingt keinen Text generieren. Sie können das Fälligkeitsdatum zum Beispiel nicht aus der Zeile "Fällig in 30 Tagen" ableiten, ein LLM dagegen schon.
Fazit
Das kommt für die Rechnung von oben zurück:
Der Trick ist nicht auf Rechnungen beschränkt. Strom kann keinen Wert ausschreiben, aber einen auswählen: das Dokument in Kandidaten aufteilen, sie nummerieren und fragen, welcher die Antwort enthält. Das funktioniert genauso für Verträge (welche Klausel legt die Kündigungsfrist fest?), Belege, Formulare oder jedes andere Dokument mit einer festen Menge an gesuchten Angaben. Das Modell extrahiert die Felder, und einfacher Code übernimmt die Bereinigung und die Prüfungen.
Ihr könnt den Rechnungsanalysator hier mit euren eigenen PDFs ausprobieren oder mit der API eure eigene Pipeline bauen.