paint-brush
Erstellen einer Frage-Antwort-CLI mit Dewy und LangChain.jsvon@kerinin
494 Lesungen
494 Lesungen

Erstellen einer Frage-Antwort-CLI mit Dewy und LangChain.js

von Ryan11m2024/02/17
Read on Terminal Reader

Zu lang; Lesen

In diesem Tutorial konzentrieren wir uns darauf, wie man mit Dewy und LangChain.js ein CLI-Tool zur Beantwortung von Fragen erstellt.
featured image - Erstellen einer Frage-Antwort-CLI mit Dewy und LangChain.js
Ryan HackerNoon profile picture
0-item
1-item
2-item

In diesem Tutorial konzentrieren wir uns darauf, wie man mit Dewy und LangChain.js ein CLI-Tool zur Beantwortung von Fragen erstellt. Dewy ist eine Open-Source-Wissensdatenbank, die Entwicklern hilft, Informationen effizient zu organisieren und abzurufen. LangChain.js ist ein Framework, das die Integration großer Sprachmodelle (LLMs) in Anwendungen vereinfacht. Durch die Kombination der Fähigkeiten von Dewy zur Wissensverwaltung mit der LLM-Integration von LangChain.js können Sie Tools erstellen, die komplexe Anfragen mit präzisen und relevanten Informationen beantworten.


Dieser Leitfaden führt Sie durch die Einrichtung Ihrer Umgebung, das Laden von Dokumenten in Dewy und die Verwendung eines LLM über LangChain.js, um Fragen basierend auf den gespeicherten Daten zu beantworten. Es richtet sich an Ingenieure, die ihre Projekte mit erweiterten Frage-Antwort-Funktionen erweitern möchten.

Warum Dewy und LangChain.js?

Dewy ist eine OSS-Wissensdatenbank, die entwickelt wurde, um die Art und Weise zu optimieren, wie Entwickler Informationen speichern, organisieren und abrufen. Seine Flexibilität und Benutzerfreundlichkeit machen es zu einer ausgezeichneten Wahl für Entwickler, die wissensbasierte Anwendungen erstellen möchten.


LangChain.js hingegen ist ein leistungsstarkes Framework, das es Entwicklern ermöglicht, LLMs nahtlos in ihre Anwendungen zu integrieren. Durch die Kombination des strukturierten Wissensmanagements von Dewy mit den LLM-Funktionen von LangChain.js können Entwickler anspruchsvolle Frage-Antwort-Systeme erstellen, die komplexe Abfragen verstehen und verarbeiten können und präzise und kontextrelevante Antworten bieten.

Das Ziel

Unser Ziel ist es, ein einfaches, aber leistungsstarkes CLI-Skript zur Beantwortung von Fragen zu erstellen. Dieses Skript ermöglicht es Benutzern, Dokumente in die Dewy-Wissensdatenbank zu laden und dann über LangChain.js ein LLM zu verwenden, um Fragen basierend auf den in Dewy gespeicherten Informationen zu beantworten. Dieses Tutorial führt Sie durch den Prozess, von der Einrichtung Ihrer Umgebung bis zur Implementierung des CLI-Skripts.


Sie erfahren, wie Sie mit LangChain eine einfache Anwendung zur Beantwortung von Fragen erstellen und wie Sie Dewy als Wissensquelle integrieren, sodass Ihre Anwendung Fragen auf der Grundlage spezifischer Dokumente beantworten kann, die Sie ihr bereitstellen.

Voraussetzungen

Bevor Sie mit dem Tutorial beginnen, stellen Sie sicher, dass die folgenden Voraussetzungen erfüllt sind:

  • Grundkenntnisse der Typescript-Programmierung
  • Vertrautheit mit der Entwicklung von CLI-Tools
  • Eine Kopie von Dewy, die auf Ihrem lokalen Computer ausgeführt wird (lesen Sie die Installationsanweisungen von Dewy, wenn Sie hier Hilfe benötigen).

Schritt 1: Richten Sie Ihr Projekt ein

Der endgültige Code für dieses Beispiel ist im Dewy-Repo verfügbar, wenn Sie weitermachen möchten.

Erstellen Sie zunächst ein Verzeichnis für das TypeScript-CLI-Projekt und wechseln Sie in das Verzeichnis

 mkdir dewy_qa cd dewy_qa

Wenn das Verzeichnis eingerichtet ist, können Sie TypeScript installieren und das Projekt initialisieren:

 npm init -y npm i typescript --save-dev npx tsc --init

Abhängig von Ihrer Umgebung müssen Sie möglicherweise einige Änderungen an Ihrer TypeScript-Konfiguration vornehmen. Stellen Sie sicher, dass Ihre tsconfig.json etwa wie folgt aussieht:

 { "compilerOptions": { "target": "ES6", "module": "CommonJS", "moduleResolution": "node", "declaration": true, "outDir": "./dist", "esModuleInterop": true, "strict": true, }

Jetzt können Sie die CLI-Anwendung erstellen. Damit der Code nicht zu unübersichtlich wird, organisieren Sie ihn in mehreren Verzeichnissen mit dem folgenden Layout

 dewy_qa/ ├── commands/ │ └── ... ├── utils/ │ └── ... ├── index.ts ├── package.json └── tsconfig.ts

Jeder Befehl wird im commands implementiert und gemeinsam genutzter Code wird im utils Verzeichnis abgelegt. Der Einstiegspunkt zur CLI-Anwendung ist die Datei index.ts .

Beginnen Sie mit einer einfachen „Hallo Welt“-Version von index.ts – mit dem Ausfüllen beginnen Sie im nächsten Abschnitt

 #!/usr/bin/env ts-node-script console.log("hello world");

Um zu überprüfen, ob die Umgebung korrekt eingerichtet ist, versuchen Sie, den folgenden Befehl auszuführen. In der Konsole sollte „Hallo Welt“ angezeigt werden:

 npx ts-node index.ts

Anstatt diesen sehr langen Befehl jedes Mal einzugeben, erstellen wir einen Eintrag in package.json für den Befehl. Dies hilft uns, uns daran zu erinnern, wie die CLI aufgerufen wird, und erleichtert die Installation als Befehl:

 { ... "bin": { "dewy_qa": "./index.ts" } ... }

Jetzt können Sie Ihr Skript mit npm exec dewy_qa ausführen oder das Paket npm link und es einfach als dewy_qa ausführen

Schritt 2: Implementieren Sie das Laden von Dokumenten

Laden Sie Dokumente, indem Sie den Dewy-Client einrichten. Der erste Schritt besteht darin, dem Projekt einige Abhängigkeiten hinzuzufügen. Die erste ist dewy-ts , die Client-Bibliothek für Dewy. Der zweite ist commander , der uns beim Erstellen einer CLI-Anwendung mit Argumentanalyse, Unterbefehlen und mehr hilft. Abschließend können chalk die Aufforderungen bunter gestalten.

 npm install dewy-ts commander chalk

Als nächstes implementieren Sie die Logik des Ladebefehls. Sie tun dies in einer separaten Datei mit dem Namen commands/load.ts . Diese Datei implementiert eine Funktion namens „ load , die eine URL und einige zusätzliche Optionen erwartet – dies wird in einem späteren Abschnitt mit der CLI verknüpft.


Dewy macht das Laden von Dokumenten ganz einfach – richten Sie einfach den Client ein und rufen Sie addDocument mit der URL der Datei auf, die Sie laden möchten. Dewy kümmert sich darum, den Inhalt der PDF-Datei zu extrahieren, sie in Stücke aufzuteilen, die genau die richtige Größe für den Versand an ein LLM haben, und sie für die semantische Suche zu indizieren.

 import { Dewy } from 'dewy-ts'; import { success, error } from '../utils/colors'; export async function load(url: string, options: { collection: string, dewy_endpoint: string }): Promise<void> { console.log(success(`Loading ${url} into collection: ${options.collection}`)); try { const dewy = new Dewy({ BASE: options.dewy_endpoint }) const result = await dewy.kb.addDocument({ collection: options.collection, url }); console.log(success(`File loaded successfully`)); console.log(JSON.stringify(result, null, 2)); } catch (err: any) { console.error(error(`Failed to load file: ${err.message}`)); } }

Möglicherweise ist Ihnen aufgefallen, dass einige Funktionen aus ../utils/colors importiert wurden. Diese Datei richtet lediglich einige Hilfsprogramme zum Färben der Konsolenausgabe ein. Fügen Sie sie in utils ein, damit sie an anderer Stelle verwendet werden kann:

 import chalk from 'chalk'; export const success = (message: string) => chalk.green(message); export const info = (message: string) => chalk.blue(message); export const error = (message: string) => chalk.red(message);

Schritt 3: Implementieren Sie die Beantwortung von Fragen

Mit der Möglichkeit, Dokumente in Dewy zu laden, ist es an der Zeit, LangChain.js zu integrieren, um LLMs zur Beantwortung von Fragen zu nutzen. In diesem Schritt wird LangChain.js eingerichtet, um die Dewy-Wissensdatenbank abzufragen und die Ergebnisse mithilfe eines LLM zu verarbeiten, um Antworten zu generieren.


Installieren Sie zunächst einige zusätzliche Pakete – langchain und openai , um die OpenAI-API als LLM zu verwenden:

 npm install dewy-langchain langchain @langchain/openai openai

Dieser Befehl ist ziemlich lang, daher werden wir mehrere Teile davon durchgehen, bevor wir sie am Ende kombinieren

Erstellen Sie Clients für OpenAI und Dewy

Das erste, was eingerichtet werden muss, ist Dewy (wie zuvor) und ein LLM. Ein Unterschied zu zuvor besteht darin, dass dewy zum Erstellen eines DewyRetriever verwendet wird: Dies ist ein spezieller Typ, der von LangChain zum Abrufen von Informationen als Teil einer Kette verwendet wird. Sie werden in nur einer Minute sehen, wie der Retriever verwendet wird.

 const model = new ChatOpenAI({ openAIApiKey: options.openai_api_key, }); const dewy = new Dewy({ BASE: options.dewy_endpoint }) const retriever = new DewyRetriever({ dewy, collection });

Erstellen Sie eine LangChain-Eingabeaufforderung

Dabei handelt es sich um eine String-Vorlage, die dem LLM anweist, wie er sich verhalten soll, mit Platzhaltern für zusätzlichen Kontext, der beim Erstellen der „Kette“ bereitgestellt wird. In diesem Fall wird das LLM angewiesen, die Frage zu beantworten, jedoch nur unter Verwendung der von ihm bereitgestellten Informationen. Dies verringert die Tendenz des Modells, zu „halluzinieren“ oder eine Antwort zu finden, die plausibel, aber falsch ist. Die Werte context und question werden im nächsten Schritt bereitgestellt:

 const prompt = PromptTemplate.fromTemplate(`Answer the question based only on the following context: {context} Question: {question}`);

Bauen Sie die Kette auf

LangChain funktioniert durch den Aufbau von Verhaltensketten, die steuern, wie das LLM und andere Datenquellen abgefragt werden. In diesem Beispiel wird LCEL verwendet, das ein flexibleres Programmiererlebnis bietet als einige der ursprünglichen Schnittstellen von LangChain.


Verwenden Sie eine RunnableSequence , um eine LCEL-Kette zu erstellen. In dieser Kette wird beschrieben, wie die context und question generiert werden: Der Kontext wird mithilfe des zuvor erstellten Retrievers generiert, und die Frage wird durch Durchlaufen der Schritteingabe generiert. Die von Dewy abgerufenen Ergebnisse werden als Zeichenfolge formatiert, indem sie an die Funktion formatDocumentsAsString weitergeleitet werden.


Diese Kette bewirkt Folgendes:

  1. Es ruft Dokumente mit dem DewyRetriever ab, ordnet sie dem context zu und weist den Eingabewert der Kette question zu.
  2. Es formatiert die Eingabeaufforderungszeichenfolge mithilfe der context und question .
  3. Es übergibt die formatierte Eingabeaufforderung an den LLM, um eine Antwort zu generieren.
  4. Es formatiert die Antwort des LLM als Zeichenfolge.
 const chain = RunnableSequence.from([ { context: retriever.pipe(formatDocumentsAsString), question: new RunnablePassthrough(), }, prompt, model, new StringOutputParser(), ]);

Führen Sie die Kette aus

Nachdem die Kette nun erstellt wurde, führen Sie sie aus und geben Sie die Ergebnisse an die Konsole aus. Wie Sie sehen werden, ist question ein Eingabeargument, das vom Aufrufer der Funktion bereitgestellt wird.


Wenn Sie die Kette mit chain.streamLog() ausführen, können Sie jeden Antwortblock sehen, der vom LLM zurückgegeben wird. Die Stream-Handler-Schleife ist irgendwie hässlich, aber sie filtert nur nach geeigneten Stream-Ergebnissen und schreibt sie nach STDOUT (mit console.log wären nach jedem Block neue Zeilen eingefügt worden).

 const stream = await chain.streamLog(question); // Write chunks of the response to STDOUT as they're received console.log("Answer:"); for await (const chunk of stream) { if (chunk.ops?.length > 0 && chunk.ops[0].op === "add") { const addOp = chunk.ops[0]; if ( addOp.path.startsWith("/logs/ChatOpenAI") && typeof addOp.value === "string" && addOp.value.length ) { process.stdout.write(addOp.value); } } }

Fassen Sie alles als Befehl zusammen

Nachdem Sie nun alle Teile gesehen haben, können Sie den query erstellen. Dies sollte ähnlich wie der load von zuvor aussehen, mit einigen zusätzlichen Importen.

 import { StringOutputParser } from "@langchain/core/output_parsers"; import { PromptTemplate } from "@langchain/core/prompts"; import { formatDocumentsAsString } from "langchain/util/document"; import { RunnablePassthrough, RunnableSequence } from "@langchain/core/runnables"; import { ChatOpenAI } from "@langchain/openai"; import { Dewy } from 'dewy-ts'; import { DewyRetriever } from 'dewy-langchain'; import { success, error } from '../utils/colors'; export async function query(question: string, options: { collection: string, dewy_endpoint: string, openai_api_key: string }): Promise<void> { console.log(success(`Querying ${options.collection} collection for: "${question}"`)); try { const model = new ChatOpenAI({ openAIApiKey: options.openai_api_key, }); const dewy = new Dewy({ BASE: options.dewy_endpoint }) const retriever = new DewyRetriever({ dewy, collection: options.collection }); const prompt = PromptTemplate.fromTemplate(`Answer the question based only on the following context: {context} Question: {question}`); const chain = RunnableSequence.from([ { context: retriever.pipe(formatDocumentsAsString), question: new RunnablePassthrough(), }, prompt, model, new StringOutputParser(), ]); const stream = await chain.streamLog(question); // Write chunks of the response to STDOUT as they're received console.log("Answer:"); for await (const chunk of stream) { if (chunk.ops?.length > 0 && chunk.ops[0].op === "add") { const addOp = chunk.ops[0]; if ( addOp.path.startsWith("/logs/ChatOpenAI") && typeof addOp.value === "string" && addOp.value.length ) { process.stdout.write(addOp.value); } } } } catch (err: any) { console.error(error(`Failed to query: ${err.message}`)); } }

Schritt 4: Erstellen der CLI

Nachdem Dewy und LangChain.js integriert sind, besteht der nächste Schritt darin, die CLI-Schnittstelle zu erstellen. Verwenden Sie eine Bibliothek wie commander , um eine benutzerfreundliche Befehlszeilenschnittstelle zu erstellen, die Befehle zum Laden von Dokumenten in Dewy und zum Abfragen der Wissensdatenbank mithilfe von LangChain.js unterstützt.


Schreiben Sie zunächst index.ts um, um die Unterbefehle load und query zu erstellen. Das Argument --collection bestimmt, in welche Dewy-Sammlung das Dokument geladen werden soll (mit Dewy können Sie Dokumente in verschiedenen Sammlungen organisieren, ähnlich wie Dateiordner). Mit dem Argument --dewy-endpoint können Sie angeben, wie eine Verbindung zu Dewy hergestellt wird. Standardmäßig wird davon ausgegangen, dass eine Instanz lokal auf Port 8000 ausgeführt wird. Schließlich konfiguriert das Argument --openai_api_key (das standardmäßig eine Umgebungsvariable ist) die OpenAI-API:

 #!/usr/bin/env ts-node-script import { Command } from 'commander'; import { load } from './commands/load'; import { query } from './commands/query'; const program = new Command(); program.name('dewy-qa').description('CLI tool for interacting with a knowledge base API').version('1.0.0'); const defaultOpenAIKey = process.env.OPENAI_API_KEY; program .command('load') .description("Load documents into Dewy from a URL") .option('--collection <collection>', 'Specify the collection name', 'main') .option('--dewy-endpoint <endpoint>', 'Specify the collection name', 'http://localhost:8000') .argument('<url>', 'URL to load into the knowledge base') .action(load); program .command('query') .description('Ask questions using an LLM and the loaded documents for answers') .option('--collection <collection>', 'Specify the collection name', 'main') .option('--dewy-endpoint <endpoint>', 'Specify the collection name', 'http://localhost:8000') .option('--openai-api-key <key>', 'Specify the collection name', defaultOpenAIKey) .argument('<question>', 'Question to ask the knowledge base') .action(query); program.parse(process.argv);

OK, alles erledigt – war das nicht einfach? Sie können es ausprobieren, indem Sie den folgenden Befehl ausführen:

 dewy_qa load https://arxiv.org/pdf/2009.08553.pdf

Sie sollten so etwas sehen wie

 Loading https://arxiv.org/pdf/2009.08553.pdf into collection: main File loaded successfully { "id": 18, "collection": "main", "extracted_text": null, "url": "https://arxiv.org/pdf/2009.08553.pdf", "ingest_state": "pending", "ingest_error": null }

Das Extrahieren des Inhalts einer großen PDF-Datei kann ein oder zwei Minuten dauern. Daher wird häufig "ingest_state": "pending" angezeigt, wenn Sie zum ersten Mal ein neues Dokument laden.

Versuchen Sie als Nächstes, einige Fragen zu stellen:

 dewy_qa query "tell me about RAG

Sie sollten so etwas sehen wie

 Querying main collection for: "tell me about RAG" Answer: Based on the given context, RAG refers to the RAG proteins, which are involved in DNA binding and V(D)J recombination. The RAG1 and RAG2 proteins work together to bind specific DNA sequences known as RSS (recombination signal sequences) and facilitate the cutting and rearrangement of DNA segments during the process of V(D)J recombination...

Abschluss

Durch Befolgen dieser Anleitung haben Sie gelernt, wie Sie eine CLI erstellen, die Dewy zum Verwalten von Wissen und LangChain.js zum Verarbeiten von Fragen und Generieren von Antworten verwendet. Dieses Tool demonstriert die praktische Anwendung der Kombination einer strukturierten Wissensbasis mit der Analyseleistung von LLMs und ermöglicht es Entwicklern, intelligentere und reaktionsfähigere Anwendungen zu erstellen.

Weiterführende Literatur und Ressourcen