Zum Inhalt springen

DACH FinTech Scale-up · Finanzdienstleistungen

Wie wir in vier Wochen einen Rechnungs-Triage-Agenten in Produktion gebracht haben — und dem Operations-Team 180 Stunden im Monat zurückgegeben haben

Bearbeitungszeit pro Rechnung um 78% reduziert — mit einem KI-Agenten und klarem Human-in-the-Loop

78%
Schneller pro Rechnung
180 h
Operator-Stunden / Monat
99,2%
Extraktions-Genauigkeit
4 Wochen
Von Kick-off bis Produktion

<div class="not-prose relative my-12 overflow-hidden rounded-3xl border border-white/10 bg-ink-900/40 p-6 md:p-10 reveal">
<div aria-hidden="true" class="absolute inset-0 opacity-70" style="background: radial-gradient(closest-side at 50% 50%, rgba(232,149,74,0.22), transparent 70%);"></div>
<svg viewBox="0 0 880 220" class="relative h-auto w-full" role="img" aria-label="Pipeline-Diagramm des Rechnungs-Triage-Agenten">
<defs>
<linearGradient id="iv-line-de" x1="0" x2="1">
<stop offset="0%" stop-color="#E8954A" stop-opacity="0.15"/>
<stop offset="50%" stop-color="#E8954A" stop-opacity="0.8"/>
<stop offset="100%" stop-color="#6EE7E0" stop-opacity="0.7"/>
</linearGradient>
</defs>
<path d="M 90 110 L 790 110" stroke="url(#iv-line-de)" stroke-width="2" fill="none"/>
<path d="M 90 110 L 790 110" stroke="#E8954A" stroke-width="2" fill="none" class="dash-anim" opacity="0.8"/>
<g transform="translate(32,60)">
<rect x="4" y="6" width="52" height="68" rx="4" fill="rgba(255,255,255,0.03)" stroke="rgba(255,255,255,0.12)"/>
<rect x="0" y="0" width="52" height="68" rx="4" fill="rgba(255,255,255,0.05)" stroke="rgba(255,255,255,0.22)"/>
<line x1="10" y1="16" x2="42" y2="16" stroke="rgba(255,255,255,0.35)" stroke-width="1.5"/>
<line x1="10" y1="26" x2="42" y2="26" stroke="rgba(255,255,255,0.35)" stroke-width="1.5"/>
<line x1="10" y1="36" x2="30" y2="36" stroke="rgba(255,255,255,0.35)" stroke-width="1.5"/>
<text x="26" y="90" text-anchor="middle" fill="rgba(255,255,255,0.55)" font-size="10" font-family="ui-monospace, monospace" letter-spacing="0.18em">INBOX</text>
</g>
<g transform="translate(150,70)">
<rect width="120" height="80" rx="14" fill="rgba(232,149,74,0.06)" stroke="rgba(232,149,74,0.45)"/>
<circle cx="60" cy="30" r="12" fill="none" stroke="#E8954A" stroke-width="1.8" class="pulse-soft"/>
<circle cx="60" cy="30" r="3" fill="#E8954A"/>
<text x="60" y="60" text-anchor="middle" fill="#F5EFE6" font-size="12" font-family="inherit" font-weight="500">Klassifizieren</text>
<text x="60" y="100" text-anchor="middle" fill="rgba(232,149,74,0.7)" font-size="9" font-family="ui-monospace, monospace" letter-spacing="0.18em">01</text>
</g>
<g transform="translate(300,70)">
<rect width="120" height="80" rx="14" fill="rgba(232,149,74,0.09)" stroke="rgba(232,149,74,0.55)"/>
<rect x="20" y="24" width="36" height="4" rx="1.5" fill="#E8954A" opacity="0.85"/>
<rect x="62" y="24" width="38" height="4" rx="1.5" fill="#E8954A" opacity="0.5"/>
<rect x="20" y="34" width="56" height="4" rx="1.5" fill="#E8954A" opacity="0.7"/>
<rect x="82" y="34" width="18" height="4" rx="1.5" fill="#E8954A" opacity="0.4"/>
<text x="60" y="60" text-anchor="middle" fill="#F5EFE6" font-size="12" font-family="inherit" font-weight="500">Extrahieren</text>
<text x="60" y="100" text-anchor="middle" fill="rgba(232,149,74,0.7)" font-size="9" font-family="ui-monospace, monospace" letter-spacing="0.18em">02</text>
</g>
<g transform="translate(450,70)">
<rect width="120" height="80" rx="14" fill="rgba(232,149,74,0.06)" stroke="rgba(232,149,74,0.45)"/>
<path d="M 48 34 l 8 8 l 18 -18" fill="none" stroke="#E8954A" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="pulse-soft"/>
<text x="60" y="60" text-anchor="middle" fill="#F5EFE6" font-size="12" font-family="inherit" font-weight="500">Validieren</text>
<text x="60" y="100" text-anchor="middle" fill="rgba(232,149,74,0.7)" font-size="9" font-family="ui-monospace, monospace" letter-spacing="0.18em">03</text>
</g>
<g transform="translate(600,70)">
<rect width="120" height="80" rx="14" fill="rgba(232,149,74,0.12)" stroke="rgba(232,149,74,0.65)"/>
<circle cx="44" cy="34" r="6" fill="none" stroke="#E8954A" stroke-width="1.5"/>
<circle cx="76" cy="34" r="6" fill="none" stroke="#E8954A" stroke-width="1.5"/>
<line x1="50" y1="34" x2="70" y2="34" stroke="#E8954A" stroke-width="1.5"/>
<text x="60" y="60" text-anchor="middle" fill="#F5EFE6" font-size="12" font-family="inherit" font-weight="500">Zuordnen</text>
<text x="60" y="100" text-anchor="middle" fill="rgba(232,149,74,0.7)" font-size="9" font-family="ui-monospace, monospace" letter-spacing="0.18em">04</text>
</g>
<g transform="translate(770,60)">
<circle cx="36" cy="50" r="30" fill="rgba(110,231,224,0.1)" stroke="rgba(110,231,224,0.55)" stroke-width="1.5" class="pulse-soft"/>
<path d="M 22 50 l 10 10 l 18 -20" fill="none" stroke="#6EE7E0" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"/>
<text x="36" y="102" text-anchor="middle" fill="rgba(110,231,224,0.75)" font-size="10" font-family="ui-monospace, monospace" letter-spacing="0.18em">ERP</text>
</g>
</svg>
<p class="relative mt-6 text-center text-xs uppercase tracking-eyebrow text-copper-400">Vier deterministische Schritte · ein Human-in-the-Loop · kein Lock-in</p>
</div>

Die Ausgangslage

Das Accounts-Payable-Team verarbeitete rund 4.000 Lieferantenrechnungen pro Monat — PDFs, Scans, gelegentlich ein abfotografiertes Dokument. Pro Rechnung brauchten Operatoren 12–16 Minuten: herunterladen, neu erfassen, PO zuordnen, in die Freigabe schicken. Fehler schlichen sich ein. Neue Mitarbeitende brauchten Wochen, bis sie sicher in der Routine waren.

Im Vorjahr hatten sie einen OCR-Anbieter ausprobiert. Dessen Extraktion lag an einem guten Tag bei 82% Genauigkeit — also musste ein Mensch trotzdem jedes Feld nachprüfen. Statt Workflow war aus dem Tool noch ein weiterer offener Tab geworden.

Der Auftrag an uns war klar: "Baut uns etwas, das wirklich Stunden spart — nicht noch ein Dashboard."

Unsere Roadmap

<div class="not-prose relative my-12">
<ol class="relative space-y-6 md:space-y-8">
<li class="reveal group relative pl-14 md:pl-20" style="transition-delay: 0ms;">
<div aria-hidden="true" class="absolute left-[1.1rem] top-12 bottom-[-1.5rem] w-px bg-gradient-to-b from-copper-500/30 to-copper-500/5 md:left-[1.6rem]"></div>
<div class="absolute left-0 top-0 flex h-10 w-10 items-center justify-center rounded-full border border-copper-500/40 bg-ink-900 font-display text-sm font-semibold text-copper-300 shadow-[0_0_0_4px_var(--color-ink-950)] md:h-[3.25rem] md:w-[3.25rem] md:text-base">01</div>
<div class="absolute left-[2.05rem] top-[1.1rem] md:left-[2.9rem] md:top-6">
<span class="relative flex h-2 w-2">
<span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-copper-400 opacity-60"></span>
<span class="relative inline-flex h-2 w-2 rounded-full bg-copper-400"></span>
</span>
</div>
<div class="rounded-2xl border border-white/10 bg-gradient-to-br from-ink-800/40 via-ink-900/60 to-ink-950/80 p-5 transition-all duration-300 group-hover:border-copper-500/40 group-hover:shadow-[0_16px_48px_-16px_rgba(232,149,74,0.3)] md:p-6">
<div class="flex flex-wrap items-center gap-x-3 gap-y-1">
<span class="font-mono text-[10px] uppercase tracking-[0.22em] text-copper-400">Phase 01</span>
<span aria-hidden="true" class="h-px w-6 bg-copper-500/30"></span>
<span class="text-xs uppercase tracking-eyebrow text-ink-300">Woche 1</span>
</div>
<h3 class="mt-2 font-display text-lg leading-snug text-porcelain-100 md:text-xl">Discovery &amp; Daten</h3>
<p class="mt-3 text-sm leading-relaxed text-ink-300 md:text-base md:leading-relaxed">Drei Operatoren beim Arbeiten begleitet, 500 reale Rechnungen als Gold-Set gelabelt, zwei LLMs gegen den Status quo gebenchmarkt.</p>
</div>
</li>
<li class="reveal group relative pl-14 md:pl-20" style="transition-delay: 100ms;">
<div aria-hidden="true" class="absolute left-[1.1rem] top-12 bottom-[-1.5rem] w-px bg-gradient-to-b from-copper-500/30 to-copper-500/5 md:left-[1.6rem]"></div>
<div class="absolute left-0 top-0 flex h-10 w-10 items-center justify-center rounded-full border border-copper-500/40 bg-ink-900 font-display text-sm font-semibold text-copper-300 shadow-[0_0_0_4px_var(--color-ink-950)] md:h-[3.25rem] md:w-[3.25rem] md:text-base">02</div>
<div class="absolute left-[2.05rem] top-[1.1rem] md:left-[2.9rem] md:top-6">
<span class="relative flex h-2 w-2">
<span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-copper-400 opacity-60"></span>
<span class="relative inline-flex h-2 w-2 rounded-full bg-copper-400"></span>
</span>
</div>
<div class="rounded-2xl border border-white/10 bg-gradient-to-br from-ink-800/40 via-ink-900/60 to-ink-950/80 p-5 transition-all duration-300 group-hover:border-copper-500/40 group-hover:shadow-[0_16px_48px_-16px_rgba(232,149,74,0.3)] md:p-6">
<div class="flex flex-wrap items-center gap-x-3 gap-y-1">
<span class="font-mono text-[10px] uppercase tracking-[0.22em] text-copper-400">Phase 02</span>
<span aria-hidden="true" class="h-px w-6 bg-copper-500/30"></span>
<span class="text-xs uppercase tracking-eyebrow text-ink-300">Woche 2</span>
</div>
<h3 class="mt-2 font-display text-lg leading-snug text-porcelain-100 md:text-xl">Agent &amp; Extraktion</h3>
<p class="mt-3 text-sm leading-relaxed text-ink-300 md:text-base md:leading-relaxed">Mehrstufigen Agenten gebaut: klassifizieren, extrahieren, validieren, PO zuordnen. Structured Outputs, JSON-Schema, deterministische Retries.</p>
</div>
</li>
<li class="reveal group relative pl-14 md:pl-20" style="transition-delay: 200ms;">
<div aria-hidden="true" class="absolute left-[1.1rem] top-12 bottom-[-1.5rem] w-px bg-gradient-to-b from-copper-500/30 to-copper-500/5 md:left-[1.6rem]"></div>
<div class="absolute left-0 top-0 flex h-10 w-10 items-center justify-center rounded-full border border-copper-500/40 bg-ink-900 font-display text-sm font-semibold text-copper-300 shadow-[0_0_0_4px_var(--color-ink-950)] md:h-[3.25rem] md:w-[3.25rem] md:text-base">03</div>
<div class="absolute left-[2.05rem] top-[1.1rem] md:left-[2.9rem] md:top-6">
<span class="relative flex h-2 w-2">
<span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-copper-400 opacity-60"></span>
<span class="relative inline-flex h-2 w-2 rounded-full bg-copper-400"></span>
</span>
</div>
<div class="rounded-2xl border border-white/10 bg-gradient-to-br from-ink-800/40 via-ink-900/60 to-ink-950/80 p-5 transition-all duration-300 group-hover:border-copper-500/40 group-hover:shadow-[0_16px_48px_-16px_rgba(232,149,74,0.3)] md:p-6">
<div class="flex flex-wrap items-center gap-x-3 gap-y-1">
<span class="font-mono text-[10px] uppercase tracking-[0.22em] text-copper-400">Phase 03</span>
<span aria-hidden="true" class="h-px w-6 bg-copper-500/30"></span>
<span class="text-xs uppercase tracking-eyebrow text-ink-300">Woche 3</span>
</div>
<h3 class="mt-2 font-display text-lg leading-snug text-porcelain-100 md:text-xl">Prüf-UI mit Human-in-the-Loop</h3>
<p class="mt-3 text-sm leading-relaxed text-ink-300 md:text-base md:leading-relaxed">Single-Pane-UI mit Inline-Korrekturen gelauncht. Ein Tastendruck bestätigt, Korrekturen landen automatisch im Evaluation-Set.</p>
</div>
</li>
<li class="reveal group relative pl-14 md:pl-20" style="transition-delay: 300ms;">
<div aria-hidden="true" class="absolute left-[1.1rem] top-12 bottom-[-1.5rem] w-px bg-gradient-to-b from-copper-500/30 to-copper-500/5 md:left-[1.6rem] hidden"></div>
<div class="absolute left-0 top-0 flex h-10 w-10 items-center justify-center rounded-full border border-copper-500/40 bg-ink-900 font-display text-sm font-semibold text-copper-300 shadow-[0_0_0_4px_var(--color-ink-950)] md:h-[3.25rem] md:w-[3.25rem] md:text-base">04</div>
<div class="absolute left-[2.05rem] top-[1.1rem] md:left-[2.9rem] md:top-6">
<span class="relative flex h-2 w-2">
<span class="absolute inline-flex h-full w-full animate-ping rounded-full bg-copper-400 opacity-60"></span>
<span class="relative inline-flex h-2 w-2 rounded-full bg-copper-400"></span>
</span>
</div>
<div class="rounded-2xl border border-white/10 bg-gradient-to-br from-ink-800/40 via-ink-900/60 to-ink-950/80 p-5 transition-all duration-300 group-hover:border-copper-500/40 group-hover:shadow-[0_16px_48px_-16px_rgba(232,149,74,0.3)] md:p-6">
<div class="flex flex-wrap items-center gap-x-3 gap-y-1">
<span class="font-mono text-[10px] uppercase tracking-[0.22em] text-copper-400">Phase 04</span>
<span aria-hidden="true" class="h-px w-6 bg-copper-500/30"></span>
<span class="text-xs uppercase tracking-eyebrow text-ink-300">Woche 4</span>
</div>
<h3 class="mt-2 font-display text-lg leading-snug text-porcelain-100 md:text-xl">Härten &amp; Go-Live</h3>
<p class="mt-3 text-sm leading-relaxed text-ink-300 md:text-base md:leading-relaxed">Kosten-Caps, PII-Guardrails, DATEV-Export, On-Call-Runbook. Rollout ans gesamte Ops-Team an Tag 28.</p>
</div>
</li>
</ol>
</div>

Wie wir gebaut haben

Woche 1 — Discovery, die sich selbst bezahlt

Bevor wir den ersten Prompt geschrieben haben, haben wir drei AP-Operatoren jeweils einen Tag begleitet. Der eigentliche Flaschenhals war nicht die Extraktion — es waren die sechs kleinen Entscheidungen, die ein Mensch pro Rechnung traf (Duplikat? VAT-ID im Lieferantenstamm? Budget im PO noch verfügbar?). Diese Entscheidungen wurden zur Spezifikation für den Agenten, nicht umgekehrt.

500 repräsentative Rechnungen haben wir als Gold-Set gelabelt. Dieses Set blieb für jeden Benchmark danach die Wahrheitsquelle.

Woche 2 — Der Agent, bewusst langweilig gebaut

Vier deterministische Schritte statt ein Mega-Prompt:

  1. Klassifizieren — Rechnung, Gutschrift, Kontoauszug oder etwas anderes?
  2. Extrahieren — strukturiertes JSON gegen ein Zod-Schema (Kopf, Positionen, Summen, Umsatzsteuer).
  3. Validieren — Summen stimmen, VAT-IDs im EU-VIES-Register, Währung passt zum Lieferantenstamm.
  4. Zuordnen — Vorschlag für Bestellung und Kostenstelle mit Confidence-Score.

Jeder Schritt wird eigenständig evaluiert, retried und gecached. Das ist der langweilige Teil, der das System günstig macht und um 2 Uhr nachts debugbar.

Woche 3 — Eine Prüf-UI, die niemand gehasst hat

Links das PDF, rechts die extrahierten Felder, farblich nach Confidence. Grüne Felder nur kurz überfliegen. Orange kurz bestätigen. Rote sind fokussiert, bereit zur Korrektur. Alles ist tastaturgesteuert — Tab, Enter, fertig.

Jede Korrektur landet automatisch im gelabelten Evaluation-Set. Die Genauigkeit des Agenten steigt, ohne dass jemand einen Trainingslauf startet.

Woche 4 — Härten vor der Übergabe

  • Kosten-Caps pro Rechnung und pro Tag, hart durchgesetzt.
  • PII-Redaktion auf allem, was in Logs landet.
  • DATEV-Export im Format der Steuerkanzlei.
  • On-Call-Runbook, Grafana-Board, Slack-Alert, wenn der Agent zweimal hintereinander unsicher war.

Wir sind an einem Donnerstag live gegangen. Der Ops-Lead hat uns am Freitagabend geschrieben: "Zum ersten Mal seit zwei Jahren gehe ich pünktlich nach Hause."

Die Architektur

Ein lesbarer Stack ist ein wartbarer Stack. Nichts Exotisches.

  • Ingestion: Microsoft-365-Konnektor + überwachtes Postfach → S3-kompatibler Bucket.
  • Agent-Runtime: TypeScript, Anthropic Claude Sonnet fürs Reasoning, Structured Outputs gegen Zod, strenge JSON-Validierung.
  • Orchestrierung: Temporal für Retries, Idempotenz und Human-in-the-Loop-Waits.
  • Validierung: EU VIES für USt-IDs, Lieferantenstamm als Read-only-Source-of-Truth.
  • Prüf-UI: Astro + HTMX auf Cloudflare, Deploy in unter einer Minute pro Change.
  • Export: DATEV-CSV direkt in die ERP-Importqueue des Kunden.
  • Observability: OpenTelemetry-Traces, Token-Spend-Dashboards, Eval-Regressionen als CI-Gate.

Kein Lock-in. Der Kunde besitzt Repo, Infrastruktur und Evaluation-Set ab Tag 1.

Die Ergebnisse

Vier Wochen nach Kick-off, gemessen über die folgenden 90 Tage:

  • Bearbeitungszeit von 14 auf 3 Minuten pro Rechnung gesunken.
  • 99,2% Feldgenauigkeit auf dem Gold-Set — Tendenz steigend durch Feedback-Loop.
  • 180 Operator-Stunden / Monat frei — eingesetzt für Lieferantenbeziehungen, die ein Jahr liegen geblieben waren.
  • Null Incidents in den ersten 90 Tagen. Der Agent hat bei 2,1% der Rechnungen bewusst zurückgehalten, Menschen haben reibungslos nachgeprüft.
  • EU-AI-Act-ready — als Limited Risk klassifiziert, dokumentiert, jede automatisierte Entscheidung nachvollziehbar.

Wie es weitergeht

Das gleiche Agenten-Muster wird jetzt auf Reisekostenabrechnungen und KYC im Kunden-Onboarding ausgerollt — 80% der Infrastruktur aus dem ersten Monat werden wiederverwendet. Das ist der Compounding-Effekt von Craft-first Engineering: der zweite Agent kostet einen Bruchteil des ersten.

Wenn Sie auf einen repetitiven Back-Office-Prozess schauen und unsicher sind, ob sich ein Agent lohnt — reden Sie mit uns. Wir sagen ehrlich, wenn es nicht passt, und wenn es passt, sind wir in Produktion, bevor die meisten Anbieter das zweite Meeting terminiert haben.

Ihr Zug

Lassen Sie uns Ihre Software unausweichlich machen.

Sagen Sie uns, was Sie brauchen. Wir antworten innerhalb eines Arbeitstags — mit echter Meinung, nicht mit Verkaufspitch.