Ein Backend-Team in einem SaaS-Unternehmen hat 180.000 Codezeilen, 40 Runbooks in Confluence und eine API-Referenz, die automatisch aus Swagger generiert wird. Ein neuer Entwickler verbringt die erste Woche hauptsächlich mit Fragen wie: „Wo wird dieser Fehler behandelt?“, „Wie funktioniert die Autorisierung für Endpunkt X?“ und „Was macht dieses Flag?“. Die erfahrenen Kollegen wissen es. Das Problem ist, dass dieses Wissen nirgends in einer durchsuchbaren Form festgehalten ist.
Wir bei Cashcrown untersuchen, wie RAG über Repositories und technische Dokumentation in praktischen Implementierungen funktioniert. Der folgende Artikel beschreibt die Unterschiede zu RAG über Prosa, den Ansatz für symbolisches Chunking, die Rolle von Hybrid Search und die Grenzen dessen, was eine Entscheidung des Entwicklers erfordert.
Warum Code und technische Dokumentation eine andere Herausforderung sind als Prosa
#HR-Dokumente, Verfahren oder FAQs haben eine lineare Struktur. Ein Splitter, der auf Zeichen oder Token basiert, liefert sinnvolle Fragmente, weil ein aus dem Kontext gerissener Satz immer noch ein Satz ist.
Code hat eine symbolische Struktur. Die Funktion calculate_discount(order_id, user_tier) ist eine semantische Einheit. Unterbricht man ihre Definition in der Mitte, erhält man ein Fragment ohne Signatur oder ein Fragment ohne Körper – jedes für sich unbrauchbar. Dasselbe gilt für Klassen, Methoden, try/except-Blöcke und Dekoratoren.
Technische Dokumentation ist ein Hybrid: Ein Runbook enthält eine Liste von Schritten, die sich auf konkrete Befehle und Umgebungsvariablen beziehen, ein API-Wiki beschreibt Endpunkte mit exakten Parametertypen. Die Suche nach Schlüsselwörtern funktioniert hier deutlich besser als bei freier Prosa. Dazu kommt die Veränderlichkeit: Ein RAG, der einmal im Monat indexiert, zitiert Signaturen, die zwei Wochen zuvor nicht mehr existierten.
Chunking nach Symbolen, nicht nach Absätzen
#Eine gute Chunking-Strategie für Code basiert auf Symbolgrenzen, nicht auf Token. Ein AST-Parser (Abstract Syntax Tree) extrahiert Funktionen, Klassen und Methoden als geschlossene Einheiten. Bibliotheken wie tree-sitter unterstützen über 40 Sprachen und geben die Grenzen jedes Symbols als Zeilennummern zurück.
Praktisches Muster: chunk = ein Symbol mit Docstring, Signatur und Körper. Pflichtmetadaten sind file_path, symbol_name, start_line, end_line, last_commit_sha. Für technische Dokumentation ist die Regel einfacher: Teile nach Abschnittsüberschriften (H2/H3), nicht nach Tokenanzahl. Ein nach Schritten unterteilter Runbook liefert prozedural selbstständige Fragmente.
Die folgende Tabelle vergleicht den Chunking-Ansatz für verschiedene Ressourcentypen:
| Ressourcentyp | Chunking-Strategie | Pflichtmetadaten | Richtgröße |
|---|---|---|---|
| Quellcode (Python, TS, Go) | AST nach Symbolgrenzen | file_path, symbol_name, start_line, end_line, last_commit_sha | 50–300 Zeilen pro Symbol |
| API-Referenz (OpenAPI/Swagger) | Ein Endpunkt = ein Chunk | method, path, operationId, version | 200–600 Token |
| Runbook / Betriebsprozedur | Recursive nach H2/H3-Überschriften | Abschnittstitel, service_name, last_modified | 300–800 Token |
| Internes Wiki (technische Prosa) | Recursive mit Overlap 10–15% | page_title, page_url, author, last_modified | 512–1024 Token |
| Changelog / Commit-Nachrichten | Fixed-size oder ganzer Eintrag | commit_sha, author, date, branch | 128–256 Token |
Mehr zu Chunking-Strategien im Allgemeinen beschreibt der Artikel Chunking von Dokumenten für RAG.
Warum Hybrid Search hier unverzichtbar ist
#Bei prosaischen Dokumenten kommt die rein vektorielle Suche gut zurecht, weil die Abfragen semantisch sind: „Wie bearbeite ich eine Reklamation?“ trifft den richtigen Absatz auch ohne wörtliche Übereinstimmung.
Bei Code enthalten Abfragen oft exakte Identifikatoren: UserRepository.findByEmail, POST /v1/orders/{id}/cancel, CASHCROWN_API_JWT_SECRET. Die semantische Suche (Embedding-basiert) kommt mit seltenen Token nicht zurecht. Das Modell sieht UserRepository als Zeichenkette ohne breite semantische Bedeutung und trifft allgemeine Fragmente statt der Klassendefinition.
BM25 ist ein invertierter Index, der auf Worthäufigkeit basiert. Für Identifikatoren im Quellcode funktioniert er wie eine Volltextsuche: Er findet UserRepository.findByEmail genau dort, wo diese Methode definiert oder aufgerufen wird. Die Kombination von BM25 mit vektorieller Suche durch Hybrid Search (RRF oder lineare Gewichtung des Ergebnisses) erhöht den Recall für Abfragen mit exakten Namen, ohne die Ergebnisse für semantische Abfragen zu verschlechtern.
In internen Tests von Cashcrown auf einem Datensatz von 12.000 Symbolen aus einem kommerziellen Projekt betrug der recall@5 bei reiner Vektorsuche 61%. Nach der Hinzunahme von BM25 im Hybridmodus stieg er auf 79%. Der Unterschied war vor allem bei Abfragen mit Methodensignaturen und Dateipfaden sichtbar. Dies sind Richtwerte aus einem Projekt, keine Garantie für Wiederholbarkeit in anderem Code.
Nach dem Retrieval lohnt sich eine Reranking-Schicht, die die Top-k-Fragmente im Hinblick auf die Relevanz für die konkrete Abfrage neu sortiert. Für Code ist das wichtig, weil BM25 Fragmente mit lexikalisch identischem Namen, aber aus einem anderen Modul oder Namensraum, befördern kann. Der Reranker bewertet den vollständigen Kontext, nicht nur das Vorhandensein eines Tokens. Details zum Vergleich von Vektordatenbanken, die Hybrid Search nativ unterstützen, beschreibt der Artikel Wie wählt man eine Vektordatenbank aus.
Index-Frische: Ein Problem, das man nicht ignorieren kann
#Code hat einen anderen Lebenszyklus als eine HR-Prozedur. Eine Urlaubsprozedur ändert sich einmal im Jahr. Die Signatur einer Methode in einem aktiven Projekt ändert sich jeden Sprint.
Ein RAG über Code, der den Index nicht aktualisiert, produziert Antworten mit veralteten APIs. Ein Entwickler, der ein Beispiel für die Verwendung einer vor zwei Commits entfernten Funktion erhält, verschwendet Zeit mit dem Debuggen eines Fehlers, der vom Assistenten generiert wurde.
Drei Aktualisierungsstufen, die wir je nach Änderungsgeschwindigkeit des Projekts anwenden:
Inkrementelle Reindexierung nach Commit. Ein Webhook von GitLab/GitHub (oder ein post-receive-Hook) löst die Reindexierung nur der im Commit geänderten Dateien aus. git diff --name-only HEAD~1 HEAD liefert die Liste der Dateien. Jede wird erneut durch den AST-Parser verarbeitet. Symbole, deren Grenzen sich nicht geändert haben, bleiben im Index; geänderte ersetzen die vorherigen Versionen.
Versionsverwaltung von Chunks durch Commit SHA. Jeder Chunk speichert last_commit_sha in den Metadaten. Bei einer Abfrage kann nach Branch gefiltert werden (branch: main), was Antworten sowohl über den aktuellen Code als auch über eine bestimmte historische Version ermöglicht.
TTL für Dokumentation. Runbooks und Wikis haben keinen Webhook. Wir setzen ein TTL, nach dem das Dokument automatisch reindexiert wird: 24–48 Stunden für sich aktiv ändernde Dokumentation, 7–14 Tage für stabile Spezifikationen.
Der Assistent sollte das Datum der letzten Indexierung des Dokuments im Zitat offenlegen. „Quelle: src/auth/user_service.py, Zeile 142, indexiert vor 2 Stunden“ gibt dem Entwickler ein Signal, ob er der Antwort vertrauen kann. Das Weglassen dieser Information ist ein verstecktes Risiko.
Zitieren der Quelle als Anforderung, nicht als Option
#Bei prosaischen Dokumenten ist das Zitieren des Dateinamens und der Seitenzahl eine gute Praxis. Für Code ist es eine Sicherheitsanforderung.
Ein Entwickler, der die Antwort „Die Funktion calculate_discount ist im Modul pricing“ erhält, kann sie nicht ohne Überprüfung anwenden. Es könnte mehrere pricing-Module im Monorepo geben. Die Methode könnte im letzten Commit die Signatur geändert haben. Der Assistent könnte eine ähnlich benannte Methode aus einem anderen Modul verwechselt haben.
Eine technisch nützliche Antwort sieht so aus: „calculate_discount(order_id: int, user_tier: str) -> Decimal (Datei: src/billing/pricing.py, Zeile 87, Commit a3f9c12, indexiert vor 40 Minuten)“. Der Entwickler klickt auf den Link zur Datei, sieht den aktuellen Code, überprüft die Signatur und wendet ihn erst dann an.
Guardrails für RAG über Code sollten zwei Klassen von Antworten blockieren:
Keine Abdeckung im Index. Wenn das Retrieval kein Fragment mit einer Ähnlichkeitsbewertung über dem Schwellenwert (orientierend 0,65–0,75 für das Modell der semantischen Suche) zurückgibt, sollte der Assistent antworten: „Ich habe diese Signatur in der indexierten Version des Codes nicht gefunden.“ Das ist besser als der Versuch, sie aus dem Gedächtnis des Modells zu rekonstruieren, was nicht existierende APIs produzieren würde.
Veralteter Index. Wenn die Metadaten des Chunks anzeigen, dass die Datei seit mehr als X Stunden nicht reindexiert wurde (Schwellenwert abhängig von der Änderungsgeschwindigkeit des Projekts), sollte die Antwort eine Warnung vor möglicher Veralterung enthalten.
Mehr darüber, wie RAG über eine Wissensbasis Zitate und Guardrails handhabt, im Artikel Firmen-GPT auf Wissensbasis.
Anwendungsfälle: Wo der Assistent am meisten hilft
#Drei Fälle, die wir am häufigsten in Projekten antreffen, und welche Rolle der Mensch in jedem davon spielt:
Onboarding von Entwicklern. Ein neues Teammitglied fragt: „Wo wird die OAuth-Autorisierung behandelt?“ Der Assistent gibt das Fragment src/auth/oauth_handler.py mit Startzeile, Docstring und dem Namen des Committers zurück. Der Entwickler liest den Code. Der Assistent verkürzt die Zeit bis zur ersten sinnvollen Frage an einen erfahrenen Kollegen, ersetzt aber nicht die Codeprüfung.
Fragen „Wo ist X implementiert?“. Während des Code-Reviews oder Debuggings: „Wo ist der Retry-Mechanismus für 503-Fehler implementiert?“ Der Assistent gibt eine Liste von Stellen im Code zurück, die semantisch und lexikalisch passen. Der Entwickler entscheidet, welche davon die richtige für den jeweiligen Kontext ist. Der Assistent weiß nichts über die architektonische Absicht, die im Kopf des Architekten existiert.
Beantwortung von Support-Fragen aus der Dokumentation. Ein Kunde des Supports fragt nach einem API-Parameter. Der Assistent sucht in der indexierten OpenAPI-Referenz und gibt die Beschreibung mit der Versionsnummer der Spezifikation zurück. Der Support überprüft in Swagger UI vor der Antwort. Der Assistent reduziert die Suchzeit, eliminiert aber nicht die Überprüfung.
In allen drei Fällen ist die Rolle des Menschen unverzichtbar: Architekturentscheidungen, die Anwendung von Code in der Produktion und Antworten, bei denen Fehler reale Konsequenzen haben, erfordern immer menschliches Urteilsvermögen. Der RAG-Assistent über Code ist ein Navigationswerkzeug, keine Autorität.
Einen breiteren Kontext zu Hybrid Search für technische Wissensbasen beschreibt der Artikel Hybrid Search: BM25 und Vektoren.
FAQ
#Kann RAG über Code fertige Code-Snippets zum Einfügen vorschlagen?
#Er kann ein bestehendes Code-Fragment aus dem Repository als Zitat zurückgeben. Das unterscheidet sich von der Generierung neuen Codes: Der Assistent zeigt, wie ein bestimmtes Muster bereits im Projekt umgesetzt ist, mit Angabe von Datei und Zeile. Der Entwickler bewertet, ob das Fragment im neuen Kontext wiederverwendbar ist. Der Assistent sollte keinen Code generieren, der nicht in der Wissensbasis vorhanden ist, da das Risiko, eine nicht existierende Signatur zu erfinden, hoch ist.
Wie geht man mit Fragen zu Code um, der noch nicht indexiert ist?
#Wenn das Retrieval keine Ergebnisse oder Ergebnisse unter dem Ähnlichkeitsschwellenwert zurückgibt, sollte der Guardrail direkt antworten: „Ich habe keine Abdeckung für diese Frage in der indexierten Version des Repositorys gefunden.“ Der Assistent kann eine alternative Abfrage vorschlagen oder darauf hinweisen, dass die betreffende Datei möglicherweise noch nicht indexiert wurde. Das Erraten von Funktionssignaturen auf Basis des allgemeinen Wissens des Modells ist die häufigste Ursache für falsche Antworten in solchen Systemen.
Wie oft sollte ich technische Dokumentation in Confluence reindexieren?
#Das hängt von der Änderungsgeschwindigkeit ab. Runbooks für aktiv entwickelte Dienste sollten alle 24 Stunden reindexiert werden. Eine stabile Architekturspezifikation kann ein TTL von 7–14 Tagen haben. Entscheidend ist, dass der Assistent in jeder Antwort das Datum der letzten Indexierung angibt, damit der Nutzer weiß, ob die zitierten Inhalte aktuell sind. Ein veralteter Index ohne Warnung ist schlimmer als kein Index.
Warum reicht rein vektorielle Suche für Code nicht aus?
#Das Embedding-Modell repräsentiert semantische Bedeutung, aber Funktions-, Klassen- und Variablennamen sind seltene Token ohne breiten semantischen Kontext im allgemeinen Korpus. Rein vektorielle Suche wird allgemeine Fragmente zum Thema Authentifizierung statt der konkreten Klasse AuthService bevorzugen. BM25 behandelt Identifikatoren wie Schlüsselwörter und trifft sie exakt. Die Kombination beider durch Hybrid Search unterstützt sowohl semantische als auch lexikalische Abfragen.
Was tun, wenn der Assistent eine Signatur zitiert, die nicht mehr existiert?
#Das ist ein Signal, dass der Index veraltet ist. Die Reaktion sollte zweistufig sein: Auf Nutzerseite die Überprüfung der Quelldatei vor der Anwendung, da dies immer erforderlich ist. Auf Systemseite die Verkürzung des TTL für die Reindexierung sich ändernder Dateien und das Hinzufügen einer Warnung in der Antwort, wenn die Metadaten auf einen alten Commit SHA hinweisen. Niemals Code anwenden, der vom Assistenten zurückgegeben wurde, ohne die aktuelle Version im Repository zu überprüfen.