PageRangers AI Suite: Multi-Modell-Pipelines für KI-Sichtbarkeit
Projekt-Übersicht
PageRangers ist eine SEO- und Online-Marketing-Software, die ich als Geschäftsführer verantworte und deren Architektur ich festlege. Die AI Suite ist der Teil des Produkts, der eine neue Frage beantwortet: Wie sichtbar ist eine Marke, wenn Menschen nicht mehr in Google suchen, sondern ChatGPT, Claude, Gemini oder Perplexity fragen?
Seit Ende 2024 ist daraus ein System aus mehreren LLM-Pipelines geworden. Es schickt definierte Fragen an die Modelle verschiedener Anbieter, wertet die Antworten auf Marken, Entitäten und zitierte Quellen aus, erzeugt mit einer mehrstufigen Pipeline neue, realistische Fragen für das Monitoring, findet inhaltliche Lücken gegenüber dem Wettbewerb und verbucht jeden einzelnen Modellaufruf mit seinen Kosten. Das Produkt wird von mehreren Entwicklern betreut; diese Fallstudie beschreibt die Architekturentscheidungen, die ich dafür getroffen habe, und die Lehren aus dem Betrieb.
Ausgangslage
Klassisches SEO-Monitoring misst Rankings: Position 3 für ein Keyword ist eine eindeutige, reproduzierbare Zahl. KI-Assistenten liefern keine Rankings, sondern Fließtext. Ob und wie eine Marke darin vorkommt, hängt vom Anbieter, vom Modell, von der Formulierung der Frage und davon ab, welche Webquellen das Modell bei seiner Suche heranzieht. Dieselbe Frage kann am Montag eine Marke empfehlen und am Dienstag nicht.
Daraus ergaben sich vier Anforderungen:
- Messung über mehrere Anbieter. Eine Aussage über „KI-Sichtbarkeit“ ist nur belastbar, wenn sie nicht von einem einzigen Modell abhängt.
- Gute Fragen. Ein Monitoring ist nur so aussagekräftig wie die Fragen, die es stellt. Nutzer bringen selten eine fertige Liste mit; die meisten haben Keywords, aber keine Vorstellung davon, wie Menschen mit einem Assistenten sprechen.
- Strukturierte Auswertung. Aus Fließtext müssen Marken, Positionen, Entitäten und Quellen werden, die sich über Wochen vergleichen lassen.
- Kostenkontrolle. Jede Frage an jeden Anbieter kostet Geld, jede Auswertung noch einmal. Ohne Verbuchung pro Aufruf lässt sich weder ein Preismodell kalkulieren noch ein Fehler erkennen, der still Kosten verursacht.
Architektur
Die AI Suite besteht aus zwei großen Abläufen, die über die Datenbank lose gekoppelt sind. Der Monitoring-Ablauf fragt die Anbieter ab und wertet die Antworten aus. Die Prompt-Research erzeugt die Fragen, die das Monitoring stellt. Beide schreiben jeden Modellaufruf in ein zentrales Kostenprotokoll.
flowchart TD
subgraph Research["Prompt-Research"]
B["Markenprofil aus Projekt und Website"] --> P["Abdeckungsplan: Themen, Zielgruppen, Bereiche"]
P --> G["Generierung je Zelle, parallel"]
G --> V["LLM-Verifier in Batches"]
V --> D["Embedding-Deduplizierung"]
D --> L["Prompt-Bibliothek"]
end
L --> O["Observer: getrackte Prompts"]
subgraph Monitoring["Monitoring"]
O --> X["LLM-Executer mit Reservierung und Parallelität"]
X --> A1["OpenAI"]
X --> A2["Anthropic"]
X --> A3["Gemini"]
X --> A4["Perplexity"]
A1 --> R["Antworten mit Zitaten und Suchanfragen"]
A2 --> R
A3 --> R
A4 --> R
R --> RP["Response-Processor: Marken, Entitäten"]
end
G --> C["Kostenprotokoll je Aufruf"]
V --> C
X --> C
RP --> C
C --> CB["Notaus bei reinen Fehlläufen"]
Im Backend ist das C# mit Microsoft Semantic Kernel für die strukturierten Aufrufe, ergänzt um eigene Provider-Clients für die Monitoring-Abfragen. Das Frontend ist eine Angular-19-Anwendung mit Modulen für Marken- und Domain-Analysen, Anbietervergleich, Kostenübersicht, die vom Modell selbst ausgeführten Suchanfragen und die Prompt-Bibliothek.
Technische Umsetzung
Monitoring über vier Anbieter
Ein Observer ist eine getrackte Frage mit einer Anbieterdefinition. Der Executer zieht fällige Observer, ruft je nach Anbieter OpenAI, Anthropic, Perplexity oder Gemini auf und normalisiert die Antworten in ein einheitliches Format: Antworttext, Token-Verbrauch, Metadaten, zitierte Quellen mit Titel und Position sowie die Suchanfragen, die das Modell bei seiner Websuche selbst gestellt hat. Diese sogenannten Fan-outs liefern derzeit nur OpenAI und Gemini aus; für die Analyse sind sie wertvoll, weil sie zeigen, nach welchen Begriffen ein Assistent sucht, bevor er antwortet.
Zwei Entscheidungen haben den Durchsatz bestimmt. Erstens laufen Observer nebenläufig, standardmäßig acht gleichzeitig. Die Wartezeit ist fast ausschließlich Modell-Latenz von gemessen 20 bis 70 Sekunden pro Observer; sequenziell zu arbeiten hätte den Rückstand um genau diesen Faktor verlängert. Zweitens werden Observer in einer einzigen SQL-Anweisung gezogen und reserviert, mit dem Warteschlangenmuster UPDLOCK, READPAST. Zwei parallel laufende Verarbeiter überspringen damit gegenseitig reservierte Zeilen, statt aufeinander zu warten oder dieselbe Frage doppelt zu bezahlen. Die Reservierung ist eine Lease: Stirbt ein Worker mitten im Lauf, verfällt sie, und der Observer wird beim nächsten Durchgang erneut gezogen.
Auswertung der Antworten
Jede Antwort durchläuft danach den Response-Processor, mit vier parallelen Analysen, weil pro Antwort mehrere Modellaufrufe anfallen. Marken werden zweistufig erkannt: deterministisch per normalisierter Textsuche nach den bekannten eigenen und fremden Marken mit absoluter und relativer Position im Text, zusätzlich per Modell, das auch Marken findet, die niemand vorab eingetragen hat. Eine dritte Analyse extrahiert Entitäten mit Typ.
Alle diese Aufrufe nutzen strukturierte Ausgaben: Das JSON-Schema wird aus dem C#-Ergebnistyp erzeugt, die Temperatur steht auf 0. Ein Detail aus dem Betrieb hat hier eine feste Regel hinterlassen. gpt-4o-mini geriet gelegentlich in eine Wiederholschleife und lief bis an sein Ausgabelimit, was länger dauerte als der HTTP-Timeout. Seitdem hat jeder Aufruf ein explizites MaxTokens, abgeleitet aus gemessenen Werten: Die größte echte Entitäten-Ausgabe lag bei 6050 Token, Markenantworten im Schnitt bei 32. Scheitert das Parsen, protokolliert der Code den FinishReason mit, damit ein zu eng gesetztes Limit nicht still Ergebnisse verschluckt.
Fehlgeschlagene Analysen bekommen einen Zwischenzustand. Eine Antwort steht während der Analyse auf processing, bei einem Fehler geht sie zurück auf new und wird bis zu einer festen Zahl von Versuchen erneut verarbeitet. Bleibt sie zu lange in processing hängen, etwa nach einem Pod-Neustart, wird sie automatisch wieder gezogen. So kann eine gescheiterte Analyse nicht still als erledigt im System landen.
Prompt-Research als mehrstufige Pipeline
Der aufwendigste Teil ist die Prompt-Research. Sie erzeugt pro Projekt eine dauerhafte, facettierte Bibliothek realistischer Fragen in fünf Schritten:
- Markenprofil. Aus den Projektdaten werden eigene Marken, Wettbewerber und Wettbewerber-Domains gesammelt, dazu ein Auszug der Startseite als Markdown und die zuletzt getrackten Fragen.
- Abdeckungsplan. Ein Planungsmodell (GPT-4o) leitet daraus eine Kurzbeschreibung der Marke ab, sechs bis zehn Themen des Bedarfsraums mit Gewichtung, drei bis sechs Zielgruppen und eine Einschätzung, welche von sechs festen Bereichen relevant sind: Produkte und Kauf, Marke und Vergleich, Service, Reputation, Arbeitgeber und lokaler Bezug.
- Generierung je Zelle. Der Plan wird in Zellen zerlegt, im Kern Thema mal Funnel-Stufe. Ein günstigeres Modell (GPT-4o-mini) erzeugt die Fragen jeder Zelle, sechs Zellen parallel.
- Qualitätsprüfung. Ein LLM-Verifier prüft die Kandidaten in Batches zu je 40 und verwirft unnatürliche, anderssprachige oder inhaltsleere Fragen.
- Deduplizierung. Embeddings sortieren Beinahe-Duplikate aus, auch gegenüber dem, was das Projekt bereits trackt.
Die festen Facetten (Bereich, Funnel-Stufe, Intent) sind bewusst nicht vom Modell erfunden, sondern als Taxonomie im Code hinterlegt. Nur Themen und Zielgruppen erzeugt die KI pro Projekt. Damit haben Filter, Assistent und automatische Tags projektübergreifend dieselben Schlüssel, und jede Modellausgabe wird beim Normalisieren auf gültige Werte zurückgeführt.
Weil Prüfung und Duplikatfilter einen Teil aussortieren, produziert die Pipeline bewusst mehr, als der Nutzer angefordert hat, und verteilt die Menge nach Gewichtung auf die Zellen:
var target = Math.Clamp(p.TargetCount, 20, MaxTargetCount);
// Überproduktion, weil Qualitätsprüfung und Duplikatfilter rund ein Viertel aussortieren.
var toGenerate = (int)Math.Ceiling(target * 1.35);
// ...
var weightSum = cells.Sum(c => c.Count);
foreach (var c in cells)
c.Count = Math.Max(2, (int)Math.Round((double)toGenerate * c.Count / weightSum));Für die Deduplizierung nutze ich BGE-M3-Embeddings. Ein Kandidat fliegt raus, wenn seine Kosinus-Ähnlichkeit zu einer bereits getrackten Frage, zu einem Bibliothekseintrag oder zu einem schon akzeptierten Kandidaten bei 0,9 oder darüber liegt:
var tooSimilar =
existing.Any(e => e.Length == c.Embedding.Length
&& Embedder.CosineSimilarity(e, c.Embedding) >= DuplicateThreshold)
|| chosen.Any(e => Embedder.CosineSimilarity(e, c.Embedding) >= DuplicateThreshold);
if (tooSimilar) continue;
chosen.Add(c.Embedding);
result.Add(c);Die Längenprüfung ist kein Zufall: Ältere Einträge können mit einem anderen Embedding-Modell und damit anderer Dimension gespeichert sein. Statt sie fälschlich zu vergleichen, werden sie übergangen.
Eine Designentscheidung betrifft die Fehlertoleranz. Fällt ein Verifier-Batch aus, bleiben dessen Kandidaten erhalten, denn die Prüfung ist ein Filter und kein Erzeuger. Fällt dagegen die Generierung einer Zelle aus, fehlt nur diese Zelle; erst wenn gar nichts erzeugt wurde, bricht der Lauf ab. Der Fortschritt läuft im Hintergrund und steht in der Datenbank, das Frontend fragt ihn alle drei Sekunden ab. Läufe, die 30 Minuten ohne Abschluss stehen, gelten als abgebrochen.
Daneben gibt es einen Keyword-Modus, der importierte Suchbegriffe in Gruppen zu je zwölf in natürliche Fragen übersetzt. Dort zählen als Beleg nur die tatsächlich importierten Keywords, nicht Wörter, die das Modell ergänzt hat. Auf der Bibliothek setzen weitere Funktionen auf: ein Assistent, der per Maximal-Marginal-Relevanz ein ausgewogenes Set nach Bereichen zusammenstellt, eine Nachfrageschätzung über das Google-Suchvolumen der Seed-Keywords und automatische Tags für Thema, Funnel-Stufe, Bereich, Marke und Zielgruppe.
Content-Gaps und Themenextraktion
Für die Content-Gap-Analyse lädt das System Seiten der Wettbewerber und optional eine eigene URL als Markdown, extrahiert Themen und lässt ein Modell die Lücken zwischen beiden synthetisieren. Für diese Synthese setze ich Claude Sonnet ein, für die Massenaufgaben GPT-4o-mini. Diese Aufteilung zieht sich durch die ganze Suite: Planung und Synthese bekommen ein stärkeres Modell, die vielen kleinen Aufrufe ein günstiges.
Betrieb
Kostentracking pro Aufruf
Jeder Modellaufruf wird mit Anbieter, Modell, Verarbeitungsschritt, Projekt, Modul und Token-Zahlen protokolliert. Die Preise stehen an genau einer Stelle im Code, damit Kostenschätzung und Ist-Verbuchung nicht auseinanderlaufen. Das Tracking ist „best effort“: Ein Fehler beim Verbuchen darf nie den eigentlichen Ablauf abbrechen. In der Prompt-Research werden die Verbräuche parallel gesammelt und erst danach geschrieben, weil der Datenbankkontext keinen parallelen Zugriff erlaubt.
Die Preistabelle prüft Modelle vom spezifischsten zum allgemeinsten Namen und fällt erst danach auf einen Preis je Anbieter zurück. Die Reihenfolge ist entscheidend, denn ein allgemeiner Treffer würde ein günstiges Modell sonst mit dem Preis eines großen verbuchen:
// Model-specific (most specific first).
if (m.Contains("gpt-5-nano")) return (0.05, 0.40);
if (m.Contains("gpt-5-mini")) return (0.25, 2.00);
if (m.Contains("gpt-5")) return (1.25, 10.00);
// ...
// Embeddings kennen keine Output-Tokens. Ohne diese Zeilen griffe für
// text-embedding-3-small der 125-fache Preis.
if (m.Contains("text-embedding-3-small")) return (0.02, 0.00);Notaus auf Job-Ebene
Manche Fehler betreffen nicht einen einzelnen Observer, sondern alle gleichzeitig, etwa ein ungültiger Zugang bei einem Anbieter. Ein Backoff je Observer würde einen solchen Ausfall nur bremsen. Deshalb gibt es einen Notaus auf Job-Ebene: Liefern mehrere Läufe hintereinander ausschließlich Fehlschläge, schaltet sich der Job selbst ab und stellt keine weiteren Anfragen, bis er manuell wieder aktiviert wird. Ausgelöst wird er bewusst nur bei null Erfolgen. Solange irgendetwas durchkommt, gilt die Verarbeitung als gesund, und einzelne Fehler gehören zum Betrieb. Wird der Job von Hand wieder eingeschaltet, beginnt die Zählung neu, damit ihn der erste Fehlschlag nach der Reaktivierung nicht sofort wieder abschaltet.
Entwicklungs-Cache
Für die Entwicklung gibt es einen dateibasierten Cache für Modellantworten. Ohne ihn kostet jeder Reload einer Oberfläche echtes Geld und liefert wegen des Samplings jedes Mal ein anderes Ergebnis. In der Produktion ist er abgeschaltet, und der Cache-Schlüssel enthält eine Prompt-Version, damit geänderte Prompts keine alten Antworten zurückbekommen.
Ergebnis
Die Entwicklung der AI Suite begann Ende 2024, seitdem wird sie laufend erweitert. Technisch hat sie drei Dinge erreicht, die zu Beginn offen waren:
- Antworten von vier Anbietern landen in einem einheitlichen Datenmodell mit Marken, Positionen, Entitäten, zitierten Quellen und den Suchanfragen der Modelle und sind damit über die Zeit vergleichbar.
- Die Prompt-Research übernimmt Arbeitsschritte, die vorher manuell erledigt wurden: Fragen für das Monitoring formulieren, nach Zielgruppen und Kaufphasen ordnen und Dubletten aussortieren. Jeder Lauf meldet transparent, wie viele Kandidaten erzeugt, bei der Prüfung verworfen und als zu ähnlich aussortiert wurden.
- Jeder Modellaufruf ist mit seinen Kosten nachvollziehbar, und ein systemweiter Ausfall stoppt sich selbst, statt unbemerkt Anfragen zu erzeugen.
Was ich dabei gelernt habe
- Ein Ausgabelimit ist eine Sicherheitsvorkehrung, kein Tuning-Parameter. Ohne
MaxTokenskann ein kleines Modell in eine Schleife geraten und einen Timeout auslösen, der wie ein Netzwerkfehler aussieht. Die Grenze sollte aus gemessenen Ausgabelängen abgeleitet werden. - Fehlertoleranz hängt von der Rolle eines Schritts ab. Ein ausgefallener Filter darf Kandidaten durchlassen, ein ausgefallener Erzeuger darf nicht still leere Ergebnisse liefern. Diese Unterscheidung muss im Code explizit sein.
- Kostenberechnung braucht dieselbe Sorgfalt wie Abrechnung. Ein Fallback auf Provider-Ebene ist bequem, verbucht ein neues Modell aber mit einem pauschalen Preis, der weit danebenliegen kann. Neue Modelle gehören in die Preistabelle, bevor sie produktiv genutzt werden.
- Feste Taxonomie, freie Inhalte. Was gefiltert und verglichen werden soll, gehört in den Code. Was projektspezifisch ist, darf das Modell erzeugen. Die Mischung macht die Ausgaben stabil, ohne sie starr zu machen.
- Nebenläufigkeit braucht Reservierungen. Sobald mehrere Worker dieselbe Warteschlange lesen, entscheidet die Reservierung in einer einzigen Anweisung darüber, ob Aufträge doppelt bezahlt oder verloren werden.
Technologien
- Backend: C# und .NET, Entity Framework, SQL Server mit Warteschlangenmuster per
UPDLOCK/READPAST - LLM-Orchestrierung: Microsoft Semantic Kernel mit strukturierten Ausgaben aus C#-Typen, eigene Provider-Clients für das Monitoring
- Modelle: OpenAI (GPT-4o, GPT-4o-mini und neuere), Anthropic Claude, Google Gemini, Perplexity
- Embeddings: BGE-M3 für Ähnlichkeit und Deduplizierung
- Externe Daten: Suchvolumen für die Nachfrageschätzung der Seed-Keywords
- Frontend: Angular 19 mit Tailwind CSS
- Betrieb: Hintergrund-Jobs mit Notaus, Lease-basierte Reservierung, Kostenprotokoll pro Modellaufruf