Unsere Reise durch die innovative Welt von LangChain hat dessen umfassende Fähigkeiten bei der Transformation von Datenmanagement und Anwendungsfunktionalität offenbart.
In früheren Diskussionen haben wir uns mit mehreren Themen befasst und dabei die komplexen Funktionen von LangChain erkundet. In diesem Artikel bauen wir auf den Konzepten auf, die in „Langchain-Agenten mit MinIO stärken“ behandelt werden, indem wir die Funktionalität eines MinIO-Agenten erweitern, um zusätzliche Fähigkeiten einzubinden und den benutzerdefinierten Agenten über LangServe bereitzustellen.
Aufbauend auf diesen Erkenntnissen richten wir nun unseren Fokus auf
Automatische Erstellung von API-Endpunkten: Die Automatisierungsfunktionen von LangServe generieren mühelos die erforderlichen API-Endpunkte, rationalisieren den Entwicklungsaufwand und verkürzen die Bereitstellungszeit erheblich.
Schemagenerierung und -validierung: Mit seiner intelligenten Schemainferenz stellt LangServe sicher, dass APIs gut definierte Schnittstellen bieten und so eine einfachere Integration und ein nahtloses Benutzererlebnis ermöglichen.
Anpassbare Endpunktkonfiguration: LangServe bietet eine Vielzahl von Endpunkten für unterschiedliche Anwendungsanforderungen, von synchronen Vorgängen bis hin zu Echtzeitaktualisierungen, und bietet Entwicklern eine beispiellose Flexibilität.
Mühelose Integration: Das vielleicht überzeugendste Merkmal von LangServe ist die Fähigkeit, sich nahtlos in vorhandenen LangChain-Code zu integrieren. Dies bedeutet, dass Entwickler ihre aktuelle Codebasis und ihr Fachwissen ohne wesentliche Änderungen nutzen können.
Wir werden in den folgenden Schritten tiefer in den Prozess der Integration von MinIO mit LangChain eintauchen.
langchain-cli
.agent.py
Datei.server.py
, um ihn als LangServe-API auszuführen.Die Bereitstellung von LangChain-Anwendungen mit LangServe ermöglicht eine nahtlose Integration und schließt die Lücke zwischen komplexen KI-Funktionen und der Verwendung von RESTful API. So können Entwickler das gesamte Spektrum der LangChain-Funktionen effizient nutzen und einen neuen Standard für die Bereitstellung intelligenter Anwendungen in der heutigen schnelllebigen digitalen Landschaft setzen.
LangChain bietet eine bequeme und einfache Methode zum Erstellen von Anwendungen mit ihrem langchain-cli
pip
installiert werden kann. Dieses Paket bietet eine Schnittstelle, mit der Benutzer problemlos neue Anwendungen erstellen können, indem sie vorhandene
Hinweis: Alle erforderlichen Dateien befinden sich im MinIO-Repository „blog-assets“ im Verzeichnis „minio-langserve-deployment “.
Um eine neue LangChain-Anwendung zu erstellen, können wir mit den folgenden Befehlen beginnen, um eine virtuelle Umgebung zu erstellen und das Paket langchain-cli
zu installieren:
mkdir minio-langserve-testing cd minio-Langserve-testing python -m venv .myenv source .myenv/bin/activate pip install langchain-cli
Um mit langchain-cli
eine neue App zu erstellen, können wir langchain
in unser Terminal eingeben. Der folgende Befehl wird geschrieben, um ein neues Anwendungsverzeichnis mit dem Namen my-app
zu erstellen.
langchain app new my-app
Die mit den obigen Befehlen erstellte Langchain-App übernimmt die ganze schwere Arbeit, indem sie eine konsistente Umgebung für die Entwicklung erstellt. Die Struktur einer neuen LangChain-Anwendung sieht sofort nach dem Auspacken so aus:
./my-app ├── Dockerfile ├── README.md ├── app │ ├── __init__.py │ └── server.py ⇐ (This is where we will import our agent into) ├── packages ⇐ (This directory is where we will write our agent) │ └── README.md └── pyproject.toml
In den folgenden Schritten nehmen wir Änderungen an der neu erstellten LangChain-Anwendung ( my-app
) vor, indem wir eine neue Datei mit dem Namen packages/agent.py schreiben und Änderungen an app/server.py
vornehmen.
Dies sind die Dateien, die wir in diesem Artikel besprechen werden:
my-app/packages/agent.py
my-app/app/server.py
Um die Bereitstellung eines MinIO-integrierten LangChain-Agenten mit LangServe zu veranschaulichen, speichern wir zunächst den Agent-Chain-Code in agent.py
.
Lassen Sie uns zunächst einen minio_client
initialisieren, der eine Verbindung zum öffentlichen Server „play.min.io:443“ herstellt. Diese Datei ruft schließlich agent_executor
von LangChain auf, sodass wir sie an add_route
Wrapper von LangServe übergeben können.
Hinweis: Lesen der vorherigen Veröffentlichung "
Öffnen Sie zunächst die Datei agent.py in einem Texteditor:
sudo nano packages/agent.py
Importieren Sie am Anfang der Datei die erforderlichen Pakete wie os
, io
, minio
und ChatOpenAI
:
import os import io from minio import Minio from minio.error import S3Error from langchain_openai import ChatOpenAI os.environ["OPENAI_API_KEY"] = "<<Your API Key Here>>" # Initialize llm llm = ChatOpenAI(api_key=os.environ["OPENAI_API_KEY"]) # Initialize MinIO client minio_client = Minio('play.min.io:443', access_key='minioadmin', secret_key='minioadmin', secure=True)
In diesem Codeausschnitt importieren wir die erforderlichen Pakete und initialisieren das ChatOpenAI-Sprachmodell mit dem OpenAI-API-Schlüssel, der in der Umgebungsvariable OPENAI_API_KEY
gespeichert ist. Wir initialisieren auch den minio_client, indem wir die erforderlichen Verbindungsdetails zum öffentlichen Server „play.min.io“ bereitstellen.
Als nächstes definieren wir den MinIO-Bucket und erstellen ihn, falls er nicht existiert:
# This variable will check if bucket exists bucket_name = "test" try: # Check if bucket exists if not minio_client.bucket_exists(bucket_name): # Create the bucket because it does not exist minio_client.make_bucket(bucket_name) print(f"Bucket '{bucket_name}' created successfully.") else: print(f"Bucket '{bucket_name}' already exists.") except S3Error as err: print(f"Error encountered: {err}")
Hier definieren wir den bucket_name
als „Test“ und prüfen, ob er bereits existiert, indem wir die Methode minio_client.bucket_exists()
verwenden. Wenn der Bucket nicht existiert, erstellen wir ihn mit minio_client.make_bucket()
. Wenn der Bucket bereits existiert, drucken wir eine entsprechende Meldung. Wir schließen auch eine Fehlerbehandlung mit einem Try-Except-Block ein, um alle S3Error
abzufangen und auszudrucken, die während des Prozesses auftreten können.
Nachdem die Grundkonfiguration abgeschlossen ist, können wir nun mit der Definition der MinIO-Toolfunktionen und der Erstellung des Agent-Executors fortfahren, was wir in den nächsten Schritten behandeln werden.
Langchain und Langserve bieten beide einen ähnlichen Ansatz zur Kapselung von Logik und Funktionalität, sodass diese nahtlos in die Agenten- und Kettenlogik integriert werden können. Dies wird durch die Verwendung des @tool
Dekorators mit einer detaillierten Docstring innerhalb der definierten Funktion erreicht, die Funktionen als wiederverwendbare Komponenten kennzeichnet, die vom KI-Agenten verwendet und interpretiert werden können.
Schauen wir uns die bereitgestellten Codebeispiele genauer an:
from langchain.agents import tool @tool def upload_file_to_minio(bucket_name: str, object_name: str, data_bytes: bytes): """ Uploads a file to MinIO. Parameters: bucket_name (str): The name of the bucket. object_name (str): The name of the object to create in the bucket. data_bytes (bytes): The raw bytes of the file to upload. """ data_stream = io.BytesIO(data_bytes) minio_client.put_object(bucket_name, object_name, data_stream, length=len(data_bytes)) return f"File {object_name} uploaded successfully to bucket {bucket_name}."
Die Funktion upload_file_to_minio
ist mit @tool
versehen, was darauf hinweist, dass es sich um eine wiederverwendbare Komponente handelt. Sie nimmt die erforderlichen Parameter auf, um eine Datei in einen MinIO-Bucket hochzuladen, wie z. B. den Bucket-Namen, den Objektnamen und die Rohbytes der Datei. Die Funktion verwendet den minio_client
um den Datei-Upload-Vorgang durchzuführen, und gibt nach Abschluss eine Erfolgsmeldung zurück.
@tool def download_file_from_minio(file_info): """ Custom function to download a file from MinIO. Expects file_info dict with 'bucket_name', 'object_name', and 'save_path' keys. 'save_path' should be the local path where the file will be saved. """ bucket_name = file_info['bucket_name'] object_name = file_info['object_name'] save_path = file_info['save_path'] minio_client.get_object(bucket_name, object_name, save_path)
Ebenso ist die Funktion download_file_from_minio
mit @tool
gekennzeichnet. Sie erwartet ein file_info
Wörterbuch, das die erforderlichen Informationen zum Herunterladen einer Datei aus einem MinIO-Bucket enthält, z. B. den Bucket-Namen, den Objektnamen und den lokalen Pfad, in dem die Datei gespeichert werden soll. Die Funktion verwendet den minio_client
um das Objekt aus dem angegebenen Bucket abzurufen und es im angegebenen lokalen Pfad zu speichern.
@tool def list_objects_in_minio_bucket(file_info): """ Custom function to list objects in a MinIO bucket. Expects file_info dict with 'bucket_name' key. Returns a list of dictionaries containing 'ObjectKey' and 'Size' keys. """ bucket_name = file_info['bucket_name'] response = minio_client.list_objects(bucket_name) return [{'ObjectKey': obj.object_name, 'Size': obj.size} for obj in response.items]
Die Funktion list_objects_in_minio_bucket
, die ebenfalls mit @tool
dekoriert ist, ist für die Auflistung der in einem MinIO-Bucket vorhandenen Objekte verantwortlich. Sie erwartet ein file_info
Wörterbuch mit dem Schlüssel bucket_name
. Die Funktion verwendet den minio_client
, um die Liste der Objekte im angegebenen Bucket abzurufen, und gibt eine Liste von Wörterbüchern zurück, die den Objektschlüssel und die Größe für jedes Objekt enthalten.
Indem sie diese Funktionalitäten als Tools kapseln, ermöglichen Langchain und Langserve dem KI-Agenten, sie nahtlos in seinen Logik- und Entscheidungsprozess zu integrieren. Der Agent kann je nach anstehender Aufgabe das geeignete Tool intelligent auswählen und ausführen, was seine Fähigkeiten erweitert und komplexere und dynamischere Interaktionen mit dem MinIO-Speichersystem ermöglicht.
LangChain bietet eine Vielzahl von Methoden zum Erstellen mit benutzerdefinierter Logik. Ein solcher Ansatz ist „RunnableLambda
eine von LangChain bereitgestellte Konstruktion, die es ermöglicht, Funktionen als ausführbare Einheiten innerhalb der Logik des KI-Agenten zu behandeln.
from langchain_core.runnables import RunnableLambda upload_file_runnable = RunnableLambda(upload_file_to_minio) download_file_runnable = RunnableLambda(download_file_from_minio) list_objects_runnable = RunnableLambda(list_objects_in_minio_bucket)
Indem wir die Toolfunktionen mit RunnableLambda umschließen, erstellen wir ausführbare Instanzen ( upload_file_runnable
, download_file_runnable
und list_objects_runnable
), die vom Agenten während seiner Ausführung aufgerufen werden können. Diese Runnables kapseln die entsprechenden Toolfunktionen und bieten dem Agenten eine einheitliche Schnittstelle für die Interaktion mit ihnen.
tools = [upload_file_to_minio, download_file_from_minio, list_objects_in_minio_bucket] llm_with_tools = llm.bind_tools(tools)
Die Toolliste enthält die ursprünglichen Toolfunktionen ( upload_file_to_minio
, download_file_from_minio
und list_objects_in_minio_bucket
), die als Bausteine für die Fähigkeiten des Agenten dienen. Die Zeile llm.bind_tools(tools)
bindet die Tools an das Sprachmodell ( llm
) und stellt eine Verbindung zwischen den Denkfähigkeiten des Modells und den spezifischen Funktionen her, die die Tools bieten. Das resultierende llm_with_tools
stellt das Sprachmodell dar, das mit dem Wissen und der Fähigkeit zur Verwendung der gebundenen Tools erweitert wurde.
Die Verwendung von RunnableLambda
und die Bindung von Tools an das Sprachmodell demonstrieren die Flexibilität und Erweiterbarkeit von LangChain und LangServe bei der Erstellung leistungsstarker und anpassbarer KI-Agenten. Durch die Kombination der Leistungsfähigkeit des Sprachmodells mit den in den Tools gekapselten spezifischen Funktionen erhält der KI-Agent die Fähigkeit, komplexe Aufgaben auszuführen, wie z. B. das Hochladen von Dateien auf MinIO, das Herunterladen von Dateien von MinIO und das Auflisten von Objekten in einem MinIO-Bucket.
Als Nächstes richten wir unseren Fokus auf die Eingabeaufforderungsvorlage, die dem KI-Agenten beim Verstehen und Reagieren auf Benutzereingaben hilft. Sie wird mithilfe der Methode ChatPromptTemplate.from_messages()
definiert, die eine Liste von Nachrichten entgegennimmt, die als Tupel dargestellt werden, die die Rolle und den Nachrichteninhalt enthalten.
from langchain_core.prompts import ChatPromptTemplate, MessagesPlaceholder from langchain.agents.format_scratchpad.openai_tools import format_to_openai_tool_messages from langchain.agents.output_parsers.openai_tools import OpenAIToolsAgentOutputParser from langchain_core.messages import AIMessage, HumanMessage prompt_template = ChatPromptTemplate.from_messages([ ("system", "You are a powerful assistant equipped with file management capabilities."), ("user", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad"), ])
Die Eingabeaufforderung besteht aus drei Meldungen:
Eine „System“-Nachricht, die den Kontext für den KI-Agenten als leistungsstarken Assistenten mit Dateiverwaltungsfunktionen festlegt.
Eine „Benutzer“-Nachricht, die die Eingabe des Benutzers unter Verwendung des Platzhalters {input}
darstellt.
Ein MessagesPlaceholder
mit dem Namen „agent_scratchpad“ zum Speichern der Zwischenschritte und Denkprozesse des Agenten.
Die Funktion format_to_openai_tool_messages
formatiert das Scratchpad des Agenten in ein kompatibles Format für die Tools von OpenAI, während die Klasse „OpenAIToolsAgentOutputParser“ die Antwort des Modells in ein strukturiertes Format analysiert, das vom Agenten interpretiert werden kann.
Die Klassen AIMessage
und HumanMessage
stellen die zwischen dem Agenten und dem Benutzer ausgetauschten Nachrichten dar und bieten eine standardisierte Möglichkeit, die Kommunikation innerhalb der Logik des Agenten zu handhaben.
Durch die Definition der Eingabeaufforderungsvorlage bieten wir dem KI-Agenten eine klare Struktur und einen klaren Kontext zum Verstehen und Reagieren auf Benutzereingaben. Dabei verwenden wir den Platzhalter „agent_scratchpad“, um seine Zwischenschritte und Denkprozesse beim Lösen der Aufgabe zu verfolgen.
Um schließlich unser agent.py
zu vervollständigen, definieren wir unseren Agenten und erstellen einen AgentExecutor, der mithilfe der Funktion add_route
aus der LangServe-Bibliothek in ein server.py
Skript importiert und von dort aufgerufen werden kann.
Wir instanziieren die erforderlichen Komponenten und verketten sie, um eine einzelne Agentenvariable zu erstellen.
agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai_tool_messages(x["intermediate_steps"]), } | prompt_template | llm_with_tools | OpenAIToolsAgentOutputParser() )
Der Agent wird mithilfe einer Kombination aus Wörterbüchern und verketteten Operationen definiert. Der Schlüssel input extrahiert die Benutzereingabe aus den eingehenden Daten, während der Schlüssel agent_scratchpad
die Zwischenschritte des Denkprozesses des Agenten mithilfe der Funktion format_to_openai_tool_messages
formatiert. Der Agent enthält außerdem die Eingabeaufforderungsvorlage ( prompt_template
), das Sprachmodell mit Tools ( llm_with_tools
) und den Ausgabeparser ( OpenAIToolsAgentOutputParser()
).
Um einen AgentExecutor
zu erstellen, stellen wir ihm den definierten Agenten und die verfügbaren Tools zur Verfügung und setzen verbose=True
für eine detaillierte Ausgabe.
from langchain.agents import tool, AgentExecutor agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True)
Der AgentExecutor
verwendet den bereitgestellten Agenten und die bereitgestellten Tools, um die Aufgabe zu verstehen und basierend auf der Benutzereingabe das entsprechende Tool auszuwählen. Anstatt separate Eingabeaufforderungen für jedes Tool zu haben, verwendet der Agent eine einzige Eingabeaufforderungsvorlage, die ihn anhand der gegebenen Eingabe durch die Verwendung der Tools führt. Der Agent wählt während des Ausführungsprozesses dynamisch das entsprechende Tool aus.
Die Einrichtung unserer Anwendung durch Integration mit LangServe bietet einen optimierten Weg zur Bereitstellung und Verwaltung unserer LangChain-Anwendungen als APIs. FastAPI wurde aufgrund seiner Leistung und Benutzerfreundlichkeit ausgewählt, da es asynchrone Vorgänge unterstützt und automatisch API-Dokumentation generiert.
Der
Weitere ausführliche Demonstrationen/Anwendungsfälle finden Sie unter
langchain-ai/langserve GitHub-Repository unter demBeispiele-Verzeichnis .
from fastapi import FastAPI app = FastAPI( title="MinIO Agent API", version="1.0", description="A conversational agent facilitating data storage and retrieval with MinIO", )
Zum Festlegen von CORS-Headern können wir die folgenden Zeilen hinzufügen, um unsere Sicherheit zu erhöhen:
from fastapi.middleware.cors import CORSMiddleware # Set all CORS enabled origins app.add_middleware( CORSMiddleware, allow_origins=["*"], allow_credentials=True, allow_methods=["*"], allow_headers=["*"], expose_headers=["*"], )
Nachdem wir nun mit packages/agent.py
fertig sind, können wir es importieren und die add_route
Funktion aus der LangServe-Bibliothek in unserem app/server.py
Skript verwenden.
from packages.agent import agent_executor from langserve import add_routes add_routes( app, agent_executor.with_types(input_type=Input, output_type=Output).with_config( {"run_name": "agent"} ), path=”/invoke” )
Durch den Aufruf von add_route(app, agent_executor(…), path="/invoke")
fügen wir unserer Serveranwendung ( app
) eine Route hinzu, die den /invoke
Pfad der agent_executor()
Funktion zuordnet. Dadurch kann der Agent-Executor aufgerufen werden, wenn eine Anfrage an den /invoke
Endpunkt gestellt wird.
Mit dieser Konfiguration kann der Server eingehende Anfragen verarbeiten, sie an den Agent-Executor weiterleiten und die Antwort des Agenten an den Client zurücksenden. Der Agent-Executor verwendet den definierten Agenten, der die Eingabeaufforderungsvorlage, das Sprachmodell mit Tools und den Ausgabeparser enthält, um die Benutzereingabe zu verarbeiten und basierend auf den verfügbaren Tools eine entsprechende Antwort zu generieren.
Um die LangServe-Anwendung zu starten, verwenden wir Uvicorn als ASGI-Server und bereiten damit die Voraussetzungen für die Ausführung unserer App vor. Dieser Codeausschnitt ist von entscheidender Bedeutung, da er den Server aktiviert und den Universalhost und den angegebenen Port für die Zugriffspunkte der Anwendung angibt.
if __name__ == "__main__": import uvicorn uvicorn.run(app, host="0.0.0.0", port=8000)
Indem wir diesen Block in den Haupteintrag der Anwendung einbetten, stellen wir sicher, dass Uvicorn das Ruder übernimmt, wenn das Skript direkt ausgeführt wird, und so unsere FastAPI-Anwendung auf einem vordefinierten Host und Port aktiviert. Dieser Ansatz vereinfacht nicht nur den Bereitstellungsprozess, sondern markiert auch einen klaren Eintrag zum Ausführen der Anwendung in einer Entwicklungs- oder Produktionsumgebung.
Der obige Code demonstriert einen modularen Ansatz, der die Verwendung der Bibliothek „langchain-cli“, das Erstellen einer neuen Langchain-App und das Speichern der Kettenlogik in agent.py
umfasst, während die FastAPI- und LangServe-Implementierung in server.py
gespeichert wird.
Da dies unser letzter Schritt ist, speichern wir unseren Anwendungscode zu Demonstrationszwecken zum Erstellen unserer Anwendung in server.py
.
Am einfachsten können Sie unseren Dienst folgendermaßen ausführen:
python server.py
Dieser Befehl führt die Anwendung aus und gibt gleichzeitig alle Protokolle oder Fehlermeldungen zurück, die noch debuggt werden müssen.
In der Python-Ausgabe identifizieren die LangServe-Protokolle /invoke/playground
als Anwendungsendpunkt. Wir können nun die Playground-WebUI sowie die automatisierte Dokumentation für unsere API aufrufen, die verfügbar ist, wenn wir den Pfad /docs
unserer API aufrufen. Dies vereinfacht uns das Testen und Konfigurieren, indem es für jede unserer Anwendungsfunktionen eine Schaltfläche „Ausprobieren“ sowie vordefinierte cURL-Anfragen enthält, die wir von der WebUI aus ausführen können.
Folglich wurde unser in MinIO integrierter LangChain-Agent nun geschickt in eine einsetzbare API umgewandelt, die für Benutzer mit Funktionen von der Stapelverarbeitung bis hin zu Echtzeit-Interaktionen weiterentwickelt und erweitert werden kann.
Wenn die LangServe-Anwendung läuft, können wir sie von außerhalb unseres server.py
verwenden, indem wir unseren Endpunkt anvisieren und ihn in das RemoteRunnable
-Modul von Langserve einbinden:
from langserve import RemoteRunnable remote_runnable = RemoteRunnable("http://localhost:8000/<path>/")
Hinzufügen
LangChain bietet eine große Auswahl an Modulen in seinen Bibliotheken und stellt damit ein vielfältiges Toolkit zur Verfügung, das Entwicklern die Erstellung anspruchsvoller KI-gesteuerter Anwendungen ermöglicht. Von komplexen Kettenkonstruktionen bis hin zur nahtlosen Integration mit verschiedenen KI-Modellen ermöglicht die modulare Architektur von LangChain eine breite Palette an Funktionen und ermöglicht die Erstellung hochgradig anpassbarer und fortschrittlicher Lösungen im Bereich KI und maschinelles Lernen.
LangServe entmystifiziert nicht nur den Bereitstellungsprozess von LangChain-Anwendungen, sondern vereinfacht ihn auch erheblich. Indem es die Lücke zwischen Entwicklung und Bereitstellung schließt, stellt es sicher, dass innovative Anwendungen, die MinIO und LangChain nutzen, schnell vom Konzept zur Realität werden können, bereit sind, in das breitere Ökosystem integriert zu werden und das Benutzererlebnis zu verbessern.
Durch die Entwicklung, die wir in unseren Untersuchungen behandelt haben, haben wir die nahtlose Integration von MinIO mit
Bei MinIO sind wir von der Kreativität und dem Potenzial der Entwickler-Community in diesem technologiereichen Zeitalter begeistert. Es gibt keinen besseren Zeitpunkt für Zusammenarbeit und Wissensaustausch. Wir freuen uns darauf, mit Ihnen in Kontakt zu treten! Besuchen Sie uns auf unserer