Entwicklung eines Multi-Agenten-Stellenfinders: Pipeline, HyDE und Observabilität
Ein neunstufiger LangGraph-Pipeline, der Lebensläufe mit Stellen abgleicht, mit acht Gestaltungsoptionen bezüglich der HyDE-Auswertung, Modellzuweisung, Rate Limits und Überwachbarkeit.
Quellen: Agentic AI in Practice: A Case Study in Multi-Agent System Design
Agenten, agierende KI, Mehr-Agentensysteme: Das Vokabular ist überall zu finden, und jede Woche erscheint ein neues Modell, eine neue Framework oder ein neues Orchestrierungsmuster. Prompting, RAG, Aufruf von Tools, MCP, Speicherschichten – das Ökosystem entwickelt sich schneller, als die meisten Praktiker folgen können. Unter dem Lärm haben sich die grundlegenden Fragen nicht geändert:
- Wo sollte ein Problem in logische Teile aufgeteilt werden?
- Welche Aufrufe gehören zu einem LLM und welche sollten niemals ihm überlassen werden?
- Wie kann man sicherstellen, dass das System tatsächlich das tut, wofür es gehalten wird?
Eine neue Framework-Version macht die Dinge nicht einfacher. Um es konkret zu machen, verwendet diese Fallstudie ein Problem, das Millionen von Menschen haben: die richtigen Jobs in einer überwältigenden Menge an Stellenanzeigen zu finden. Sie entwirft dazu ein End-to-End-KI-System und nutzt dieses Design, um drei praktische Fragen zu beantworten. Was bedeutet „aggressiv“ im architektonischen Kontext? Wann fügen mehrere Agenten Wert hinzu und wann stellen sie nur eine Belastung dar? Und was macht ein KI-System beobachtbar, zuverlässig und für die Produktion geeignet?
Stellen suchen ist eigentlich keine Suche
Die meisten Menschen betrachten das Stellensuchen als eine Suchaufgabe. Tatsächlich handelt es sich dabei eher um eine Abgleichsaufgabe. Niemand sucht wirklich nach Stellenanzeigen, die bestimmte Schlüsselwörter enthalten. Die zugrundeliegende Frage ist schwieriger: Angesichts dieser Erfahrungen, dieser Fähigkeiten und dieser Karriererichtung – welche Stellenangebote passen wirklich dazu?
Jobbörsen handhaben das als Suche. Man gibt ein paar Begriffe ein, fügt einen Standort hinzu und hofft, dass etwas Relevantes auftaucht. Ein Lebenslauf hingegen enthält Jahre an Erfahrung, Fachwissen, technische Tiefe, übertragbare Fähigkeiten, Karriereschritte und Kontext – doch ein Suchfeld presst all das in wenige Worte und geht davon aus, dass übereinstimmende Wörter auch eine übereinstimmende Absicht bedeuten.
Jeder weiß, wie das abläuft:
- Das Durchscrollen von Hunderten von Stellenanzeigen auf verschiedenen Plattformen
- Die Beurteilung der Relevanz einer Anzeige nach der anderen
- Das Aufstoßen auf Duplikate, abgelaufene Anzeigen und gebrochene Links
- Die Frage, ob die ausgewählten Stellen überhaupt die richtigen waren
Die Langeweile ist nicht das eigentliche Problem. Der wahre Unterschied liegt zwischen dem, was die Vergangenheit eines Kandidaten verrät, und dem, was eine Stellenausschreibung tatsächlich verlangt – und diesen Unterschied zu überbrücken erfordert Interpretation, Kontext und Urteilsvermögen. Kurz gesagt: Es braucht logisches Denken, in dem große Sprachmodelle stark sind. Stellen Sie sich vor, ein System könnte ein Lebenslauf lesen, sinnvolle Karrierewege ableiten, offene Stellen finden und diese anhand der tatsächlichen Passgenauigkeit statt aufgrund von Schlagwortüberschneidungen bewerten. Das ist das Problem, für das dieses System entwickelt wurde.
Der Ablauf, Schritt für Schritt
Alles beginnt mit einer Aktion: Der Hochladen eines Lebenslaufs. Danach berührt niemand mehr das Suchfeld, scrollt durch die Liste oder entscheidet, auf welche Stellen sich beworben werden soll. Das System übernimmt und führt neun Schritte aus, wobei jeder Schritt eine bestimmte Aufgabe hat.
- Lebenslauf-Parser-Agent. Er handelt wie ein erfahrener Personalvermittler und wandelt den Lebenslauf in ein strukturiertes Profil um anstelle einer Liste von Schlüsselwörtern. Das Profil umfasst bisherige Arbeitsstellen, Fähigkeiten, Spezialgebiete, den Karriereweg sowie eine kurze, ATS-ähnliche Beschreibung, die alle nachfolgenden Agenten als die kanonische Beschreibung des Kandidaten verwenden. Modell: Claude Sonnet.
- Profil-Empfehlungs-Agent. Er schlägt zwei bis drei passende Stellenbezeichnungen vor, die zum Niveau, zum Fachgebiet und zu den Fähigkeiten des Kandidaten passen, zusammen mit Varianten von Suchanfragen für jede davon. Modell: Claude Haiku.
- Menschliche Bestätigungsstufe. Dies ist der einzige Punkt, an dem eine Person Entscheidungen trifft. Der Benutzer prüft die vorgeschlagenen Profile, wählt das passende aus, fügt gegebenenfalls Präferenzen bezüglich Standort und Berufserfahrung hinzu und bestätigt die Auswahl. Der Prozess wartet bis dahin – es sind keine Modelle beteiligt, nur menschliches Urteilsvermögen.
Das ergibt insgesamt neun Schritte, vier Aufrufe eines LLMs, eine menschliche Entscheidung sowie eine Gesamtbereitzeit von unter drei Minuten.
Die Technologiekarte
Das obige Diagramm zeigt jeden wesentlichen Bestandteil eines aktuellen AI-Stacks innerhalb dieses Pipelines. Jedes System ist eine Kombination aus verschiedenen Entscheidungen, weshalb die folgenden Abschnitte erläutern, was in Betracht gezogen wurde, was abgelehnt wurde und welche Kosten damit verbunden waren.
Acht Designentscheidungen
1. LangGraph statt CrewAI, AutoGen oder eines ReAct-Laufs
Die üblichen Kandidaten waren LangGraph, CrewAI und AutoGen; innerhalb von LangGraph gibt es außerdem eine weitere Unterscheidung zwischen einem gerichteten Graphen und einem ReAct-Lauf.
CrewAI legt Wert auf autonome Zusammenarbeit, wobei Rollenspieler-Agenten miteinander verhandeln und Aufgaben delegieren. AutoGen konzentriert sich auf konversationellen Mehr-Agenten-Dialog. Beide eignen sich für offene Arbeitsabläufe. Gleichzeitig bringen sie Koordinationsaufwände sowie Nichtdeterminismus mit sich, den ein fester Pipeline-Struktur nicht bewältigen kann.
ReAct-Schleifen sind besonders nützlich, wenn die Anzahl der Schritte im Voraus nicht bekannt ist – wie beispielsweise bei einem LLM, das im Internet surft und nicht vorhersagen kann, wie viele Suchanfragen nötig sind. Die Stellensuche funktioniert jedoch nicht so: Die Struktur des Problems legt die Schritte fest – Zerlegen vor Empfehlung geben, Suchen vor Filtern, Duplikatentfernung vor Einbetten. Im Laufe der Ausführung wird nichts neu entdeckt.
Ein gerichteter Graph passt perfekt dazu. Jeder Übergang ist explizit definiert, die Einmischung eines Menschen in den Prozess ist eine erstklassige Möglichkeit, und der Zustand wird durch ein gemeinsames Pydantic-Modell repräsentiert, das jeder Knoten lesen und schreiben kann. Wenn etwas fehlschlägt, ist der fehlerhafte Knoten sofort erkennbar.
2. Spezialisierte Agenten statt eines einzigen Mega-Prompts
Es ist verlockend, einen einzigen großen Prompt zu schreiben, der den Lebenslauf analysiert, Titel vorschlägt und Bewertungen ausgibt – außerdem ist so eine Implementierung schneller. Doch dieser Ansatz versagt auf unklare Weise, wodurch die Probleme sich verschärfen. Ein Fehler an einer Stelle führt überall zu Fehlern. Es ist unmöglich herauszufinden, welche Anweisung zu einem schlechten Ergebnis geführt hat; die Anpassung eines Teils birgt das Risiko von Rückschritten in einem anderen Bereich, und der Kontext füllt sich mit Anweisungen, die für die zu bewältigende Aufgabe irrelevant sind.
Separate Agenten vermeiden dieses Problem. Ein schwacher Bewertungsscore kann durch die Betrachtung des jeweiligen Promptes für die Bewertung allein debuggt werden. Jeder Agent verfügt über sein eigenes Testskript, sodass der Parser unabhängig vom gesamten Pipeline-System auf Rückschritte überprüft werden kann. Zudem können unterschiedliche Agenten an verschiedene Modelle weitergeleitet werden, wie in Entscheidung 6 gezeigt wird.
3. Ein menschlicher Kontrollmechanismus
Die meisten Anleitungen zu Agenten betrachten die menschliche Überprüfung als optionalen Feinschliff, etwas, das hinzugefügt wird, damit die Nutzer ein Gefühl der Beteiligung haben. Hier hingegen ist dieser Kontrollmechanismus eine zentrale architektonische Entscheidung.
Der Empfehlungsdienst bietet zwei oder drei Titel an, und das von dem Benutzer bestätigte Profil leitet jede weitere Phase: die Suchanfragen, die Filter sowie die Bewertung. Lässt man das System automatisch wählen, kann eine falsche Entscheidung alles verderben und so eine ordentlich gerankte Liste für ein Profil erstellen, das der Kandidat überhaupt nicht wollte. Keine andere Entscheidung im Prozess birgt so viel Risiko, und keine wird besser von einem Menschen getroffen, da Kandidaten Dinge über ihre eigene Richtung wissen, die ein Parser nicht herausfinden kann.
4. Ein Vorfilter vor dem Ranker
Reale Daten sind niemals sauber, und Einträge aus fünf APIs weisen vorhersehbare Probleme auf:
- Tote Links und 404-Fehler durch abgelaufene Einträge, die nie entfernt wurden
- Duplikate, da derselbe Job gleichzeitig über mehrere APIs angezeigt wird
- Umleitungen durch Aggregator-Seiten, bei denen eine URL auf der Startseite einer Stellenbörse landet und nicht direkt auf dem Eintrag
Das sind keine Randfälle. Es handelt sich dabei um den normalen Zustand der Daten externer APIs. Die Validierungs- und Deduplizierungsverfahren dienen dazu, den Datensatz vor dem Auftreten kostspieliger Probleme zu bereinigen, sodass das, was den semantischen Präfilter erreicht, gültig, einzigartig und echt ist.
Dann wird der Kostenfaktor wichtig. In den Produktivbetriebsabläufen macht der Rangierer 70 bis 80 Prozent der gesamten Ausgaben für LLMs aus. Der Parser kostet unabhängig davon, wie viele Aufgaben durchlaufen, fest 2,7 bis 3,0 ₹, und der Empfehlungsalgorithmus ebenfalls fest etwa 0,30 ₹. Der Rangierer variiert je nach Anzahl der an ihn übergebenen Aufgaben zwischen 3 und 11 ₹, wodurch die Gesamtkosten pro Lauf zwischen 6 und 14 ₹ liegen. Der Präfilter behält nur die Einträge bei, die am besten zum Kandidaten passen, sodass der Rangierer mit einem hochwertigen Datensatz arbeiten kann anstelle des störanfälligen Rohdatenoutputs von fünf API-Anfragen.
5. HyDE anstelle direkter Vergleiche
Der offensichtliche Ansatz besteht darin, die ATS-Zusammenfassung des Kandidaten einzubetten und sie mithilfe der Kosinusähnlichkeit mit jeder Stellenbeschreibung zu vergleichen. Das ist einfach, schnell und erfordert keine zusätzlichen Aufrufe eines LLMs. In den Tests waren die Ergebnisse enttäuschend.
Der Grund liegt in einer Unstimmigkeit im Embedding-Raum. Eine Kandidatenzusammenfassung wird als Erst-Person-Geschichte dargestellt, etwa „Habe ML-Pipelines implementiert, die Implementierung von Modellen übernommen und mit verschiedenen Teams zusammengearbeitet.“ Eine Stellenanzeige hingegen wird als Liste von Anforderungen in Dritter Person dargestellt, wie zum Beispiel „Erfahrung von mindestens 3 Jahren in ML, Kenntnisse in PyTorch und gute Kommunikationsfähigkeiten erforderlich.“ Selbst wenn beide dieselben Fähigkeiten beschreiben, landen die beiden Stile in unterschiedlichen Bereichen des Embedding-Raums, wodurch direkte Vergleiche echte Passungen unterschätzen.
HyDE umgeht dieses Problem, indem es eine andere Frage stellt: Wie würde die ideale Stellenbeschreibung für diesen Kandidaten aussehen? Ein LLM erstellt anschließend zwei hypothetische Beschreibungen auf der Grundlage des Lebenslaufs.
- JD1 ist domainbezogen formuliert, als würde ein Unternehmen aus dem genauen Fachbereich des Kandidaten jemanden mit dieser Erfahrung einstellen.
- JD2 konzentriert sich auf übertragbare Fähigkeiten, als wären fachliche Kenntnisse sekundär und allgemeine Fähigkeiten das Hauptkriterium.
Diese synthetischen Beschreibungen befinden sich im selben Bereich wie echte Stellenausschreibungen, da es sich um hypothetische Stellenbeschreibungen handelt. Der Vergleich mit echten Anzeigen ermöglicht eine semantische Übereinstimmung auf Augenhöhe. Jede echte Anzeige wird anschließend der synthetischen Beschreibung zugeordnet, der sie am nächsten kommt. Wenn sie JD1 näher ist, wird sie in Abschnitt 1, also zu Stellen im Fachbereich des Kandidaten, eingestuft. Wenn sie JD2 näher ist, wird sie in Abschnitt 2, also zu breiteren Möglichkeiten, eingestuft.
Eine Einschränkung blieb die ganze Zeit bestehen: nur allgemein einsetzbare Embeddings, keine domainspezifischen Modelle. Die Domänespezifität stammt vom HyDE-Inhalt, den das LLM in die synthetischen Beschreibungen einbaut, und nicht von der Wahl des Embedding-Modells. Dadurch bleibt das System für verschiedene Berufe nutzbar.
6. Verschiedene Modelle für verschiedene Agenten
Nicht jede Aufgabe erfordert dieselbe Rechenleistung. Der Parser und der HyDE-Generator kosten etwa 2,7 bis 3,0 sowie 0,50 pro Ausführung – unabhängig vom Volumen konstant. Ihre Qualität bestimmt alles, was danach folgt, denn eine schwache Analyse verfälscht das Profil und eine schlechte hypothetische Beschreibung beeinträchtigt die Passgenauigkeit der Embeddings, weshalb Sonnet die richtige Wahl ist.
Die Bewertung erfolgt pro Aufgabe im Ranker – es handelt sich dabei um die Stufe, deren Kosten mit dem Volumen ansteigen, und sie verbraucht bereits 70 bis 80 Prozent des Budgets. Ohne besser strukturierte Bewertungsmethoden würde Sonnet die Kosten dabei etwa verdreifachen. Haiku erledigt die Aufgabe hingegen effektiv. Hier ist die Routierung:
7. Eine Konfigurationsdatei für jede Einstellmöglichkeit
Agierende Systeme entwickeln irgendwann ein Problem bei der Anpassung. Das Wechseln eines Modells, das Anpassen einer Schwellenwert oder die Änderung einer Konkurrenzgrenze sollte nicht bedeuten, dass man in fünf Agenten-Dateien nach der richtigen Konstante suchen muss.
Dieses System verwendet eine einzige YAML-Datei, die alle Einstellmöglichkeiten im Pipeline-Verlauf enthält – dadurch sind keine Konstanten im Agentencodex fest codiert und es verbergen sich keine „Zauberzahlen“ in den Anweisungen. Es regelt Folgendes:
- Modell pro Agent. Das Ersetzen von Claude Haiku durch ein neueres Modell erfordert lediglich eine Änderung in einer Zeile.
semaphore_size: 4, batch_size: 4 und batch_delay_secs: 2, wie im Folgenden erläutert.8. Gleichzeitige Rangliste, beeinflusst durch Geschwindigkeitsbeschränkungen
Der ursprüngliche Rangieralgorithmus arbeitete sequenziell: eine Aufrufung des LLM, Wartezeit, dann der nächste Auftrag. Bei 40 Aufträgen und etwa 2,5 Sekunden pro Aufruf entspricht das 100 Sekunden Laufzeit. Die Pipeline-Daten bestätigen dies, wobei allein der Rangieralgorithmus etwa 95 Sekunden einer typischen Gesamtlaufzeit von 166 Sekunden in Anspruch nimmt.
Das gleichzeitige Senden aller 40 Anfragen scheint die Lösung zu sein, stößt aber auf die Rate-Limits von Anthropic. Der Zugriff auf Ebene 1 begrenzt die Anfragen pro Minute, wodurch 40 bis 60 gleichzeitige Anfragen sofort diese Grenze überschreiten und als 429-Fehler zurückkommen. Die erste Produktionsversion ohne jegliche Drosselung lieferte nur einen Teil der Ergebnisse: Die Aufgaben 1 bis 70 wurden bewertet, bevor die API aufhörte zu antworten.
Die Lösung besteht aus einem dreiteiligen Konzept zur Konkurrenzverwaltung, das vollständig über die Konfigurationsdatei gesteuert wird:
- Ein Semaphor (
semaphore_size: 4) begrenzt die gleichzeitig laufenden Anfragen. Vier Anfragen auf einmal liegen deutlich innerhalb der Grenzen von Ebene 1. - Durch Batching (
batch_size: 4) werden die Aufgaben in Gruppen zu je vier bearbeitet, wobei jede Gruppe fertig wird, bevor die nächste beginnt. - Eine Pausendauer zwischen den Gruppen (
batch_delay_secs: 2) sorgt für eine zweisekündige Pause, um gegenüber den plötzlichen Anfragemengen Puffer zu schaffen.
Der Vorteil: 60 Aufgaben in 15 Chargen werden in etwa 90 bis 95 Sekunden bearbeitet, was etwa viermal schneller ist als die sequenzielle Baseline bei derselben Anzahl an Aufgaben – ohne auf Grenzen zu stoßen.
Beobachtbarkeit
Ein System, das niemand beobachten kann, ist nur ein Wunschtraum, kein echtes System. Ein echter Vorfall zeigt das deutlich. Bei dem ersten vollständigen Produktivbetrieb fehlte auf der EC2-Instanz VOYAGE_API_KEY. Der HyDE-Vorfilter übersprang stillschweigend das Einbetten und leitete alle 89 Aufgaben an den Ranker weiter, wodurch bei Aufgabe 70 die Geschwindigkeitsbeschränkung erreicht wurde und nur eine teilweise Liste ausgegeben werden konnte. Ohne Beobachtbarkeit würde das wie zufälliges, rätselhaftes Verhalten erscheinen. Mit ihr dauerte es weniger als eine Minute, um die Ursache zu ermitteln.
Die Beobachtbarkeit funktioniert hier auf zwei Ebenen:
- LangSmith protokolliert jeden Aufruf eines LLM: die genaue Anfrage, die Antwort, die Latenz pro Aufruf sowie die Token-Zahlen. Es bietet eine mikrofeine Sicht auf das Denkverhalten und wird während der Entwicklung eingesetzt, um Anfrage-Regressionen frühzeitig zu erkennen, bevor sie den gesamten Prozess beeinträchtigen.
- MLflow speichert jeden Lauf mit der Latenz pro Agenten, der Gesamtkosten sowie den Token-Zahlen. Sein Artefakt
job_audit.jsonist das nützlichste Diagnoseinstrument – es enthält eine vollständige Aufzeichnung für jeden Job, der in den Prozess eingegangen ist: in welche HyDE-Kategorie er eingeteilt wurde, seinen Ähnlichkeitswert, welcher Filter ihn ausgeschlossen hat und warum, die Komponenten seines Passungswerts sowie seine endgültige Rangfolge.
Wie Reifegrad aussieht
Die Reife eines KI-Systems wird nicht danach gemessen, wie autonom es ist. Sie wird vielmehr dadurch bestimmt, inwieweit die Menschen verstehen, was es tut, warum es es tut und wo Fehler auftreten. Die Diskussionen über agierende KI sind an falschen Messkriterien ausgerichtet. Autonomie sorgt zwar für beeindruckende Demonstrationen, ist aber oft eine schlechte ingenieurtechnische Eigenschaft – schließlich ist es kostspielig, autonomes Verhalten zu beobachten und zu debuggen.
Für alle, die heute ein KI-System entwickeln, sind die relevanten Fragen nicht, wie agierend es ist oder wie viele „Agenten“ es hat. Stattdessen lauten sie:
- Können Sie beobachten, was es in jedem Schritt tut?
- Können Sie eine bestimmte Ausgabe ohne Einsicht in den Quellcode erklären?
- Können Sie es neu kalibrieren, wenn sich sein Verhalten verschiebt?
- Können Sie gute Leistung von stillschweigendem Versagen unterscheiden?
Ein System, das alle vier Kriterien erfüllt, ist ein funktionsfähiges ML-System. Alles andere ist lediglich ein Prototyp mit gutem Marketing.