Mittelstufe 11 Min.Finanzen

Buchhaltung: Extraktion von factures

Direkte Antwort

Um Rechnungen lokal auszulesen, stellen Sie mit Ollama ein Vision-Modell (Qwen 3.5 9B, 6,6 GB, oder Gemma 4) bereit, geben Sie ein JSON-Schema für seine Antwort vor und validieren Sie anschließend per Code: Nettobetrag plus Mehrwertsteuer gleich Bruttobetrag, SIRET, Datumsangaben. Rechnungen, die die Prüfung nicht bestehen, werden zur menschlichen Nachprüfung weitergeleitet. Seit September 2026 kommen strukturierte elektronische Rechnungen ohne KI aus: Diese Pipeline dient der Verarbeitung einfacher PDF-Dateien und Scans.

Die manuelle Eingabe von Rechnungen ist langsam und anfällig für Fehler, aber die Übertragung von Buchhaltungsunterlagen an einen Online-Dienst stellt ein Datenschutzproblem dar. Ein lokaler Vision-Modell liest die Seite, ein Schema bestimmt die Struktur des Ergebnisses und deterministische Kontrollen filtern Fehler. Dieser Leitfaden zeigt den vollständigen Pipeline-Prozess von der Sortierung von PDF-Dateien bis zur Buchhaltungsimportierung auf und erinnert daran, was die elektronische Rechnung ab September 2026 verändert.

Von Mohamed Meguedmi·Aktualisierung 2026-09-30·Unter Windows, macOS und Linux getestet

#Was sich automatisieren lässt und wie zuverlässig

Aus einer Lieferantenrechnung im PDF-Format soll strukturiertes JSON entstehen (Lieferant, Nummer, Datum, Nettobeträge, Mehrwertsteuer und Bruttobeträge, Rechnungspositionen), das sich stapelweise in die Buchhaltungssoftware importieren lässt. Ein über Ollama bereitgestelltes Vision-Modell liest direkt das Bild der Seite, ohne separate OCR. Die Regel, die diesen Aufbau zuverlässig macht, lässt sich in einem Satz zusammenfassen: Das Modell liest, der Code prüft. Extrahierte Daten werden niemals importiert, ohne zuvor rechnerische Prüfungen und Prüfungen der Kennungen zu bestehen; alles, was dabei durchfällt, landet in einer Warteschlange zur menschlichen Nachprüfung.

Dieser Leitfaden behandelt einen konkreten Fall: ein Büro oder ein kleines oder mittleres Unternehmen, das einige hundert Rechnungen pro Monat erhält und sie auf einem Arbeitsplatzrechner oder einem kleinen lokalen Server verarbeitet. Hier werden keine Zahlen zur Genauigkeit versprochen: Die Genauigkeit hängt von Ihren Lieferanten, der Qualität der Scans und dem Modell ab. Weiter unten wird die Messmethode anhand einer Stichprobe Ihrer eigenen Rechnungen erläutert.

#Elektronische Rechnung: Was sich 2026 und 2027 ändert

Das Lokale-KI-Paket

Ihr privates, kostenloses ChatGPT auf Ihrem Rechner in einer Stunde – mit LM Studio, Ollama, Open WebUI und Ihren Dokumenten, ganz ohne Cloud.

  • Lebenslanger Online-Zugang
  • PDF + Dateien
  • Erstattung binnen 30 Tagen

Bevor man eine Pipeline zum Einlesen erstellt, muss man prüfen, wie sich die Reform auf eingehende Rechnungen auswirkt. Seit dem 1. September 2026 müssen laut impots.gouv.fr große Unternehmen und Unternehmen mittlerer Größe ihre Rechnungen über eine zugelassene Plattform ausstellen, und alle Unternehmen müssen elektronische Rechnungen empfangen können. Für kleine und mittlere Unternehmen, Kleinstunternehmen und Mikro-Unternehmen gilt die Pflicht zur Rechnungsausstellung laut dem Praxisleitfaden der Steuerverwaltung ab dem 1. September 2027.

Das hat zwei praktische Konsequenzen. Einerseits wird ein wachsender Anteil Ihrer eingehenden Rechnungen bereits in strukturierter Form eintreffen, ohne dass eine KI sie auslesen muss. Andererseits vereint das Format Factur-X, ein deutsch-französischer Standard für hybride Rechnungen, ein lesbares PDF und XML-Daten für die automatisierte Verarbeitung in derselben Datei und bietet mehrere Datenprofile. Wenn ein PDF dieses XML enthält, ist es sicherer, die Daten direkt auszulesen, als sie von einem Modell erschließen zu lassen. Die folgende Pipeline arbeitet daher nach dieser Reihenfolge: zuerst strukturierte Daten, sofern vorhanden, dann der native PDF-Text und erst als letzte Möglichkeit die Bildanalyse.

i
Was dieser Leitfaden nicht abdeckt
Der Empfang über eine zugelassene Plattform, das E-Reporting und die Pflichten zur Rechnungsausstellung hängen von Ihrer Plattformwahl und dem Anbieter Ihrer Buchhaltungssoftware ab. Diese Pipeline betrifft Rechnungen, die noch als einfache PDF-Datei oder als Scan eingehen: ausländische Lieferanten, kleine Dienstleister, Kassenbons, digitalisierte Papierdokumente.

#Das Modell auswählen: Wie viel Speicher die Bildverarbeitung benötigt

Zum Auslesen von Rechnungen eignen sich zwei Modellfamilien aus der Ollama-Bibliothek. Qwen 3.5 mit 9 Milliarden Parametern belegt 6,6 GB, verarbeitet Text und Bilder und gibt ein Kontextfenster von 256.000 Tokens an; die 27B-Version belegt 17 GB. Gemma 4 belegt in der Variante e4b laut Ollama-Modellseite zwischen 6,6 und 9,5 GB und gibt ein Kontextfenster von 128.000 Tokens sowie Unterstützung für Text und Bilder an. Eine Grafikkarte mit 12 GB reicht daher für die Variante 9B oder e4b aus, mit Spielraum für Seitenbilder.

Welches Tool für welche Art von PDF
DateitypToolWarum
Factur-X-PDF oder eingebettetes XMLDirektes Auslesen des XMLExakte Daten, kein Risiko von Lesefehlern
Natives PDF mit auswählbarem TextTextextraktion, dann LLM für TextSchnell, keine Bilder zu verarbeiten
Gescanntes PDF oder sauberes FotoVision-Modell (Qwen 3.5 9B, Gemma 4)Liest das Layout und die Tabellen
Scan von schlechter QualitätOCR mit Tesseract, dann menschliche ÜberprüfungDie Bilderkennung lässt sich durch Rauschen in die Irre führen; ein Mensch wird die Entscheidung treffen.

Richtwert dieser Website für den Speicherbedarf: Ein Modell mit 9 Milliarden Parametern in Q4 benötigt etwa 5 bis 6 GB, hinzu kommen der Kontextcache und die Bilder der Seite. Seiten mehrseitiger Rechnungen verursachen einen höheren Aufwand als andere: Zehn Seiten in einer einzigen Anfrage können das standardmäßige Kontextfenster von Ollama überschreiten. Dieses bleibt deutlich unter den für das Modell angegebenen 256.000 Tokens, solange Sie es nicht vergrößern.

#PDFs vor dem Lesen sortieren: nativ, gescannt, strukturiert

Die Erkennung des Dateityps verhindert, dass unnötig ein Bild an ein Vision-Modell gesendet wird. Bei der Textextraktion mit der Bibliothek PyMuPDF gilt: Ein PDF, dessen extrahierter Text mehr als einige hundert Zeichen umfasst, ist ein natives PDF; ein PDF mit nahezu keinem Text ist ein Scan. Factur-X-Dateien enthalten einen XML-Anhang, der vor jeder weiteren Verarbeitung aufgelistet werden kann.

Je nach PDF-Typ weiterleiten
import fitz  # PyMuPDF

def type_pdf(chemin):
    doc = fitz.open(chemin)
    pieces = doc.embfile_names()  # pièces jointes intégrées
    if any(n.lower().endswith('.xml') for n in pieces):
        return 'structure'
    texte = ''.join(page.get_text() for page in doc)
    return 'natif' if len(texte.strip()) > 300 else 'scan'

Bei Scans von schlechter Qualität bleibt Tesseract eine kostenlose Offline-Ausweichlösung: Dafür muss die französische Sprachdatei installiert und mit 300 Punkten pro Zoll gescannt werden. Der Leitfaden zu Tesseract erläutert die Einstellungen. Text aus einer fehlerhaften OCR darf niemals ungeprüft weiterverarbeitet werden: Er kommt dann in die Warteschlange für die manuelle Prüfung.

Tesseract mit französischer Sprachunterstützung installieren
# macOS
brew install tesseract tesseract-lang

# Ubuntu / Debian
sudo apt install tesseract-ocr tesseract-ocr-fra

#Mit einem Vision-Modell und einem vorgegebenen Schema extrahieren

Ollama kann die Antwort des Modells auf ein JSON-Schema beschränken: Laut seiner Dokumentation wird ein Schema im Feld format angegeben, und es wird empfohlen, es auch im Prompt zu wiederholen, um die Antwort daran auszurichten. Das ist deutlich robuster, als in freiem Text „ein JSON“ zu verlangen, da Schlüssel und Typen vorgegeben sind. Für Bilder erwartet die REST-API Base64-kodierte Bilder im Feld images der Nachricht.

Strukturierte Extraktion einer Rechnung (Ollama, Vision)
import base64, json, requests
from io import BytesIO
from pdf2image import convert_from_path

SCHEMA = {
  'type': 'object',
  'properties': {
    'fournisseur': {'type': 'object', 'properties': {
      'nom': {'type': 'string'},
      'siret': {'type': ['string', 'null']},
      'tva_intra': {'type': ['string', 'null']}}},
    'facture': {'type': 'object', 'properties': {
      'numero': {'type': 'string'},
      'date': {'type': 'string'},
      'echeance': {'type': ['string', 'null']}}},
    'montants': {'type': 'object', 'properties': {
      'ht': {'type': 'number'}, 'tva': {'type': 'number'},
      'ttc': {'type': 'number'}, 'devise': {'type': 'string'}}},
    'lignes': {'type': 'array', 'items': {'type': 'object', 'properties': {
      'description': {'type': 'string'}, 'quantite': {'type': 'number'},
      'pu_ht': {'type': 'number'}, 'total_ht': {'type': 'number'}}}}
  },
  'required': ['fournisseur', 'facture', 'montants']
}

PROMPT = ("Tu extrais les données d'une facture française. "
  "Réponds uniquement par un JSON conforme à ce schéma : " + json.dumps(SCHEMA) +
  ". Si une donnée est absente ou illisible, mets null. Les montants sont des nombres (1234.56), "
  "les dates au format AAAA-MM-JJ. N'invente rien.")

def pages_b64(pdf, dpi=200):
    sortie = []
    for img in convert_from_path(pdf, dpi=dpi):
        buf = BytesIO(); img.save(buf, format='PNG')
        sortie.append(base64.b64encode(buf.getvalue()).decode())
    return sortie

def extraire(pdf):
    r = requests.post('http://localhost:11434/api/chat', json={
      'model': 'qwen3.5:9b', 'stream': False, 'format': SCHEMA,
      'messages': [{'role': 'user', 'content': PROMPT, 'images': pages_b64(pdf)}],
      'options': {'temperature': 0, 'num_ctx': 16384}})
    return json.loads(r.json()['message']['content'])

Drei Entscheidungen verdienen eine Erklärung. Eine Temperatur von null macht die Ausgabe reproduzierbar. Der Parameter num_ctx vergrößert das Kontextfenster, da die Bilder mehrerer Seiten das kleine Standardkontextfenster von Ollama schnell ausschöpfen; der Leitfaden zum Kontextfenster erläutert diesen Mechanismus im Detail. Schließlich verringert die Anweisung „Erfinde nichts“ zusammen mit einem zulässigen null-Wert das gravierendste Risiko: dass ein Modell ein unleserliches Feld mit einem plausiblen Wert füllt. Ein striktes Schema erzwingt die Form der Antwort, nicht die Richtigkeit ihres Inhalts.

#Das Schema auf Ihre tatsächlichen Anwendungsfälle erweitern

Das Basisschema deckt die meisten Rechnungen gängiger Lieferanten ab. Welche Erweiterungen erforderlich sind, hängt von Ihrer Tätigkeit ab. Fügen Sie sie einzeln hinzu und messen Sie die Wirkung jeder Erweiterung anhand Ihrer Stichprobe: Ein überladenes Schema beeinträchtigt das Auslesen der wesentlichen Felder.

Anzahlung und Restbetrag
Fügen Sie ein Feld acompte_paye hinzu. Ohne dieses Feld entspricht der Gesamtbetrag inklusive Mehrwertsteuer nicht dem noch zu zahlenden Betrag.
Bestellreferenzen
Ein Feld namens bon_commande_ref ermöglicht die Abstimmung mit Ihren Bestellungen.
Versandkosten und Rabatte
Separate Zeile oder Feld port_ht, sonst stimmt die Summe der Zeilen nicht mit dem Nettobetrag überein.
Mehrwertsteueraufschlüsselung
Eine Liste mit Steuersatz, Bemessungsgrundlage und Steuerbetrag. Unverzichtbar, sobald eine Rechnung mehrere Steuersätze enthält.
Kontierung
Fordern Sie das Modell nicht auf, das Konto zu erraten: Erstellen Sie einen als solchen gekennzeichneten Vorschlag, der durch Ihre Geschäftsregel oder einen Menschen bestätigt wird.

#Vor dem Import validieren: Prüfungen, die Fehler erkennen

Dieser Schritt entscheidet über die Qualität des gesamten Aufbaus. Jede Prüfung ist deterministisch und damit zuverlässiger als das Modell. Die erste ist arithmetisch: Nettobetrag plus Mehrwertsteuer muss den Bruttobetrag ergeben, mit einer Toleranz von wenigen Cent für Rundungen. Die zweite betrifft die Rechnungspositionen: Ihre Summe muss den Nettobetrag ergeben. Die dritte betrifft die Datumsangaben: Sie dürfen weder vor einer vernünftigen zeitlichen Grenze noch in der Zukunft liegen. Die vierte betrifft die SIRET-Nummer.

Die Prüfung der SIRET-Nummer verdient besondere Aufmerksamkeit. Die Nummer besteht aus 14 Ziffern; ihre letzte Ziffer ist eine Prüfziffer, die laut Wikipedia mit der Luhn-Formel berechnet wird. Es gibt eine Ausnahme: Die Betriebsstätten von La Poste, deren SIREN 356000000 lautet, folgen einer anderen Regel, bei der die Summe der 14 Ziffern ein Vielfaches von 5 sein muss. Eine naive Prüfung mit Luhn würde daher Rechnungen von La Poste zu Unrecht zurückweisen. Der folgende Code behandelt beide Fälle.

Konsistenzkontrollen für eine extrahierte Rechnung
from datetime import date

def luhn_ok(s):
    total = 0
    for i, c in enumerate(reversed(s)):
        d = int(c)
        if i % 2 == 1:
            d *= 2
            if d > 9:
                d -= 9
        total += d
    return total % 10 == 0

def siret_valide(s):
    if not (s.isdigit() and len(s) == 14):
        return False
    if s.startswith('356000000'):  # La Poste : somme multiple de 5
        return sum(int(c) for c in s) % 5 == 0
    return luhn_ok(s)

def valider(f):
    erreurs = []
    m = f['montants']
    if abs(m['ht'] + m['tva'] - m['ttc']) > 0.02:
        erreurs.append('HT + TVA différent du TTC')
    lignes = f.get('lignes') or []
    if lignes and abs(sum(l['total_ht'] for l in lignes) - m['ht']) > 0.05:
        erreurs.append('somme des lignes différente du HT')
    siret = (f['fournisseur'].get('siret') or '').replace(' ', '')
    if siret and not siret_valide(siret):
        erreurs.append('SIRET invalide : ' + siret)
    try:
        d = date.fromisoformat(f['facture']['date'])
        if d.year < 2000 or d > date.today():
            erreurs.append('date suspecte : ' + str(d))
    except ValueError:
        erreurs.append('date illisible')
    return erreurs
!
Niemals eine Inkonsistenz importieren
Eine Rechnung, deren Gesamtbetrag nicht stimmt, muss in die Warteschlange „Zu prüfen“. Eine Extraktion, die alle Prüfungen besteht, ist nicht garantiert korrekt. Extraktionen, die diese Prüfungen nicht bestehen, müssen jedoch auf jeden Fall überprüft werden: Darauf konzentriert sich die menschliche Sichtung.

#Messung der Genauigkeit anhand Ihrer eigenen Rechnungen

Keine veröffentlichte Genauigkeitsangabe ersetzt eine Messung anhand Ihres Korpus, denn eine Kanzlei, die Rechnungen von Großhändlern verarbeitet, hat andere Dokumente als ein Verein. Stellen Sie eine Stichprobe aus etwa fünfzig repräsentativen Rechnungen zusammen, erfassen Sie die wesentlichen Felder von Hand und vergleichen Sie anschließend Feld für Feld.

  1. 01
    Die Stichprobe erstellen
    Verwenden Sie unterschiedliche echte Rechnungen: Scans, native PDF-Dateien, mehrseitige Rechnungen und Rechnungen verschiedener Lieferanten. Anonymisieren Sie die Daten, wenn Sie die Ergebnisse teilen.
  2. 02
    Die Referenzdaten erfassen
    Notieren Sie von Hand die Felder, die automatisiert werden sollen: Nummer, Datum, Netto, MwSt., Brutto, SIRET.
  3. 03
    Feld für Feld vergleichen
    Berechnen Sie die Genauigkeit für jedes Feld einzeln, nicht insgesamt: Ein Modell kann Datumsangaben perfekt lesen und bei den Umsatzsteuerangaben Fehler machen.
  4. 04
    Schwellenwert für Automatisierung festlegen
    Entscheiden Sie, welche Felder ohne erneute Prüfung importiert werden können. Beträge sind gute Kandidaten, sofern sie die rechnerische Prüfung bestehen; die Kontierung hingegen niemals.
  5. 05
    Bei jeder Änderung erneut ausführen
    Wenn Sie das Modell, die Auflösung oder den Prompt ändern, führen Sie den Test mit der Stichprobe erneut durch, bevor Sie in den Produktivbetrieb gehen.

#Einen Ordner mit Rechnungen stapelweise verarbeiten

Die Stapelverarbeitung führt Sortierung, Extraktion und Validierung nacheinander durch und legt anschließend jede Rechnung entsprechend dem Ergebnis ab. Bewahren Sie immer zwei Dateien nebeneinander auf: das Original-PDF und die extrahierte JSON-Datei.

Stapelverarbeitung mit Warteschlange zur Überprüfung
from pathlib import Path
import json

def traiter(dossier_in, dossier_ok, dossier_revue):
    for pdf in Path(dossier_in).glob('*.pdf'):
        try:
            f = extraire(str(pdf))
            erreurs = valider(f)
        except Exception as e:
            f, erreurs = {}, ['échec extraction : ' + str(e)]
        dest = Path(dossier_ok if not erreurs else dossier_revue)
        (dest / (pdf.stem + '.json')).write_text(
            json.dumps({'donnees': f, 'erreurs': erreurs}, ensure_ascii=False, indent=2))
        pdf.rename(dest / pdf.name)
        print(('OK ' if not erreurs else 'A VERIFIER ') + pdf.name)

#Die Daten in die Buchhaltungssoftware übertragen

Jeder Editor hat seinen eigenen Importformat und seine Spezifikationen, die sich verändern: Beginnen Sie mit der Dokumentation Ihres Tools, nicht mit einem allgemeinen Modell. Finanzsoftware bietet normalerweise einen Import über strukturierte Dateien oder eine Programmierschnittstelle an. Der sicherste Weg ist, einen konformen Importdatei zu erstellen, ihn in ein Testverzeichnis zu laden und die erzeugten Einträge mit denen zu vergleichen, die Sie manuell eingegeben hätten.

Bewahren Sie den Prüfpfad auf: das Original-PDF, das extrahierte JSON, die Modellversion und das Verarbeitungsdatum. Bei einer Prüfung müssen Sie vom Buchungssatz zum zugehörigen Beleg zurückverfolgen können. Rechnungen enthalten personenbezogene und geschäftliche Daten: Wenn die Verarbeitung lokal bleibt, werden diese keinem Dritten anvertraut. Die Speicherung der Dateien unterliegt jedoch weiterhin Ihren Aufbewahrungs- und Sicherheitsregeln.

FAQ
Kann ein lokaler LLM ein gescanntes Rechnungsdokument lesen?+
Ja, ein Vision-Modell wie Qwen 3.5 9B oder Gemma 4 liest das Bild einer Seite und extrahiert daraus die Felder. Die Zuverlässigkeit hängt von der Qualität des Scans und vom Layout ab. Das Ergebnis muss daher durch arithmetische Prüfungen validiert werden, und jede Rechnung, die diese Prüfungen nicht besteht, muss an einen Menschen weitergegeben werden.
Ist zusätzlich zum Vision-Modell ein OCR-System erforderlich?+
Nicht grundsätzlich. Ein Vision-Modell liest das Bild direkt, wodurch der Informationsverlust durch eine separate OCR vermieden wird. Tesseract bleibt als Sicherheitsnetz für Scans von sehr schlechter Qualität und für native PDFs nützlich, aus denen sich der Text einfach extrahieren lässt. Testen Sie beide anhand Ihrer Stichprobe, statt von Annahmen auszugehen.
Wie kann man eine gültige JSON-Ausgabe gewährleisten?+
Ollama ermöglicht es, ein JSON-Schema im API-Feld format zu übergeben: Die Antwort wird dann auf diese Struktur beschränkt. Das garantiert die Form, nicht die Richtigkeit der Werte. Fügen Sie daher immer Konsistenzprüfungen im Code hinzu: Nettosumme plus Mehrwertsteuer, SIRET, Datumsangaben, Summe der Rechnungspositionen.
Was ändert die Pflicht zur elektronischen Rechnung für diese Art von Tool?+
Seit dem 1. September 2026 müssen alle Unternehmen elektronische Rechnungen empfangen können, und die Ausstellung wird für kleine und mittlere Unternehmen im September 2027 verpflichtend. Strukturierte Rechnungen wie Factur-X lassen sich ohne KI lesen. Die Pipeline dient vor allem der Verarbeitung von Rechnungen von Lieferanten, die weiterhin einfache PDFs oder Papier schicken.
Welche Grafikkarte benötigt man, um Rechnungen zu extrahieren?+
Ein Modell mit 9 Milliarden Parametern in Q4 benötigt etwa 6 GB Speicher; Seitenbilder und Kontext kommen hinzu. Eine Grafikkarte mit 12 GB ist geeignet, eine mit 8 GB reicht für einseitige Rechnungen mit reduziertem Kontext aus. Ohne GPU funktioniert die Verarbeitung, wird aber langsam: Planen Sie die Verarbeitung über Nacht ein.
Kann man der vom Modell vorgeschlagenen Kontierung vertrauen?+
Nein, nicht ohne Validierung. Das Modell kann anhand der Lieferantenbezeichnung ein Buchungskonto vorschlagen, doch dieser Vorschlag muss durch eine Geschäftsregel oder den Buchhalter bestätigt werden. Ein Kontierungsfehler bleibt unbemerkt: Er besteht alle rechnerischen Prüfungen. Behandeln Sie die Kontierung als den einzigen Bereich, der immer eine menschliche Prüfung erfordert.
Hat Ihnen dieser Guide geholfen?

Haben Sie Feedback, einen Fehler entdeckt oder möchten Sie etwas präzisieren? Geben Sie uns Bescheid – so wird der Guide für alle besser.