Was ich bei KI-Agenten sehe, ist ein aufregender Trend, dem meiner Meinung nach jeder, der KI entwickelt, Aufmerksamkeit schenken sollte…
Andrew Ng, Mitbegründer von Google Brain, ehemaliger Chief Scientist bei Baidu, Gründer von Coursera
Vor einigen Wochen habe ich einen geheimen Hack entdeckt, um kostenlos Gradio API-Aufrufe zu nutzen (mehr dazu könnt ihr hier und hier lesen). Außerdem habe ich mein Studium des beeindruckenden Buchs von Ben Auffarth über Langchain in der KI abgeschlossen… und ich wurde inspiriert.
Ich fragte mich, ob es eine Möglichkeit gibt, Gradio API mit Langchain zu nutzen, um die endlosen Möglichkeiten von KI-Agenten kostenlos zu testen. Seid ihr bereit, die Grundlagen für kostenlose Agenten zu legen, die für euch arbeiten?
Schnallt euch an, denn in diesem Artikel werde ich erklären, wie ihr das auch tun könnt.
Warum KI-Agenten
Ich muss zugeben, dass all die Diskussionen über KI-Agenten bisher für mich im Hintergrund waren. Zum einen, weil ich die Idee habe, dass ich nur mit Open-Source-Modellen arbeiten möchte; und zum anderen, weil ich nach kleinen, aber genauen Modellen gesucht habe, um in die Welt der KI-Agenten einzusteigen. Da ich keinen GPU habe, ist für mich die Wahl und die Größe des Modells immer eine Priorität.
Aber… was zum Teufel sind das für Agenten?
Ich bin Ingenieur für Prozesssteuerung und industrielle Automatisierung, deshalb fällt es mir leicht, zu erklären, was Agenten sind: Agenten sind die treibende Kraft hinter Entscheidungsprozessen. Sie sind
- Computerprogramme oder -systeme, die darauf ausgelegt sind, mit ihrer Umgebung zu interagieren, Entscheidungen zu treffen und bestimmte Ziele zu erreichen.
- nicht direkt von Menschen kontrolliert: diese autonomen Einheiten arbeiten unabhängig, was flexible Problemlösungsfähigkeiten ermöglicht.
Agenten können nach ihren unterschiedlichen Eigenschaften kategorisiert werden, wie zum Beispiel ihrer Reaktivität (reaktiv) oder ihrer Proaktivität, der Stabilität ihrer Umgebung (statisch oder dynamisch) und ihrer Beteiligung an Multi-Agenten-Systemen.
- Reaktive Agenten reagieren schnell auf Umweltreize und führen Aktionen auf der Grundlage dieser Eingaben aus.
- Proaktive Agenten planen und handeln proaktiv, um ihre Ziele zu erreichen.
Wenn mehrere Agenten zusammenarbeiten, bilden sie ein Multi-Agenten-System, in dem jeder Agent zu einem gemeinsamen Ziel beiträgt. Um eine effektive Koordination und Kommunikation zu gewährleisten, müssen diese Agenten ihre Aktionen synchronisieren und miteinander interagieren.
Bild aus dem Matrix – Warner Bros – bearbeitet vom AutorLangchain ist ein leistungsstarkes Framework, das kostenlos ist und über integrierte Funktionen zur Organisation und Koordination von KI-Agenten verfügt. Wir werden im nächsten Artikel mehr darüber lernen.
]
Hier werden wir die grundlegende Werkzeug für eine agentische Anwendung aufbauen.
Die Dokumentation ist das Puzzle
Es gibt noch keine verfügbaren Beispiele, und obwohl die Dokumentation zu Gradio
und Langchain
ziemlich gut ist, konzentriert sie sich hauptsächlich auf OpenAI
Beispiele. Und das ist das Hauptproblem jedes Mal, wenn Sie etwas mit Open-Source-Tools und KI machen wollen.
Ich habe mich daher entschlossen, es selbst zu erstellen. Nach einer Woche voller Kämpfe kann ich sagen, dass es möglich ist.
Gleichzeitig ist eine gute Dokumentation die Quelle der Lösung. Und wir wissen, was das Problem zu lösen ist: die Bindung eines Gradio API-Aufrufs an eine LLM-Instanz in Langchain.
Beim Durchsuchen der Dokumentation beider Frameworks fand ich einige Inspirationen:
Gradio Python-Client: Der Gradio Python-Client macht es sehr einfach, jede Gradio-App als API zu verwenden. Als Beispiel betrachten wir diesen Hugging Face Space, der Audiodateien transkribiert, die vom Mikrofon aufgenommen wurden. Hier ist ein Beispiel:
Mit der gradio_client
-Bibliothek können wir Gradio ganz einfach als API verwenden, um Audiodateien programmgesteuert zu transkribieren. Sie können sich meine vorherigen Artikel Chatbot Cheat Code: Build Your AI Assistant Running A HUGE LLM Without Spending A Penny — Part 1/Part 2 ansehen, um zu verstehen, wie sie funktionieren
Langchain Gradio-Komponente: Es gibt viele 1000s von Gradio
-Apps auf Hugging Face Spaces
. Diese Bibliothek stellt sie an den Fingerspitzen Ihrer LLM bereit 🦾 Speziell ist gradio-tools
eine Python-Bibliothek zum Konvertieren von Gradio
-Apps in Tools, die von einem großen, auf LLM basierenden Agenten genutzt werden können, um seine Aufgabe zu erfüllen.
Zum Beispiel könnte ein LLM ein Gradio
-Tool verwenden, um eine Sprachaufnahme zu transkribieren, die er online findet, und sie dann für Sie zusammenzufassen. Oder er könnte ein anderes Gradio
-Tool verwenden, um OCR auf einem Dokument auf Ihrem Google Drive anzuwenden und dann Fragen dazu zu beantworten.
Laut dem Langchain-Blog ist es sehr einfach, ein eigenes Tool zu erstellen, wenn Sie einen Space nutzen möchten, der nicht eines der vorgefertigten Tools ist. Sie können selbst entscheiden, ob der Prozess wirklich einfach ist…
Bild vom Autor
Wir brauchen eine benutzerdefinierte Wrapper
Langchain hat eine riesige Sammlung von Integrationen: Sie können sich mit Sprachmodellen, Dokumentenladern, Datenbanken und vielem mehr auf modulare und einfache Weise verbinden.
Glücklicherweise haben sie die Möglichkeit offen gelassen, benutzerdefinierte LLM-Klassen zu erstellen, die mit ihrem gesamten Toolset verwendet werden können.
Hier habe ich gelernt, wie man einen benutzerdefinierten LLM-Wrapper erstellt, falls Sie Ihren eigenen LLM oder einen anderen Wrapper als den von LangChain unterstützten verwenden möchten.
Das Einwickeln Ihres LLM mit der Standard-
LLM
-Schnittstelle ermöglicht es Ihnen, Ihren LLM in bestehenden LangChain-Programmen mit minimalen Codeänderungen zu verwenden!
Als Bonus wird Ihr LLM automatisch zu einem LangChain-
Runnable
und profitiert von einigen Optimierungen aus der Box, Unterstützung für async, derastream_events
-API, etc.
Lasst uns das tun. In diesem Beispiel werden wir Langchain mit Llama-3–8b
verbinden, aber der Prozess ist der gleiche (mit ein paar kleinen Tricks) für alle anderen Gradio API
auf den Hugging Face Hub Demo-Anwendungen.
Öffnet ein kostenloses Google Colab Notebook, eines mit nur CPU ist mehr als ausreichend. Wenn Sie neu bei Google Colab sind und wie Sie es kostenlos erhalten, lesen Sie die Anweisungen hier:
Zuerst installieren wir die erforderlichen Bibliotheken
%pip install --upgrade --quiet gradio_tools huggingface_hub langchain
Dieses Notebook wird auch ohne einen HuggingFace-Token funktionieren, aber ich empfehle Ihnen, ihn zu erstellen: Folgen Sie den Anweisungen in den Artikeln hier.
Instanziieren Sie den Gradio-Client
Dies ist der erste Schritt. Wir verwenden gradio tools
, um eine API-Anfrage an den HuggingFace Space einzurichten, der die Gradio Demo-Anwendung hostet: Die Inferenz wird dort durchgeführt und wir werden die Antwort von der LLM erhalten.
from gradio_client import Client
client = Client("ysharma/Chat_with_Meta_llama3_8b")
# this part is only to test the connection
result = client.predict(
message="Hello!!",
request=0.95,
param_3=512,
api_name="/chat"
)
print(result)
Wenn Sie die Notebook-Zelle ausführen, sehen Sie die Verbindung zum Demo-Endpunkt und das Ergebnis. BEACHTEN SIE, dass Sie eine Warnung erhalten, wenn Sie den HF-Token nicht übergeben.
Sie können das Problem lösen, indem Sie den HF-Token hier hinzufügen
Um es zu beheben, tun Sie Folgendes:
from gradio_client import Client
yourHFtoken = "hf_xxxxxxxxxxxxxxxxxxxx" #here your HF token
client = Client("ysharma/Chat_with_Meta_llama3_8b", hf_token=yourHFtoken)
Jetzt wissen wir, dass der Gradio-Client funktioniert. Wir müssen eine neue LLM-Wrapper in Langchain erstellen, um Gradio und Langchain zu verbinden
Sie finden das gesamte Notebook im dedizierten GitHub-Repository:
Der benutzerdefinierte LLM-Wrapper
Es gibt nur zwei erforderliche Dinge, die ein benutzerdefinierter LLM implementieren muss:
Bild aus den langchain docs
Laut der Dokumentationsseite oben beginnen wir mit dem Minimum: _call
und _llm_type
-Parameter in der neuen Klasse.
HINWEIS: 80% des folgenden Python-Codes stammen direkt aus der Langchain-Dokumentation 😅 Keine Sorge, ich werde einen Link zum Colab-Notebook bereitstellen. Ich werde jedoch Schritt für Schritt Erklärungen geben.
from typing import Any, List, Mapping, Optional
from langchain.callbacks.manager import CallbackManagerForLLMRun
from langchain_core.language_models.llms import LLM
from langchain_core.output_parsers import StrOutputParser
from langchain_core.prompts import ChatPromptTemplate
class GradioClientChat(LLM):
"""
Custom LLM class based on the Gradio API call.
"""
from gradio_client import Client
chatbot: Any = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Instantiating the ChatBot class
self.chatbot = Client("ysharma/Chat_with_Meta_llama3_8b")
@property
def _llm_type(self) -> str:
return "Gradio API client Meta_llama3_8b"
def _call(
self,
prompt: str,
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
chatbot=None,
request: float = 0.95,
param: float = 512,
) -> str:
"""
Make an API call to the Gradio API client Meta_llama3_8b using the specified prompt and return the response.
"""
if chatbot is None:
chatbot = self.chatbot
if stop is not None:
raise ValueError("stop kwargs are not permitted.")
# Return the response from the API
result = chatbot.predict( #.submit for streaming effect / .predict for normal output
message=prompt,
request=request,
param_3=param,
api_name="/chat"
)
return str(result)
Wenn Sie neu sind, erstellen wir hier keine Funktion, sondern eine Klasse. Eine Python-Klasse ist eine Vorlage oder ein Schablone, die eine Reihe von Methoden (Funktionen) und Attributen (Variablen) definiert, die eine Gruppe ähnlicher Objekte gemeinsam nutzen können. Sie dient als Schablone für die Erstellung von Objekten, ähnlich wie ein Bauplan die Gestaltung und Struktur eines Gebäudes beschreibt. Klassen helfen dabei, den Code zu organisieren und die Wiederverwendbarkeit von Code zu ermöglichen, was es einfacher macht, große Programme zu schreiben und zu warten.
Zurück zu unserer Klasse: Nachdem wir alle erforderlichen langchain Bibliotheken importiert haben, erstellen wir eine neue Klasse namens GradioClientChat(LLM)
. Hier verwenden wir den Gradio Client
, um als Chatbot zu fungieren. Beachten Sie, dass die Klasse die Eigenschaften der LLM Langchain-Klasse erbt. Dies ist der Grund, warum es einige Eigenschaften und Methoden gibt, die in einer benutzerdefinierten Objekt obligatorisch sind, wie zum Beispiel _call
und _llm_type
)
Der erste Teil ist also für die Initialisierung des Objekts und die _llm_type
:
class GradioClientChat(LLM):
"""
Custom LLM class based on the Gradio API call.
"""
from gradio_client import Client
chatbot: Any = None
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Instantiating the ChatBot class
self.chatbot = Client("ysharma/Chat_with_Meta_llama3_8b")
@property
def _llm_type(self) -> str:
return "Gradio API client Meta_llama3_8b"
Danach erstellen wir die _call
-Methode: Dies ist die wichtigste, denn sie ist für das Ausführen der Inferenz zuständig, wobei sie den Prompt und die Modellparameter akzeptiert (nur diejenigen, die für die spezifische Gradio API konfiguriert sind)
def _call(
self,
prompt: str,
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
chatbot=None,
request: float = 0.95,
param: float = 512,
) -> str:
"""
Make an API call to the Gradio API client Meta_llama3_8b using the specified prompt and return the response.
"""
if chatbot is None:
chatbot = self.chatbot
if stop is not None:
raise ValueError("stop kwargs are not permitted.")
# Return the response from the API
result = chatbot.predict( #.submit for streaming effect / .predict for normal output
message=prompt,
request=request,
param_3=param,
api_name="/chat"
)
return str(result)
In den Eingabeparametern setzen wir die Namen der Variablen und auch einige Standardwerte request: float = 0.95, param: float = 512
zum Beispiel. Sie müssen die spezifische Gradio API widerspiegeln, in unserem Fall aus der API-Dokumentation in ysharma/Chat_with_Meta_llama3_8b
https://huggingface.co/spaces/ysharma/Chat_with_Meta_llama3_8b
Dann rufen wir die Inferenz mit dem Gradio API-Aufruf auf und geben den Text zurück
# Return the response from the API
result = chatbot.predict( #.submit for streaming effect / .predict for normal output
message=prompt,
request=request,
param_3=param,
api_name="/chat"
)
return str(result)
Führen Sie die Zelle mit der neu erstellten Klasse aus.
Es ist Zeit zu laufen – von lexica.art
Instanziieren Sie unseren benutzerdefinierten LLM und führen Sie ihn aus
Jetzt sind wir bereit, den Langchain LLM auszuführen, der um den HuggingFace Demo-Space herum gewickelt ist:
# Instantiate the llm
llm = GradioClientChat()
# run the _call method with invoke
result = llm.invoke("what is artificial Intelligence?")
print(result)
Wenn Sie es ausführen, erhalten Sie in wenigen Sekunden die Antwort!
Mission erfüllt
Bonus-Track: Streaming-Effekt
Ein weiterer Schritt sollte kein Problem sein, oder? Wir haben gesehen, dass wir einige Mindestanforderungen und einige zusätzliche Methoden haben, die wir in unserer benutzerdefinierten Klasse erstellen können. Einer von ihnen ist _stream
, der dafür verantwortlich ist, die Token einzeln zurückzugeben, wenn sie generiert werden. Um dies zu tun, können wir am Ende unserer vorherigen Klasse eine weitere Methode hinzufügen:
def _stream(
self,
prompt: str,
stop: Optional[List[str]] = None,
run_manager: Optional[CallbackManagerForLLMRun] = None,
chatbot=None,
request: float = 0.95,
param: float = 512,
**kwargs: Any,
) -> Iterator[GenerationChunk]:
"""Stream the LLM on the given prompt.
This method should be overridden by subclasses that support streaming.
If not implemented, the default behavior of calls to stream will be to
fallback to the non-streaming version of the model and return
the output as a single chunk.
Args:
prompt: The prompt to generate from.
stop: Stop words to use when generating. Model output is cut off at the
first occurrence of any of these substrings.
run_manager: Callback manager for the run.
**kwargs: Arbitrary additional keyword arguments. These are usually passed
to the model provider API call.
Returns:
An iterator of GenerationChunks.
"""
if chatbot is None:
chatbot = self.chatbot
if stop is not None:
raise ValueError("stop kwargs are not permitted.")
# Return the response from the API
for char in chatbot.submit( #.submit for streaming effect / .predict for normal output
message=prompt,
request=request,
param_3=param,
api_name="/chat"
):
chunk = GenerationChunk(text=char)
if run_manager:
run_manager.on_llm_new_token(chunk.text, chunk=chunk)
yield chunk
Sie werden bemerken, dass der erste Teil im Wesentlichen der gleiche ist. Die Änderungen erfolgen an 2 Stellen:
- am Anfang, wo wir deklarieren, dass die Ausgabe der Methode ein
Iterator
-Objekt ist, nicht eineZeichenkette
- am Ende, wo wir eine for-Schleife starten und die
submit()
-Methode anstelle derpredict
-Methode aufrufen. Ich habe den Unterschied in meinem Artikel Teil 2 erklärt.
Jetzt können wir die Klasse erneut ausführen, mit der neuen Ergänzung, und mit einer kleinen Änderung in der print()
-Anweisung werden wir auch in Google Colab den Text sehen, der während der Generierung gestreamt wird.
llm = GradioClientChat()
# code required for textual interfaces - not required with Steramlit
final = ''
for token in llm.stream("what is science?"):
if final == '':
final=token
print(token, end="", flush=True)
else:
try:
print(token.replace(final,''), end="", flush=True)
final = token
except:
pass
Google Colab streamt ein benutzerdefiniertes LLM von LangChain – bereit für Agenten
In streamlit benötigen Sie den obigen Code nicht. Ein Iterator-Objekt ist inkrementell, d.h. es stapelt alle Token nacheinander auf. In Google Colab können wir uns das jedoch nicht leisten. Wir müssen die print-Funktion entsprechend anpassen, indem wir von der neuen Iterator-Stream die bereits generierten Wörter subtrahieren.
Zwischenstand…
Wir haben gerade die Grundlagen für eine Herde von KI-Agenten gelegt, die wir von überall aus ausführen können. Ehrlich gesagt, können Sie mit jedem Langchain-Tutorial versuchen, unsere brandneue Wrapper um die Gradio API zu verwenden.
Sie können auch versuchen, ein anderes großes Modell wie Qwen100b mit kleinen Anpassungen auszuführen. Lassen Sie mich wissen, ob Sie erfolgreich waren.
Was warten Sie noch?
Ich hoffe, Ihnen hat der Artikel gefallen. Denken Sie daran, dass es das Notebook für diesen Artikel gibt
Wenn dieser Artikel einen Wert geliefert hat und Sie ein wenig Unterstützung zeigen möchten, können Sie:
- Mehrmals für diese Geschichte klatschen
- Markieren Sie die relevanteren Teile, damit sie leichter zu finden sind (für Sie zum späteren Lesen und für mich, um bessere Artikel zu schreiben)
- Lernen Sie, wie Sie Ihre eigene KI aufbauen, Laden Sie Dieses kostenlose eBook herunter
- Melden Sie sich für eine Medium-Mitgliedschaft mit meinem Link an — (5 $/Monat, um unbegrenzt Medium-Geschichten zu lesen)
- Folgen Sie mir auf Medium
- Lesen Sie meine neuesten Artikel https://medium.com/@fabio.matricardi
Wenn Sie mehr lesen möchten, hier sind einige Ideen:
Sie können es selbst mit diesem Artikel von Youssef Hosni versuchen
Lernmaterial:
Beispiel für eine Python-Klasse:
Stellen Sie sich vor, Sie möchten ein Programm erstellen, das ein einfaches Bankkonto darstellt. Sie könnten eine Klasse mit dem Namen BankAccount
definieren, die zwei Attribute hat: account_number
(zur Speicherung der Kontonummer) und balance
(zur Speicherung des aktuellen Kontostands). Die Klasse würde auch über eine Methode mit dem Namen deposit()
verfügen, um Geld auf das Konto einzuzahlen, und eine Methode mit dem Namen withdraw()
, um Geld vom Konto abzuheben.
Um eine Instanz dieser Klasse zu erstellen, würden Sie sie instanziieren, indem Sie die Klasse wie eine Funktion aufrufen, z.B. so:
account1 = BankAccount("12345", 1000)
Jetzt ist account1
ein Objekt der Klasse BankAccount
mit der Kontonummer „12345“ und einem Anfangskontostand von 1000. Sie können dann Methoden auf account1
aufrufen, wie z.B. deposit(500)
, um 500 zum Kontostand hinzuzufügen, oder withdraw(200)
, um 200 vom Kontostand abzuziehen.
Klassen sind ein grundlegendes Konzept in der objektorientierten Programmierung und ermöglichen es Ihnen, komplexe Programme zu erstellen, indem Sie verwandte Daten und Funktionen in wiederverwendbare Komponenten organisieren.