Startseite / Artikel

Erstellung eines Wissensassistenten-Agenten auf Databricks mit LangGraph

Erstellen Sie schrittweise einen LangGraph-Agenten auf Databricks: einen minimalen Agenten, Vector Search RAG, Lakebase-Checkpointing für das Kurzzeitgedächtnis sowie einen Speicher für das Langzeitgedächtnis.

Verlag: REACTAPP.TOP7 Min. Lesezeit1720 Wörter

Quellen: Building Custom Code Agents on Databricks — Getting Started

Ein einfacher benutzerdefinierter Agent auf Databricks kann von einem reinen Aufruf einer KI-Modell entwickelt werden zu einem Wissensassistenten, der Dokumente durchsucht und sich an Benutzer erinnert – wobei jeder Schritt klein ist. Der fertige Agent wird mit dem langgraph-Framework erstellt. Er verfügt über einen Vektorsuche-Modul zur Suche in Texten sowie ein Gedächtnismodul, sodass er sich daran erinnern kann, was ein Endnutzer in einem Gespräch oder bei verschiedenen Gesprächen gesagt hat. Nach dem Start folgt die Bewertung: Die Leistung wird während der Entwicklung sowie in der Produktion gemessen.

Die Anleitung folgt einer Reihe von Notebooks, die in Ordnern für Grundlagen, den RAG-Pipeline-Prozess und das Gedächtnis gruppiert sind.

Aufbereitung der Arbeitsumgebung

Ein vollständiger Agent enthält Vektorindizes, Tools und Protokolle, und diese benötigen zunächst einen ordentlichen Aufbewahrungsort. Bei Databricks ist die Governance-Schicht Unity Catalog (UC), die alle Ressourcen in einem dreistufigen Namespace verwaltet. Das Ausführen der Notebooks im Ordner 00_foundations in der richtigen Reihenfolge erstellt alle Ressourcen, auf die die späteren Schritte angewiesen sind – einschließlich einer Mischung aus strukturierten und unstrukturierten Daten, mit denen der Agent in Verbindung treten wird.

Der Speicher erfolgt in Lakebase, einer automatisch skaliierbaren, postgrepskompatiblen Datenbank. Damit die Tabellen später reibungslos erstellt werden können, erstellt das Setup-Notebook außerdem ein Lakebase-Projekt sowie einen Branch, um sie zu speichern.

Ein erster, minimaler Agent

Danach folgen die Notebooks unter 01_rag_pipeline, angefangen mit 0_your_first_agent_on_databricks.

Jeder Agent basiert auf einem Grundmodell. Databricks Model Serving listet die verfügbaren Modelle auf, wobei sich diese Liste je nach Konfiguration Ihrer Arbeitsumgebung unterscheiden kann. Die Endpunkte sind mit dem OpenAI API-Format kompatibel, doch für eine enge Integration von LangGraph ist die offizielle databricks-langchain-Bibliothek die bessere Wahl.

Ein kurzer Hinweis zu LangGraph: Ein Produktionsagent ist selten nur auf eine einzige Anfrage ausgerichtet. Er enthält in der Regel verzweigte Logiken, die von der Frage sowie der Antwort des Benutzers abhängen, sowie Schleifen zur Abfrage externer Systeme und zur Neuformulierung von Anfragen anhand der Rückmeldungen. LangGraph organisiert dies, indem es den Agenten als Graph modelliert. Knoten enthalten Funktionen und Aufrufe von LLMs, während Kanten bestimmen, wie der Kontext zwischen ihnen übertragen wird. Der Ausgangsgraph ist sehr einfach gestaltet.

Man ruft den Agenten auf, und es erscheint ein Protokoll, das die Eingabefrage, die Ausgabe des Modells sowie jeden dazwischenliegenden logischen Schritt auflistet. Das stammt von MLflow, das nahtlos mit LangGraph integriert ist. Ein einziger Aufruf von mlflow.langchain.autolog() am Anfang des Notebooks aktiviert diese Protokolle und Diagnosefunktionen. MLflow wird später ausführlicher behandelt.

Die erste Version übermittelt lediglich die Frage des Benutzers an das Modell. Ein echter Agent fügt einen Systemprompt hinzu, um den Ton zu bestimmen, die Ausgabe zu formen und Hintergrundinformationen bereitzustellen – beispielsweise wofür der Assistent dient und was er ablehnen sollte zu beantworten. Daher wird in der zweiten Iteration ein Systemprompt in das Diagramm eingefügt.

Datenerfassung hinzufügen

Einer der häufigsten Agententypen ist der Wissensabruf-Agent, auch RAG-Agent genannt. Er hilft Menschen dabei, in einer Menge von Dokumenten zu suchen und Fragen dazu zu beantworten. Um einem Agenten diese Fähigkeit zu verleihen, benötigt er einen Vektor-Suchindex – im Grunde eine Datenbank für unstrukturierten Text.

Das Notebook 01_building_a_doc_store_on_vector_search behandelt den Aufbau eines solchen Indexes. Bevor ein Index einem Agenten zugeordnet werden kann, muss er bereits existieren. Dieser Teil konzentriert sich auf die grundlegenden Schritte und überspringt Anpassungen sowie Optimierungen.

Der Aufbau eines Indexes erfordert drei Schritte:

  • Parsing bedeutet, ein Dokument zu öffnen und seinen Inhalt zu lesen.
  • Chunking bedeutet, ein Trennwerkzeug zu verwenden, um das Dokument in Abschnitte aufzuteilen.
  • Embedding bedeutet, jeden Abschnitt in einen semantischen Vektor umzuwandeln, der im Index gespeichert wird.

Jeder Ansatz weist seine eigenen Feinheiten auf, und Fehler in einem frühen Schritt beeinträchtigen leise alles danach. Das Tutorial verwendet überall Standardwerte. In der Produktion können unterschiedliche Dokumente verschiedene Parser benötigen, um den Text korrekt zu extrahieren, und unterschiedliche Anwendungsfälle erfordern möglicherweise andere Blöchengrößen für Texte, Tabellen und Abbildungen sowie unterschiedliche Einbettungsmodelle.

Databricks stellt Werkzeuge bereit, um dies zu erleichtern. Volumes bieten einen cloud-basierten, vollständig verwalteten Objektspeicher für Rohdateien. Die Funktion ai_parse_documents extrahiert Texte, Abbildungen und Tabellen mit geringer Konfiguration und skaliert gut. Spark UDFs können den extrahierten Text in Blöcke mit unterschiedlicher Granularität aufteilen, die für die Einbettung durch beliebige der bereitgestellten Einbettungsmodelle geeignet sind.

Sobald Embeddings vorhanden sind, benötigt die Ähnlichkeitssuche einen Vektor-Suchindex. Ein neuer Datenspeicher scheint zusätzliche Arbeit zu bedeuten, doch Delta Sync erledigt dies, indem es Blöcke automatisch embeddet und indiziert, sobald diese hinzugefügt, geändert oder gelöscht werden. Es muss keine neue Infrastruktur verwaltet werden, und es gibt keinen Synchronisierungsjob, der zwischen der Blöckeltabelle und dem Index aufrechterhalten werden muss.

In den ersten beiden Schritten des Notebooks werden die während der Einrichtung erzeugten Markdown-Dateien aufgenommen und in überschneidende Blöcke à 800 Zeichen aufgeteilt, bevor sie in Databricks Vector Search geladen werden. Die databricks_langchain-Bibliothek enthält ein fertig erstelltes VectorSearchRetrieverTool, das den Index mit dem langgraph-Agenten verbindet.

Sobald der Index erstellt und getestet wurde, definiert Schritt drei den Agenten neu. Er sieht den früheren Versionen sehr ähnlich aus, mit einer Ergänzung: einem ToolNode, der eine Liste von Werkzeugen enthält. In diesem Fall beinhaltet diese Liste nur den VectorSearchRetrieverTool.

In dem entstehenden Ablauf gelangt eine Frage ein und durchläuft das Prompt-Muster. Das Modell sieht das Prompt zusammen mit den Werkzeugen und deren Beschreibungen und entscheidet, ob es den Index konsultieren soll. Es kann dies wiederholt tun und antwortet dem Benutzer erst, wenn es das Gesuchte gefunden hat.

Das ist ein funktionsfähiger RAG-Agent. Das Diagramm bleibt kompakt, wobei der Tool-Node die einzige Ergänzung darstellt – was zeigt, wie geringe Struktur ein Abrufzyklus benötigt. Ein Wissensassistent braucht jedoch noch einen weiteren Bestandteil: Gedächtnis.

Gedächtnis für den Agenten bereitstellen

Bislang verfügt der Agent über keinerlei Gedächtnis. Eine nachfolgende Frage, die auf die vorherige Antwort verweist, scheitert einfach, weil das Modell nicht weiß, was gerade gesagt wurde.

Damit der Agent frühere Gesprächspunkte berücksichtigen kann, benötigt langgraph einen Checkpointer, der die Chat-Geschichte speichert. Checkpointers reichen von einfachen Textdateien bis hin zu vollständigen Datenbanken. Aus Gründen der Skalierbarkeit, Latenz und Sicherheit ist eine Datenbank die bessere Wahl – auf Databricks bedeutet das Lakebase.

Gedächtnis gibt es in zwei Arten. Das Kurzzeitgedächtnis umfasst nur die aktuelle Sitzung. Das Langzeitgedächtnis speichert Fakten über mehrere Sitzungen hinweg. Fast jede Anwendung benötigt das eine, ob man das andere braucht, hängt vom Anwendungsfall ab.

Kurzzeitgedächtnis

Die Dateiordner 02_memory wird zusammen mit 01_short_term_memory geöffnet, wobei letzterer einen Checkpointer hinzufügt. In den Schritten 1 bis 3 wird ein StateGraph erstellt, der dem vorherigen identisch ist, und Schritt 4 zeigt, wie unangenehm ein Gespräch ohne Speicherfunktionen verläuft.

Durch die Erstellung eines mit Lakebase verbundenen Checkpointers wird die Kontinuität wiederhergestellt, und databricks_langchain bietet eine native CheckpointSaver-Klasse zur Instanziierung und Anbindung an den Graphen.

Ein Agent ist ein von vielen Benutzern gemeinsam genutzter Dienst, weshalb gespeicherte Gespräche einen Eigentümer benötigen. Der thread_id übernimmt diese Funktion. In einer Produktivanwendung sollte die Benutzeroberfläche für jede aktive Sitzung einen eindeutigen thread_id erzeugen, damit jeder Benutzer nur seine eigene Chatgeschichte sieht.

Bis zum Schritt 6 ist der Checkpointer vorhanden und das Gespräch verläuft natürlich.

Langfristiger Speicher

Das Kurzzeitgedächtnis verschwindet, wenn die Sitzung endet. Um sich an einen Benutzer und seine Präferenzen zu erinnern, benötigt der Agent ein Langzeitgedächtnis – ob dieses hinzugefügt wird, hängt vom Produkt ab. Ein langlebiger persönlicher Assistent sollte frühere Gespräche sowie Fakten wie den Namen des Benutzers und Präferenzen wie kurze, prägnante Antworten gegenüber ausführlichen Erklärungen speichern. Ein Hilfeservice auf einem Kundenportal sollte diese Details möglicherweise nicht aufbewahren, da dies die Last der Sicherung, Verschlüsselung und Verwaltung personenbezogener Daten über einen langen Zeitraum bedeutet.

Für das Kurzzeitgedächtnis reicht ein CheckpointSaver aus. Für das Langzeitgedächtnis ist eine gewisse Gestaltung notwendig. Die Aufzeichnung jedes Gesprächs für die Zukunft wird in der Regel nicht gewünscht. Wertvoll sind hingegen Fakten wie Name oder Heimatort sowie Präferenzen.

Das Notebook 02_long_term_memory erläutert die zugrundeliegenden Mechanismen. In den Schritten 1 bis 4 wird der RAG-Agent mit kurzfristiger Speicherfunktion neu erstellt, und Schritt 5 zeigt, dass Präferenzen verschwinden, wenn sich die Sitzung sowie der thread_id ändern.

Schritt 6 führt ein DatabricksStore-Objekt ein, das Daten in Lakebase speichert. Dieser Teil ist einfach. Die eigentliche Designfrage besteht darin, zu entscheiden, welche Daten gespeichert werden sollen. Schritt 7 verfolgt einen grundlegenden Ansatz: Einige fest programmierte Fakten werden in den Speicher geschrieben.

Zum Einsatz dieser Fakten wird in Schritt 8 der Agent neu erstellt. Zuvor war der Agent-Node eine einfache Funktion, die invoke am Grundmodell aufrief. Jetzt handelt es sich um eine komplexere Funktion, die eine Benutzer-ID entgegennimmt (für die Demo fest programmiert), die entsprechenden Fakten des Benutzers aus dem DatabricksStore abruft und sie im Kontext zusammenfügt, der an das Modell gesendet wird. Dieses Muster erfordert ein sorgfältiges Design, um langfristig zu funktionieren.

Ein flexiblerer Ansatz ermöglicht es dem Modell selbst, zu entscheiden, wann Erinnerungen gespeichert, gelöscht oder abgerufen werden sollen. Schritt 12 implementiert eine grundlegende Version: Drei neue Tools interagieren mit dem Speichermodul, und der Systemhinweis ändert sich, um das Modell über sie zu informieren und ihre Nutzung zu fördern.

Das Ergebnis ist ein vollständiger Assistent, wobei jede Funktion einzeln getestet werden kann, da sie über ein separates Notebook sowie eine separate Änderung im Graphen implementiert wurde. Er durchsucht Dokumente mithilfe eines Vektorindex, verfolgt das aktuelle Gespräch mit kurzfristiger Erinnerung und merkt sich Details über Benutzer über verschiedene Sitzungen hinweg mit langfristiger Erinnerung.

Welcher nächste Schritt?

Der Weg führte von einem Bot, der Fragen direkt an ein LLM weiterleitete, zu einem Bot mit Prompt-Vorlage, kurzfristiger und langfristiger Speicherung sowie Vector Search zur Kontextbereitstellung. Die weitere Arbeit besteht darin, dieses System in die Produktion zu bringen: Die Qualität des Agents zu bewerten, weitere Funktionen hinzuzufügen und es als Service für Endnutzer bereitzustellen.