Case Study
OrionReach — Von 8 % auf 34 % Response Rate
Ein architektonischer Deep-Dive in eine produktive Multi-Model-AI-SaaS für LinkedIn-Outreach: warum eine Browser-Extension statt Scraping-Backend, warum Claude Haiku zuerst und Sonnet später, warum Qdrant statt Pinecone — und was die Zahl 34 % praktisch bedeutet.
8 % → 34 %
Antwort-Rate auf erste Outbound-Nachricht
12 k+
Importierte LinkedIn-Profile pro Monat
Multi-Tenant
Workspace-Isolation auf Postgres-Ebene
DSGVO
Hetzner Hosting in Deutschland
Problem — warum klassisches Outreach unter 10 % bleibt
LinkedIn-Outreach im B2B leidet an einem strukturellen Problem: Die meisten Tools verschicken Templates mit Platzhaltern wie {{firstName}} oder {{company}} — der Empfänger erkennt das in unter zwei Sekunden. Die Folge sind Antwort-Raten zwischen 5 % und 10 % und ein steigendes Risiko, vom LinkedIn-Spam-Filter erwischt zu werden.
Gleichzeitig gibt es einen zweiten Effekt: Lead-Listen sind zu breit. Wenn die ICP-Definition nur aus Job-Title und Branche besteht, landen Profile in der Kampagne, die fachlich gar nicht passen. Eine generische Nachricht an einen schlecht qualifizierten Lead ist die schlechteste Kombination.
OrionReach setzt deshalb an zwei Stellen gleichzeitig an: Lead-Klassifikation vor dem Versand (passt der Kontakt überhaupt?) und echte Personalisierung pro Nachricht (basierend auf Profil-Signal, nicht auf Mustertext).
Ansatz — Multi-Model-AI mit klarer Aufgabentrennung
Die Kernentscheidung war früh: kein Single-Model-Ansatz. Ein einzelnes LLM, das gleichzeitig klassifiziert, extrahiert, schreibt und routet, ist teuer, langsam und in der Qualität nicht reproduzierbar. Stattdessen läuft pro Profil eine kurze Pipeline mit verschiedenen Modellen für verschiedene Aufgaben.
Die Pipeline folgt dem Prinzip "klein und schnell zuerst, groß und teuer nur wenn nötig". Das hält Token-Kosten beherrschbar und macht die Latenz pro Lead vorhersagbar — wichtig, wenn ein Nutzer im Browser auf "Kampagne starten" drückt und nicht 90 Sekunden warten will.
- Claude Haiku für die erste Klassifikation: passt der Lead zum ICP? Klein, schnell, billig — und gut genug, um 60 %–70 % der Profile sauber auszusortieren, bevor sie überhaupt teurer werden.
- Claude Sonnet für die personalisierte Nachricht: nur Leads, die die Klassifikation überstehen, bekommen das größere Modell. Sonnet bekommt extrahierte Profil-Signale (Position, Branche, Posts, Tätigkeitsfeld) und schreibt eine Nachricht, die spezifisch klingt, weil sie spezifisch ist.
- GPT-4o-mini als Fallback und für strukturierte Extraktionen mit
response_format: json_schema— wo Anthropic Tool-Use overkill ist und ein direktes JSON-Schema reicht. - OpenRouter als Routing-Layer für Self-Hosted-Modelle (Qwen, DeepSeek) bei rein deutschsprachigen Kampagnen — günstiger und für die Sprachqualität ausreichend.
Architektur — warum Browser-Extension statt zentrales Scraping
Die wahrscheinlich wichtigste Architektur-Entscheidung: OrionReach scrapt LinkedIn nicht serverseitig. Stattdessen läuft eine Browser-Extension für Chrome und Firefox, die im authentifizierten Kontext des Nutzers Profile importiert und Nachrichten sendet. Das ist nicht nur sauberer gegenüber den LinkedIn-ToS — es ist auch technisch robuster: keine Captchas, keine IP-Blocks, keine Cookie-Pools.
Backend ist eine FastAPI-Anwendung auf Python 3.11, die ausschließlich mit der Extension und dem Web-Dashboard spricht. Persistenz läuft auf Postgres (Workspaces, Kampagnen, Konversations-Status), während die Vektor-Suche für ICP-Match und semantisches Lead-Clustering in Qdrant liegt. Pinecone war im Pricing für ein bootstrapped SaaS unattraktiv — Qdrant lässt sich auf Hetzner für einen Bruchteil betreiben und liefert für unter 50 k Vektoren pro Tenant ausreichend Latenz unter 50 ms.
Outbound-Nachrichten werden in einer Job-Queue priorisiert und mit menschenähnlichem Timing (jittered Delays, Tageszeitfenster, Pause bei Wochenenden) abgearbeitet. Activity-Mails an den Operator (Reply eingegangen, Lead-Antwort erkannt) gehen über AWS SES als Default und SendGrid als Fallback.
Systemarchitektur in 5 Layern
Daten fließen vom authentifizierten LinkedIn-Tab des Nutzers über die Extension in das Backend, werden dort durch einen Multi-Model-Router geleitet, persistiert und versendet. Jeder Layer ist explizit isoliert — kein direkter Zugriff der Extension auf Datenbanken, kein direkter Zugriff der LLM-Layer auf Outbound-Mailing.
Layer 1Browser-Extension (Chrome & Firefox)
Manifest V3 Extension, läuft im authentifizierten LinkedIn-Tab des Nutzers. Importiert Profile, sendet ausgehende Nachrichten und erkennt eingehende Replies. Kein zentrales Scraping — alle Aktionen passieren im legitimen Kontext des Nutzers.
Manifest V3TypeScriptViteIndexedDB-CacheLayer 2Backend API (FastAPI)
Async FastAPI-Service, terminiert die Extension-Calls, validiert mit Pydantic, serialisiert Jobs in Redis und schreibt relationale Daten nach Postgres. Eigene Auth-Layer pro Workspace mit kurzlebigen Tokens.
FastAPIPydantic v2SQLAlchemy 2.0httpxLayer 3Multi-Model-AI-Router
Internes Routing-Interface, das pro Aufgabe das passende Modell wählt. Haiku klassifiziert, Sonnet schreibt, GPT-4o-mini extrahiert strukturiert, OpenRouter dient als günstiger Fallback. Tenant-spezifische Provider-Config ist hot-swappable.
Claude HaikuClaude SonnetGPT-4o-miniOpenRouterLayer 4Postgres + Qdrant
Postgres 16 hält Workspaces, Kampagnen, Konversations-Status und Audit-Logs — Multi-Tenant über Workspace-IDs plus Row-Level-Security. Qdrant speichert Profil-Embeddings für ICP-Matching und semantisches Lead-Clustering.
Postgres 16QdrantAlembicRLSLayer 5Activity-Mailing (SES + SendGrid)
Operator-Benachrichtigungen (Reply eingegangen, Kampagne fertig, Klassifikator-Anomalie) gehen primär über AWS SES; SendGrid ist Fallback. Versand ist idempotent über eine Outbox-Tabelle in Postgres — keine doppelten Mails bei Retry-Storms.
AWS SESSendGridPostgres-Outbox
Stack — bewusst boring, dort wo es zählt
Bewusste Stack-Wahl entlang einer einfachen Regel: boring tech in der Plattform, scharfe Technik nur am AI-Layer. Das spart Maintenance-Zeit, die direkt in Produkt fließt.
- Frontend (Dashboard): Next.js 15 mit App Router, Tailwind, Shadcn-Komponenten — Server Components für Listen, Client Components nur dort, wo Interaktivität echt nötig ist.
- Browser-Extension: Manifest V3, Vanilla TypeScript, Bundling über Vite. Kein React in der Extension — das hält den Memory-Footprint niedrig, was bei Dauerbetrieb in einem Tab spürbar ist.
- Backend: FastAPI + Pydantic v2, async durchgehend,
httpxfür ausgehende Calls, SQLAlchemy 2.0 + Alembic für Migrations. - AI-Layer: Anthropic SDK (Claude Haiku/Sonnet), OpenAI SDK (GPT-4o-mini), OpenRouter als optionaler Provider — alles hinter einem internen
LLMRouter-Interface, das pro Tenant konfigurierbar ist. - Datenbanken: Postgres 16 (relational), Qdrant (Vektoren), Redis (Job-Queue + Rate-Limit-Window).
- Hosting: Hetzner Cloud in Nürnberg/Falkenstein, Container über Coolify, Traefik für TLS und Routing — DSGVO-relevant: alle Daten und Backups bleiben in Deutschland.
Ergebnis — was die 34 % konkret bedeuten
Die Headline-Zahl 8 % → 34 % Antwort-Rate ist der Median über alle aktiven Workspaces, gemessen an der ersten ausgehenden Nachricht in einer neuen Kampagne. Wichtig dabei: der Vergleich ist nicht "OrionReach vs. nichts", sondern OrionReach gegen den vorherigen Outreach-Stack derselben Kunden — meistens generische Tools mit Templates.
Was unter der Headline-Zahl interessanter ist:
- Pre-Filter-Wirkung: Etwa zwei Drittel der ursprünglichen Lead-Listen werden vor dem Versand aussortiert. Das senkt die ausgehenden Nachrichten, hebt die Antwort-Rate und hält den LinkedIn-Account gesund.
- Antwort-Qualität: Die Replies sind länger und inhaltlich relevanter — was darauf hindeutet, dass die personalisierte erste Nachricht tatsächlich als Gespräch und nicht als Cold-Pitch gelesen wird.
- Token-Budget: Durchschnittlich unter 0,9 Cent pro qualifiziertem Lead bei Claude Haiku + Sonnet, weil Sonnet nur ~30 % der Profile überhaupt sieht.
- Multi-Tenant-Stabilität: Keine Cross-Tenant-Datenleaks seit Launch — die Postgres-Isolation läuft über workspace-scoped Queries plus Row-Level-Security als zweite Schicht.
“Der größte Hebel war nicht das größere Modell — es war die saubere Trennung zwischen "ist dieser Lead überhaupt relevant?" und "wie spreche ich ihn an?". Erst diese zwei Schritte hintereinander, mit den jeweils passenden Modellgrößen, haben aus einem AI-Feature ein produktionsreifes System gemacht.”
Lessons Learned — was ich anders machen würde
Drei Lektionen, die im Rückblick deutlich sind und die in den nächsten Build einfließen werden:
- Streaming früher. Die ersten sechs Monate liefen alle LLM-Calls synchron. Sobald die Pipeline drei Stages hatte, war die Wartezeit im Dashboard zu lang. Streaming + Tool-Status hätte ich von Anfang an einbauen sollen — der UX-Gewinn ist riesig, der technische Aufwand überschaubar.
- Klassifikator zuerst, nicht parallel. Anfangs lief Klassifikation und Extraktion parallel — gut für Latenz, schlecht für Kosten, weil teure Modelle Profile gesehen haben, die gleich aussortiert wurden. Sequentiell mit Early-Exit ist die bessere Default-Strategie.
- Eval-Suite vor Feature-Tempo. Eine kleine, eigene Eval-Suite mit ~200 anonymisierten Profilen pro Sprache hätte mir mehrere Wochen Debugging gespart. Ohne Evals ist jede Modell-Migration ein Blindflug — mit Evals ist sie ein normales Pull-Request-Review.
- Boring Tech zahlt sich aus. Die Entscheidungen für Postgres + Qdrant + FastAPI + Hetzner waren bewusst unspektakulär. In der Summe haben sie weniger als zwei Stunden Incident-Zeit pro Quartal gekostet.
Timeline — von Prototyp zu produktiver SaaS
Prototyp — Single-Model, Single-Tenant — Q4/2024
Erste Version mit Claude Sonnet für alles und einem hartcodierten Workspace. Genug, um die Kernhypothese zu testen: lassen sich Profile sinnvoll vor-klassifizieren? Antwort: ja, aber Token-Kosten waren doppelt so hoch wie ein produktiver Plan tragen würde.
MVP-Launch — Multi-Model-Routing live — Q1/2025
Aufteilung in Haiku-Klassifikation und Sonnet-Personalisierung. Browser-Extension v1 für Chrome. Erste drei Pilot-Kunden auf einem geteilten Hetzner-CX22. Token-Kosten halbiert, Antwort-Rate erstmals stabil über 25 %.
Multi-Tenant-Refactor — Q2/2025
Echte Workspace-Isolation in Postgres mit Row-Level-Security. Self-Service-Onboarding für neue Workspaces. Qdrant als zweites Datenbanksystem dazu, Redis als Job-Queue eingeführt. Erste DSGVO-AVV mit zahlenden Kunden.
Firefox-Extension & Reply-Detection — Q3/2025
Firefox-Build über das gleiche Manifest-V3-Codebook. Eingehende Replies werden im Tab erkannt und ans Backend zurückgespielt — damit kann der Klassifikator lernen, welche Personalisierungen tatsächlich Antworten erzeugen.
Median-Antwort-Rate erreicht 34 % — Q4/2025
Über alle aktiven Workspaces gemessen, auf der ersten Outbound-Nachricht. Pre-Filter sortiert ~65 % der ursprünglichen Listen aus, Sonnet sieht nur noch das qualifizierte Drittel — Token-Budget pro Lead unter 0,9 Cent.
Eval-Suite & OpenRouter-Self-Hosting — Q1/2026
Interne Eval-Suite mit ~200 anonymisierten Profilen pro Sprache. OpenRouter angebunden für Self-Hosted-Qwen/DeepSeek bei rein deutschsprachigen Kampagnen — weitere Kostensenkung ohne spürbare Qualitätsdellen.
Mehr Details? Schreib mir.
Konkrete Fragen zur Pipeline, zum Multi-Model-Routing oder zum Multi-Tenant-Setup — am liebsten direkt im Gespräch.