Entwicklung eines agentenbasierten RAG-Assistenten mit JavaScript und Mastra und Elasticsearch

Lerne, wie du KI-Agenten im JavaScript-Ökosystem entwickelst.

Elasticsearch verfügt über native Integrationen mit den branchenführenden Gen-AI-Tools und -Anbietern. Sehen Sie sich unsere Webinare zu den Themen „RAG-Grundlagen“ oder zum „Erstellen produktionsreifer Apps“ mit der Elastic-Vektordatenbank an.

Um die besten Suchlösungen für Ihren Anwendungsfall zu entwickeln, starten Sie jetzt eine kostenlose Cloud-Testversion oder testen Sie Elastic auf Ihrem lokalen Rechner.

Diese Idee kam mir mitten in einer hitzigen Fantasy-Basketball-Liga mit hohem Einsatz. Ich fragte mich: Könnte ich einen KI-Agenten entwickeln, der mir hilft, meine wöchentlichen Begegnungen zu dominieren? Absolut!

In diesem Beitrag zeigen wir Ihnen, wie Sie mit Mastra einen agentenbasierten RAG-Assistenten und eine leichtgewichtige JavaScript-Webanwendung zur Interaktion mit diesem erstellen. Durch die Anbindung dieses Agenten an Elasticsearch erhalten Sie Zugriff auf strukturierte Spielerdaten und die Möglichkeit, statistische Aggregationen in Echtzeit durchzuführen, um Ihnen auf Spielerstatistiken basierende Empfehlungen geben zu können. Besuchen Sie das GitHub- Repository , um die Schritte nachzuvollziehen; die README-Datei enthält Anweisungen zum Klonen und Ausführen der Anwendung.

So sollte es aussehen, wenn alles zusammengebaut ist:

Hinweis: Dieser Blogbeitrag baut auf „ Entwicklung von KI-Agenten mit AI SDK und Elastic“ auf. Wenn Sie sich mit KI-Agenten im Allgemeinen noch nicht auskennen und nicht wissen, wofür sie eingesetzt werden könnten, fangen Sie dort an.

Architekturübersicht

Kernstück des Systems ist ein großes Sprachmodell (LLM), das als Denkmaschine (das Gehirn) des Agenten fungiert. Es interpretiert die Benutzereingaben, entscheidet, welche Tools aufgerufen werden sollen, und koordiniert die notwendigen Schritte, um eine relevante Antwort zu generieren.

Der Agent selbst wird von Mastra, einem Agenten-Framework im JavaScript-Ökosystem, bereitgestellt. Mastra umschließt das LLM mit einer Backend-Infrastruktur, stellt es als API-Endpunkt bereit und bietet eine Schnittstelle zur Definition von Tools, Systemaufforderungen und Agentenverhalten.

Im Frontend verwenden wir Vite , um schnell eine React-Webanwendung zu erstellen, die eine Chat-Oberfläche zum Senden von Anfragen an den Agenten und zum Empfangen seiner Antworten bereitstellt.

Schließlich gibt es noch Elasticsearch, das Spielerstatistiken und Matchup-Daten speichert, die der Agent abfragen und aggregieren kann.

Hintergrund

Lassen Sie uns einige grundlegende Konzepte durchgehen:

Was ist agentic RAG?

KI-Agenten können mit anderen Systemen interagieren, unabhängig agieren und Aktionen auf Basis ihrer definierten Parameter ausführen. Agentic RAG kombiniert die Autonomie eines KI-Agenten mit den Prinzipien der abrufverstärkten Generierung und ermöglicht es einem LLM, auszuwählen, welche Werkzeuge aufgerufen und welche Daten als Kontext verwendet werden sollen, um eine Antwort zu generieren. Lesen Sie hier mehr über RAG.

Warum sollte man bei der Wahl eines Frameworks über das AI-SDK hinausgehen?

Es gibt viele KI-Agenten-Frameworks, und Sie haben wahrscheinlich schon von den bekannteren wie CrewAI, AutoGen und LangGraph gehört. Die meisten dieser Frameworks verfügen über eine gemeinsame Funktionspalette, darunter die Unterstützung verschiedener Modelle, die Verwendung von Werkzeugen und das Speichermanagement.

Hier finden Sie eine Vergleichstabelle der verschiedenen Frameworks von Harrison Chase (CEO von LangChain).

Was mich an Mastra besonders interessiert hat, ist, dass es sich um ein JavaScript-basiertes Framework handelt, das für Full-Stack-Entwickler entwickelt wurde, um Agenten einfach in ihr Ökosystem zu integrieren. Das AI-SDK von Vercel kann das meiste davon auch, aber Mastra glänzt vor allem dann, wenn Ihre Projekte komplexere Agenten-Workflows beinhalten. Mastra erweitert die vom AI-SDK festgelegten Basismuster, und in diesem Projekt werden wir sie gemeinsam verwenden.

Rahmenwerke und Überlegungen zur Modellwahl

Diese Frameworks können zwar dabei helfen, schnell KI-Agenten zu entwickeln, es gibt jedoch einige Nachteile zu beachten. Wenn man beispielsweise andere Frameworks als KI-Agenten oder Abstraktionsschichten im Allgemeinen verwendet, verliert man ein Stück weit die Kontrolle. Wenn das LLM die Werkzeuge nicht korrekt verwendet oder etwas tut, was Sie nicht möchten, erschwert die Abstraktion die Fehlersuche. Dennoch ist dieser Kompromiss meiner Meinung nach den Komfort und die Geschwindigkeit wert, die man beim Erstellen von Projekten erhält, insbesondere weil diese Frameworks immer beliebter werden und ständig weiterentwickelt werden.

Auch diese Frameworks sind modellagnostisch, das heißt, Sie können verschiedene Modelle einsetzen und verwenden. Bedenken Sie jedoch, dass sich die Modelle in den Datensätzen unterscheiden, mit denen sie trainiert wurden, und dass sich dadurch auch die Ergebnisse unterscheiden. Manche Modelle unterstützen nicht einmal den Aufruf von Tools. Es ist also möglich, zwischen verschiedenen Modellen zu wechseln und diese auszuprobieren, um zu sehen, welches die besten Ergebnisse liefert. Bedenken Sie jedoch, dass Sie höchstwahrscheinlich für jedes Modell die Systemabfrage neu schreiben müssen. Zum Beispiel mit Llama3.3 Im Vergleich zu GPT-4o sind deutlich mehr Aufforderungen und spezifische Anweisungen erforderlich, um die gewünschte Antwort zu erhalten.

NBA Fantasy Basketball

Beim Fantasy-Basketball geht es darum, mit einer Gruppe von Freunden eine Liga zu gründen (Achtung: Je nachdem, wie wettbewerbsorientiert eure Gruppe ist, könnte dies den Status eurer Freundschaften beeinträchtigen), wobei in der Regel auch Geld auf dem Spiel steht. Jeder von euch stellt dann ein Team aus 10 Spielern zusammen, die abwechselnd wöchentlich gegen die 10 Spieler eines anderen Freundes antreten. Die Punkte, die zu Ihrer Gesamtpunktzahl beitragen, ergeben sich aus der Leistung jedes Ihrer Spieler gegen seine Gegner in einer bestimmten Woche.

Wenn ein Spieler Ihres Teams verletzt, gesperrt usw. wird, steht Ihnen eine Liste von Free Agents zur Verfügung, die Sie Ihrem Team hinzufügen können. Hier findet ein Großteil des schwierigen Denkens im Fantasy-Sport statt, denn man hat nur eine begrenzte Anzahl an Spielern zur Auswahl und jeder ist ständig auf der Suche nach dem besten Spieler.

Hier wird unser NBA-KI-Assistent seine Stärken ausspielen, insbesondere in Situationen, in denen Sie schnell entscheiden müssen, welchen Spieler Sie auswählen. Anstatt manuell nachschlagen zu müssen, wie ein Spieler gegen einen bestimmten Gegner abschneidet, kann der Assistent diese Daten schnell finden und Durchschnittswerte vergleichen, um Ihnen eine fundierte Empfehlung zu geben.

Nachdem Sie nun einige Grundlagen zu Agentic RAG und NBA Fantasy Basketball kennengelernt haben, sehen wir uns das Ganze mal in der Praxis an.

Aufbau des Projekts

Falls Sie an irgendeiner Stelle nicht weiterkommen oder es nicht von Grund auf neu erstellen möchten, schauen Sie bitte im Repository nach.

Was wir behandeln werden

  1. Gerüstbau für das Projekt:
    1. Backend (Mastra): Verwenden Sie npx create mastra@latest, um das Backend zu erstellen und die Agentenlogik zu definieren.
    2. Frontend (Vite + React): Verwenden Sie npm create vite@latest, um die Frontend-Chat-Oberfläche für die Interaktion mit dem Agenten zu erstellen.
  2. Einrichten von Umgebungsvariablen
    1. Installieren Sie dotenv, um Umgebungsvariablen zu verwalten.
    2. Erstellen Sie eine .env-Datei Datei und geben Sie die erforderlichen Variablen an.
  3. Elasticsearch einrichten
    1. Erstellen Sie einen Elasticsearch-Cluster (entweder lokal oder in der Cloud).
    2. Installieren Sie den offiziellen Elasticsearch-Client.
    3. Stellen Sie sicher, dass Umgebungsvariablen zugänglich sind.
    4. Verbindung zum Client herstellen.
  4. Massenhaftes Einlesen von NBA-Daten in Elasticsearch
    1. Erstellen Sie einen Index mit den entsprechenden Zuordnungen, um Aggregationen zu ermöglichen.
    2. Spielerstatistiken aus einer CSV-Datei massenhaft in einen Elasticsearch-Index importieren.
  5. Elasticsearch-Aggregationen definieren
    1. Abfrage zur Berechnung historischer Durchschnittswerte gegen einen bestimmten Gegner.
    2. Abfrage zur Berechnung der Saison-Durchschnittswerte gegen einen bestimmten Gegner.
  6. Datei zum Spielervergleich
    1. Konsolidiert Hilfsfunktionen und Elasticsearch-Aggregationen.
  7. Agentenaufbau
    1. Fügen Sie die Agentendefinition und die Systemeingabeaufforderung hinzu.
    2. Installieren Sie zod und definieren Sie Tools.
    3. Fügen Sie eine Middleware-Konfiguration zur Behandlung von CORS hinzu.
  8. Integration des Frontends
    1. Die Interaktion mit dem Agenten erfolgt über die useChat-Funktion des AI-SDK.
    2. Erstellen Sie eine Benutzeroberfläche, die ordnungsgemäß formatierte Konversationen ermöglicht.
  9. Die Anwendung ausführen
    1. Starten Sie sowohl das Backend (Mastra-Server) als auch das Frontend (React-App).
    2. Beispielabfragen und Anwendungsbeispiele.
  10. Was kommt als Nächstes: Den Agenten intelligenter machen.
    1. Durch die Integration semantischer Suchfunktionen können aussagekräftigere Empfehlungen ermöglicht werden.
    2. Aktivieren Sie dynamische Abfragen, indem Sie die Suchlogik auf den Elasticsearch MCP (Model Context Protocol)-Server verlagern.

Voraussetzungen

  • Node.js und npm: Sowohl das Backend als auch das Frontend laufen auf Node.js. Stellen Sie sicher, dass Sie Node 18+ und npm v9+ installiert haben (das in Node 18+ standardmäßig enthalten ist).
  • Elasticsearch-Cluster: Ein aktiver Elasticsearch-Cluster, entweder lokal oder in der Cloud.
  • OpenAI API-Schlüssel: Generieren Sie einen auf der Seite „API-Schlüssel“ im Entwicklerportal von OpenAI.

Projektstruktur

Schritt 1: Das Projektgerüst erstellen

  1. Erstellen Sie zunächst das Verzeichnis nba-ai-assistant-js und navigieren Sie darin mit folgendem Befehl:

Backend:

  1. Verwenden Sie das Mastra-Erstellungstool mit folgendem Befehl:

2. Sie sollten nun einige Eingabeaufforderungen in Ihrem Terminal erhalten. Bei der ersten nennen wir das Projekt-Backend:

3. Als nächstes behalten wir die Standardstruktur für die Speicherung der Mastra-Dateien bei, also Eingabe src/.

4. Dann wählen wir OpenAI als unseren Standard-LLM-Anbieter.

5. Abschließend werden Sie nach Ihrem OpenAI-API-Schlüssel gefragt. Fürs Erste wählen wir die Option, dies zu überspringen und es später in einer .env -Datei bereitzustellen.

Frontend:

  1. Wechseln Sie zurück in das Stammverzeichnis und führen Sie das Vite-Erstellungstool mit folgendem Befehl aus: npm create vite@latest frontend -- --template react

Dadurch sollte eine leichtgewichtige React-App mit dem Namen frontend und einer spezifischen Vorlage für React erstellt werden.

Wenn alles gut geht, sollten Sie in Ihrem Projektverzeichnis ein Backend-Verzeichnis sehen, das den Mastra-Code enthält, und ein frontend -Verzeichnis mit Ihrer React-App.

Schritt 2: Umgebungsvariablen einrichten

  1. Zur Verwaltung sensibler Schlüssel verwenden wir das Paket dotenv , um unsere Umgebungsvariablen aus der .env-Datei zu laden. Datei. Navigieren Sie zum Backend-Verzeichnis und installieren Sie dotenv:

2. Im Backend-Verzeichnis befindet sich eine example.env-Datei mit den entsprechenden Variablen zum Ausfüllen. Wenn Sie Ihre eigene Version erstellen, achten Sie darauf, die folgenden Variablen einzubeziehen:

Hinweis: Stellen Sie sicher, dass diese Datei von Ihrer Versionskontrolle ausgeschlossen wird, indem Sie .env zu .gitignore hinzufügen.

Schritt 3: Elasticsearch einrichten

Als Erstes benötigen Sie einen aktiven Elasticsearch-Cluster. Es gibt zwei Möglichkeiten:

  • Option A: Elasticsearch Cloud verwenden
    • Registrieren Sie sich für Elastic Cloud
    • Erstellen Sie eine neue Bereitstellung
    • Rufen Sie Ihre Endpunkt-URL und Ihren API-Schlüssel (kodiert) ab.
  • Option B: Elasticsearch lokal ausführen
    • Elasticsearch lokal installieren und ausführen
    • Verwenden Sie http://localhost:9200 als Endpunkt.
    • API-Schlüssel generieren

Installation des Elasticsearch-Clients auf dem Backend:

  1. Installieren Sie zunächst den offiziellen Elasticsearch-Client in Ihrem Backend-Verzeichnis:

2. Erstellen Sie anschließend ein Verzeichnis „lib“, um wiederverwendbare Funktionen zu speichern, und wechseln Sie in dieses Verzeichnis:

3. Erstellen Sie darin eine neue Datei namens elasticClient.js. Diese Datei initialisiert den Elasticsearch-Client und stellt ihn für die Verwendung in Ihrem gesamten Projekt zur Verfügung.

4. Da wir ECMAScript-Module (ESM) verwenden, sind __dirname and __-Dateinamen nicht verfügbar. Um sicherzustellen, dass Ihre Umgebungsvariablen korrekt aus der .env-Datei geladen werden Fügen Sie diese Konfiguration am Anfang der Datei im Backend-Ordner hinzu:

5. Initialisieren Sie nun den Elasticsearch-Client mithilfe Ihrer Umgebungsvariablen und überprüfen Sie die Verbindung:

Nun können wir diese Clientinstanz in jede Datei importieren, die mit Ihrem Elasticsearch-Cluster interagieren muss.

Schritt 4: Massenhaftes Einlesen von NBA-Daten in Elasticsearch

Datensatz:

Für dieses Projekt werden wir auf die Datensätze im Verzeichnis backend/data des Repos zurückgreifen. Unser NBA-Assistent wird diese Daten als Wissensbasis für statistische Vergleiche und die Generierung von Empfehlungen nutzen.

  • sample_player_game_stats.csv - Beispielhafte Spielstatistiken eines Spielers (z. B. Punkte, Rebounds, Steals usw.) pro Spiel und Spieler während seiner gesamten NBA-Karriere. Wir werden diesen Datensatz für Aggregationen verwenden. (Hinweis: Dies sind Beispieldaten, die zu Demonstrationszwecken generiert wurden und nicht aus offiziellen NBA-Quellen stammen.)
  • playerAndTeamInfo.js - Ersetzt die Spieler- und Team-Metadaten, die normalerweise über einen API-Aufruf bereitgestellt werden, damit der Agent Spieler- und Teamnamen IDs zuordnen kann. Da wir Beispieldaten verwenden, möchten wir den Aufwand des Abrufens von einer externen API vermeiden. Daher haben wir einige Werte fest codiert, auf die der Agent zugreifen kann.

Durchführung:

  1. Erstellen Sie im Verzeichnis backend/lib eine Datei mit dem Namen playerDataIngestion.js.
  2. Importe einrichten, den CSV-Dateipfad auflösen und das Parsen einrichten. Da wir ESM verwenden, müssen wir __dirname rekonstruieren, um den Pfad zur Beispiel-CSV-Datei aufzulösen. Außerdem importieren wir Node.js. eingebaute Module fs und readline, um die gegebene CSV-Datei Zeile für Zeile zu analysieren.

Damit sind Sie bestens gerüstet, um die CSV-Datei effizient zu lesen und zu analysieren, wenn wir zum Schritt der Massenverarbeitung übergehen.

3. Erstellen Sie einen Index mit der entsprechenden Zuordnung. Obwohl Elasticsearch Feldtypen mithilfe von Dynamic Mapping automatisch ableiten kann, möchten wir hier explizit vorgehen, damit jede Statistik als numerisches Feld behandelt wird. Dies ist wichtig, da wir diese Felder später für Aggregationen verwenden werden. Wir möchten außerdem den Typ float für Statistiken wie Punkte, Rebounds usw. verwenden, um sicherzustellen, dass wir Dezimalwerte einbeziehen. Zum Schluss möchten wir die Mapping-Eigenschaft dynamic: 'strict' hinzufügen, damit Elasticsearch nicht dynamisch nicht erkannte Felder zuordnet. 

4. Fügen Sie die Funktion hinzu, um die CSV-Daten in Ihren Elasticsearch-Index zu importieren. Innerhalb des Codeblocks überspringen wir die Kopfzeile. Anschließend werden die einzelnen Zeilen durch Kommas getrennt und in das Dokumentobjekt eingefügt. Dieser Schritt reinigt sie außerdem und stellt sicher, dass es sich um den richtigen Typ handelt. Als nächstes fügen wir die Dokumente zusammen mit den Indexinformationen in das bulkBody-Array ein, welches als Nutzlast für die Massenaufnahme in Elasticsearch dient.

5. Anschließend können wir die Bulk-API von Elasticsearch mit elasticClient.bulk() verwenden, um mehrere Dokumente in einer einzigen Anfrage zu erfassen. Die unten beschriebene Fehlerbehandlung ist so aufgebaut, dass sie Ihnen eine Übersicht darüber gibt, wie viele Dokumente nicht eingelesen werden konnten und wie viele erfolgreich eingelesen wurden.

6. Führen Sie die unten stehende Funktion main() aus, um die Funktionen createIndex() und bulkIngestCsv() nacheinander auszuführen.

Wenn in der Konsole eine Meldung erscheint, dass die Massenaufnahme erfolgreich war, überprüfen Sie kurz Ihren Elasticsearch-Index, um festzustellen, ob die Dokumente tatsächlich erfolgreich aufgenommen wurden.

Schritt 5: Elasticsearch-Aggregationen definieren und konsolidieren

Dies sind die Hauptfunktionen, die wir verwenden werden, wenn wir die Werkzeuge für den KI-Agenten definieren, um die Statistiken der Spieler miteinander zu vergleichen.

1. Navigieren Sie zum Verzeichnis backend/lib und erstellen Sie eine Datei namens elasticAggs.js.

2. Fügen Sie die unten stehende Abfrage hinzu, um historische Durchschnittswerte für einen Spieler gegen einen bestimmten Gegner zu berechnen. Diese Abfrage verwendet einen bool -Filter mit 2 Bedingungen: eine, die player_id entspricht, und eine weitere, die opponent_team_id entspricht, um nur die relevanten Spiele abzurufen. Wir müssen keine Dokumente zurückgeben, uns geht es nur um die Aggregationen, deshalb setzen wir size:0. Im Block aggs führen wir mehrere Metrikaggregationen parallel auf Feldern wie points, rebounds, assists, steals, blocks und fg_percentage durch, um deren Durchschnittswerte zu berechnen. LLMs können bei Berechnungen ungenau sein, und dies lagert diesen Prozess an Elasticsearch aus, um sicherzustellen, dass unser NBA-KI-Assistent Zugriff auf genaue Daten hat.

3. Um die Saisondurchschnittswerte eines Spielers gegen einen bestimmten Gegner zu berechnen, verwenden wir praktisch die gleiche Abfrage wie für die historischen Ergebnisse. Der einzige Unterschied bei dieser Abfrage besteht darin, dass der bool -Filter eine zusätzliche Bedingung für game_date enthält. Das Feld game_date muss innerhalb des Bereichs der aktuellen NBA-Saison liegen. In diesem Fall liegt der Bereich zwischen 2024-10-01 und 2025-06-30. Die unten stehende zusätzliche Bedingung stellt sicher, dass die nachfolgenden Aggregationen nur die Spiele dieser Saison berücksichtigen.

Schritt 6: Spielervergleichstool

Um unseren Code modular und wartbar zu halten, erstellen wir eine Hilfsdatei, die Metadaten-Hilfsfunktionen und Elasticsearch-Aggregationen zusammenfasst. Dies wird das Hauptwerkzeug des Agenten mit Strom versorgen. Mehr dazu später:

1. Erstellen Sie eine neue Datei comparePlayers.js im Verzeichnis backend/lib .

2. Fügen Sie die unten stehende Funktion hinzu, um Metadaten-Helfer und Elasticsearch-Aggregationslogik in einer einzigen Funktion zu konsolidieren, die das Hauptwerkzeug des Agenten antreibt.

Schritt 7: Erstellung des Agenten

Nachdem Sie nun das Frontend- und Backend-Gerüst erstellt, NBA-Spieldaten eingespielt und eine Verbindung zu Elasticsearch hergestellt haben, können wir damit beginnen, alle Teile zusammenzufügen, um den Agenten zu entwickeln.

Definition des Agenten

1. Navigieren Sie zur Datei index.ts im Verzeichnis backend/src/mastra/agents und fügen Sie die Agentendefinition hinzu. Sie können Felder wie die folgenden angeben:

  • Name: Geben Sie Ihrem Agenten einen Namen, der als Referenz verwendet wird, wenn er im Frontend aufgerufen wird.
  • Anweisungen/Systemaufforderung: Eine Systemaufforderung gibt dem LLM den anfänglichen Kontext und die Regeln vor, die während der Interaktion zu befolgen sind. Es ähnelt der Aufforderung, die Benutzer über das Chatfenster senden, diese wird jedoch vor jeglicher Benutzereingabe angezeigt. Auch dies hängt vom gewählten Modell ab.
  • Modell: Welches LLM soll verwendet werden (Mastra unterstützt OpenAI, Anthropic, lokale Modelle usw.)?
  • Tools: Eine Liste der Tool-Funktionen, die der Agent aufrufen kann.
  • Speicher: (Optional) Wenn der Agent sich den Gesprächsverlauf usw. merken soll. Der Einfachheit halber können wir ohne persistenten Speicher beginnen, obwohl Mastra diesen unterstützt.


Werkzeuge definieren

  1. Navigieren Sie zur Datei index.ts im Verzeichnis backend/src/mastra/tools .
  2. Installieren Sie Zod mit folgendem Befehl:

3. Werkzeugdefinitionen hinzufügen. Beachten Sie, dass wir die Funktion innerhalb der Datei comparePlayers.js als Hauptfunktion importieren, die der Agent beim Aufruf dieses Tools verwenden wird. Mit der Funktion createTool() von Mastra registrieren wir unser playerComparisonTool. Zu den Feldern gehören:

  • idDies ist eine Beschreibung in natürlicher Sprache, die dem Agenten hilft zu verstehen, was das Tool leistet.
  • input schemaUm die Form der Eingabe für das Tool zu definieren, verwendet Mastra das Zod -Schema, eine TypeScript-Bibliothek zur Schema-Validierung. Zod hilft dabei, indem es sicherstellt, dass der Agent korrekt strukturierte Eingaben vornimmt und die Ausführung des Tools verhindert, wenn die Eingabestruktur nicht übereinstimmt.
  • descriptionDies ist eine Beschreibung in natürlicher Sprache, die dem Agenten helfen soll zu verstehen, wann er anrufen und das Tool verwenden soll.
  • executeDie Logik, die beim Aufruf des Tools ausgeführt wird. In unserem Fall verwenden wir eine importierte Hilfsfunktion, um Leistungsstatistiken zurückzugeben.

Hinzufügen von Middleware zur Behandlung von CORS

Fügen Sie Middleware auf dem Mastra-Server hinzu, um CORS zu behandeln. Man sagt, es gäbe drei Dinge im Leben, denen man nicht entkommen kann: den Tod, die Steuern und für Webentwickler zusätzlich CORS. Kurz gesagt, Cross-Origin Resource Sharing ist eine Browser-Sicherheitsfunktion, die verhindert, dass das Frontend Anfragen an ein Backend sendet, das auf einer anderen Domain oder einem anderen Port läuft. Obwohl wir sowohl das Backend als auch das Frontend auf localhost betreiben, verwenden sie unterschiedliche Ports, wodurch die CORS-Richtlinie ausgelöst wird. Wir müssen die in der Mastra-Dokumentation beschriebene Middleware hinzufügen, damit unser Backend diese Anfragen vom Frontend zulässt.

1. Navigieren Sie zur Datei index.ts im Verzeichnis backend/src/mastra und fügen Sie die Konfiguration für CORS hinzu:

  • origin: ['http://localhost:5173']
    • Erlaubt Anfragen nur von dieser Adresse (Vite-Standardadresse)
  • allowMethods: ["GET", "POST"]
    • Zulässige HTTP-Methoden. In den meisten Fällen wird POST verwendet.
  • allowHeaders: ["Content-Type", "Authorization", "x-mastra-client-type, "x-highlight-request", "traceparent"],
    • Diese legen fest, welche benutzerdefinierten Header in Anfragen verwendet werden können.

Schritt 8: Integration des Frontends

Diese React-Komponente stellt eine einfache Chat-Oberfläche bereit, die über den useChat() -Hook aus @ai-sdk/react eine Verbindung zum Mastra AI-Agenten herstellt. Wir werden diesen Hook auch verwenden, um die Tokenverwendung und Toolaufrufe anzuzeigen sowie die Konversation darzustellen. In der obigen Systemabfrage bitten wir den Agenten außerdem, die Antwort im Markdown-Format auszugeben. Daher verwenden wir react-markdown , um die Antwort korrekt zu formatieren.

1. Installieren Sie im Frontend-Verzeichnis das Paket @ai-sdk/react, um den useChat()-Hook verwenden zu können.

2. Installieren Sie im selben Verzeichnis React Markdown, damit wir die vom Agenten generierte Antwort richtig formatieren können.

3. Implementiere useChat(). Dieser Hook steuert die Interaktion zwischen Ihrem Frontend und Ihrem KI-Agenten-Backend. Es verarbeitet Nachrichtenstatus, Benutzereingaben und Statusinformationen und bietet Lebenszyklus-Hooks zur Überwachung. Zu den Optionen, die wir übergeben, gehören:

  • api: Dies definiert den Endpunkt Ihres Mastra AI-Agenten. Standardmäßig wird Port 4111 verwendet, und wir möchten außerdem die Route hinzufügen, die Streaming-Antworten unterstützt.
  • onToolCallDies wird immer dann ausgeführt, wenn der Agent ein Tool aufruft; wir verwenden es, um zu verfolgen, welche Tools unser Agent aufruft.
  • onFinishDies wird ausgeführt, nachdem der Agent eine vollständige Antwort abgegeben hat. Auch wenn wir Streaming aktiviert haben, wird onFinish erst ausgeführt, nachdem die gesamte Nachricht empfangen wurde, und nicht nach jedem einzelnen Datenblock. Hier verwenden wir es, um unsere Token-Nutzung zu verfolgen. Dies kann hilfreich sein, um die LLM-Kosten zu überwachen und zu optimieren.

4. Zum Schluss gehen Sie zur Komponente ChatUI.jsx im Verzeichnis frontend/components , um die Benutzeroberfläche für unsere Konversation zu erstellen. Als Nächstes muss die Antwort in eine ReactMarkdown -Komponente eingeschlossen werden, um die Antwort des Agenten korrekt zu formatieren.

Schritt 9: Ausführen der Anwendung

Glückwunsch! Sie können die Anwendung nun ausführen. Folgen Sie diesen Schritten, um sowohl das Backend als auch das Frontend zu starten.

  1. Öffnen Sie ein Terminalfenster, beginnend im Stammverzeichnis, und navigieren Sie zum Backend-Verzeichnis. Starten Sie dort den Mastra-Server:

2. Öffnen Sie ein weiteres Terminalfenster, beginnend mit dem Stammverzeichnis, und navigieren Sie zum Frontend-Verzeichnis. Starten Sie dort die React-App:

3. Öffnen Sie Ihren Browser und navigieren Sie zu:

http://localhost:5173

Sie sollten die Chat-Oberfläche sehen können. Probieren Sie diese Beispielaufforderungen aus:

  • „Vergleiche LeBron James und Stephen Curry“
  • "Wen soll ich wählen, Jayson Tatum oder Luka Doncic?"

Was kommt als Nächstes: Den Agenten intelligenter machen.

Um den Assistenten handlungsfähiger und die Empfehlungen aussagekräftiger zu gestalten, werde ich in der nächsten Version einige wichtige Verbesserungen vornehmen.

Semantische Suche nach NBA-Nachrichten

Es gibt unzählige Faktoren, die die Leistung eines Spielers beeinflussen können, viele davon spiegeln sich nicht in den reinen Statistiken wider. Dinge wie Verletzungsberichte, Aufstellungsänderungen oder auch eine Spielanalyse nach dem Spiel findet man nur in Nachrichtenartikeln. Um diesen zusätzlichen Kontext zu erfassen, werde ich semantische Suchfunktionen hinzufügen, damit der Agent relevante NBA-Artikel abrufen und diese Erzählung in seine Empfehlungen einbeziehen kann.

Dynamische Suche mit dem Elasticsearch MCP-Server

MCP (Model Context Protocol) entwickelt sich schnell zum Standard für die Art und Weise, wie Agenten Verbindungen zu Datenquellen herstellen. Ich werde die Suchlogik auf den Elasticsearch MCP-Server migrieren, wodurch der Agent Abfragen dynamisch erstellen kann, anstatt sich auf vordefinierte Suchfunktionen zu verlassen, die wir bereitstellen. Dies ermöglicht uns die Nutzung von Workflows in natürlicher Sprache und reduziert den Aufwand, jede einzelne Suchanfrage manuell zu formulieren. Erfahren Sie hier mehr über den Elasticsearch MCP-Server und den aktuellen Stand des Ökosystems.

Diese Änderungen sind bereits im Gange, bleiben Sie gespannt!

Fazit

In diesem Blog haben wir einen agentenbasierten RAG-Assistenten entwickelt, der mithilfe von JavaScript, Mastra und Elasticsearch maßgeschneiderte Empfehlungen für Ihr Fantasy-Basketballteam liefert. Wir behandelten Folgendes:

  • Grundlagen von Agentic RAG und wie die Kombination der Autonomie eines KI-Agenten mit den Werkzeugen zur effektiven Nutzung von RAG zu differenzierteren und dynamischeren Agenten führen kann.
  • Elasticsearch und wie seine Datenspeicherfunktionen und leistungsstarken nativen Aggregationen es zu einem großartigen Partner als Wissensbasis für ein LLM machen.
  • Das Mastra- Framework und wie es die Entwicklung dieser Agenten für Entwickler im JavaScript-Ökosystem vereinfacht.

Egal, ob Sie ein Basketballfanatiker sind, sich damit beschäftigen, wie man KI-Agenten entwickelt, oder beides wie ich, ich hoffe, dieser Blog hat Ihnen einige Bausteine für den Einstieg geliefert. Das vollständige Repository ist auf GitHub verfügbar, Sie können es gerne klonen und damit experimentieren. Jetzt hol dir den Sieg in der Fantasy-Liga!

Zugehörige Inhalte

Sind Sie bereit, hochmoderne Sucherlebnisse zu schaffen?

Eine ausreichend fortgeschrittene Suche kann nicht durch die Bemühungen einer einzelnen Person erreicht werden. Elasticsearch wird von Datenwissenschaftlern, ML-Ops-Experten, Ingenieuren und vielen anderen unterstützt, die genauso leidenschaftlich an der Suche interessiert sind wie Sie. Lasst uns in Kontakt treten und zusammenarbeiten, um das magische Sucherlebnis zu schaffen, das Ihnen die gewünschten Ergebnisse liefert.

Probieren Sie es selbst aus