\n\n\n\n Meine Erfahrung mit dem SDK LangChain.js V2 für IA-Agenten - AgntBox Meine Erfahrung mit dem SDK LangChain.js V2 für IA-Agenten - AgntBox \n

Meine Erfahrung mit dem SDK LangChain.js V2 für IA-Agenten

📖 11 min read2,158 wordsUpdated Mar 30, 2026

Hallo zusammen, hier ist Nina von agntbox.com! Heute möchte ich über etwas sprechen, das in meinem Arbeitsumfeld seit einigen Wochen viel Aufsehen erregt: die neue Version von LangChain.js. Genauer gesagt habe ich tief in das aktualisierte SDK eingetaucht und wie es mein Leben als Entwickler von KI-Agenten erheblich erleichtert – und manchmal auch ein wenig frustrierend ist, aber im positiven Sinne des Lernens.

Wenn ihr meine Beiträge verfolgt, wisst ihr, dass ich ein großer Fan von JavaScript wegen seiner Vielseitigkeit bin, und wenn es darum geht, große Sprachmodelle zu orchestrieren, war LangChain.js schon immer mein Referenzpunkt. Aber seien wir ehrlich, die Anfänge hatten ihre Besonderheiten. Komplexe Chains aufzusetzen, den Speicher zwischen den Aufrufen zu verwalten und verschiedene Tools zu integrieren, schien manchmal, als würde ich versuchen, Katzen zusammenzubringen. Mit den neuesten Updates des SDKs bemerke ich jedoch einen signifikanten Wechsel hin zu intuitiveren Mustern und einer besseren Entwicklererfahrung. Und ehrlich gesagt, es wurde Zeit.

Also anstelle eines generischen Artikels „Was ist LangChain.js?“ (das haben wir schon gemacht!), möchte ich meine praktischen Erfahrungen mit dem neuen SDK teilen, wobei ich mich darauf konzentriere, wie es die Entwicklung von Agenten vereinfacht, insbesondere wenn man Agenten anvisiert, die tatsächlich Handlungen in der realen Welt durchführen können – nicht nur diskutieren.

Meine Kopfschmerzen bei der Erstellung von Agenten vor dem Update

Bevor ich in die guten Dinge eintauche, lasst mich ein Bild meiner früheren Kämpfe zeichnen. Ich arbeitete an einem Projekt für einen Kunden – nennen wir sie „Acme Analytics“ – die einen Agenten benötigten, um Datenanalysen durchzuführen. Dieser Agent sollte in der Lage sein:

  • Auf eine SQL-Datenbank zuzugreifen, um Rohdaten abzurufen.
  • Einige grundlegende statistische Berechnungen (Durchschnitt, Median usw.) durchzuführen.
  • Einfache Diagramme mit einer Diagrammbibliothek zu generieren.
  • Die Ergebnisse zusammenzufassen und dem Benutzer zu präsentieren.

Das klingt einfach, oder? Nun, all diese „Tools“ mit einem LLM zu integrieren, den Gesprächsspeicher zu verwalten und sicherzustellen, dass der Agent korrekt entscheiden konnte, welches Tool wann verwendet werden sollte, war… eine Reise. Ich habe viel Zeit damit verbracht, mit der Prompt-Engineering zu kämpfen, um das LLM zu leiten, benutzerdefinierte Tool-Definitionen zu entwerfen, die sich in die bestehende Struktur von LangChain einfügten, und Speicherlecks zu debuggieren, die aus dem Nichts auftauchten. Es fühlte sich an, als würde ich die Dinge nur patchen, anstatt elegant zu bauen.

Der Tango der „Tool-Definition“

Einer der größten Schmerzpunkte war die Definition der Tools. Man hatte seine Funktion und wickelte sie dann in ein `Tool`-Objekt, wobei man sicherstellte, dass die Beschreibung absolut perfekt war, damit das LLM sie verstehen konnte. Wenn deine Beschreibung nur um ein Wort ungenau war, konnte das LLM halluzinieren oder dein Tool einfach ignorieren. Es war ein delikater Tanz.


// Alte Methode (vereinfacht für das Beispiel)
import { Tool } from "langchain/tools";

const sqlQueryTool = new Tool({
 name: "SQL_Query_Executor",
 description: "Verwende dieses Tool, um SQL-Abfragen auf der Datenbank von Acme Analytics auszuführen. Die Eingabe muss eine gültige SQL SELECT-Anweisung sein. Gibt das Ergebnis der Abfrage zurück.",
 func: async (query: string) => {
 // ... Logik zum Verbinden mit der DB und Ausführen der Abfrage
 return "Ergebnisse der Abfrage...";
 },
});

Das funktionierte, aber es war umständlich, und jede Änderung an der zugrunde liegenden Funktion bedeutete oft, dass die Beschreibung ebenfalls angepasst werden musste. Man hatte wirklich das Gefühl, dass man eine sehr manuelle Übersetzungsschicht hatte.

Mit dem neuen SDK LangChain.js: Ein frischer Wind?

Als das neue SDK zu implementieren begann, war ich vorsichtig optimistisch. „Bessere Tool-Definitionen“, sagten sie. „Vereinfachte Agentenerstellung“, versprachen sie. Mein Skepsis war hoch, aber mein Bedarf an einem reibungsloseren Workflow war noch stärker.

Ich beschloss, eine vereinfachte Version des Acme Analytics-Agenten mit den neuen Modellen des SDKs neu zu erstellen, wobei ich mich auf die Integration der Kern-Tools und die Orchestrierung des Agenten konzentrierte. Und ehrlich gesagt war ich positiv überrascht.

Moderne Tools mit Zod-Schemas

Die größte Verbesserung für mich war, wie die Tools definiert sind. Das neue SDK setzt stark auf die Verwendung von Zod zur Validierung der Eingabe-Schemas. Das mag wie eine kleine Änderung erscheinen, aber es ist ein riesiger Fortschritt aus mehreren Gründen:

  1. Typensicherheit: Du erhältst eine entsprechende Typüberprüfung für deine Tool-Eingaben, was die Laufzeitfehler erheblich reduziert.
  2. Klarere Beschreibungen: Zod ermöglicht es dir, Beschreibungen direkt zu deinen Schemafeldern hinzuzufügen, die LangChain dann zur Generierung einer genaueren und maschinenlesbaren Tool-Beschreibung für das LLM nutzen kann. Das bedeutet weniger manuelle Prompt-Engineering deinerseits.
  3. Integrierte Validierung: Wenn das LLM versucht, dein Tool mit ungültigen Argumenten aufzurufen, erkennt Zod dies sofort und bietet dir ein besseres Feedback zum Debugging.

Lass uns unser SQL-Abfrage-Tool mit dem neuen Ansatz überarbeiten:


// Neue Methode mit Zod
import { DynamicTool } from "@langchain/core/tools";
import { z } from "zod";

const sqlQueryTool = new DynamicTool({
 name: "SQL_Query_Executor",
 description: "Führt SQL-Abfragen auf der Datenbank von Acme Analytics aus.",
 schema: z.object({
 query: z.string().describe("Eine gültige SQL SELECT-Anweisung, die auf der Datenbank ausgeführt werden soll."),
 }),
 func: async ({ query }) => {
 try {
 // ... Logik zum Verbinden mit der DB und Ausführen der Abfrage
 console.log(`Führe SQL-Abfrage aus: ${query}`);
 // Simuliere einen Aufruf zur Datenbank
 await new Promise(resolve => setTimeout(resolve, 500)); 
 if (query.includes("SELECT * FROM users")) {
 return JSON.stringify([{ id: 1, name: "Alice" }, { id: 2, name: "Bob" }]);
 }
 return JSON.stringify([{ result: "Daten erfolgreich abgerufen für die Abfrage: " + query }]);
 } catch (error) {
 return `Fehler beim Ausführen der Abfrage: ${error.message}`;
 }
 },
});

Siehst du den Unterschied? Die Eigenschaft `schema`, die `z.object` und `z.string().describe()` verwendet, bietet eine viel strukturiertere und solidere Möglichkeit, festzulegen, was dein Tool erwartet. Die `description` des Tools selbst bleibt wichtig, aber die detaillierten Beschreibungen innerhalb des Schemas bieten dem LLM einen viel besseren Kontext für jedes Argument. Ich habe festgestellt, dass das LLM viel effizienter ist, korrekte Funktionsaufrufe zu erzeugen, wenn es über diese expliziten Schemata verfügt, mit denen es arbeiten kann.

Vereinfachte Erstellung von Agenten mit `createOpenAIFunctionsAgent`

Ein weiteres Gebiet, in dem das neue SDK glänzt, ist die Erstellung von Agenten. Für jeden, der die OpenAI-Modelle verwendet (was, seien wir ehrlich, viele von uns tun), war die Funktion `createOpenAIFunctionsAgent` eine echte Bereicherung. Sie kümmert sich um viel des Standardcodes, der erforderlich ist, um einen Agenten einzurichten, der die Funktionalitäten von OpenAI nutzen kann.

Früher baute ich oft manuell `RunnableSequence`-Objekte, indem ich sorgfältig ein `ChatPromptTemplate`, das LLM und dann einen `ToolExecutor` miteinander verband. Das funktionierte, aber es fühlte sich an, als würde ich IKEA-Möbel ohne alle Anleitungen zusammenbauen.

Jetzt ist es viel direkter:


import { ChatOpenAI } from "@langchain/openai";
import { createOpenAIFunctionsAgent, AgentExecutor } from "langchain/agents";
import { ChatPromptTemplate } from "@langchain/core/prompts";

// ... (Definition von sqlQueryTool wie oben)

const llm = new ChatOpenAI({
 model: "gpt-4-0125-preview", // Oder welches aktuelle Modell Sie bevorzugen
 temperature: 0,
});

const prompt = ChatPromptTemplate.fromMessages([
 ["system", "Sie sind ein nützlicher KI-Assistent, der in der Lage ist, Daten zu analysieren. Verwenden Sie die bereitgestellten Werkzeuge, um Fragen zu den Daten von Acme Analytics zu beantworten."],
 ["human", "{input}"],
 ["placeholder", "{agent_scratchpad}"], // Wichtig für den internen Denkprozess des Agenten
]);

const tools = [sqlQueryTool]; // Fügen Sie hier bei Bedarf weitere Werkzeuge hinzu

const agent = await createOpenAIFunctionsAgent({
 llm,
 tools,
 prompt,
});

const agentExecutor = new AgentExecutor({
 agent,
 tools,
 verbose: true, // Immer gut zu sehen, was der Agent macht!
});

// Testen wir es !
const result = await agentExecutor.invoke({
 input: "Kannst du mir die Namen aller Benutzer in der Datenbank geben?",
});

console.log("Endgültige Antwort des Agents:", result.output);

Dieser Code-Snippet ist so viel klarer! Die `createOpenAIFunctionsAgent` verwaltet die komplexe Logik der Umwandlung von Funktionsaufrufen des LLM in tatsächliche Tool-Ausführungen. Der `AgentExecutor` orchestriert dann den gesamten Prozess, führt den Agenten aus, überprüft, ob er ein Werkzeug verwenden muss, führt das Werkzeug aus und gibt das Ergebnis an den Agenten zur weiteren Verarbeitung zurück. Die Option `verbose: true` ist ein Retter für das Debugging, da sie es Ihnen ermöglicht, die Schritt-für-Schritt-Überlegungen des Agents zu sehen.

Verbesserte Speicherverwaltung (Noch ein Bereich für Verbesserungen, aber besser!)

Speicher war schon immer ein heikles Thema in der dialogbasierten KI. Frühere Interaktionen zu verfolgen, ohne die Kontextfenster des LLM zu überladen, erfordert ein ständiges Gleichgewicht. Das neue SDK löst nicht magisch alle Speicherprobleme, bietet aber geschmeidigere Möglichkeiten, verschiedene Speicherarten zu integrieren.

Für meinen Acme Analytics-Agent benötigte ich einen einfachen Konversationspuffer. Die Integration dieses Puffers mit der neuen Agenten-Konfiguration ist ziemlich einfach:


import { BufferWindowMemory } from "langchain/memory";

const memory = new BufferWindowMemory({
 k: 5, // Die letzten 5 Interaktionen im Gedächtnis behalten
 memoryKey: "chat_history", // Wird an das Prompt übergeben
 returnMessages: true,
});

// ... (restliche Agentenkonfiguration)

// Prompt anpassen, um den Gesprächsverlauf einzubeziehen
const promptWithMemory = ChatPromptTemplate.fromMessages([
 ["system", "Sie sind ein nützlicher KI-Assistent, der in der Lage ist, Daten zu analysieren. Verwenden Sie die bereitgestellten Werkzeuge, um Fragen zu den Daten von Acme Analytics zu beantworten."],
 new MessagesPlaceholder("chat_history"), // Platzhalter für den Speicher
 ["human", "{input}"],
 ["placeholder", "{agent_scratchpad}"],
]);

const agentWithMemory = await createOpenAIFunctionsAgent({
 llm,
 tools,
 prompt: promptWithMemory,
});

const agentExecutorWithMemory = new AgentExecutor({
 agent: agentWithMemory,
 tools,
 memory, // Speicher hier übergeben
 verbose: true,
});

// Beispielinteraktion
await agentExecutorWithMemory.invoke({
 input: "Hallo, was kannst du tun?",
});

await agentExecutorWithMemory.invoke({
 input: "Kannst du mir die Namen aller Benutzer in der Datenbank geben?",
});

// Der Speicher wird nun den Austausch "Hallo, was kannst du tun?" behalten

Der `MessagesPlaceholder` im Prompt ist entscheidend, da er es dem `AgentExecutor` ermöglicht, die `chat_history` aus der `BufferWindowMemory` direkt in das Prompt einzufügen. Obwohl die Grenzen des Kontextfensters nach wie vor eine Realität sind, macht diese Integration die Verwaltung dieses Verlaufs viel geschmeidiger als zuvor.

Praktische Tipps für Ihr nächstes KI-Projekt

Nachdem ich eine gute Zeit mit dem neuen SDK LangChain.js verbracht habe, hier ist, was ich gelernt habe und was ich empfehle, wenn Sie die Entwicklung von Agenten erkunden:

  1. Nutzen Sie Zod für die Definition von Werkzeugen:

    Ehrlich gesagt, das ist eine wesentliche Veränderung. Es macht Ihre Werkzeuge solider, einfacher für das LLM verständlich und bietet Ihnen eine bessere Typensicherheit. Investieren Sie zu Beginn die notwendige Zeit, um Ihre Werkzeug-Schemata korrekt zu definieren.

    
    // Immer ein klares Schema für Ihre Werkzeuge definieren
    const myNewTool = new DynamicTool({
     name: "WeatherDataFetcher",
     description: "Ruft die aktuellen Wetterdaten für eine bestimmte Stadt ab.",
     schema: z.object({
     city: z.string().describe("Der Name der Stadt, für die das Wetter abgerufen werden soll."),
     unit: z.enum(["celsius", "fahrenheit"]).default("celsius").describe("Die zu returnierende Temperatureinheit."),
     }),
     func: async ({ city, unit }) => {
     // ... Logik für den Wetter-API-Aufruf
     return `Das Wetter in ${city} beträgt 25 Grad ${unit}.`;
     },
    });
     
  2. Beginnen Sie mit `createOpenAIFunctionsAgent` (wenn Sie OpenAI verwenden):

    Es sei denn, Sie haben sehr spezifische Gründe, dies nicht zu tun, vereinfacht diese Funktion die Erstellung von Agenten erheblich. Sie verwaltet die Feinheiten der Funktionsaufruf-API von OpenAI, so dass Sie sich auf Ihre Werkzeuge und Prompts konzentrieren können.

  3. Halten Sie Ihre Prompts gezielt und klar:

    Obwohl mit besseren Werkzeugdefinitionen das System-Prompt nach wie vor der Nordstern Ihres Agents bleibt. Definieren Sie klar seine Rolle, Fähigkeiten und alle Einschränkungen. Nutzen Sie den Platzhalter `agent_scratchpad` für das innere Monolog des Agents.

  4. Aktivieren Sie `verbose: true` für das Debugging:

    Wenn die Dinge schief gehen (und das passiert!), ist `verbose: true` auf Ihrem `AgentExecutor` Ihr bester Freund. Es gibt das Denken des LLM aus, welches Werkzeug es zu rufen versucht und die Ergebnisse, was Ihnen hilft, Probleme schnell zu identifizieren.

  5. Verwalten Sie den Speicher sorgfältig:

    Obwohl die Integration besser ist, denken Sie daran, dass Speicher Tokens kostet. Wählen Sie den geeigneten Speichertyp für Ihren Anwendungsfall (z.B. `BufferWindowMemory` für kurzfristige Gespräche oder eine ausgefeiltere Zusammenfassung, wenn die Länge des Kontexts ein wichtiges Anliegen ist). Fügen Sie immer den `MessagesPlaceholder` in Ihr Prompt ein, wenn Sie den Speicher verwenden.

  6. Testen Sie iterativ:

    Bauen Sie ein Werkzeug, testen Sie es. Fügen Sie es dem Agenten hinzu, testen Sie es. Fügen Sie ein weiteres Werkzeug hinzu, testen Sie es erneut. Die Entwicklung von KI-Agenten ist intrinsisch iterativ. Kleine gezielte Tests ersparen Ihnen später Kopfschmerzen.

Das neue SDK LangChain.js scheint einen signifikanten Schritt in Richtung Erleichterung der Entwicklung von KI-Agenten und Reduzierung von kryptischen Fehlern darzustellen. Es ist nicht perfekt, und es gibt immer eine Lernkurve mit neuen Schemata, aber die Verbesserungen bei der Werkzeugdefinition und der Orchestrierung von Agenten machen meine Projekte tatsächlich reibungsloser. Wenn Sie zögern, LangChain.js zu erkunden, oder wenn Sie mit früheren Versionen weniger zufrieden waren, ist jetzt der perfekte Zeitpunkt, um dem aktualisierten SDK eine neue Chance zu geben.

Was sind Ihre Erfahrungen mit dem neuen SDK LangChain.js? Haben Sie nützliche Tipps oder interessante Herausforderungen entdeckt? Lassen Sie es mich in den Kommentaren unten wissen! Viel Spaß beim Coden!

🕒 Published:

🧰
Written by Jake Chen

Software reviewer and AI tool expert. Independently tests and benchmarks AI products. No sponsored reviews — ever.

Learn more →
Browse Topics: AI & Automation | Comparisons | Dev Tools | Infrastructure | Security & Monitoring
Scroll to Top