Parallel arbeitende LangGraph-Agenten, die Pull-Requests über FastAPI-Webhooks überprüfen.
Wie ein webhook, eine Redis-Queue und vier LangGraph-Agenten eine Pull-Request in etwa 30 Sekunden in eine bewertete, strukturierte KI-Überprüfung umwandeln, wobei ngrok für lokale Tests verwendet wird.
Quellen: Building a Multi-Agent PR Code Review System With LangGraph, FastAPI, Webhooks, and Docker
Jeder, der bereits eine Pull-Request erstellt hat, kennt das Warten. Eine Funktion ist fertiggestellt, der Code wird hochgeladen – danach folgen zwei Stunden, ein ganzer Tag oder sogar länger. Wenn schließlich ein Teamkollege den Code prüft, gibt es Dutzende von Kommentaren, von denen die Hälfte Probleme betrifft, die das Software-System bereits hätte erkennen können: eine hardcodierte API-Schlüssel, eine Funktion mit dem Namen x, eine SQL-Abfrage, die anfällig für Injection-Angriffe ist. Der Autor behebt alles, lädt den Code erneut hoch und wartet wieder.
Die Code-Review an sich ist unerlässlich, daher liegt der Kritikpunkt nicht darin. Die Frustration entsteht dadurch, dass so viel Feedback in der ersten Prüfung mechanisch ist und immer wieder dieselben Problemtypen auftauchen. Die Idee hinter diesem System ist es, einer KI zu ermöglichen, alle offensichtlichen Fehler sofort zu erkennen, damit menschliche Prüfer ihre Zeit auf Architektur und Logik konzentrieren können, wo tatsächlich menschliches Urteilsvermögen benötigt wird. Es funktioniert besser, als man erwarten könnte.
Warum mehrere Agenten besser sind als einer
Das naive Design sendet den PR-Unterschied an ein Modell mit der Anweisung, ihn zu überprüfen. Das ist für kleine Änderungen in Ordnung. Wenn die PRs größer werden, verliert ein Modell, das gleichzeitig über Sicherheit, Leistung und Codequalität nachdenken soll, den Fokus, wodurch die Ergebnisse schlechter werden.
Spezialisierung behebt dieses Problem. Geben Sie jedem Agenten eine einzige Aufgabe: Einer soll nur über Sicherheit nachdenken, ein anderer nur über Leistung, ein weiterer nur über Codequalität, und ein vierter soll die drei Berichte zusammenfassen und eine klare, professionelle Bewertung erstellen. Dieses Mehr-Agenten-Modell liefert deutlich bessere Ergebnisse als ein allgemeinistischer Agent.
Das Gesamtdesign, bei dem jede Komponente eine einzige Verantwortung hat:
You open a Pull Request on GitHub
│
▼
GitHub fires a webhook
│
▼
FastAPI receives it instantly
└── Verifies HMAC signature
└── Pushes job to Redis queue
└── Returns 202 to GitHub ✅
│
▼
ARQ Worker picks up the job
│
▼
LangGraph Pipeline starts
│
┌─────────┼─────────┐
▼ ▼ ▼
Agent 1 Agent 2 Agent 3
Quality Security Performance
│ │ │
└─────────┼─────────┘
▼
Agent 4
Final Reviewer
│
▼
Comment posted on your PR ✅
(in under 30 seconds)
Schritt 1: Der GitHub-Webhook
Alles beginnt mit einem Webhook. Wenn eine Pull-Request erstellt oder aktualisiert wird, sendet GitHub einen HTTP POST-Anfragen an eine von Ihnen konfigurierte URL. In dieser Anfrage sind die PR-Nummer, der Titel, der Autor, das Repository sowie die auslösende Aktion enthalten. Ein FastAPI-Server lauscht an dieser URL.
Die erste Aktion des Servers auf jede Anfrage besteht darin, die Signatur zu überprüfen. GitHub signiert jeden Payload mit einem HMAC-SHA256-Hash unter Verwendung eines von Ihnen definierten Geheimnisses. Falls es keine Übereinstimmung gibt, wird die Anfrage sofort abgelehnt – so können keine falschen PR-Ereignisse an den Endpunkt gesendet werden.
Die nächste Entscheidung ist entscheidend: Der Server beginnt die KI-Überprüfung nicht sofort. Er legt eine Aufgabe in eine Redis-Warteschlange und antwortet GitHub innerhalb von weniger als einer Sekunde mit 202 Accepted. Der Grund dafür ist, dass GitHub eine Antwort über den Webhook innerhalb von 10 Sekunden erwartet, während eine vollständige Überprüfung mit drei parallelen LLM-Aufrufen 25 bis 30 Sekunden dauert. Eine Überprüfung direkt im Text würde dazu führen, dass GitHub denkt, der Server habe versagt, und erneut versucht, die Überprüfung durchzuführen – dadurch würde der Pull Request mehrmals mit doppelten Kommentaren überprüft. Eine Aufgabenschlange löst dieses Problem vollständig, da GitHub schnell eine Antwort erhält und die eigentliche Arbeit im Hintergrund stattfindet.
Schritt 2: ngrok für die lokale Entwicklung
Während der lokalen Entwicklung läuft der FastAPI-Server unter localhost:8000, auf den GitHub von der Internetseite aus nicht zugreifen kann. ngrok schließt diese Lücke, indem es einen sicheren Tunnel zwischen einer öffentlichen URL und dem lokalen Rechner erstellt. Mit einem Befehl kann man es starten:
ngrok http 8000
Es gibt sofort eine öffentliche HTTPS-Adresse zurück, wie zum Beispiel:
https://abc123.ngrok-free.app
Fügen Sie diese Adresse in die GitHub-Webhook-Einstellungen ein, damit GitHub Ereignisse direkt auf den Laptop übertragen kann. Jedes Mal, wenn ein PR eröffnet wird, wird die Anfrage von GitHubs Servern über ngroks Server an die lokale FastAPI-App gesendet. Im Terminal erscheint der gesamte Austausch als eine einzige Zeile:
23:03:02 POST /api/webhook 202 Accepted ✅
Eine Zeile, darunter eine weitere – und GitHub ist zufrieden, während die eigentliche Arbeit im Hintergrund beginnt. Eine Warnung: Die kostenlose Version von ngrok generiert bei jedem Neustart eine neue URL, sodass die GitHub-Webhook-URL jedes Mal aktualisiert werden muss.
Schritt 3: Der LangGraph-Pipeline
Dies ist das Herzstück des Systems. LangGraph ist ein Framework für Zustandsbasierte, mehragentige Workflows. Agenten werden zu Knoten in einem Graphen, Kanten verbinden sie miteinander und gemeinsamer Zustand fließt zwischen ihnen hin und her. Stellen Sie sich ein Flussdiagramm vor, bei dem jede Kasteneinheit ein KI-Agent ist und die Pfeile angeben, welche Daten wohin und in welcher Reihenfolge übertragen werden.
Gemeinsamer Zustand
Sie alle lesen von und schreiben in ein gemeinsames Zustandsobjekt ein, das die PR-Nummer und Repository-Details, den heruntergeladenen Diff mit den tatsächlichen Codeänderungen, die Überprüfungsergebnisse jedes Agenten sowie den endgültigen, synthetisierten Kommentar enthält. Dieser Zustand wird im Graphen wie ein Staffelstab in einem Staffellauf weitergegeben, wobei jeder Agent seinen Teil hinzufügt, bevor er ihn weiterleitet.
Node 0: PR herunterladen
Ein spezieller Node läuft vor allen Agenten und fragt die GitHub-API nach dem Titel, dem Autor und der Branch der PR sowie nach dem vollständigen Diff jeder geänderten Datei. Er wandelt all das in einen übersichtlichen Textstring um, den die LLMs lesen können, und der gleiche formatierte Diff wird an jeden der Überprüfer weitergeleitet.
Die parallele Verteilung: Agenten 1, 2 und 3
Nach dem Herunterladen teilt sich der Graph gleichzeitig auf drei Agenten auf. Sie erhalten denselben Diff, arbeiten zur gleichen Zeit und wissen voneinander nichts.
Der Code-Qualitäts-Agent existiert vollständig in seiner eigenen Welt. Sein Systemprompt befasst sich mit Lesbarkeit, Namenskonventionen, Verstößen gegen das DRY-Prinzip, Fehlerbehandlung und Wartbarkeit, und er gibt strukturierte JSON-Daten zurück, die eine Bewertung von 10 Punkten sowie eine Liste spezifischer Probleme enthalten – jeweils mit Dateinamen, Zeilennummer und vorgeschlagener Korrektur.
Der Sicherheits-Agent sucht ausschließlich nach Schwachstellen: SQL-Injection durch ungesäuberte Eingaben, in Code festgeschriebene Schlüssel, Passwörter oder Tokens, fehlende Authentifizierungsprüfungen sowie sensible Daten in Protokollen. Er weiß nichts über Leistung oder Stil.
Der Leistungs-Agent denkt nur an Effizienz: N+1-Datenbankabfragemuster, verschachtelte Schleifen mit einer Komplexität von O(n²) oder schlimmer, blockierende IO-Aufrufe innerhalb asynchroner Funktionen sowie fehlende Indizes oder Caching-Möglichkeiten.
Parallelität ist für die Zeitdauer entscheidend. Wenn sie nacheinander ausgeführt werden, benötigen die drei Agenten insgesamt 60 bis 90 Sekunden. Wenn sie gemeinsam laufen, sind sie in etwa 7 bis 12 Sekunden fertig – das ist die Zeit des langsamsten einzelnen Agenten und nicht die Summe aller drei.
Der Fan-in: Agent 4
Der endgültige Prüfer wartet automatisch, bis alle drei Spezialisten fertig sind. LangGraph übernimmt diese Synchronisierung, sodass keine Wartungs- oder Abfragenlogik geschrieben werden muss. Wenn die drei Berichte als strukturiertes JSON eintreffen, führt Agent 4 eine Aufgabe aus und schreibt den endgültigen Prüfkommentar in Markdown.
Agent 4 führt keine Analyse durch. Er prüft den Code niemals erneut und kombiniert sowie formatiert lediglich das, was die Spezialisten berichtet haben. Das ist beabsichtigt: Auch wenn seine Formulierungen etwas unpräzise sind, bleiben die darunterliegenden Erkenntnisse genau so, wie sie von den Spezialisten ermittelt wurden. Sein Kommentar beginnt mit einem Gesamtfazit sowie einer Punktzahl, die der Durchschnitt der Punktzahlen der drei Agenten ist, fasst anschließend zusammen, was jeder Agent festgestellt hat, und endet mit einer Liste „Muss vor dem Merge repariert werden“, die sich auf kritische und hochgradig ernste Probleme beschränkt.
Eine Fallstrick in Zuständen der Parallelität
Ein subtiler technischer Aspekt kann leicht übersehen werden. Sobald die parallelen Agenten ihre Arbeit abgeschlossen haben und in den gemeinsamen Zustand schreiben, muss jeder von ihnen nur den Schlüssel zurückgeben, den er besitzt. Wenn jeder Agent das gesamte Zustandsobjekt zurückgeben würde, erhält LangGraph gleichzeitig drei kollidierende Kopien jedes gemeinsamen Feldes und wirft einen InvalidUpdateError aus. Die Lösung ist einfach, aber nicht offensichtlich: Fügen Sie zu den Feldern, in die die parallelen Agenten schreiben, einen Annotated Reducer hinzu und lassen Sie jeden Agenten nur seinen eigenen Ausgabewert zurückgeben. Man lernt dies erst, wenn man auf diesen Fehler stößt – und die meisten LangGraph-Tutorials erwähnen ihn nie.
Schritt 4: die Ausgabe
Der Beweis liegt in einem Test. Eine Python-Datei mit vier absichtlich gestellten Problemen, einem fest codierten Geheimnis, einer SQL-Injection-Lücke, einem verschachtelten Loop mit Komplexität O(n²) sowie schlechten Namenskonventionen wurde in einen Branch gepusht und als Pull Request eingereicht. Bereits 27 Sekunden später erschien eine Überprüfung zum PR. Dies war der Code, der eingefügt wurde:
import sqlite3
# Hardcoded secret — security agent should catch this
API_KEY = "sk-prod-supersecretkey123"
def get_user(user_id):
conn = sqlite3.connect("users.db")
# SQL injection — security agent should catch this
query = f"SELECT * FROM users WHERE id = {user_id}"
return conn.execute(query)
def process(users):
# O(n²) nested loop — performance agent should catch this
for user in users:
for item in users:
print(user, item)
# Bad naming — quality agent should catch this
def x(a, b, c):
return a + b + c
Und das ist es, was das System im PR veröffentlicht hat:
## 🤖 AI Code Review
**Overall Verdict:** ❌ REJECTED
**Score:** 2.33/10
---
### 📋 Code Quality
Score: 2/10 | 8 Issues Found
Function naming is completely unclear — x, a, b, c give no
indication of purpose. No error handling on database operations.
No docstrings or type hints on any function.
### 🔒 Security
Score: 2/10 | 4 Critical Vulnerabilities
Hardcoded API key on line 3 exposes credentials in version
control — CRITICAL. SQL query on line 9 directly interpolates
user input, creating a SQL injection vulnerability — CRITICAL.
### ⚡ Performance
Score: 3/10 | 4 Issues Found
Nested loop in process() creates O(n²) complexity — will become
extremely slow as the users list grows. Database connection is
opened but never closed, creating a connection leak.
---
### 🚨 Must Fix Before Merge
- Remove API_KEY hardcoding — use environment variables instead
- Parameterize the SQL query to prevent injection attacks
- Refactor nested loop — use set operations or single pass
- Close database connections properly or use a context manager
---
Great effort on the overall structure! Addressing these critical
issues will significantly improve the security and reliability
of this code. Looking forward to the revised version. 🙌
Bereits 27 Sekunden nach der Erstellung des Pull Requests identifizierte die Überprüfung vier konkrete Problemkategorien mit spezifischen Zeilenreferenzen sowie Vorschlägen zur Behebung. Dabei war kein Mensch beteiligt und es musste nicht gewartet werden – es gab sofort strukturierte, umsetzbare Rückmeldungen.
Lokale Ausführung
Alles beginnt mit einem einzigen Docker-Befehl: Es werden Umgebungsvariablen gesetzt, ein GitHub-Token erstellt und der webhook konfiguriert. ngrok verbindet den lokalen Server mit GitHub, wodurch ein Test-Pull Request zeigt, wie die Überprüfung in Echtzeit angezeigt wird. Der Wechsel zwischen Claude und OpenAI erfordert lediglich eine Umgebungsvariable, und die Einrichtungsschritte sind im README des Repositoriums dokumentiert.
Lektionen aus dem Aufbau
Spezialisiertere Agenten übertriffen Allrounder. Eine Aufgabe pro Agent führt zu präziseren, gezielteren Ergebnissen, da der Sicherheitsagent nicht von Stilaspekten des Codes abgelenkt wird und der Leistungsagent keine Tokens für Variablennamen verbraucht.
Die Auftragswarteschlange ist Teil der Architektur und keine Option. GitHubs 10-Sekunden-Timeout ist streng, und ohne Redis sowie einen Hintergrundprozess werden fehlgeschlagene Lieferungen erneut versucht und es stapeln sich doppelte Überprüfungen. Viele Tutorials überspringen diesen Aspekt, doch gerade er sorgt für Zuverlässigkeit des Systems.
Parallelisierte Ausführung ändert die Rechenweise. Drei sequenzielle Aufrufe à 10 Sekunden benötigen mindestens 30 Sekunden, während drei parallele Aufrufe nur 10 Sekunden brauchen. LangGraph macht die Parallelisierung einfach umsetzbar, und der Unterschied ist enorm.
Eine strukturierte Ausgabe macht Agenten für die Produktion bereit. Jeder Agent gibt ein striktes JSON-Schema zurück, und falls die Parsung fehlschlägt, scheitert der Auftrag sauber, ohne dass etwas an GitHub gesendet wird. Das System liefert entweder eine gute Überprüfung oder gar nichts – niemals Unbrauchbares.
Von Anfang an den LLM abstrahieren. Ein Factory-Muster, das durch eine Umgebungsvariable zwischen Claude und OpenAI wechselt, dauert etwa zehn Minuten zum Aufbau und spart später Stunden an Refactoring, da Modelle frei getestet und ihre Qualität verglichen werden kann.
Welche Auswirkungen es auf die Code-Review-Prozesse hat
Code-Reviews werden nicht verschwinden, und bei Architekturentscheidungen, Geschäftslogik sowie feinen Design-Kompromissen kann nichts einen Menschen ersetzen. Die mechanische Erstprüfung ist jedoch eine andere Sache: Hartecodierte Geheimnisse, SQL-Injektionen, quadratische Schleifen sowie unklare Namen können automatisiert werden, wodurch menschliche Reviewer für Aufgaben frei werden, die menschliches Verständnis erfordern. Dieses System erkennt offensichtliche Probleme in etwa 30 Sekunden, sodass Teammitglieder sich auf die wichtigen konzentrieren können.