Startseite / Artikel / Das erste Werkzeug für einen LangGraph-Support-Agenten: Stichwortsuche in der Doku

Das erste Werkzeug für einen LangGraph-Support-Agenten: Stichwortsuche in der Doku

Wie ein Support-Agent auf LangGraph ein einziges Suchwerkzeug über Markdown-Dokumentation bekommt: warum er auf RAG verzichtet, wie Werkzeug und Implementierung getrennt sind und wie der State die Belege bis zur Antwort trägt.

975 Wörter

Der Graph des LEPA-Support-Agenten kann bereits danach verzweigen, wie klar eine Frage ist:

vague question  → ask for clarification
clear question  → continue

Aber "weitermachen" ist hohl, wenn der Agent nichts hat, womit er weitermachen kann. Die nächste Ergänzung gibt ihm eine konkrete Aufgabe: die Support-Dokumentation der Schule durchsuchen und jede Antwort auf das stützen, was dabei herauskommt.

Warum überhaupt Werkzeuge

Ein Sprachmodell kann über alles selbstsicher klingen, und ein Support-Agent für LEPA darf keine Schulabläufe erfinden. Werkzeuge sind die Antwort. Ein Werkzeug ist eine Aktion, die der Agent oder ein einzelner Knoten im Graphen außerhalb der eingefrorenen Gewichte des Modells ausführen kann. Man stelle sich eine Empfangskraft vor, die nur redet, und eine, die das Mitarbeiterhandbuch aufschlagen kann; nützlich ist die zweite. In einem KI-Workflow sieht das Muster so aus:

User question
     ↓
Decide what is needed
     ↓
Use a tool (search docs, call an API, …)
     ↓
Read the tool result
     ↓
Answer with evidence

Dasselbe Muster tauchte schon in früheren Projekten auf. TAM nutzte einfache Python-Funktionen als Werkzeuge, und DevAssist stellte sie über MCP für Clients bereit. In diesem Projekt lebt das Werkzeug in der LangGraph-App und schreibt in den State. Gleiche Idee, andere Verkabelung.

Das einzige Werkzeug

Es gibt genau eins:

search_knowledge(query, category?)

Es durchsucht Markdown-Dateien im Ordner knowledge/:

knowledge/
  authentication.md
  students.md
  attendance.md
  grades.md
  reports.md

Jede Datei enthält realistische LEPA-Support-Inhalte: Anmeldeprobleme, Einschreibung, Anwesenheitslisten, Veröffentlichung von Noten und Berichte.

Was es bewusst nicht ist

Keine Vektordatenbank, keine Embeddings und keine vollständige RAG-Architektur. Die Suche ist absichtlich einfach gehalten:

  • Dokumente werden an ##-Überschriften aufgeteilt.
  • Abschnitte werden nach Überschneidung der Stichwörter bewertet.
  • Bis zu 4 Ausschnitte kommen zurück, auf eine Maximallänge gekürzt.
  • Wenn die Klassifizierung das Thema schon kennt, wird die passende Datei {category}.md bevorzugt.

Der Grund: In diesem Projekt geht es um LangGraph und nicht um Retrieval-Forschung. Das README sagt es direkt: Die Lektion ist Werkzeug plus Graph, die Qualität der Suche steht nicht im Mittelpunkt.

Zwei Ebenen im Code

Die Logik existiert in zwei Formen. search_knowledge_impl(...) ist gewöhnliches Python und gibt eine Liste von Ausschnitten zurück, während @tool search_knowledge(...) dieselbe Logik für LangChain verpackt. Der Wissensknoten des Graphen umgeht die Verpackung und ruft die Implementierung auf:

def run_knowledge(state: SupportState) -> dict:
    query = last_user_text(state)
    category = state.get("issue_category") or "unknown"
    snippets = search_knowledge_impl(query, category=category)
    return {"retrieved_documents": snippets}

Diese Entscheidung hat einen Zweck. Die Suche bleibt sichtbar, Tests laufen offline, und die @tool-Verpackung steht für spätere Experimente mit Tool-Calling durch das LLM bereit. Der Graph nutzt also eine Fähigkeit in Werkzeugform, auch wenn nicht das LLM den Werkzeugaufruf auswählt.

Wie sich der Ablauf ändert

Vor den Werkzeugen war der Weitermachen-Zweig ein Platzhalter. Mit dem Werkzeug sieht er so aus:

classify → continue
              ↓
          knowledge   (search_knowledge_impl → retrieved_documents)
              ↓
          support     (turn snippets into final_answer)
              ↓
             END

Ein Beispiel aus LEPA

Nehmen wir einen Nutzer, der fragt, warum keine Noten angezeigt werden:

User: "Why aren't grades showing?"
        ↓
classify → grades
        ↓
knowledge searches grades.md
        ↓
snippets mention Draft vs Publish
        ↓
support answers using those snippets

Das ist der Unterschied zwischen Raten, warum Noten fehlen, und einer Antwort anhand einer Handbuchseite, auf der steht, dass Erziehungsberechtigte nur veröffentlichte Noten sehen.

Der Support hängt davon ab, was das Werkzeug liefert

Der Support-Knoten legt keine zweite Wissensbasis an. Er liest retrieved_documents aus dem State. Ohne Dokumente bittet er den Nutzer, den LEPA-Bereich zu nennen. Mit Dokumenten baut er daraus eine Antwort. Ist ein API-Schlüssel konfiguriert, kann er ein LLM bitten, dieselben Ausschnitte sauberer umzuformulieren, und fällt trotzdem auf eine Vorlage zurück, wenn das LLM scheitert.

Die Grenze ist einfach: Das Werkzeug liefert Belege, der Support-Schritt formuliert die Antwort, und der Graph entscheidet, wann das Werkzeug läuft. Diese Trennung half beim Debuggen. Bei jeder falschen Antwort konnte man fragen, ob Routing, Suche oder Formulierung schuld war.

Eine Lektion aus der MCP-Arbeit

Ein früheres MCP-Projekt hat gelehrt, dass ein Werkzeug auf das Modell zugeschnitten sein sollte, das seine Ausgabe liest, und das gilt sogar für eine Stichwortsuche. Ausschnitte aus search_knowledge tragen ein Label wie [grades.md] und danach gekürzten Abschnittstext, sodass der nächste Schritt oder ein künftiges LLM sieht, woher die Belege stammen. Auch die Größe der Ausschnitte ist begrenzt. Den nächsten Schritt mit einem ganzen Handbuch zu fluten, würde das Problem mit zu viel Kontext zurückbringen, auf das man beim Entwurf von search_code in DevAssist gestoßen war. Anderes Projekt, gleicher Designdruck.

Was ein Werkzeug gelehrt hat

  1. Ein Graph ohne Werkzeuge kann routen, aber seine Antworten nicht auf Fakten stützen.
  2. Ein einziges langweiliges Werkzeug reicht, um das Produkt zu verändern.
  3. Ein Werkzeug aus einem Knoten aufzurufen, ist ein legitimer Weg zum Lernen, bevor man zum vollständigen Tool-Calling durch das LLM übergeht.
  4. Für ein LangGraph-Tutorial ist "noch kein RAG" eine Eigenschaft und kein Versagen.
  5. Der State dient als Bus: Die Ausgabe des Werkzeugs wird zu retrieved_documents, und der Support liest sie.

Kurz gesagt

Mit einem Werkzeug ist der LEPA-Agent kein Flussdiagramm mehr und kann echte Schulabläufe nachschlagen. Konkret heißt das search_knowledge und search_knowledge_impl, eine einfache Markdown-Suche, die aus dem Knoten knowledge aufgerufen wird und ihre Ergebnisse über den State an den Knoten support weitergibt. Die schwierigere Frage kommt als Nächstes: Erinnert sich der Agent bei der nächsten Nachricht an das Gespräch? Hier kommen Checkpoints, thread_id und kurzfristiger Gesprächszustand ins Spiel.