Im Kern, LangChain ist ein innovatives Framework, das auf die Erstellung von Anwendungen zugeschnitten ist, die die Fähigkeiten von Sprachmodellen nutzen. Es handelt sich um ein Toolkit, das für Entwickler entwickelt wurde, um Anwendungen zu erstellen, die kontextbewusst sind und zu anspruchsvollen Überlegungen fähig sind.
Das bedeutet, dass LangChain-Anwendungen den Kontext verstehen können, wie z. B. Aufforderungsanweisungen oder inhaltsbegründende Antworten, und Sprachmodelle für komplexe Argumentationsaufgaben verwenden können, wie z. B. die Entscheidung, wie reagiert oder welche Maßnahmen ergriffen werden sollen. LangChain stellt einen einheitlichen Ansatz zur Entwicklung intelligenter Anwendungen dar und vereinfacht mit seinen vielfältigen Komponenten den Weg vom Konzept bis zur Ausführung.
LangChain verstehen
LangChain ist viel mehr als nur ein Framework; Es handelt sich um ein vollwertiges Ökosystem, das aus mehreren integralen Teilen besteht.
- Erstens gibt es die LangChain-Bibliotheken, die sowohl in Python als auch in JavaScript verfügbar sind. Diese Bibliotheken bilden das Rückgrat von LangChain und bieten Schnittstellen und Integrationen für verschiedene Komponenten. Sie bieten eine grundlegende Laufzeit für die Kombination dieser Komponenten zu zusammenhängenden Ketten und Agenten sowie vorgefertigte Implementierungen für den sofortigen Einsatz.
- Als nächstes haben wir LangChain-Vorlagen. Hierbei handelt es sich um eine Sammlung einsetzbarer Referenzarchitekturen, die auf eine Vielzahl von Aufgaben zugeschnitten sind. Unabhängig davon, ob Sie einen Chatbot oder ein komplexes Analysetool erstellen, bieten diese Vorlagen einen soliden Ausgangspunkt.
- LangServe fungiert als vielseitige Bibliothek für die Bereitstellung von LangChain-Ketten als REST-APIs. Dieses Tool ist unerlässlich, um Ihre LangChain-Projekte in zugängliche und skalierbare Webdienste umzuwandeln.
- Schließlich dient LangSmith als Entwicklerplattform. Es dient zum Debuggen, Testen, Bewerten und Überwachen von Ketten, die auf einem beliebigen LLM-Framework basieren. Die nahtlose Integration mit LangChain macht es zu einem unverzichtbaren Werkzeug für Entwickler, die ihre Anwendungen verfeinern und perfektionieren möchten.
Zusammen ermöglichen Ihnen diese Komponenten die einfache Entwicklung, Produktion und Bereitstellung von Anwendungen. Mit LangChain beginnen Sie damit, Ihre Anwendungen mithilfe der Bibliotheken zu schreiben und sich dabei an Vorlagen zu orientieren. LangSmith unterstützt Sie dann bei der Inspektion, dem Testen und der Überwachung Ihrer Ketten und stellt so sicher, dass Ihre Anwendungen ständig verbessert werden und für den Einsatz bereit sind. Schließlich können Sie mit LangServe jede Kette ganz einfach in eine API umwandeln und so die Bereitstellung zum Kinderspiel machen.
In den nächsten Abschnitten werden wir uns eingehender mit der Einrichtung von LangChain befassen und Ihre Reise zur Erstellung intelligenter, sprachmodellgestützter Anwendungen beginnen.
Automatisieren Sie manuelle Aufgaben und Arbeitsabläufe mit unserem KI-gesteuerten Workflow-Builder, der von Nanonets für Sie und Ihre Teams entwickelt wurde.
Installation und Einrichtung
Sind Sie bereit, in die Welt von LangChain einzutauchen? Die Einrichtung ist unkompliziert und diese Anleitung führt Sie Schritt für Schritt durch den Vorgang.
Der erste Schritt auf Ihrer LangChain-Reise ist die Installation. Sie können dies ganz einfach mit Pip oder Conda tun. Führen Sie den folgenden Befehl in Ihrem Terminal aus:
pip install langchain
Für diejenigen, die die neuesten Funktionen bevorzugen und sich mit etwas mehr Abenteuer auskennen, können Sie LangChain direkt von der Quelle installieren. Klonen Sie das Repository und navigieren Sie zu langchain/libs/langchain
Verzeichnis. Dann renne:
pip install -e .
Für experimentelle Funktionen sollten Sie die Installation in Betracht ziehen langchain-experimental
. Es handelt sich um ein Paket, das modernsten Code enthält und für Forschungs- und Versuchszwecke gedacht ist. Installieren Sie es mit:
pip install langchain-experimental
LangChain CLI ist ein praktisches Tool für die Arbeit mit LangChain-Vorlagen und LangServe-Projekten. Um die LangChain-CLI zu installieren, verwenden Sie:
pip install langchain-cli
LangServe ist für die Bereitstellung Ihrer LangChain-Ketten als REST-API unerlässlich. Es wird zusammen mit der LangChain-CLI installiert.
LangChain erfordert häufig Integrationen mit Modellanbietern, Datenspeichern, APIs usw. In diesem Beispiel verwenden wir die Modell-APIs von OpenAI. Installieren Sie das OpenAI-Python-Paket mit:
pip install openai
Um auf die API zuzugreifen, legen Sie Ihren OpenAI-API-Schlüssel als Umgebungsvariable fest:
export OPENAI_API_KEY="your_api_key"
Alternativ können Sie den Schlüssel auch direkt in Ihrer Python-Umgebung übergeben:
import os
os.environ['OPENAI_API_KEY'] = 'your_api_key'
LangChain ermöglicht die Erstellung von Sprachmodellanwendungen über Module. Diese Module können entweder eigenständig sein oder für komplexe Anwendungsfälle zusammengestellt werden. Diese Module sind –
- Modell I/O: Erleichtert die Interaktion mit verschiedenen Sprachmodellen und verarbeitet deren Ein- und Ausgaben effizient.
- Abruf: Ermöglicht den Zugriff auf und die Interaktion mit anwendungsspezifischen Daten, was für die dynamische Datennutzung von entscheidender Bedeutung ist.
- Mitarbeiter: Ermöglichen Sie Anwendungen die Auswahl geeigneter Tools auf der Grundlage übergeordneter Richtlinien und verbessern Sie so die Entscheidungsfähigkeit.
- Ketten: Bietet vordefinierte, wiederverwendbare Kompositionen, die als Bausteine für die Anwendungsentwicklung dienen.
- Memory: Behält den Anwendungsstatus über mehrere Kettenausführungen hinweg bei, was für kontextbezogene Interaktionen unerlässlich ist.
Jedes Modul zielt auf spezifische Entwicklungsanforderungen ab und macht LangChain zu einem umfassenden Toolkit für die Erstellung fortschrittlicher Sprachmodellanwendungen.
Neben den oben genannten Komponenten haben wir auch LangChain Expression Language (LCEL)Dies ist eine deklarative Methode zum einfachen Zusammensetzen von Modulen und ermöglicht die Verkettung von Komponenten mithilfe einer universellen Runnable-Schnittstelle.
LCEL sieht ungefähr so aus –
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import BaseOutputParser # Example chain
chain = ChatPromptTemplate() | ChatOpenAI() | CustomOutputParser()
Nachdem wir uns nun mit den Grundlagen befasst haben, fahren wir fort mit:
- Tauchen Sie im Detail in jedes Langchain-Modul ein.
- Erfahren Sie, wie Sie die LangChain Expression Language verwenden.
- Entdecken Sie häufige Anwendungsfälle und implementieren Sie sie.
- Stellen Sie eine End-to-End-Anwendung mit LangServe bereit.
- Schauen Sie sich LangSmith zum Debuggen, Testen und Überwachen an.
Lass uns loslegen!
Modul I: Modell-I/O
In LangChain dreht sich das Kernelement jeder Anwendung um das Sprachmodell. Dieses Modul bietet die wesentlichen Bausteine für eine effektive Schnittstelle zu jedem Sprachmodell und gewährleistet so eine nahtlose Integration und Kommunikation.
Schlüsselkomponenten der Modell-I/O
- LLMs und Chat-Modelle (austauschbar verwendet):
- LLMs:
- Definition: Reine Textvervollständigungsmodelle.
- Input / Output: Nehmen Sie eine Textzeichenfolge als Eingabe und geben Sie eine Textzeichenfolge als Ausgabe zurück.
- Chat-Modelle
- LLMs:
- Definition: Modelle, die ein Sprachmodell als Basis verwenden, sich jedoch in den Eingabe- und Ausgabeformaten unterscheiden.
- Input / Output: Akzeptieren Sie eine Liste von Chat-Nachrichten als Eingabe und geben Sie eine Chat-Nachricht zurück.
- Eingabeaufforderungen: Modelleingaben als Vorlage erstellen, dynamisch auswählen und verwalten. Ermöglicht die Erstellung flexibler und kontextspezifischer Eingabeaufforderungen, die die Antworten des Sprachmodells leiten.
- Ausgabeparser: Informationen aus Modellausgaben extrahieren und formatieren. Nützlich zum Konvertieren der Rohausgabe von Sprachmodellen in strukturierte Daten oder spezifische Formate, die von der Anwendung benötigt werden.
LLMs
Die Integration von LangChain mit Large Language Models (LLMs) wie OpenAI, Cohere und Hugging Face ist ein grundlegender Aspekt seiner Funktionalität. LangChain selbst hostet keine LLMs, bietet aber eine einheitliche Schnittstelle zur Interaktion mit verschiedenen LLMs.
Dieser Abschnitt bietet einen Überblick über die Verwendung des OpenAI LLM-Wrappers in LangChain, der auch auf andere LLM-Typen anwendbar ist. Wir haben dies bereits im Abschnitt „Erste Schritte“ installiert. Lassen Sie uns das LLM initialisieren.
from langchain.llms import OpenAI
llm = OpenAI()
- LLMs implementieren das Ausführbare Schnittstelle, der Grundbaustein der LangChain Expression Language (LCEL). Das heißt, sie unterstützen
invoke
,ainvoke
,stream
,astream
,batch
,abatch
,astream_log
Anrufe. - LLMs akzeptieren Streicher als Eingaben oder Objekte, die in String-Eingabeaufforderungen umgewandelt werden können, einschließlich
List[BaseMessage]
undPromptValue
. (mehr dazu später)
Sehen wir uns einige Beispiele an.
response = llm.invoke("List the seven wonders of the world.")
print(response)
Alternativ können Sie die Stream-Methode aufrufen, um die Textantwort zu streamen.
for chunk in llm.stream("Where were the 2012 Olympics held?"): print(chunk, end="", flush=True)
Chat-Modelle
Die Integration von LangChain mit Chat-Modellen, einer speziellen Variante von Sprachmodellen, ist für die Erstellung interaktiver Chat-Anwendungen unerlässlich. Während sie intern Sprachmodelle verwenden, stellen Chat-Modelle eine eigene Schnittstelle dar, die sich auf Chat-Nachrichten als Ein- und Ausgänge konzentriert. Dieser Abschnitt bietet einen detaillierten Überblick über die Verwendung des Chat-Modells von OpenAI in LangChain.
from langchain.chat_models import ChatOpenAI
chat = ChatOpenAI()
Chat-Modelle in LangChain funktionieren mit verschiedenen Nachrichtentypen wie z AIMessage
, HumanMessage
, SystemMessage
, FunctionMessage
und ChatMessage
(mit einem beliebigen Rollenparameter). Allgemein, HumanMessage
, AIMessage
und SystemMessage
werden am häufigsten verwendet.
Chat-Modelle akzeptieren in erster Linie List[BaseMessage]
als Eingaben. Zeichenfolgen können konvertiert werden HumanMessage
und PromptValue
wird auch unterstützt.
from langchain.schema.messages import HumanMessage, SystemMessage
messages = [ SystemMessage(content="You are Micheal Jordan."), HumanMessage(content="Which shoe manufacturer are you associated with?"),
]
response = chat.invoke(messages)
print(response.content)
Eingabeaufforderungen
Eingabeaufforderungen sind für die Steuerung von Sprachmodellen von entscheidender Bedeutung, um relevante und kohärente Ausgaben zu generieren. Sie können von einfachen Anweisungen bis hin zu komplexen Beispielen mit wenigen Aufnahmen reichen. In LangChain kann die Bearbeitung von Eingabeaufforderungen dank mehrerer dedizierter Klassen und Funktionen ein sehr rationalisierter Prozess sein.
LangChains PromptTemplate
Die Klasse ist ein vielseitiges Tool zum Erstellen von String-Eingabeaufforderungen. Es verwendet Pythons str.format
Syntax, die eine dynamische Eingabeaufforderungsgenerierung ermöglicht. Sie können eine Vorlage mit Platzhaltern definieren und diese nach Bedarf mit bestimmten Werten füllen.
from langchain.prompts import PromptTemplate # Simple prompt with placeholders
prompt_template = PromptTemplate.from_template( "Tell me a {adjective} joke about {content}."
) # Filling placeholders to create a prompt
filled_prompt = prompt_template.format(adjective="funny", content="robots")
print(filled_prompt)
Bei Chat-Modellen sind Eingabeaufforderungen strukturierter und umfassen Nachrichten mit bestimmten Rollen. LangChain bietet ChatPromptTemplate
für diesen Zweck.
from langchain.prompts import ChatPromptTemplate # Defining a chat prompt with various roles
chat_template = ChatPromptTemplate.from_messages( [ ("system", "You are a helpful AI bot. Your name is {name}."), ("human", "Hello, how are you doing?"), ("ai", "I'm doing well, thanks!"), ("human", "{user_input}"), ]
) # Formatting the chat prompt
formatted_messages = chat_template.format_messages(name="Bob", user_input="What is your name?")
for message in formatted_messages: print(message)
Dieser Ansatz ermöglicht die Erstellung interaktiver, ansprechender Chatbots mit dynamischen Antworten.
Beide PromptTemplate
und ChatPromptTemplate
lassen sich nahtlos in die LangChain Expression Language (LCEL) integrieren, sodass sie Teil größerer, komplexer Arbeitsabläufe sein können. Wir werden später mehr darüber besprechen.
Benutzerdefinierte Eingabeaufforderungsvorlagen sind manchmal für Aufgaben unerlässlich, die eine eindeutige Formatierung oder spezifische Anweisungen erfordern. Das Erstellen einer benutzerdefinierten Eingabeaufforderungsvorlage umfasst die Definition von Eingabevariablen und einer benutzerdefinierten Formatierungsmethode. Diese Flexibilität ermöglicht es LangChain, auf eine Vielzahl anwendungsspezifischer Anforderungen einzugehen. Lesen Sie hier mehr.
LangChain unterstützt auch Few-Shot-Prompting, sodass das Modell aus Beispielen lernen kann. Diese Funktion ist für Aufgaben, die ein kontextbezogenes Verständnis oder bestimmte Muster erfordern, von entscheidender Bedeutung. Vorlagen für Few-Shot-Eingabeaufforderungen können aus einer Reihe von Beispielen oder mithilfe eines Beispielauswahlobjekts erstellt werden. Lesen Sie hier mehr.
Ausgabeparser
Ausgabeparser spielen in Langchain eine entscheidende Rolle, da sie es Benutzern ermöglichen, die von Sprachmodellen generierten Antworten zu strukturieren. In diesem Abschnitt untersuchen wir das Konzept von Ausgabeparsern und stellen Codebeispiele mit PydanticOutputParser, SimpleJsonOutputParser, CommaSeparatedListOutputParser, DatetimeOutputParser und XMLOutputParser von Langchain bereit.
PydanticOutputParser
Langchain stellt den PydanticOutputParser zum Parsen von Antworten in Pydantic-Datenstrukturen bereit. Unten finden Sie ein Schritt-für-Schritt-Beispiel für die Verwendung:
from typing import List
from langchain.llms import OpenAI
from langchain.output_parsers import PydanticOutputParser
from langchain.prompts import PromptTemplate
from langchain.pydantic_v1 import BaseModel, Field, validator # Initialize the language model
model = OpenAI(model_name="text-davinci-003", temperature=0.0) # Define your desired data structure using Pydantic
class Joke(BaseModel): setup: str = Field(description="question to set up a joke") punchline: str = Field(description="answer to resolve the joke") @validator("setup") def question_ends_with_question_mark(cls, field): if field[-1] != "?": raise ValueError("Badly formed question!") return field # Set up a PydanticOutputParser
parser = PydanticOutputParser(pydantic_object=Joke) # Create a prompt with format instructions
prompt = PromptTemplate( template="Answer the user query.n{format_instructions}n{query}n", input_variables=["query"], partial_variables={"format_instructions": parser.get_format_instructions()},
) # Define a query to prompt the language model
query = "Tell me a joke." # Combine prompt, model, and parser to get structured output
prompt_and_model = prompt | model
output = prompt_and_model.invoke({"query": query}) # Parse the output using the parser
parsed_result = parser.invoke(output) # The result is a structured object
print(parsed_result)
Der Ausgang wird:
SimpleJsonOutputParser
Der SimpleJsonOutputParser von Langchain wird verwendet, wenn Sie JSON-ähnliche Ausgaben analysieren möchten. Hier ist ein Beispiel:
from langchain.output_parsers.json import SimpleJsonOutputParser # Create a JSON prompt
json_prompt = PromptTemplate.from_template( "Return a JSON object with `birthdate` and `birthplace` key that answers the following question: {question}"
) # Initialize the JSON parser
json_parser = SimpleJsonOutputParser() # Create a chain with the prompt, model, and parser
json_chain = json_prompt | model | json_parser # Stream through the results
result_list = list(json_chain.stream({"question": "When and where was Elon Musk born?"})) # The result is a list of JSON-like dictionaries
print(result_list)
CommaSeparatedListOutputParser
Der CommaSeparatedListOutputParser ist praktisch, wenn Sie durch Kommas getrennte Listen aus Modellantworten extrahieren möchten. Hier ist ein Beispiel:
from langchain.output_parsers import CommaSeparatedListOutputParser
from langchain.prompts import PromptTemplate
from langchain.llms import OpenAI # Initialize the parser
output_parser = CommaSeparatedListOutputParser() # Create format instructions
format_instructions = output_parser.get_format_instructions() # Create a prompt to request a list
prompt = PromptTemplate( template="List five {subject}.n{format_instructions}", input_variables=["subject"], partial_variables={"format_instructions": format_instructions}
) # Define a query to prompt the model
query = "English Premier League Teams" # Generate the output
output = model(prompt.format(subject=query)) # Parse the output using the parser
parsed_result = output_parser.parse(output) # The result is a list of items
print(parsed_result)
DatetimeOutputParser
Der DatetimeOutputParser von Langchain dient zum Parsen von Datetime-Informationen. So verwenden Sie es:
from langchain.prompts import PromptTemplate
from langchain.output_parsers import DatetimeOutputParser
from langchain.chains import LLMChain
from langchain.llms import OpenAI # Initialize the DatetimeOutputParser
output_parser = DatetimeOutputParser() # Create a prompt with format instructions
template = """
Answer the user's question:
{question}
{format_instructions} """ prompt = PromptTemplate.from_template( template, partial_variables={"format_instructions": output_parser.get_format_instructions()},
) # Create a chain with the prompt and language model
chain = LLMChain(prompt=prompt, llm=OpenAI()) # Define a query to prompt the model
query = "when did Neil Armstrong land on the moon in terms of GMT?" # Run the chain
output = chain.run(query) # Parse the output using the datetime parser
parsed_result = output_parser.parse(output) # The result is a datetime object
print(parsed_result)
Diese Beispiele zeigen, wie die Ausgabeparser von Langchain verwendet werden können, um verschiedene Arten von Modellantworten zu strukturieren und sie für verschiedene Anwendungen und Formate geeignet zu machen. Ausgabeparser sind ein wertvolles Werkzeug zur Verbesserung der Benutzerfreundlichkeit und Interpretierbarkeit von Sprachmodellausgaben in Langchain.
Automatisieren Sie manuelle Aufgaben und Arbeitsabläufe mit unserem KI-gesteuerten Workflow-Builder, der von Nanonets für Sie und Ihre Teams entwickelt wurde.
Modul II: Retrieval
Der Abruf in LangChain spielt eine entscheidende Rolle bei Anwendungen, die benutzerspezifische Daten erfordern, die nicht im Trainingssatz des Modells enthalten sind. Bei diesem als Retrieval Augmented Generation (RAG) bezeichneten Prozess werden externe Daten abgerufen und in den Generierungsprozess des Sprachmodells integriert. LangChain bietet eine umfassende Suite von Tools und Funktionalitäten, um diesen Prozess zu erleichtern und sowohl einfache als auch komplexe Anwendungen abzudecken.
LangChain erreicht den Abruf durch eine Reihe von Komponenten, die wir einzeln besprechen werden.
Dokumentlader
Dokumentenlader in LangChain ermöglichen die Extraktion von Daten aus verschiedenen Quellen. Mit über 100 verfügbaren Loadern unterstützen sie eine Reihe von Dokumenttypen, Apps und Quellen (private S3-Buckets, öffentliche Websites, Datenbanken).
Sie können einen Dokumentenlader entsprechend Ihren Anforderungen auswählen hier.
Alle diese Loader nehmen Daten auf Dokument Klassen. Wir werden später lernen, wie man in Document-Klassen aufgenommene Daten verwendet.
Textdatei-Loader: Laden Sie ein einfaches .txt
Datei in ein Dokument umwandeln.
from langchain.document_loaders import TextLoader loader = TextLoader("./sample.txt")
document = loader.load()
CSV-Loader: Laden Sie eine CSV-Datei in ein Dokument.
from langchain.document_loaders.csv_loader import CSVLoader loader = CSVLoader(file_path='./example_data/sample.csv')
documents = loader.load()
Wir können die Analyse anpassen, indem wir Feldnamen angeben –
loader = CSVLoader(file_path='./example_data/mlb_teams_2012.csv', csv_args={ 'delimiter': ',', 'quotechar': '"', 'fieldnames': ['MLB Team', 'Payroll in millions', 'Wins']
})
documents = loader.load()
PDF-Loader: PDF-Loader in LangChain bieten verschiedene Methoden zum Parsen und Extrahieren von Inhalten aus PDF-Dateien. Jeder Loader erfüllt unterschiedliche Anforderungen und verwendet unterschiedliche zugrunde liegende Bibliotheken. Nachfolgend finden Sie detaillierte Beispiele für jeden Lader.
PyPDFLoader wird für die grundlegende PDF-Analyse verwendet.
from langchain.document_loaders import PyPDFLoader loader = PyPDFLoader("example_data/layout-parser-paper.pdf")
pages = loader.load_and_split()
MathPixLoader eignet sich ideal zum Extrahieren mathematischer Inhalte und Diagramme.
from langchain.document_loaders import MathpixPDFLoader loader = MathpixPDFLoader("example_data/math-content.pdf")
data = loader.load()
PyMuPDFLoader ist schnell und beinhaltet eine detaillierte Metadatenextraktion.
from langchain.document_loaders import PyMuPDFLoader loader = PyMuPDFLoader("example_data/layout-parser-paper.pdf")
data = loader.load() # Optionally pass additional arguments for PyMuPDF's get_text() call
data = loader.load(option="text")
PDFMiner Loader wird für eine detailliertere Kontrolle der Textextraktion verwendet.
from langchain.document_loaders import PDFMinerLoader loader = PDFMinerLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
AmazonTextractPDFParser nutzt AWS Textract für OCR und andere erweiterte PDF-Analysefunktionen.
from langchain.document_loaders import AmazonTextractPDFLoader # Requires AWS account and configuration
loader = AmazonTextractPDFLoader("example_data/complex-layout.pdf")
documents = loader.load()
PDFMinerPDFasHTMLLoader generiert HTML aus PDF für die semantische Analyse.
from langchain.document_loaders import PDFMinerPDFasHTMLLoader loader = PDFMinerPDFasHTMLLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
PDFPlumberLoader stellt detaillierte Metadaten bereit und unterstützt ein Dokument pro Seite.
from langchain.document_loaders import PDFPlumberLoader loader = PDFPlumberLoader("example_data/layout-parser-paper.pdf")
data = loader.load()
Integrierte Lader: LangChain bietet eine Vielzahl benutzerdefinierter Loader, um Daten direkt aus Ihren Apps (wie Slack, Sigma, Notion, Confluence, Google Drive und vielen mehr) und Datenbanken zu laden und in LLM-Anwendungen zu verwenden.
Die vollständige Liste ist hier.
Nachfolgend finden Sie einige Beispiele zur Veranschaulichung:
Beispiel I – Slack
Slack, eine weit verbreitete Instant-Messaging-Plattform, kann in LLM-Workflows und -Anwendungen integriert werden.
- Gehen Sie zu Ihrer Slack Workspace Management-Seite.
- Navigieren
{your_slack_domain}.slack.com/services/export
. - Wählen Sie den gewünschten Datumsbereich aus und starten Sie den Export.
- Slack benachrichtigt per E-Mail und DM, sobald der Export fertig ist.
- Der Export führt zu einem
.zip
Datei, die sich in Ihrem Download-Ordner oder Ihrem angegebenen Download-Pfad befindet. - Weisen Sie den Pfad der heruntergeladenen Datei zu
.zip
Datei aufLOCAL_ZIPFILE
. - Verwenden Sie das
SlackDirectoryLoader
von demlangchain.document_loaders
Paket.
from langchain.document_loaders import SlackDirectoryLoader SLACK_WORKSPACE_URL = "https://xxx.slack.com" # Replace with your Slack URL
LOCAL_ZIPFILE = "" # Path to the Slack zip file loader = SlackDirectoryLoader(LOCAL_ZIPFILE, SLACK_WORKSPACE_URL)
docs = loader.load()
print(docs)
Beispiel II – Figma
Figma, ein beliebtes Tool für Schnittstellendesign, bietet eine REST-API für die Datenintegration.
- Erhalten Sie den Figma-Dateischlüssel aus dem URL-Format:
https://www.figma.com/file/{filekey}/sampleFilename
. - Knoten-IDs finden Sie im URL-Parameter
?node-id={node_id}
. - Generieren Sie ein Zugriffstoken gemäß den Anweisungen unter Figma-Hilfecenter.
- Das
FigmaFileLoader
Klasse vonlangchain.document_loaders.figma
wird zum Laden von Figma-Daten verwendet. - Verschiedene LangChain-Module wie
CharacterTextSplitter
,ChatOpenAI
usw. werden zur Verarbeitung eingesetzt.
import os
from langchain.document_loaders.figma import FigmaFileLoader
from langchain.text_splitter import CharacterTextSplitter
from langchain.chat_models import ChatOpenAI
from langchain.indexes import VectorstoreIndexCreator
from langchain.chains import ConversationChain, LLMChain
from langchain.memory import ConversationBufferWindowMemory
from langchain.prompts.chat import ChatPromptTemplate, SystemMessagePromptTemplate, AIMessagePromptTemplate, HumanMessagePromptTemplate figma_loader = FigmaFileLoader( os.environ.get("ACCESS_TOKEN"), os.environ.get("NODE_IDS"), os.environ.get("FILE_KEY"),
) index = VectorstoreIndexCreator().from_loaders([figma_loader])
figma_doc_retriever = index.vectorstore.as_retriever()
- Das
generate_code
Die Funktion verwendet die Figma-Daten, um HTML/CSS-Code zu erstellen. - Es verwendet eine Konversationsvorlage mit einem GPT-basierten Modell.
def generate_code(human_input): # Template for system and human prompts system_prompt_template = "Your coding instructions..." human_prompt_template = "Code the {text}. Ensure it's mobile responsive" # Creating prompt templates system_message_prompt = SystemMessagePromptTemplate.from_template(system_prompt_template) human_message_prompt = HumanMessagePromptTemplate.from_template(human_prompt_template) # Setting up the AI model gpt_4 = ChatOpenAI(temperature=0.02, model_name="gpt-4") # Retrieving relevant documents relevant_nodes = figma_doc_retriever.get_relevant_documents(human_input) # Generating and formatting the prompt conversation = [system_message_prompt, human_message_prompt] chat_prompt = ChatPromptTemplate.from_messages(conversation) response = gpt_4(chat_prompt.format_prompt(context=relevant_nodes, text=human_input).to_messages()) return response # Example usage
response = generate_code("page top header")
print(response.content)
- Das
generate_code
Wenn die Funktion ausgeführt wird, gibt sie HTML/CSS-Code basierend auf der Figma-Designeingabe zurück.
Lassen Sie uns nun unser Wissen nutzen, um ein paar Dokumentensätze zu erstellen.
Wir laden zunächst ein PDF, den jährlichen Nachhaltigkeitsbericht von BCG.
Wir nutzen hierfür den PyPDFLoader.
from langchain.document_loaders import PyPDFLoader loader = PyPDFLoader("bcg-2022-annual-sustainability-report-apr-2023.pdf")
pdfpages = loader.load_and_split()
Wir werden jetzt Daten von Airtable aufnehmen. Wir haben eine Airtable mit Informationen zu verschiedenen OCR- und Datenextraktionsmodellen –
Nutzen wir hierfür den AirtableLoader, der in der Liste der integrierten Loader zu finden ist.
from langchain.document_loaders import AirtableLoader api_key = "XXXXX"
base_id = "XXXXX"
table_id = "XXXXX" loader = AirtableLoader(api_key, table_id, base_id)
airtabledocs = loader.load()
Lassen Sie uns nun fortfahren und lernen, wie Sie diese Dokumentklassen verwenden.
Dokumenttransformatoren
Dokumenttransformatoren in LangChain sind wesentliche Werkzeuge zur Bearbeitung von Dokumenten, die wir in unserem vorherigen Unterabschnitt erstellt haben.
Sie werden für Aufgaben wie das Aufteilen langer Dokumente in kleinere Teile, das Kombinieren und Filtern verwendet, die für die Anpassung von Dokumenten an das Kontextfenster eines Modells oder die Erfüllung spezifischer Anwendungsanforderungen von entscheidender Bedeutung sind.
Ein solches Tool ist der RecursiveCharacterTextSplitter, ein vielseitiger Textsplitter, der eine Zeichenliste zum Teilen verwendet. Es ermöglicht Parameter wie Blockgröße, Überlappung und Startindex. Hier ist ein Beispiel für die Verwendung in Python:
from langchain.text_splitter import RecursiveCharacterTextSplitter state_of_the_union = "Your long text here..." text_splitter = RecursiveCharacterTextSplitter( chunk_size=100, chunk_overlap=20, length_function=len, add_start_index=True,
) texts = text_splitter.create_documents([state_of_the_union])
print(texts[0])
print(texts[1])
Ein weiteres Tool ist der CharacterTextSplitter, der Text basierend auf einem bestimmten Zeichen aufteilt und Steuerelemente für Blockgröße und Überlappung enthält:
from langchain.text_splitter import CharacterTextSplitter text_splitter = CharacterTextSplitter( separator="nn", chunk_size=1000, chunk_overlap=200, length_function=len, is_separator_regex=False,
) texts = text_splitter.create_documents([state_of_the_union])
print(texts[0])
Der HTMLHeaderTextSplitter wurde entwickelt, um HTML-Inhalte basierend auf Header-Tags aufzuteilen und dabei die semantische Struktur beizubehalten:
from langchain.text_splitter import HTMLHeaderTextSplitter html_string = "Your HTML content here..."
headers_to_split_on = [("h1", "Header 1"), ("h2", "Header 2")] html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
html_header_splits = html_splitter.split_text(html_string)
print(html_header_splits[0])
Eine komplexere Manipulation kann durch die Kombination von HTMLHeaderTextSplitter mit einem anderen Splitter, wie dem Pipelined Splitter, erreicht werden:
from langchain.text_splitter import HTMLHeaderTextSplitter, RecursiveCharacterTextSplitter url = "https://example.com"
headers_to_split_on = [("h1", "Header 1"), ("h2", "Header 2")]
html_splitter = HTMLHeaderTextSplitter(headers_to_split_on=headers_to_split_on)
html_header_splits = html_splitter.split_text_from_url(url) chunk_size = 500
text_splitter = RecursiveCharacterTextSplitter(chunk_size=chunk_size)
splits = text_splitter.split_documents(html_header_splits)
print(splits[0])
LangChain bietet auch spezielle Splitter für verschiedene Programmiersprachen an, wie den Python Code Splitter und den JavaScript Code Splitter:
from langchain.text_splitter import RecursiveCharacterTextSplitter, Language python_code = """
def hello_world(): print("Hello, World!")
hello_world() """ python_splitter = RecursiveCharacterTextSplitter.from_language( language=Language.PYTHON, chunk_size=50
)
python_docs = python_splitter.create_documents([python_code])
print(python_docs[0]) js_code = """
function helloWorld() { console.log("Hello, World!");
}
helloWorld(); """ js_splitter = RecursiveCharacterTextSplitter.from_language( language=Language.JS, chunk_size=60
)
js_docs = js_splitter.create_documents([js_code])
print(js_docs[0])
Zum Aufteilen von Text basierend auf der Token-Anzahl, was für Sprachmodelle mit Token-Limits nützlich ist, wird der TokenTextSplitter verwendet:
from langchain.text_splitter import TokenTextSplitter text_splitter = TokenTextSplitter(chunk_size=10)
texts = text_splitter.split_text(state_of_the_union)
print(texts[0])
Schließlich ordnet LongContextReorder Dokumente neu an, um Leistungseinbußen in Modellen aufgrund langer Kontexte zu verhindern:
from langchain.document_transformers import LongContextReorder reordering = LongContextReorder()
reordered_docs = reordering.transform_documents(docs)
print(reordered_docs[0])
Diese Tools demonstrieren verschiedene Möglichkeiten zur Transformation von Dokumenten in LangChain, von der einfachen Textaufteilung bis hin zu komplexer Neuordnung und sprachspezifischer Aufteilung. Für detailliertere und spezifischere Anwendungsfälle sollten Sie den Abschnitt „Dokumentation und Integrationen“ von LangChain konsultieren.
In unseren Beispielen haben die Loader bereits segmentierte Dokumente für uns erstellt und dieser Teil ist bereits erledigt.
Modelle zur Texteinbettung
Texteinbettungsmodelle in LangChain bieten eine standardisierte Schnittstelle für verschiedene Anbieter von Einbettungsmodellen wie OpenAI, Cohere und Hugging Face. Diese Modelle wandeln Text in Vektordarstellungen um und ermöglichen so Operationen wie die semantische Suche durch Textähnlichkeit im Vektorraum.
Um mit Texteinbettungsmodellen zu beginnen, müssen Sie normalerweise bestimmte Pakete installieren und API-Schlüssel einrichten. Für OpenAI haben wir dies bereits getan
In LangChain ist die embed_documents
Die Methode wird zum Einbetten mehrerer Texte verwendet und stellt eine Liste von Vektordarstellungen bereit. Zum Beispiel:
from langchain.embeddings import OpenAIEmbeddings # Initialize the model
embeddings_model = OpenAIEmbeddings() # Embed a list of texts
embeddings = embeddings_model.embed_documents( ["Hi there!", "Oh, hello!", "What's your name?", "My friends call me World", "Hello World!"]
)
print("Number of documents embedded:", len(embeddings))
print("Dimension of each embedding:", len(embeddings[0]))
Zum Einbetten eines einzelnen Textes, beispielsweise einer Suchanfrage, wird der embed_query
Methode verwendet wird. Dies ist nützlich, um eine Abfrage mit einer Reihe von Dokumenteinbettungen zu vergleichen. Zum Beispiel:
from langchain.embeddings import OpenAIEmbeddings # Initialize the model
embeddings_model = OpenAIEmbeddings() # Embed a single query
embedded_query = embeddings_model.embed_query("What was the name mentioned in the conversation?")
print("First five dimensions of the embedded query:", embedded_query[:5])
Das Verständnis dieser Einbettungen ist von entscheidender Bedeutung. Jeder Text wird in einen Vektor umgewandelt, dessen Dimension vom verwendeten Modell abhängt. OpenAI-Modelle erzeugen beispielsweise typischerweise 1536-dimensionale Vektoren. Diese Einbettungen werden dann zum Abrufen relevanter Informationen verwendet.
Die Einbettungsfunktionalität von LangChain ist nicht auf OpenAI beschränkt, sondern ist für die Zusammenarbeit mit verschiedenen Anbietern konzipiert. Der Aufbau und die Nutzung können sich je nach Anbieter leicht unterscheiden, das Kernkonzept der Einbettung von Texten in den Vektorraum bleibt jedoch gleich. Für eine detaillierte Nutzung, einschließlich erweiterter Konfigurationen und Integrationen mit verschiedenen Anbietern von Einbettungsmodellen, ist die LangChain-Dokumentation im Abschnitt „Integrationen“ eine wertvolle Ressource.
Vector Stores
Vector Stores in LangChain unterstützen die effiziente Speicherung und Suche von Texteinbettungen. LangChain lässt sich in über 50 Vektorshops integrieren und bietet eine standardisierte Schnittstelle für eine einfache Bedienung.
Beispiel: Einbettungen speichern und durchsuchen
Nach dem Einbetten von Texten können wir diese in einem Vektorspeicher speichern Chroma
und führen Sie Ähnlichkeitssuchen durch:
from langchain.vectorstores import Chroma db = Chroma.from_texts(embedded_texts)
similar_texts = db.similarity_search("search query")
Alternativ können wir den FAISS-Vektorspeicher verwenden, um Indizes für unsere Dokumente zu erstellen.
from langchain.embeddings import OpenAIEmbeddings
from langchain.vectorstores import FAISS pdfstore = FAISS.from_documents(pdfpages, embedding=OpenAIEmbeddings()) airtablestore = FAISS.from_documents(airtabledocs, embedding=OpenAIEmbeddings())
Retriever
Retriever in LangChain sind Schnittstellen, die Dokumente als Antwort auf eine unstrukturierte Abfrage zurückgeben. Sie sind allgemeiner als Vektorspeicher und konzentrieren sich eher auf den Abruf als auf die Speicherung. Obwohl Vektorspeicher als Rückgrat eines Retrievers verwendet werden können, gibt es auch andere Arten von Retrievern.
Um einen Chroma-Retriever einzurichten, installieren Sie ihn zunächst mit pip install chromadb
. Anschließend laden, teilen, betten und rufen Sie Dokumente mithilfe einer Reihe von Python-Befehlen ab. Hier ist ein Codebeispiel zum Einrichten eines Chroma-Retrievers:
from langchain.embeddings import OpenAIEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores import Chroma full_text = open("state_of_the_union.txt", "r").read()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=100)
texts = text_splitter.split_text(full_text) embeddings = OpenAIEmbeddings()
db = Chroma.from_texts(texts, embeddings)
retriever = db.as_retriever() retrieved_docs = retriever.invoke("What did the president say about Ketanji Brown Jackson?")
print(retrieved_docs[0].page_content)
Der MultiQueryRetriever automatisiert die Eingabeaufforderungsoptimierung, indem er mehrere Abfragen für eine Benutzereingabeabfrage generiert und die Ergebnisse kombiniert. Hier ist ein Beispiel für die einfache Verwendung:
from langchain.chat_models import ChatOpenAI
from langchain.retrievers.multi_query import MultiQueryRetriever question = "What are the approaches to Task Decomposition?"
llm = ChatOpenAI(temperature=0)
retriever_from_llm = MultiQueryRetriever.from_llm( retriever=db.as_retriever(), llm=llm
) unique_docs = retriever_from_llm.get_relevant_documents(query=question)
print("Number of unique documents:", len(unique_docs))
Die Kontextkomprimierung in LangChain komprimiert abgerufene Dokumente mithilfe des Kontexts der Abfrage und stellt so sicher, dass nur relevante Informationen zurückgegeben werden. Dabei geht es um Inhaltsreduzierung und das Herausfiltern weniger relevanter Dokumente. Das folgende Codebeispiel zeigt, wie Contextual Compression Retriever verwendet wird:
from langchain.llms import OpenAI
from langchain.retrievers import ContextualCompressionRetriever
from langchain.retrievers.document_compressors import LLMChainExtractor llm = OpenAI(temperature=0)
compressor = LLMChainExtractor.from_llm(llm)
compression_retriever = ContextualCompressionRetriever(base_compressor=compressor, base_retriever=retriever) compressed_docs = compression_retriever.get_relevant_documents("What did the president say about Ketanji Jackson Brown")
print(compressed_docs[0].page_content)
Der EnsembleRetriever kombiniert verschiedene Retrieval-Algorithmen, um eine bessere Leistung zu erzielen. Ein Beispiel für die Kombination von BM25- und FAISS-Retrievern wird im folgenden Code gezeigt:
from langchain.retrievers import BM25Retriever, EnsembleRetriever
from langchain.vectorstores import FAISS bm25_retriever = BM25Retriever.from_texts(doc_list).set_k(2)
faiss_vectorstore = FAISS.from_texts(doc_list, OpenAIEmbeddings())
faiss_retriever = faiss_vectorstore.as_retriever(search_kwargs={"k": 2}) ensemble_retriever = EnsembleRetriever( retrievers=[bm25_retriever, faiss_retriever], weights=[0.5, 0.5]
) docs = ensemble_retriever.get_relevant_documents("apples")
print(docs[0].page_content)
MultiVector Retriever in LangChain ermöglicht die Abfrage von Dokumenten mit mehreren Vektoren pro Dokument, was für die Erfassung verschiedener semantischer Aspekte innerhalb eines Dokuments nützlich ist. Zu den Methoden zum Erstellen mehrerer Vektoren gehören das Aufteilen in kleinere Teile, das Zusammenfassen oder das Generieren hypothetischer Fragen. Zum Aufteilen von Dokumenten in kleinere Teile kann der folgende Python-Code verwendet werden:
python
from langchain.retrievers.multi_vector import MultiVectorRetriever
from langchain.vectorstores import Chroma
from langchain.embeddings import OpenAIEmbeddings
from langchain.text_splitter import RecursiveCharacterTextSplitter
from langchain.storage import InMemoryStore
from langchain.document_loaders from TextLoader
import uuid loaders = [TextLoader("file1.txt"), TextLoader("file2.txt")]
docs = [doc for loader in loaders for doc in loader.load()]
text_splitter = RecursiveCharacterTextSplitter(chunk_size=10000)
docs = text_splitter.split_documents(docs) vectorstore = Chroma(collection_name="full_documents", embedding_function=OpenAIEmbeddings())
store = InMemoryStore()
id_key = "doc_id"
retriever = MultiVectorRetriever(vectorstore=vectorstore, docstore=store, id_key=id_key) doc_ids = [str(uuid.uuid4()) for _ in docs]
child_text_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
sub_docs = [sub_doc for doc in docs for sub_doc in child_text_splitter.split_documents([doc])]
for sub_doc in sub_docs: sub_doc.metadata[id_key] = doc_ids[sub_docs.index(sub_doc)] retriever.vectorstore.add_documents(sub_docs)
retriever.docstore.mset(list(zip(doc_ids, docs)))
Eine weitere Methode ist die Generierung von Zusammenfassungen zur besseren Wiederauffindbarkeit aufgrund einer fokussierteren Inhaltsdarstellung. Hier ist ein Beispiel für die Erstellung von Zusammenfassungen:
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.document import Document chain = (lambda x: x.page_content) | ChatPromptTemplate.from_template("Summarize the following document:nn{doc}") | ChatOpenAI(max_retries=0) | StrOutputParser()
summaries = chain.batch(docs, {"max_concurrency": 5}) summary_docs = [Document(page_content=s, metadata={id_key: doc_ids[i]}) for i, s in enumerate(summaries)]
retriever.vectorstore.add_documents(summary_docs)
retriever.docstore.mset(list(zip(doc_ids, docs)))
Ein weiterer Ansatz ist die Generierung hypothetischer Fragen, die für jedes Dokument relevant sind, mithilfe von LLM. Dies kann mit dem folgenden Code erfolgen:
functions = [{"name": "hypothetical_questions", "parameters": {"questions": {"type": "array", "items": {"type": "string"}}}}]
from langchain.output_parsers.openai_functions import JsonKeyOutputFunctionsParser chain = (lambda x: x.page_content) | ChatPromptTemplate.from_template("Generate 3 hypothetical questions:nn{doc}") | ChatOpenAI(max_retries=0).bind(functions=functions, function_call={"name": "hypothetical_questions"}) | JsonKeyOutputFunctionsParser(key_name="questions")
hypothetical_questions = chain.batch(docs, {"max_concurrency": 5}) question_docs = [Document(page_content=q, metadata={id_key: doc_ids[i]}) for i, questions in enumerate(hypothetical_questions) for q in questions]
retriever.vectorstore.add_documents(question_docs)
retriever.docstore.mset(list(zip(doc_ids, docs)))
Der Parent Document Retriever ist ein weiterer Retriever, der ein Gleichgewicht zwischen Einbettungsgenauigkeit und Kontexterhaltung schafft, indem er kleine Teile speichert und ihre größeren übergeordneten Dokumente abruft. Seine Umsetzung ist wie folgt:
from langchain.retrievers import ParentDocumentRetriever loaders = [TextLoader("file1.txt"), TextLoader("file2.txt")]
docs = [doc for loader in loaders for doc in loader.load()] child_splitter = RecursiveCharacterTextSplitter(chunk_size=400)
vectorstore = Chroma(collection_name="full_documents", embedding_function=OpenAIEmbeddings())
store = InMemoryStore()
retriever = ParentDocumentRetriever(vectorstore=vectorstore, docstore=store, child_splitter=child_splitter) retriever.add_documents(docs, ids=None) retrieved_docs = retriever.get_relevant_documents("query")
Ein selbstabfragender Retriever erstellt strukturierte Abfragen aus Eingaben in natürlicher Sprache und wendet sie auf den zugrunde liegenden VectorStore an. Seine Implementierung wird im folgenden Code gezeigt:
from langchain.chat_models from ChatOpenAI
from langchain.chains.query_constructor.base from AttributeInfo
from langchain.retrievers.self_query.base from SelfQueryRetriever metadata_field_info = [AttributeInfo(name="genre", description="...", type="string"), ...]
document_content_description = "Brief summary of a movie"
llm = ChatOpenAI(temperature=0) retriever = SelfQueryRetriever.from_llm(llm, vectorstore, document_content_description, metadata_field_info) retrieved_docs = retriever.invoke("query")
Der WebResearchRetriever führt eine Webrecherche basierend auf einer bestimmten Abfrage durch –
from langchain.retrievers.web_research import WebResearchRetriever # Initialize components
llm = ChatOpenAI(temperature=0)
search = GoogleSearchAPIWrapper()
vectorstore = Chroma(embedding_function=OpenAIEmbeddings()) # Instantiate WebResearchRetriever
web_research_retriever = WebResearchRetriever.from_llm(vectorstore=vectorstore, llm=llm, search=search) # Retrieve documents
docs = web_research_retriever.get_relevant_documents("query")
Für unsere Beispiele können wir auch den Standard-Retriever verwenden, der bereits als Teil unseres Vektorspeicherobjekts implementiert ist, wie folgt:
Wir können jetzt die Retriever befragen. Die Ausgabe unserer Abfrage sind für die Abfrage relevante Dokumentobjekte. Diese werden letztendlich genutzt, um in weiteren Abschnitten relevante Antworten zu erstellen.
Automatisieren Sie manuelle Aufgaben und Arbeitsabläufe mit unserem KI-gesteuerten Workflow-Builder, der von Nanonets für Sie und Ihre Teams entwickelt wurde.
Modul III: Agenten
LangChain führt ein leistungsstarkes Konzept namens „Agents“ ein, das die Idee von Ketten auf eine ganz neue Ebene hebt. Agenten nutzen Sprachmodelle, um die auszuführenden Aktionssequenzen dynamisch zu bestimmen, was sie unglaublich vielseitig und anpassungsfähig macht. Im Gegensatz zu herkömmlichen Ketten, bei denen Aktionen fest im Code codiert sind, verwenden Agenten Sprachmodelle als Argumentationsmaschinen, um zu entscheiden, welche Aktionen in welcher Reihenfolge ausgeführt werden sollen.
Der Agent ist die Kernkomponente, die für die Entscheidungsfindung verantwortlich ist. Es nutzt die Leistungsfähigkeit eines Sprachmodells und eine Aufforderung zur Festlegung der nächsten Schritte zur Erreichung eines bestimmten Ziels. Zu den Eingaben an einen Agenten gehören typischerweise:
- Tools: Beschreibungen der verfügbaren Tools (mehr dazu später).
- Benutzereingabe: Das übergeordnete Ziel oder die Anfrage des Benutzers.
- Zwischenschritte: Ein Verlauf von (Aktion, Tool-Ausgabe)-Paaren, die ausgeführt wurden, um die aktuelle Benutzereingabe zu erreichen.
Die Ausgabe eines Agenten kann die nächste sein Aktion Maßnahmen ergreifen (Agentenaktionen) oder das Finale Antwort zum Senden an den Benutzer (AgentFinish). Ein Aktion spezifiziert a Werkzeug und für Varianten des Eingangssignals: für dieses Werkzeug.
Tools
Tools sind Schnittstellen, über die ein Agent mit der Welt interagieren kann. Sie ermöglichen es Agenten, verschiedene Aufgaben auszuführen, z. B. das Durchsuchen des Webs, das Ausführen von Shell-Befehlen oder den Zugriff auf externe APIs. In LangChain sind Tools unerlässlich, um die Fähigkeiten von Agenten zu erweitern und ihnen die Erfüllung vielfältiger Aufgaben zu ermöglichen.
Um Tools in LangChain zu verwenden, können Sie diese mit dem folgenden Snippet laden:
from langchain.agents import load_tools tool_names = [...]
tools = load_tools(tool_names)
Für die Initialisierung einiger Tools ist möglicherweise ein Basissprachenmodell (LLM) erforderlich. In solchen Fällen können Sie auch ein LLM absolvieren:
from langchain.agents import load_tools tool_names = [...]
llm = ...
tools = load_tools(tool_names, llm=llm)
Mit diesem Setup können Sie auf eine Vielzahl von Tools zugreifen und diese in die Arbeitsabläufe Ihres Agenten integrieren. Die vollständige Liste der Tools mit Nutzungsdokumentation finden Sie hier hier.
Schauen wir uns einige Beispiele für Tools an.
DuckDuckGo
Mit dem DuckDuckGo-Tool können Sie mithilfe seiner Suchmaschine Websuchen durchführen. So verwenden Sie es:
from langchain.tools import DuckDuckGoSearchRun
search = DuckDuckGoSearchRun()
search.run("manchester united vs luton town match summary")
DataForSeo
Mit dem DataForSeo-Toolkit können Sie Suchmaschinenergebnisse mithilfe der DataForSeo-API abrufen. Um dieses Toolkit verwenden zu können, müssen Sie Ihre API-Anmeldeinformationen einrichten. So konfigurieren Sie die Anmeldeinformationen:
import os os.environ["DATAFORSEO_LOGIN"] = "<your_api_access_username>"
os.environ["DATAFORSEO_PASSWORD"] = "<your_api_access_password>"
Sobald Ihre Anmeldeinformationen festgelegt sind, können Sie eine erstellen DataForSeoAPIWrapper
Tool zum Zugriff auf die API:
from langchain.utilities.dataforseo_api_search import DataForSeoAPIWrapper wrapper = DataForSeoAPIWrapper() result = wrapper.run("Weather in Los Angeles")
Das DataForSeoAPIWrapper
Das Tool ruft Suchmaschinenergebnisse aus verschiedenen Quellen ab.
Sie können die Art der Ergebnisse und Felder anpassen, die in der JSON-Antwort zurückgegeben werden. Sie können beispielsweise die Ergebnistypen und Felder angeben und eine maximale Anzahl für die Anzahl der zurückzugebenden Top-Ergebnisse festlegen:
json_wrapper = DataForSeoAPIWrapper( json_result_types=["organic", "knowledge_graph", "answer_box"], json_result_fields=["type", "title", "description", "text"], top_count=3,
) json_result = json_wrapper.results("Bill Gates")
In diesem Beispiel wird die JSON-Antwort angepasst, indem Ergebnistypen und Felder angegeben und die Anzahl der Ergebnisse begrenzt werden.
Sie können auch den Speicherort und die Sprache für Ihre Suchergebnisse angeben, indem Sie zusätzliche Parameter an den API-Wrapper übergeben:
customized_wrapper = DataForSeoAPIWrapper( top_count=10, json_result_types=["organic", "local_pack"], json_result_fields=["title", "description", "type"], params={"location_name": "Germany", "language_code": "en"},
) customized_result = customized_wrapper.results("coffee near me")
Durch die Angabe von Standort- und Sprachparametern können Sie Ihre Suchergebnisse auf bestimmte Regionen und Sprachen zuschneiden.
Sie haben die Flexibilität, die Suchmaschine auszuwählen, die Sie verwenden möchten. Geben Sie einfach die gewünschte Suchmaschine an:
customized_wrapper = DataForSeoAPIWrapper( top_count=10, json_result_types=["organic", "local_pack"], json_result_fields=["title", "description", "type"], params={"location_name": "Germany", "language_code": "en", "se_name": "bing"},
) customized_result = customized_wrapper.results("coffee near me")
In diesem Beispiel wird die Suche so angepasst, dass Bing als Suchmaschine verwendet wird.
Mit dem API-Wrapper können Sie auch die Art der Suche angeben, die Sie durchführen möchten. Sie können beispielsweise eine Kartensuche durchführen:
maps_search = DataForSeoAPIWrapper( top_count=10, json_result_fields=["title", "value", "address", "rating", "type"], params={ "location_coordinate": "52.512,13.36,12z", "language_code": "en", "se_type": "maps", },
) maps_search_result = maps_search.results("coffee near me")
Dadurch wird die Suche angepasst, um kartenbezogene Informationen abzurufen.
Shell (Bash)
Das Shell-Toolkit bietet Agenten Zugriff auf die Shell-Umgebung und ermöglicht ihnen die Ausführung von Shell-Befehlen. Diese Funktion ist leistungsstark, sollte jedoch mit Vorsicht verwendet werden, insbesondere in Sandbox-Umgebungen. So können Sie das Shell-Tool verwenden:
from langchain.tools import ShellTool shell_tool = ShellTool() result = shell_tool.run({"commands": ["echo 'Hello World!'", "time"]})
In diesem Beispiel führt das Shell-Tool zwei Shell-Befehle aus: als Echo „Hello World!“ und Anzeige der aktuellen Uhrzeit.
Sie können einem Agenten das Shell-Tool zur Verfügung stellen, um komplexere Aufgaben auszuführen. Hier ist ein Beispiel für einen Agenten, der mithilfe des Shell-Tools Links von einer Webseite abruft:
from langchain.agents import AgentType, initialize_agent
from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(temperature=0.1) shell_tool.description = shell_tool.description + f"args {shell_tool.args}".replace( "{", "{{"
).replace("}", "}}")
self_ask_with_search = initialize_agent( [shell_tool], llm, agent=AgentType.CHAT_ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)
self_ask_with_search.run( "Download the langchain.com webpage and grep for all urls. Return only a sorted list of them. Be sure to use double quotes."
)
In diesem Szenario verwendet der Agent das Shell-Tool, um eine Folge von Befehlen zum Abrufen, Filtern und Sortieren von URLs von einer Webseite auszuführen.
Die bereitgestellten Beispiele veranschaulichen einige der in LangChain verfügbaren Tools. Diese Tools erweitern letztendlich die Fähigkeiten von Agenten (siehe nächster Unterabschnitt) und befähigen sie, verschiedene Aufgaben effizient auszuführen. Abhängig von Ihren Anforderungen können Sie die Tools und Toolkits auswählen, die am besten zu den Anforderungen Ihres Projekts passen, und diese in die Arbeitsabläufe Ihres Agenten integrieren.
Zurück zu den Agenten
Kommen wir nun zu den Agenten.
Der AgentExecutor ist die Laufzeitumgebung für einen Agenten. Es ist dafür verantwortlich, den Agenten anzurufen, die von ihm ausgewählten Aktionen auszuführen, die Aktionsausgaben an den Agenten zurückzugeben und den Vorgang zu wiederholen, bis der Agent fertig ist. Im Pseudocode könnte der AgentExecutor etwa so aussehen:
next_action = agent.get_action(...)
while next_action != AgentFinish: observation = run(next_action) next_action = agent.get_action(..., next_action, observation)
return next_action
Der AgentExecutor bewältigt verschiedene Komplexitäten, z. B. die Behandlung von Fällen, in denen der Agent ein nicht vorhandenes Tool auswählt, die Behandlung von Toolfehlern, die Verwaltung der vom Agenten erzeugten Ausgaben und die Bereitstellung von Protokollierung und Beobachtbarkeit auf allen Ebenen.
Während die AgentExecutor-Klasse die primäre Agent-Laufzeit in LangChain ist, werden auch andere, experimentellere Laufzeiten unterstützt, darunter:
- Agent für Planung und Ausführung
- Baby-AGI
- Auto-GPT
Um ein besseres Verständnis des Agenten-Frameworks zu erlangen, erstellen wir einen Basisagenten von Grund auf und erkunden dann die vorgefertigten Agenten.
Bevor wir uns mit der Erstellung des Agenten befassen, ist es wichtig, einige wichtige Terminologien und Schemata noch einmal durchzugehen:
- Agentenaktion: Dies ist eine Datenklasse, die die Aktion darstellt, die ein Agent ausführen sollte. Es besteht aus a
tool
Eigenschaft (der Name des aufzurufenden Tools) und atool_input
Eigenschaft (die Eingabe für dieses Tool). - AgentFinish: Diese Datenklasse zeigt an, dass der Agent seine Aufgabe abgeschlossen hat und eine Antwort an den Benutzer zurücksenden sollte. Es enthält typischerweise ein Wörterbuch mit Rückgabewerten, oft mit einem Schlüssel „output“, der den Antworttext enthält.
- Zwischenschritte: Dabei handelt es sich um die Aufzeichnungen früherer Agentenaktionen und entsprechender Ausgaben. Sie sind entscheidend für die Weitergabe des Kontexts an zukünftige Iterationen des Agenten.
In unserem Beispiel verwenden wir OpenAI Function Calling, um unseren Agenten zu erstellen. Dieser Ansatz ist zuverlässig für die Agentenerstellung. Wir beginnen mit der Erstellung eines einfachen Tools, das die Länge eines Wortes berechnet. Dieses Tool ist nützlich, da Sprachmodelle aufgrund der Tokenisierung beim Zählen der Wortlängen manchmal Fehler machen können.
Laden wir zunächst das Sprachmodell, das wir zur Steuerung des Agenten verwenden:
from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
Testen wir das Modell mit einer Wortlängenberechnung:
llm.invoke("how many letters in the word educa?")
Die Antwort sollte die Anzahl der Buchstaben im Wort „educa“ angeben.
Als Nächstes definieren wir eine einfache Python-Funktion zur Berechnung der Länge eines Wortes:
from langchain.agents import tool @tool
def get_word_length(word: str) -> int: """Returns the length of a word.""" return len(word)
Wir haben ein Tool namens erstellt get_word_length
Das nimmt ein Wort als Eingabe und gibt seine Länge zurück.
Jetzt erstellen wir die Eingabeaufforderung für den Agenten. Die Eingabeaufforderung weist den Agenten an, wie er die Ausgabe begründen und formatieren soll. In unserem Fall verwenden wir OpenAI Function Calling, das nur minimale Anweisungen erfordert. Wir definieren die Eingabeaufforderung mit Platzhaltern für Benutzereingaben und Agenten-Notizblock:
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder prompt = ChatPromptTemplate.from_messages( [ ( "system", "You are a very powerful assistant but not great at calculating word lengths.", ), ("user", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad"), ]
)
Woher weiß der Agent nun, welche Tools er verwenden kann? Wir verlassen uns auf OpenAI-Funktionsaufruf-Sprachmodelle, die eine separate Übergabe von Funktionen erfordern. Um dem Agenten unsere Tools zur Verfügung zu stellen, formatieren wir sie als OpenAI-Funktionsaufrufe:
from langchain.tools.render import format_tool_to_openai_function llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools])
Jetzt können wir den Agenten erstellen, indem wir Eingabezuordnungen definieren und die Komponenten verbinden:
Dies ist die LCEL-Sprache. Wir werden dies später im Detail besprechen.
from langchain.agents.format_scratchpad import format_to_openai_function_messages
from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai _function_messages( x["intermediate_steps"] ), } | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser()
)
Wir haben unseren Agenten erstellt, der Benutzereingaben versteht, verfügbare Tools nutzt und die Ausgabe formatiert. Lassen Sie uns nun damit interagieren:
agent.invoke({"input": "how many letters in the word educa?", "intermediate_steps": []})
Der Agent sollte mit einer AgentAction antworten und die nächste auszuführende Aktion angeben.
Wir haben den Agenten erstellt, aber jetzt müssen wir eine Laufzeit dafür schreiben. Die einfachste Laufzeit ist eine, die den Agenten kontinuierlich aufruft, Aktionen ausführt und wiederholt, bis der Agent fertig ist. Hier ist ein Beispiel:
from langchain.schema.agent import AgentFinish user_input = "how many letters in the word educa?"
intermediate_steps = [] while True: output = agent.invoke( { "input": user_input, "intermediate_steps": intermediate_steps, } ) if isinstance(output, AgentFinish): final_result = output.return_values["output"] break else: print(f"TOOL NAME: {output.tool}") print(f"TOOL INPUT: {output.tool_input}") tool = {"get_word_length": get_word_length}[output.tool] observation = tool.run(output.tool_input) intermediate_steps.append((output, observation)) print(final_result)
In dieser Schleife rufen wir wiederholt den Agenten auf, führen Aktionen aus und aktualisieren die Zwischenschritte, bis der Agent fertig ist. Wir kümmern uns auch um Werkzeuginteraktionen innerhalb der Schleife.
Um diesen Prozess zu vereinfachen, stellt LangChain die Klasse AgentExecutor bereit, die die Agentenausführung kapselt und Fehlerbehandlung, frühzeitiges Stoppen, Nachverfolgung und andere Verbesserungen bietet. Lassen Sie uns AgentExecutor verwenden, um mit dem Agenten zu interagieren:
from langchain.agents import AgentExecutor agent_executor = AgentExecutor(agent=agent, tools=tools, verbose=True) agent_executor.invoke({"input": "how many letters in the word educa?"})
AgentExecutor vereinfacht den Ausführungsprozess und bietet eine bequeme Möglichkeit, mit dem Agenten zu interagieren.
Auch auf das Gedächtnis wird später noch ausführlich eingegangen.
Der bisher von uns erstellte Agent ist zustandslos, das heißt, er erinnert sich nicht an frühere Interaktionen. Um Folgefragen und Gespräche zu ermöglichen, müssen wir dem Agenten Speicher hinzufügen. Dies umfasst zwei Schritte:
- Fügen Sie in der Eingabeaufforderung eine Speichervariable hinzu, um den Chatverlauf zu speichern.
- Verfolgen Sie den Chatverlauf während der Interaktionen.
Beginnen wir mit dem Hinzufügen eines Speicherplatzhalters in der Eingabeaufforderung:
from langchain.prompts import MessagesPlaceholder MEMORY_KEY = "chat_history"
prompt = ChatPromptTemplate.from_messages( [ ( "system", "You are a very powerful assistant but not great at calculating word lengths.", ), MessagesPlaceholder(variable_name=MEMORY_KEY), ("user", "{input}"), MessagesPlaceholder(variable_name="agent_scratchpad"), ]
)
Erstellen Sie nun eine Liste, um den Chatverlauf zu verfolgen:
from langchain.schema.messages import HumanMessage, AIMessage chat_history = []
Im Schritt der Agentenerstellung beziehen wir auch den Speicher ein:
agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai_function_messages( x["intermediate_steps"] ), "chat_history": lambda x: x["chat_history"], } | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser()
)
Achten Sie nun beim Ausführen des Agenten darauf, den Chatverlauf zu aktualisieren:
input1 = "how many letters in the word educa?"
result = agent_executor.invoke({"input": input1, "chat_history": chat_history})
chat_history.extend([ HumanMessage(content=input1), AIMessage(content=result["output"]),
])
agent_executor.invoke({"input": "is that a real word?", "chat_history": chat_history})
Dies ermöglicht es dem Agenten, einen Gesprächsverlauf zu führen und Folgefragen basierend auf früheren Interaktionen zu beantworten.
Glückwunsch! Sie haben Ihren ersten End-to-End-Agenten in LangChain erfolgreich erstellt und ausgeführt. Um tiefer in die Fähigkeiten von LangChain einzutauchen, können Sie Folgendes erkunden:
- Verschiedene Agententypen werden unterstützt.
- Vorgefertigte Agenten
- So arbeiten Sie mit Tools und Tool-Integrationen.
Agententypen
LangChain bietet verschiedene Agententypen, die jeweils für bestimmte Anwendungsfälle geeignet sind. Hier sind einige der verfügbaren Agenten:
- Zero-Shot-ReAct: Dieser Agent verwendet das ReAct-Framework, um Tools ausschließlich auf der Grundlage ihrer Beschreibungen auszuwählen. Es erfordert Beschreibungen für jedes Werkzeug und ist äußerst vielseitig.
- Strukturierte Eingabe ReAct: Dieser Agent verarbeitet Multi-Input-Tools und eignet sich für komplexe Aufgaben wie die Navigation in einem Webbrowser. Es verwendet das Argumentschema eines Tools für strukturierte Eingaben.
- OpenAI-Funktionen: Dieser Agent wurde speziell für Modelle entwickelt, die für Funktionsaufrufe optimiert sind, und ist mit Modellen wie gpt-3.5-turbo-0613 und gpt-4-0613 kompatibel. Wir haben dies verwendet, um oben unseren ersten Agenten zu erstellen.
- Konversation: Dieser für Konversationseinstellungen konzipierte Agent verwendet ReAct für die Werkzeugauswahl und nutzt den Speicher, um sich an frühere Interaktionen zu erinnern.
- Selbstfrage mit Suche: Dieser Agent verlässt sich auf ein einziges Tool, „Intermediate Answer“, das nach sachlichen Antworten auf Fragen sucht. Es entspricht der ursprünglichen Selbstfrage mit Suchpapier.
- ReAct-Dokumentenspeicher: Dieser Agent interagiert mit einem Dokumentenspeicher über das ReAct-Framework. Es erfordert die Tools „Suchen“ und „Nachschlagen“ und ähnelt dem Wikipedia-Beispiel des ursprünglichen ReAct-Artikels.
Entdecken Sie diese Agententypen, um den Agenten zu finden, der Ihren Anforderungen in LangChain am besten entspricht. Mit diesen Agenten können Sie eine Reihe von Tools binden, um Aktionen auszuführen und Antworten zu generieren. Erfahren Sie mehr unter Hier erfahren Sie, wie Sie mit Tools Ihren eigenen Agenten erstellen.
Vorgefertigte Agenten
Lassen Sie uns unsere Erkundung von Agenten fortsetzen und uns dabei auf vorgefertigte Agenten konzentrieren, die in LangChain verfügbar sind.
Google Mail
LangChain bietet ein Gmail-Toolkit, mit dem Sie Ihre LangChain-E-Mails mit der Gmail-API verbinden können. Um zu beginnen, müssen Sie Ihre Anmeldeinformationen einrichten, die in der Gmail-API-Dokumentation erläutert werden. Sobald Sie die heruntergeladen haben credentials.json
Datei können Sie mit der Verwendung der Gmail-API fortfahren. Darüber hinaus müssen Sie einige erforderliche Bibliotheken mit den folgenden Befehlen installieren:
pip install --upgrade google-api-python-client > /dev/null
pip install --upgrade google-auth-oauthlib > /dev/null
pip install --upgrade google-auth-httplib2 > /dev/null
pip install beautifulsoup4 > /dev/null # Optional for parsing HTML messages
Sie können das Gmail-Toolkit wie folgt erstellen:
from langchain.agents.agent_toolkits import GmailToolkit toolkit = GmailToolkit()
Sie können die Authentifizierung auch an Ihre Bedürfnisse anpassen. Hinter den Kulissen wird eine GoogleAPI-Ressource mit den folgenden Methoden erstellt:
from langchain.tools.gmail.utils import build_resource_service, get_gmail_credentials credentials = get_gmail_credentials( token_file="token.json", scopes=["https://mail.google.com/"], client_secrets_file="credentials.json",
)
api_resource = build_resource_service(credentials=credentials)
toolkit = GmailToolkit(api_resource=api_resource)
Das Toolkit bietet verschiedene Tools, die innerhalb eines Agenten verwendet werden können, darunter:
GmailCreateDraft
: Erstellen Sie einen E-Mail-Entwurf mit angegebenen Nachrichtenfeldern.GmailSendMessage
: E-Mail-Nachrichten senden.GmailSearch
: Nach E-Mail-Nachrichten oder Threads suchen.GmailGetMessage
: E-Mail anhand der Nachrichten-ID abrufen.GmailGetThread
: Nach E-Mail-Nachrichten suchen.
Um diese Tools innerhalb eines Agenten zu verwenden, können Sie den Agenten wie folgt initialisieren:
from langchain.llms import OpenAI
from langchain.agents import initialize_agent, AgentType llm = OpenAI(temperature=0)
agent = initialize_agent( tools=toolkit.get_tools(), llm=llm, agent=AgentType.STRUCTURED_CHAT_ZERO_SHOT_REACT_DESCRIPTION,
)
Hier sind einige Beispiele, wie diese Tools verwendet werden können:
- Erstellen Sie einen Gmail-Entwurf zur Bearbeitung:
agent.run( "Create a gmail draft for me to edit of a letter from the perspective of a sentient parrot " "who is looking to collaborate on some research with her estranged friend, a cat. " "Under no circumstances may you send the message, however."
)
- Suchen Sie in Ihren Entwürfen nach der neuesten E-Mail:
agent.run("Could you search in my drafts for the latest email?")
Diese Beispiele veranschaulichen die Funktionen des Gmail-Toolkits von LangChain innerhalb eines Agenten, sodass Sie programmgesteuert mit Gmail interagieren können.
SQL-Datenbankagent
Dieser Abschnitt bietet einen Überblick über einen Agenten, der für die Interaktion mit SQL-Datenbanken, insbesondere der Chinook-Datenbank, konzipiert ist. Dieser Agent kann allgemeine Fragen zu einer Datenbank beantworten und Fehler beheben. Bitte beachten Sie, dass es sich noch in der aktiven Entwicklung befindet und möglicherweise nicht alle Antworten richtig sind. Seien Sie vorsichtig, wenn Sie es mit vertraulichen Daten ausführen, da es möglicherweise DML-Anweisungen für Ihre Datenbank ausführt.
Um diesen Agenten zu verwenden, können Sie ihn wie folgt initialisieren:
from langchain.agents import create_sql_agent
from langchain.agents.agent_toolkits import SQLDatabaseToolkit
from langchain.sql_database import SQLDatabase
from langchain.llms.openai import OpenAI
from langchain.agents import AgentExecutor
from langchain.agents.agent_types import AgentType
from langchain.chat_models import ChatOpenAI db = SQLDatabase.from_uri("sqlite:///../../../../../notebooks/Chinook.db")
toolkit = SQLDatabaseToolkit(db=db, llm=OpenAI(temperature=0)) agent_executor = create_sql_agent( llm=OpenAI(temperature=0), toolkit=toolkit, verbose=True, agent_type=AgentType.ZERO_SHOT_REACT_DESCRIPTION,
)
Dieser Agent kann mit initialisiert werden ZERO_SHOT_REACT_DESCRIPTION
Agententyp. Es dient der Beantwortung von Fragen und der Bereitstellung von Beschreibungen. Alternativ können Sie den Agenten mit initialisieren OPENAI_FUNCTIONS
Agententyp mit dem GPT-3.5-Turbo-Modell von OpenAI, das wir in unserem früheren Client verwendet haben.
Haftungsausschluss
- Die Abfragekette kann Einfüge-/Aktualisierungs-/Löschabfragen generieren. Seien Sie vorsichtig und verwenden Sie bei Bedarf eine benutzerdefinierte Eingabeaufforderung oder erstellen Sie einen SQL-Benutzer ohne Schreibberechtigungen.
- Beachten Sie, dass die Ausführung bestimmter Abfragen, z. B. „Führen Sie die größtmögliche Abfrage aus“, Ihre SQL-Datenbank überlasten kann, insbesondere wenn sie Millionen von Zeilen enthält.
- Data Warehouse-orientierte Datenbanken unterstützen häufig Kontingente auf Benutzerebene, um die Ressourcennutzung zu begrenzen.
Sie können den Agenten bitten, eine Tabelle zu beschreiben, beispielsweise die Tabelle „Playlisttrack“. Hier ist ein Beispiel dafür:
agent_executor.run("Describe the playlisttrack table")
Der Agent stellt Informationen zum Schema und zu den Beispielzeilen der Tabelle bereit.
Wenn Sie versehentlich nach einer Tabelle fragen, die nicht existiert, kann der Agent die Tabelle wiederherstellen und Informationen über die Tabelle mit der größten Übereinstimmung bereitstellen. Zum Beispiel:
agent_executor.run("Describe the playlistsong table")
Der Agent findet den nächstgelegenen passenden Tisch und gibt Auskunft darüber.
Sie können den Agenten auch bitten, Abfragen in der Datenbank auszuführen. Zum Beispiel:
agent_executor.run("List the total sales per country. Which country's customers spent the most?")
Der Agent führt die Abfrage aus und stellt das Ergebnis bereit, beispielsweise das Land mit den höchsten Gesamtverkäufen.
Um die Gesamtzahl der Titel in jeder Playlist zu erhalten, können Sie die folgende Abfrage verwenden:
agent_executor.run("Show the total number of tracks in each playlist. The Playlist name should be included in the result.")
Der Agent gibt die Namen der Wiedergabelisten zusammen mit der entsprechenden Gesamtzahl der Titel zurück.
In Fällen, in denen der Agent auf Fehler stößt, kann er diese beheben und genaue Antworten bereitstellen. Zum Beispiel:
agent_executor.run("Who are the top 3 best selling artists?")
Selbst wenn ein anfänglicher Fehler auftritt, passt sich der Agent an und liefert die richtige Antwort, in diesem Fall die Top 3 der meistverkauften Künstler.
Pandas DataFrame-Agent
In diesem Abschnitt wird ein Agent vorgestellt, der für die Interaktion mit Pandas DataFrames zur Beantwortung von Fragen entwickelt wurde. Bitte beachten Sie, dass dieser Agent den Python-Agenten unter der Haube nutzt, um Python-Code auszuführen, der von einem Sprachmodell (LLM) generiert wurde. Seien Sie vorsichtig, wenn Sie diesen Agenten verwenden, um mögliche Schäden durch vom LLM generierten bösartigen Python-Code zu verhindern.
Sie können den Pandas DataFrame-Agenten wie folgt initialisieren:
from langchain_experimental.agents.agent_toolkits import create_pandas_dataframe_agent
from langchain.chat_models import ChatOpenAI
from langchain.agents.agent_types import AgentType from langchain.llms import OpenAI
import pandas as pd df = pd.read_csv("titanic.csv") # Using ZERO_SHOT_REACT_DESCRIPTION agent type
agent = create_pandas_dataframe_agent(OpenAI(temperature=0), df, verbose=True) # Alternatively, using OPENAI_FUNCTIONS agent type
# agent = create_pandas_dataframe_agent(
# ChatOpenAI(temperature=0, model="gpt-3.5-turbo-0613"),
# df,
# verbose=True,
# agent_type=AgentType.OPENAI_FUNCTIONS,
# )
Sie können den Agenten bitten, die Anzahl der Zeilen im DataFrame zu zählen:
agent.run("how many rows are there?")
Der Agent führt den Code aus df.shape[0]
und geben Sie die Antwort ein, z. B. „Der Datenrahmen enthält 891 Zeilen.“
Sie können den Agenten auch bitten, Zeilen nach bestimmten Kriterien zu filtern, beispielsweise um die Anzahl der Personen mit mehr als drei Geschwistern zu ermitteln:
agent.run("how many people have more than 3 siblings")
Der Agent führt den Code aus df[df['SibSp'] > 3].shape[0]
und geben Sie die Antwort an, z. B. „30 Personen haben mehr als 3 Geschwister.“
Wenn Sie die Quadratwurzel des Durchschnittsalters berechnen möchten, können Sie den Agenten fragen:
agent.run("whats the square root of the average age?")
Der Agent berechnet das Durchschnittsalter anhand von df['Age'].mean()
und berechnen Sie dann die Quadratwurzel mit math.sqrt()
. Es liefert die Antwort, beispielsweise „Die Quadratwurzel des Durchschnittsalters beträgt 5.449689683556195.“
Erstellen wir eine Kopie des DataFrame und fehlende Alterswerte werden mit dem Durchschnittsalter gefüllt:
df1 = df.copy()
df1["Age"] = df1["Age"].fillna(df1["Age"].mean())
Anschließend können Sie den Agenten mit beiden DataFrames initialisieren und ihm eine Frage stellen:
agent = create_pandas_dataframe_agent(OpenAI(temperature=0), [df, df1], verbose=True)
agent.run("how many rows in the age column are different?")
Der Agent vergleicht die Altersspalten in beiden DataFrames und liefert die Antwort, z. B. „177 Zeilen in der Altersspalte sind unterschiedlich.“
Jira-Toolkit
In diesem Abschnitt wird die Verwendung des Jira-Toolkits erläutert, mit dem Agenten mit einer Jira-Instanz interagieren können. Mit diesem Toolkit können Sie verschiedene Aktionen ausführen, z. B. nach Problemen suchen und Probleme erstellen. Es nutzt die Atlassian-Python-API-Bibliothek. Um dieses Toolkit verwenden zu können, müssen Sie Umgebungsvariablen für Ihre Jira-Instanz festlegen, einschließlich JIRA_API_TOKEN, JIRA_USERNAME und JIRA_INSTANCE_URL. Darüber hinaus müssen Sie möglicherweise Ihren OpenAI-API-Schlüssel als Umgebungsvariable festlegen.
Installieren Sie zunächst die atlassian-python-api-Bibliothek und legen Sie die erforderlichen Umgebungsvariablen fest:
%pip install atlassian-python-api import os
from langchain.agents import AgentType
from langchain.agents import initialize_agent
from langchain.agents.agent_toolkits.jira.toolkit import JiraToolkit
from langchain.llms import OpenAI
from langchain.utilities.jira import JiraAPIWrapper os.environ["JIRA_API_TOKEN"] = "abc"
os.environ["JIRA_USERNAME"] = "123"
os.environ["JIRA_INSTANCE_URL"] = "https://jira.atlassian.com"
os.environ["OPENAI_API_KEY"] = "xyz" llm = OpenAI(temperature=0)
jira = JiraAPIWrapper()
toolkit = JiraToolkit.from_jira_api_wrapper(jira)
agent = initialize_agent( toolkit.get_tools(), llm, agent=AgentType.ZERO_SHOT_REACT_DESCRIPTION, verbose=True
)
Sie können den Agenten anweisen, in einem bestimmten Projekt ein neues Problem mit einer Zusammenfassung und Beschreibung zu erstellen:
agent.run("make a new issue in project PW to remind me to make more fried rice")
Der Agent führt die erforderlichen Aktionen aus, um das Problem zu erstellen und eine Antwort bereitzustellen, z. B. „Im Projekt PW wurde ein neues Problem mit der Zusammenfassung „Mehr gebratenen Reis zubereiten“ und der Beschreibung „Erinnerung, mehr gebratenen Reis zuzubereiten“ erstellt.“
Dadurch können Sie mit Ihrer Jira-Instanz mithilfe von Anweisungen in natürlicher Sprache und dem Jira-Toolkit interagieren.
Automatisieren Sie manuelle Aufgaben und Arbeitsabläufe mit unserem KI-gesteuerten Workflow-Builder, der von Nanonets für Sie und Ihre Teams entwickelt wurde.
Modul IV: Ketten
LangChain ist ein Tool zur Nutzung großer Sprachmodelle (LLMs) in komplexen Anwendungen. Es bietet Frameworks zum Erstellen von Komponentenketten, einschließlich LLMs und anderen Arten von Komponenten. Zwei primäre Frameworks
- Die LangChain Expression Language (LCEL)
- Legacy-Chain-Schnittstelle
Die LangChain Expression Language (LCEL) ist eine Syntax, die eine intuitive Komposition von Ketten ermöglicht. Es unterstützt erweiterte Funktionen wie Streaming, asynchrone Aufrufe, Stapelverarbeitung, Parallelisierung, Wiederholungsversuche, Fallbacks und Ablaufverfolgung. Sie können beispielsweise eine Eingabeaufforderung, ein Modell und einen Ausgabeparser in LCEL erstellen, wie im folgenden Code gezeigt:
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser model = ChatOpenAI(model="gpt-3.5-turbo", temperature=0)
prompt = ChatPromptTemplate.from_messages([ ("system", "You're a very knowledgeable historian who provides accurate and eloquent answers to historical questions."), ("human", "{question}")
])
runnable = prompt | model | StrOutputParser() for chunk in runnable.stream({"question": "What are the seven wonders of the world"}): print(chunk, end="", flush=True)
Alternativ ist die LLMChain eine ähnliche Option wie LCEL zum Zusammenstellen von Komponenten. Das LLMChain-Beispiel sieht wie folgt aus:
from langchain.chains import LLMChain chain = LLMChain(llm=model, prompt=prompt, output_parser=StrOutputParser())
chain.run(question="What are the seven wonders of the world")
Ketten in LangChain können durch die Einbindung eines Memory-Objekts auch zustandsbehaftet sein. Dies ermöglicht die Datenpersistenz über Anrufe hinweg, wie in diesem Beispiel gezeigt:
from langchain.chains import ConversationChain
from langchain.memory import ConversationBufferMemory conversation = ConversationChain(llm=chat, memory=ConversationBufferMemory())
conversation.run("Answer briefly. What are the first 3 colors of a rainbow?")
conversation.run("And the next 4?")
LangChain unterstützt auch die Integration mit den Funktionsaufruf-APIs von OpenAI, was nützlich ist, um strukturierte Ausgaben zu erhalten und Funktionen innerhalb einer Kette auszuführen. Um strukturierte Ausgaben zu erhalten, können Sie diese mithilfe von Pydantic-Klassen oder JsonSchema angeben, wie unten dargestellt:
from langchain.pydantic_v1 import BaseModel, Field
from langchain.chains.openai_functions import create_structured_output_runnable
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate class Person(BaseModel): name: str = Field(..., description="The person's name") age: int = Field(..., description="The person's age") fav_food: Optional[str] = Field(None, description="The person's favorite food") llm = ChatOpenAI(model="gpt-4", temperature=0)
prompt = ChatPromptTemplate.from_messages([ # Prompt messages here
]) runnable = create_structured_output_runnable(Person, llm, prompt)
runnable.invoke({"input": "Sally is 13"})
Für strukturierte Ausgaben ist auch ein Legacy-Ansatz mit LLMChain verfügbar:
from langchain.chains.openai_functions import create_structured_output_chain class Person(BaseModel): name: str = Field(..., description="The person's name") age: int = Field(..., description="The person's age") chain = create_structured_output_chain(Person, llm, prompt, verbose=True)
chain.run("Sally is 13")
LangChain nutzt OpenAI-Funktionen, um verschiedene spezifische Ketten für unterschiedliche Zwecke zu erstellen. Dazu gehören Ketten für Extraktion, Tagging, OpenAPI und Qualitätssicherung mit Zitaten.
Im Kontext der Extraktion ähnelt der Prozess der strukturierten Ausgabekette, konzentriert sich jedoch auf die Extraktion von Informationen oder Entitäten. Beim Markieren geht es darum, ein Dokument mit Klassen wie Stimmung, Sprache, Stil, behandelten Themen oder politischer Tendenz zu kennzeichnen.
Ein Beispiel dafür, wie Tagging in LangChain funktioniert, kann anhand eines Python-Codes demonstriert werden. Der Prozess beginnt mit der Installation der erforderlichen Pakete und der Einrichtung der Umgebung:
pip install langchain openai
# Set env var OPENAI_API_KEY or load from a .env file:
# import dotenv
# dotenv.load_dotenv() from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.chains import create_tagging_chain, create_tagging_chain_pydantic
Das Schema für das Tagging wird definiert und gibt die Eigenschaften und ihre erwarteten Typen an:
schema = { "properties": { "sentiment": {"type": "string"}, "aggressiveness": {"type": "integer"}, "language": {"type": "string"}, }
} llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo-0613")
chain = create_tagging_chain(schema, llm)
Beispiele für die Ausführung der Tagging-Kette mit verschiedenen Eingaben zeigen die Fähigkeit des Modells, Gefühle, Sprachen und Aggressivität zu interpretieren:
inp = "Estoy increiblemente contento de haberte conocido! Creo que seremos muy buenos amigos!"
chain.run(inp)
# {'sentiment': 'positive', 'language': 'Spanish'} inp = "Estoy muy enojado con vos! Te voy a dar tu merecido!"
chain.run(inp)
# {'sentiment': 'enojado', 'aggressiveness': 1, 'language': 'es'}
Für eine genauere Kontrolle kann das Schema spezifischer definiert werden, einschließlich möglicher Werte, Beschreibungen und erforderlicher Eigenschaften. Ein Beispiel für diese erweiterte Kontrolle ist unten dargestellt:
schema = { "properties": { # Schema definitions here }, "required": ["language", "sentiment", "aggressiveness"],
} chain = create_tagging_chain(schema, llm)
Pydantic-Schemas können auch zum Definieren von Tagging-Kriterien verwendet werden und bieten eine pydantische Möglichkeit, erforderliche Eigenschaften und Typen anzugeben:
from enum import Enum
from pydantic import BaseModel, Field class Tags(BaseModel): # Class fields here chain = create_tagging_chain_pydantic(Tags, llm)
Darüber hinaus kann der Metadaten-Tagger-Dokumenttransformator von LangChain zum Extrahieren von Metadaten aus LangChain-Dokumenten verwendet werden. Er bietet ähnliche Funktionen wie die Tagging-Kette, wird jedoch auf ein LangChain-Dokument angewendet.
Das Zitieren von Retrieval-Quellen ist eine weitere Funktion von LangChain, bei der OpenAI-Funktionen verwendet werden, um Zitate aus Texten zu extrahieren. Dies wird im folgenden Code demonstriert:
from langchain.chains import create_citation_fuzzy_match_chain
from langchain.chat_models import ChatOpenAI llm = ChatOpenAI(temperature=0, model="gpt-3.5-turbo-0613")
chain = create_citation_fuzzy_match_chain(llm)
# Further code for running the chain and displaying results
In LangChain umfasst die Verkettung in LLM-Anwendungen (Large Language Model) typischerweise die Kombination einer Eingabeaufforderungsvorlage mit einem LLM und optional einem Ausgabeparser. Der empfohlene Weg hierfür ist die LangChain Expression Language (LCEL), obwohl auch der ältere LLMChain-Ansatz unterstützt wird.
Mit LCEL implementieren BasePromptTemplate, BaseLanguageModel und BaseOutputParser alle die Runnable-Schnittstelle und können problemlos ineinander überführt werden. Hier ist ein Beispiel, das dies demonstriert:
from langchain.prompts import PromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain.schema import StrOutputParser prompt = PromptTemplate.from_template( "What is a good name for a company that makes {product}?"
)
runnable = prompt | ChatOpenAI() | StrOutputParser()
runnable.invoke({"product": "colorful socks"})
# Output: 'VibrantSocks'
Routing in LangChain ermöglicht die Erstellung nichtdeterministischer Ketten, bei denen die Ausgabe eines vorherigen Schritts den nächsten Schritt bestimmt. Dies hilft bei der Strukturierung und Aufrechterhaltung der Konsistenz bei Interaktionen mit LLMs. Wenn Sie beispielsweise über zwei Vorlagen verfügen, die für unterschiedliche Arten von Fragen optimiert sind, können Sie die Vorlage basierend auf Benutzereingaben auswählen.
So können Sie dies erreichen, indem Sie LCEL mit einem RunnableBranch verwenden, der mit einer Liste von (Bedingungs-, ausführbaren) Paaren und einem standardmäßigen ausführbaren Element initialisiert wird:
from langchain.chat_models import ChatOpenAI
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnableBranch
# Code for defining physics_prompt and math_prompt general_prompt = PromptTemplate.from_template( "You are a helpful assistant. Answer the question as accurately as you can.nn{input}"
)
prompt_branch = RunnableBranch( (lambda x: x["topic"] == "math", math_prompt), (lambda x: x["topic"] == "physics", physics_prompt), general_prompt,
) # More code for setting up the classifier and final chain
Die endgültige Kette wird dann mithilfe verschiedener Komponenten wie einem Themenklassifizierer, einem Eingabeaufforderungszweig und einem Ausgabeparser erstellt, um den Fluss basierend auf dem Thema der Eingabe zu bestimmen:
from operator import itemgetter
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough final_chain = ( RunnablePassthrough.assign(topic=itemgetter("input") | classifier_chain) | prompt_branch | ChatOpenAI() | StrOutputParser()
) final_chain.invoke( { "input": "What is the first prime number greater than 40 such that one plus the prime number is divisible by 3?" }
)
# Output: Detailed answer to the math question
Dieser Ansatz veranschaulicht die Flexibilität und Leistungsfähigkeit von LangChain bei der Bearbeitung komplexer Abfragen und deren entsprechende Weiterleitung basierend auf der Eingabe.
Im Bereich der Sprachmodelle besteht eine gängige Praxis darin, einem ersten Aufruf eine Reihe nachfolgender Aufrufe folgen zu lassen und dabei die Ausgabe eines Aufrufs als Eingabe für den nächsten zu verwenden. Dieser sequenzielle Ansatz ist besonders vorteilhaft, wenn Sie auf den in früheren Interaktionen generierten Informationen aufbauen möchten. Während die LangChain Expression Language (LCEL) die empfohlene Methode zum Erstellen dieser Sequenzen ist, ist die SequentialChain-Methode dennoch hinsichtlich ihrer Abwärtskompatibilität dokumentiert.
Um dies zu veranschaulichen, betrachten wir ein Szenario, in dem wir zunächst eine Spielzusammenfassung und dann eine Rezension basierend auf dieser Zusammenfassung erstellen. Verwendung von Pythons langchain.prompts
, wir erstellen zwei PromptTemplate
Instanzen: eine für die Zusammenfassung und eine für die Rezension. Hier ist der Code zum Einrichten dieser Vorlagen:
from langchain.prompts import PromptTemplate synopsis_prompt = PromptTemplate.from_template( "You are a playwright. Given the title of play, it is your job to write a synopsis for that title.nnTitle: {title}nPlaywright: This is a synopsis for the above play:"
) review_prompt = PromptTemplate.from_template( "You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.nnPlay Synopsis:n{synopsis}nReview from a New York Times play critic of the above play:"
)
Im LCEL-Ansatz verketten wir diese Eingabeaufforderungen mit ChatOpenAI
und StrOutputParser
eine Sequenz zu erstellen, die zunächst eine Zusammenfassung und dann eine Rezension generiert. Der Codeausschnitt lautet wie folgt:
from langchain.chat_models import ChatOpenAI
from langchain.schema import StrOutputParser llm = ChatOpenAI()
chain = ( {"synopsis": synopsis_prompt | llm | StrOutputParser()} | review_prompt | llm | StrOutputParser()
)
chain.invoke({"title": "Tragedy at sunset on the beach"})
Wenn wir sowohl die Zusammenfassung als auch die Rezension benötigen, können wir diese verwenden RunnablePassthrough
um für jede eine eigene Kette zu erstellen und sie dann zu kombinieren:
from langchain.schema.runnable import RunnablePassthrough synopsis_chain = synopsis_prompt | llm | StrOutputParser()
review_chain = review_prompt | llm | StrOutputParser()
chain = {"synopsis": synopsis_chain} | RunnablePassthrough.assign(review=review_chain)
chain.invoke({"title": "Tragedy at sunset on the beach"})
Für Szenarien mit komplexeren Sequenzen ist die SequentialChain
Methode kommt ins Spiel. Dies ermöglicht mehrere Ein- und Ausgänge. Stellen Sie sich einen Fall vor, in dem wir eine Zusammenfassung basierend auf dem Titel und der Ära eines Stücks benötigen. So könnten wir es einrichten:
from langchain.llms import OpenAI
from langchain.chains import LLMChain, SequentialChain
from langchain.prompts import PromptTemplate llm = OpenAI(temperature=0.7) synopsis_template = "You are a playwright. Given the title of play and the era it is set in, it is your job to write a synopsis for that title.nnTitle: {title}nEra: {era}nPlaywright: This is a synopsis for the above play:"
synopsis_prompt_template = PromptTemplate(input_variables=["title", "era"], template=synopsis_template)
synopsis_chain = LLMChain(llm=llm, prompt=synopsis_prompt_template, output_key="synopsis") review_template = "You are a play critic from the New York Times. Given the synopsis of play, it is your job to write a review for that play.nnPlay Synopsis:n{synopsis}nReview from a New York Times play critic of the above play:"
prompt_template = PromptTemplate(input_variables=["synopsis"], template=review_template)
review_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="review") overall_chain = SequentialChain( chains=[synopsis_chain, review_chain], input_variables=["era", "title"], output_variables=["synopsis", "review"], verbose=True,
) overall_chain({"title": "Tragedy at sunset on the beach", "era": "Victorian England"})
In Szenarien, in denen Sie den Kontext in einer Kette oder für einen späteren Teil der Kette beibehalten möchten, SimpleMemory
kann verwendet werden. Dies ist besonders nützlich für die Verwaltung komplexer Eingabe-/Ausgabebeziehungen. In einem Szenario, in dem wir beispielsweise Social-Media-Beiträge basierend auf dem Titel, der Ära, der Inhaltsangabe und der Rezension eines Stücks generieren möchten, SimpleMemory
kann bei der Verwaltung dieser Variablen helfen:
from langchain.memory import SimpleMemory
from langchain.chains import SequentialChain template = "You are a social media manager for a theater company. Given the title of play, the era it is set in, the date, time and location, the synopsis of the play, and the review of the play, it is your job to write a social media post for that play.nnHere is some context about the time and location of the play:nDate and Time: {time}nLocation: {location}nnPlay Synopsis:n{synopsis}nReview from a New York Times play critic of the above play:n{review}nnSocial Media Post:"
prompt_template = PromptTemplate(input_variables=["synopsis", "review", "time", "location"], template=template)
social_chain = LLMChain(llm=llm, prompt=prompt_template, output_key="social_post_text") overall_chain = SequentialChain( memory=SimpleMemory(memories={"time": "December 25th, 8pm PST", "location": "Theater in the Park"}), chains=[synopsis_chain, review_chain, social_chain], input_variables=["era", "title"], output_variables=["social_post_text"], verbose=True,
) overall_chain({"title": "Tragedy at sunset on the beach", "era": "Victorian England"})
Neben sequentiellen Ketten gibt es spezielle Ketten für die Arbeit mit Dokumenten. Jede dieser Ketten dient einem anderen Zweck, von der Kombination von Dokumenten über die Verfeinerung von Antworten auf der Grundlage einer iterativen Dokumentanalyse bis hin zur Zuordnung und Reduzierung von Dokumentinhalten zur Zusammenfassung oder Neubewertung auf Grundlage der bewerteten Antworten. Diese Ketten können für zusätzliche Flexibilität und Anpassung mit LCEL neu erstellt werden.
-
StuffDocumentsChain
fasst eine Liste von Dokumenten in einer einzigen Eingabeaufforderung zusammen, die an ein LLM übergeben wird. -
RefineDocumentsChain
Aktualisiert seine Antwort iterativ für jedes Dokument und eignet sich für Aufgaben, bei denen Dokumente die Kontextkapazität des Modells überschreiten. -
MapReduceDocumentsChain
wendet eine Kette auf jedes Dokument einzeln an und kombiniert dann die Ergebnisse. -
MapRerankDocumentsChain
bewertet jede dokumentbasierte Antwort und wählt die Antwort mit der höchsten Bewertung aus.
Hier ist ein Beispiel dafür, wie Sie eine einrichten könnten MapReduceDocumentsChain
mit LCEL:
from functools import partial
from langchain.chains.combine_documents import collapse_docs, split_list_of_docs
from langchain.schema import Document, StrOutputParser
from langchain.schema.prompt_template import format_document
from langchain.schema.runnable import RunnableParallel, RunnablePassthrough llm = ChatAnthropic()
document_prompt = PromptTemplate.from_template("{page_content}")
partial_format_document = partial(format_document, prompt=document_prompt) map_chain = ( {"context": partial_format_document} | PromptTemplate.from_template("Summarize this content:nn{context}") | llm | StrOutputParser()
) map_as_doc_chain = ( RunnableParallel({"doc": RunnablePassthrough(), "content": map_chain}) | (lambda x: Document(page_content=x["content"], metadata=x["doc"].metadata))
).with_config(run_name="Summarize (return doc)") def format_docs(docs): return "nn".join(partial_format_document(doc) for doc in docs) collapse_chain = ( {"context": format_docs} | PromptTemplate.from_template("Collapse this content:nn{context}") | llm | StrOutputParser()
) reduce_chain = ( {"context": format_docs} | PromptTemplate.from_template("Combine these summaries:nn{context}") | llm | StrOutputParser()
).with_config(run_name="Reduce") map_reduce = (map_as_doc_chain.map() | collapse | reduce_chain).with_config(run_name="Map reduce")
Diese Konfiguration ermöglicht eine detaillierte und umfassende Analyse des Dokumentinhalts und nutzt dabei die Stärken von LCEL und dem zugrunde liegenden Sprachmodell.
Automatisieren Sie manuelle Aufgaben und Arbeitsabläufe mit unserem KI-gesteuerten Workflow-Builder, der von Nanonets für Sie und Ihre Teams entwickelt wurde.
Modul V: Gedächtnis
In LangChain ist das Gedächtnis ein grundlegender Aspekt von Konversationsschnittstellen, der es Systemen ermöglicht, auf vergangene Interaktionen zu verweisen. Dies wird durch das Speichern und Abfragen von Informationen mit zwei Hauptaktionen erreicht: Lesen und Schreiben. Das Speichersystem interagiert während eines Laufs zweimal mit einer Kette, erweitert die Benutzereingaben und speichert die Ein- und Ausgaben zur späteren Bezugnahme.
Speicher in ein System einbauen
- Chat-Nachrichten speichern: Das LangChain-Speichermodul integriert verschiedene Methoden zum Speichern von Chat-Nachrichten, von In-Memory-Listen bis hin zu Datenbanken. Dadurch wird sichergestellt, dass alle Chat-Interaktionen zur späteren Bezugnahme aufgezeichnet werden.
- Chat-Nachrichten abfragen: LangChain speichert nicht nur Chat-Nachrichten, sondern nutzt auch Datenstrukturen und Algorithmen, um eine nützliche Ansicht dieser Nachrichten zu erstellen. Einfache Speichersysteme könnten aktuelle Nachrichten zurückgeben, während fortgeschrittenere Systeme frühere Interaktionen zusammenfassen oder sich auf Entitäten konzentrieren könnten, die in der aktuellen Interaktion erwähnt werden.
Um die Verwendung von Speicher in LangChain zu demonstrieren, betrachten Sie Folgendes ConversationBufferMemory
Klasse, eine einfache Speicherform, die Chat-Nachrichten in einem Puffer speichert. Hier ist ein Beispiel:
from langchain.memory import ConversationBufferMemory memory = ConversationBufferMemory()
memory.chat_memory.add_user_message("Hello!")
memory.chat_memory.add_ai_message("How can I assist you?")
Bei der Integration von Speicher in eine Kette ist es wichtig, die vom Speicher zurückgegebenen Variablen und ihre Verwendung in der Kette zu verstehen. Zum Beispiel die load_memory_variables
Die Methode hilft dabei, die aus dem Speicher gelesenen Variablen an den Erwartungen der Kette auszurichten.
End-to-End-Beispiel mit LangChain
Erwägen Sie die Verwendung ConversationBufferMemory
in eine LLMChain
. Die Kette sorgt in Kombination mit einer geeigneten Eingabeaufforderungsvorlage und dem Speicher für ein nahtloses Gesprächserlebnis. Hier ist ein vereinfachtes Beispiel:
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.chains import LLMChain
from langchain.memory import ConversationBufferMemory llm = OpenAI(temperature=0)
template = "Your conversation template here..."
prompt = PromptTemplate.from_template(template)
memory = ConversationBufferMemory(memory_key="chat_history")
conversation = LLMChain(llm=llm, prompt=prompt, memory=memory) response = conversation({"question": "What's the weather like?"})
Dieses Beispiel veranschaulicht, wie sich das Speichersystem von LangChain in seine Ketten integriert, um ein kohärentes und kontextbezogenes Gesprächserlebnis zu bieten.
Speichertypen in Langchain
Langchain bietet verschiedene Speichertypen, die zur Verbesserung der Interaktion mit den KI-Modellen genutzt werden können. Jeder Speichertyp verfügt über eigene Parameter und Rückgabetypen, wodurch er für verschiedene Szenarien geeignet ist. Lassen Sie uns einige der in Langchain verfügbaren Speichertypen zusammen mit Codebeispielen erkunden.
1. Konversationspufferspeicher
Mit diesem Speichertyp können Sie Nachrichten aus Gesprächen speichern und extrahieren. Sie können den Verlauf als Zeichenfolge oder als Nachrichtenliste extrahieren.
from langchain.memory import ConversationBufferMemory memory = ConversationBufferMemory()
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.load_memory_variables({}) # Extract history as a string
{'history': 'Human: hinAI: whats up'} # Extract history as a list of messages
{'history': [HumanMessage(content='hi', additional_kwargs={}), AIMessage(content='whats up', additional_kwargs={})]}
Sie können den Konversationspufferspeicher auch in einer Kette für chatähnliche Interaktionen verwenden.
2. Konversationspuffer-Fensterspeicher
Dieser Speichertyp führt eine Liste der letzten Interaktionen und verwendet die letzten K Interaktionen, um zu verhindern, dass der Puffer zu groß wird.
from langchain.memory import ConversationBufferWindowMemory memory = ConversationBufferWindowMemory(k=1)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.save_context({"input": "not much you"}, {"output": "not much"})
memory.load_memory_variables({}) {'history': 'Human: not much younAI: not much'}
Wie den Conversation Buffer Memory können Sie diesen Speichertyp auch in einer Kette für chatähnliche Interaktionen verwenden.
3. Konversationsentitätsgedächtnis
Dieser Speichertyp merkt sich Fakten zu bestimmten Entitäten in einer Konversation und extrahiert Informationen mithilfe eines LLM.
from langchain.memory import ConversationEntityMemory
from langchain.llms import OpenAI llm = OpenAI(temperature=0)
memory = ConversationEntityMemory(llm=llm)
_input = {"input": "Deven & Sam are working on a hackathon project"}
memory.load_memory_variables(_input)
memory.save_context( _input, {"output": " That sounds like a great project! What kind of project are they working on?"}
)
memory.load_memory_variables({"input": 'who is Sam'}) {'history': 'Human: Deven & Sam are working on a hackathon projectnAI: That sounds like a great project! What kind of project are they working on?', 'entities': {'Sam': 'Sam is working on a hackathon project with Deven.'}}
4. Konversations-Wissensgraph-Speicher
Dieser Speichertyp verwendet einen Wissensgraphen, um Speicher wiederherzustellen. Sie können aktuelle Entitäten und Wissenstripletts aus Nachrichten extrahieren.
from langchain.memory import ConversationKGMemory
from langchain.llms import OpenAI llm = OpenAI(temperature=0)
memory = ConversationKGMemory(llm=llm)
memory.save_context({"input": "say hi to sam"}, {"output": "who is sam"})
memory.save_context({"input": "sam is a friend"}, {"output": "okay"})
memory.load_memory_variables({"input": "who is sam"}) {'history': 'On Sam: Sam is friend.'}
Sie können diesen Speichertyp auch in einer Kette zum konversationsbasierten Wissensabruf verwenden.
5. Gesprächszusammenfassungsgedächtnis
Dieser Speichertyp erstellt eine Zusammenfassung des Gesprächs über einen längeren Zeitraum, was nützlich ist, um Informationen aus längeren Gesprächen zusammenzufassen.
from langchain.memory import ConversationSummaryMemory
from langchain.llms import OpenAI llm = OpenAI(temperature=0)
memory = ConversationSummaryMemory(llm=llm)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.load_memory_variables({}) {'history': 'nThe human greets the AI, to which the AI responds.'}
6. Konversationszusammenfassungspufferspeicher
Dieser Speichertyp kombiniert die Konversationszusammenfassung und den Puffer und sorgt so für ein Gleichgewicht zwischen den letzten Interaktionen und einer Zusammenfassung. Es verwendet die Tokenlänge, um zu bestimmen, wann Interaktionen geleert werden.
from langchain.memory import ConversationSummaryBufferMemory
from langchain.llms import OpenAI llm = OpenAI()
memory = ConversationSummaryBufferMemory(llm=llm, max_token_limit=10)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.save_context({"input": "not much you"}, {"output": "not much"})
memory.load_memory_variables({}) {'history': 'System: nThe human says "hi", and the AI responds with "whats up".nHuman: not much younAI: not much'}
Sie können diese Speichertypen verwenden, um Ihre Interaktionen mit KI-Modellen in Langchain zu verbessern. Jeder Speichertyp dient einem bestimmten Zweck und kann je nach Ihren Anforderungen ausgewählt werden.
7. Konversations-Token-Pufferspeicher
ConversationTokenBufferMemory ist ein weiterer Speichertyp, der einen Puffer der letzten Interaktionen im Speicher hält. Im Gegensatz zu den vorherigen Speichertypen, die sich auf die Anzahl der Interaktionen konzentrieren, verwendet dieser Speichertyp die Tokenlänge, um zu bestimmen, wann Interaktionen geleert werden.
Speicher mit LLM nutzen:
from langchain.memory import ConversationTokenBufferMemory
from langchain.llms import OpenAI llm = OpenAI() memory = ConversationTokenBufferMemory(llm=llm, max_token_limit=10)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.save_context({"input": "not much you"}, {"output": "not much"}) memory.load_memory_variables({}) {'history': 'Human: not much younAI: not much'}
In diesem Beispiel ist der Speicher so eingestellt, dass Interaktionen basierend auf der Tokenlänge und nicht auf der Anzahl der Interaktionen begrenzt werden.
Bei Verwendung dieses Speichertyps können Sie den Verlauf auch als Liste von Nachrichten abrufen.
memory = ConversationTokenBufferMemory( llm=llm, max_token_limit=10, return_messages=True
)
memory.save_context({"input": "hi"}, {"output": "whats up"})
memory.save_context({"input": "not much you"}, {"output": "not much"})
Verwendung in einer Kette:
Sie können ConversationTokenBufferMemory in einer Kette verwenden, um die Interaktionen mit dem KI-Modell zu verbessern.
from langchain.chains import ConversationChain conversation_with_summary = ConversationChain( llm=llm, # We set a very low max_token_limit for the purposes of testing. memory=ConversationTokenBufferMemory(llm=OpenAI(), max_token_limit=60), verbose=True,
)
conversation_with_summary.predict(input="Hi, what's up?")
In diesem Beispiel wird ConversationTokenBufferMemory in einer ConversationChain verwendet, um die Konversation zu verwalten und Interaktionen basierend auf der Token-Länge zu begrenzen.
8. VectorStoreRetrieverMemory
VectorStoreRetrieverMemory speichert Erinnerungen in einem Vektorspeicher und fragt bei jedem Aufruf die Top-K-Dokumente mit den meisten „Herausforderungen“ ab. Dieser Speichertyp verfolgt die Reihenfolge der Interaktionen nicht explizit, sondern nutzt die Vektorabfrage, um relevante Erinnerungen abzurufen.
from datetime import datetime
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.llms import OpenAI
from langchain.memory import VectorStoreRetrieverMemory
from langchain.chains import ConversationChain
from langchain.prompts import PromptTemplate # Initialize your vector store (specifics depend on the chosen vector store)
import faiss
from langchain.docstore import InMemoryDocstore
from langchain.vectorstores import FAISS embedding_size = 1536 # Dimensions of the OpenAIEmbeddings
index = faiss.IndexFlatL2(embedding_size)
embedding_fn = OpenAIEmbeddings().embed_query
vectorstore = FAISS(embedding_fn, index, InMemoryDocstore({}), {}) # Create your VectorStoreRetrieverMemory
retriever = vectorstore.as_retriever(search_kwargs=dict(k=1))
memory = VectorStoreRetrieverMemory(retriever=retriever) # Save context and relevant information to the memory
memory.save_context({"input": "My favorite food is pizza"}, {"output": "that's good to know"})
memory.save_context({"input": "My favorite sport is soccer"}, {"output": "..."})
memory.save_context({"input": "I don't like the Celtics"}, {"output": "ok"}) # Retrieve relevant information from memory based on a query
print(memory.load_memory_variables({"prompt": "what sport should i watch?"})["history"])
In diesem Beispiel wird VectorStoreRetrieverMemory verwendet, um relevante Informationen aus einer Konversation basierend auf dem Vektorabruf zu speichern und abzurufen.
Sie können VectorStoreRetrieverMemory auch in einer Kette zum konversationsbasierten Wissensabruf verwenden, wie in den vorherigen Beispielen gezeigt.
Diese verschiedenen Speichertypen in Langchain bieten verschiedene Möglichkeiten zum Verwalten und Abrufen von Informationen aus Gesprächen und verbessern so die Fähigkeiten von KI-Modellen, Benutzeranfragen und -kontexte zu verstehen und darauf zu reagieren. Jeder Speichertyp kann basierend auf den spezifischen Anforderungen Ihrer Anwendung ausgewählt werden.
Jetzt lernen wir, wie man Speicher mit einer LLMChain nutzt. Der Speicher in einer LLMChain ermöglicht es dem Modell, sich an frühere Interaktionen und Kontexte zu erinnern, um kohärentere und kontextbewusstere Antworten bereitzustellen.
Um Speicher in einer LLMChain einzurichten, müssen Sie eine Speicherklasse erstellen, z. B. ConversationBufferMemory. So können Sie es einrichten:
from langchain.chains import LLMChain
from langchain.llms import OpenAI
from langchain.memory import ConversationBufferMemory
from langchain.prompts import PromptTemplate template = """You are a chatbot having a conversation with a human. {chat_history}
Human: {human_input}
Chatbot:""" prompt = PromptTemplate( input_variables=["chat_history", "human_input"], template=template
)
memory = ConversationBufferMemory(memory_key="chat_history") llm = OpenAI()
llm_chain = LLMChain( llm=llm, prompt=prompt, verbose=True, memory=memory,
) llm_chain.predict(human_input="Hi there my friend")
In diesem Beispiel wird ConversationBufferMemory zum Speichern des Konversationsverlaufs verwendet. Der memory_key
Der Parameter gibt den Schlüssel an, der zum Speichern des Konversationsverlaufs verwendet wird.
Wenn Sie ein Chat-Modell anstelle eines Vervollständigungsmodells verwenden, können Sie Ihre Eingabeaufforderungen anders strukturieren, um den Speicher besser zu nutzen. Hier ist ein Beispiel für die Einrichtung einer auf einem Chat-Modell basierenden LLMChain mit Speicher:
from langchain.chat_models import ChatOpenAI
from langchain.schema import SystemMessage
from langchain.prompts import ( ChatPromptTemplate, HumanMessagePromptTemplate, MessagesPlaceholder,
) # Create a ChatPromptTemplate
prompt = ChatPromptTemplate.from_messages( [ SystemMessage( content="You are a chatbot having a conversation with a human." ), # The persistent system prompt MessagesPlaceholder( variable_name="chat_history" ), # Where the memory will be stored. HumanMessagePromptTemplate.from_template( "{human_input}" ), # Where the human input will be injected ]
) memory = ConversationBufferMemory(memory_key="chat_history", return_messages=True) llm = ChatOpenAI() chat_llm_chain = LLMChain( llm=llm, prompt=prompt, verbose=True, memory=memory,
) chat_llm_chain.predict(human_input="Hi there my friend")
In diesem Beispiel wird ChatPromptTemplate zum Strukturieren der Eingabeaufforderung und ConversationBufferMemory zum Speichern und Abrufen des Konversationsverlaufs verwendet. Dieser Ansatz ist besonders nützlich für Gespräche im Chat-Stil, bei denen Kontext und Verlauf eine entscheidende Rolle spielen.
Speicher kann auch zu einer Kette mit mehreren Eingaben hinzugefügt werden, beispielsweise einer Frage-/Antwortkette. Hier ist ein Beispiel für die Einrichtung des Speichers in einer Frage-/Antwortkette:
from langchain.embeddings.openai import OpenAIEmbeddings
from langchain.embeddings.cohere import CohereEmbeddings
from langchain.text_splitter import CharacterTextSplitter
from langchain.vectorstores.elastic_vector_search import ElasticVectorSearch
from langchain.vectorstores import Chroma
from langchain.docstore.document import Document
from langchain.chains.question_answering import load_qa_chain
from langchain.llms import OpenAI
from langchain.prompts import PromptTemplate
from langchain.memory import ConversationBufferMemory # Split a long document into smaller chunks
with open("../../state_of_the_union.txt") as f: state_of_the_union = f.read()
text_splitter = CharacterTextSplitter(chunk_size=1000, chunk_overlap=0)
texts = text_splitter.split_text(state_of_the_union) # Create an ElasticVectorSearch instance to index and search the document chunks
embeddings = OpenAIEmbeddings()
docsearch = Chroma.from_texts( texts, embeddings, metadatas=[{"source": i} for i in range(len(texts))]
) # Perform a question about the document
query = "What did the president say about Justice Breyer"
docs = docsearch.similarity_search(query) # Set up a prompt for the question-answering chain with memory
template = """You are a chatbot having a conversation with a human. Given the following extracted parts of a long document and a question, create a final answer. {context} {chat_history}
Human: {human_input}
Chatbot:""" prompt = PromptTemplate( input_variables=["chat_history", "human_input", "context"], template=template
)
memory = ConversationBufferMemory(memory_key="chat_history", input_key="human_input")
chain = load_qa_chain( OpenAI(temperature=0), chain_type="stuff", memory=memory, prompt=prompt
) # Ask the question and retrieve the answer
query = "What did the president say about Justice Breyer"
result = chain({"input_documents": docs, "human_input": query}, return_only_outputs=True) print(result)
print(chain.memory.buffer)
In diesem Beispiel wird eine Frage anhand eines in kleinere Teile aufgeteilten Dokuments beantwortet. Der ConversationBufferMemory wird zum Speichern und Abrufen des Konversationsverlaufs verwendet, sodass das Modell kontextbezogene Antworten bereitstellen kann.
Durch das Hinzufügen von Speicher zu einem Agenten kann dieser sich an frühere Interaktionen erinnern und diese nutzen, um Fragen zu beantworten und kontextbezogene Antworten bereitzustellen. So können Sie den Speicher in einem Agenten einrichten:
from langchain.agents import ZeroShotAgent, Tool, AgentExecutor
from langchain.memory import ConversationBufferMemory
from langchain.llms import OpenAI
from langchain.chains import LLMChain
from langchain.utilities import GoogleSearchAPIWrapper # Create a tool for searching
search = GoogleSearchAPIWrapper()
tools = [ Tool( name="Search", func=search.run, description="useful for when you need to answer questions about current events", )
] # Create a prompt with memory
prefix = """Have a conversation with a human, answering the following questions as best you can. You have access to the following tools:"""
suffix = """Begin!" {chat_history}
Question: {input}
{agent_scratchpad}""" prompt = ZeroShotAgent.create_prompt( tools, prefix=prefix, suffix=suffix, input_variables=["input", "chat_history", "agent_scratchpad"],
)
memory = ConversationBufferMemory(memory_key="chat_history") # Create an LLMChain with memory
llm_chain = LLMChain(llm=OpenAI(temperature=0), prompt=prompt)
agent = ZeroShotAgent(llm_chain=llm_chain, tools=tools, verbose=True)
agent_chain = AgentExecutor.from_agent_and_tools( agent=agent, tools=tools, verbose=True, memory=memory
) # Ask a question and retrieve the answer
response = agent_chain.run(input="How many people live in Canada?")
print(response) # Ask a follow-up question
response = agent_chain.run(input="What is their national anthem called?")
print(response)
In diesem Beispiel wird einem Agenten ein Speicher hinzugefügt, der es ihm ermöglicht, sich an den vorherigen Gesprächsverlauf zu erinnern und kontextbezogene Antworten bereitzustellen. Dies ermöglicht es dem Agenten, Folgefragen basierend auf den im Speicher gespeicherten Informationen präzise zu beantworten.
LangChain-Ausdruckssprache
In der Welt der Verarbeitung natürlicher Sprache und des maschinellen Lernens kann die Erstellung komplexer Operationsketten eine entmutigende Aufgabe sein. Glücklicherweise kommt LangChain Expression Language (LCEL) zur Rettung und bietet eine deklarative und effiziente Möglichkeit, anspruchsvolle Sprachverarbeitungspipelines zu erstellen und bereitzustellen. LCEL wurde entwickelt, um den Prozess der Kettenerstellung zu vereinfachen und einen einfachen Übergang vom Prototyping zur Produktion zu ermöglichen. In diesem Blog werden wir untersuchen, was LCEL ist und warum Sie es möglicherweise verwenden möchten, zusammen mit praktischen Codebeispielen, um seine Fähigkeiten zu veranschaulichen.
LCEL (LangChain Expression Language) ist ein leistungsstarkes Werkzeug zum Erstellen von Sprachverarbeitungsketten. Es wurde speziell entwickelt, um den Übergang vom Prototyping zur Produktion nahtlos zu unterstützen, ohne dass umfangreiche Codeänderungen erforderlich sind. Egal, ob Sie eine einfache „Prompt + LLM“-Kette oder eine komplexe Pipeline mit Hunderten von Schritten aufbauen, LCEL hat alles für Sie.
Hier sind einige Gründe, LCEL in Ihren Sprachverarbeitungsprojekten zu verwenden:
- Schnelles Token-Streaming: LCEL liefert Token von einem Sprachmodell in Echtzeit an einen Ausgabeparser und verbessert so die Reaktionsfähigkeit und Effizienz.
- Vielseitige APIs: LCEL unterstützt sowohl synchrone als auch asynchrone APIs für die Prototypenerstellung und den Produktionseinsatz und verarbeitet so mehrere Anfragen effizient.
- Automatische Parallelisierung: LCEL optimiert die parallele Ausführung, wenn möglich, und reduziert die Latenz sowohl bei synchronen als auch bei asynchronen Schnittstellen.
- Zuverlässige Konfigurationen: Konfigurieren Sie Wiederholungsversuche und Fallbacks für eine verbesserte Kettenzuverlässigkeit im großen Maßstab, mit Streaming-Unterstützung in der Entwicklung.
- Zwischenergebnisse streamen: Greifen Sie während der Verarbeitung auf Zwischenergebnisse für Benutzeraktualisierungen oder Debugging-Zwecke zu.
- Schemagenerierung: LCEL generiert Pydantic- und JSONSchema-Schemas für die Eingabe- und Ausgabevalidierung.
- Umfassende Ablaufverfolgung: LangSmith verfolgt automatisch alle Schritte in komplexen Ketten zur besseren Beobachtbarkeit und Fehlerbehebung.
- Einfache Bereitstellung: Stellen Sie von LCEL erstellte Ketten mühelos mit LangServe bereit.
Lassen Sie uns nun in praktische Codebeispiele eintauchen, die die Leistungsfähigkeit von LCEL demonstrieren. Wir werden gängige Aufgaben und Szenarien untersuchen, in denen LCEL glänzt.
Eingabeaufforderung + LLM
Die grundlegendste Zusammensetzung besteht darin, eine Eingabeaufforderung und ein Sprachmodell zu kombinieren, um eine Kette zu erstellen, die Benutzereingaben entgegennimmt, sie einer Eingabeaufforderung hinzufügt, sie an ein Modell übergibt und die Rohmodellausgabe zurückgibt. Hier ist ein Beispiel:
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI prompt = ChatPromptTemplate.from_template("tell me a joke about {foo}")
model = ChatOpenAI()
chain = prompt | model result = chain.invoke({"foo": "bears"})
print(result)
In diesem Beispiel generiert die Kette einen Witz über Bären.
Sie können Ihrer Kette Stoppsequenzen hinzufügen, um zu steuern, wie Text verarbeitet wird. Zum Beispiel:
chain = prompt | model.bind(stop=["n"])
result = chain.invoke({"foo": "bears"})
print(result)
Diese Konfiguration stoppt die Textgenerierung, wenn ein Zeilenumbruchzeichen auftritt.
LCEL unterstützt das Anhängen von Funktionsaufrufinformationen an Ihre Kette. Hier ist ein Beispiel:
functions = [ { "name": "joke", "description": "A joke", "parameters": { "type": "object", "properties": { "setup": {"type": "string", "description": "The setup for the joke"}, "punchline": { "type": "string", "description": "The punchline for the joke", }, }, "required": ["setup", "punchline"], }, }
]
chain = prompt | model.bind(function_call={"name": "joke"}, functions=functions)
result = chain.invoke({"foo": "bears"}, config={})
print(result)
In diesem Beispiel werden Funktionsaufrufinformationen angehängt, um einen Witz zu generieren.
Eingabeaufforderung + LLM + OutputParser
Sie können einen Ausgabeparser hinzufügen, um die Rohmodellausgabe in ein besser bearbeitbares Format umzuwandeln. So können Sie es machen:
from langchain.schema.output_parser import StrOutputParser chain = prompt | model | StrOutputParser()
result = chain.invoke({"foo": "bears"})
print(result)
Die Ausgabe erfolgt jetzt im String-Format, was für nachgelagerte Aufgaben praktischer ist.
Wenn Sie eine zurückzugebende Funktion angeben, können Sie diese direkt mit LCEL analysieren. Zum Beispiel:
from langchain.output_parsers.openai_functions import JsonOutputFunctionsParser chain = ( prompt | model.bind(function_call={"name": "joke"}, functions=functions) | JsonOutputFunctionsParser()
)
result = chain.invoke({"foo": "bears"})
print(result)
In diesem Beispiel wird die Ausgabe der Funktion „joke“ direkt analysiert.
Dies sind nur einige Beispiele dafür, wie LCEL komplexe Sprachverarbeitungsaufgaben vereinfacht. Ganz gleich, ob Sie Chatbots erstellen, Inhalte generieren oder komplexe Texttransformationen durchführen, LCEL kann Ihren Arbeitsablauf rationalisieren und Ihren Code wartbarer machen.
RAG (Retrieval-Augmented Generation)
Mit LCEL können abrufgestützte Generierungsketten erstellt werden, die Abruf- und Sprachgenerierungsschritte kombinieren. Hier ist ein Beispiel:
from operator import itemgetter from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatOpenAI
from langchain.embeddings import OpenAIEmbeddings
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough, RunnableLambda
from langchain.vectorstores import FAISS # Create a vector store and retriever
vectorstore = FAISS.from_texts( ["harrison worked at kensho"], embedding=OpenAIEmbeddings()
)
retriever = vectorstore.as_retriever() # Define templates for prompts
template = """Answer the question based only on the following context:
{context} Question: {question} """
prompt = ChatPromptTemplate.from_template(template) model = ChatOpenAI() # Create a retrieval-augmented generation chain
chain = ( {"context": retriever, "question": RunnablePassthrough()} | prompt | model | StrOutputParser()
) result = chain.invoke("where did harrison work?")
print(result)
In diesem Beispiel ruft die Kette relevante Informationen aus dem Kontext ab und generiert eine Antwort auf die Frage.
Konversationsabrufkette
Sie können den Gesprächsverlauf ganz einfach zu Ihren Ketten hinzufügen. Hier ist ein Beispiel für eine Konversationsabrufkette:
from langchain.schema.runnable import RunnableMap
from langchain.schema import format_document from langchain.prompts.prompt import PromptTemplate # Define templates for prompts
_template = """Given the following conversation and a follow up question, rephrase the follow up question to be a standalone question, in its original language. Chat History:
{chat_history}
Follow Up Input: {question}
Standalone question:"""
CONDENSE_QUESTION_PROMPT = PromptTemplate.from_template(_template) template = """Answer the question based only on the following context:
{context} Question: {question} """
ANSWER_PROMPT = ChatPromptTemplate.from_template(template) # Define input map and context
_inputs = RunnableMap( standalone_question=RunnablePassthrough.assign( chat_history=lambda x: _format_chat_history(x["chat_history"]) ) | CONDENSE_QUESTION_PROMPT | ChatOpenAI(temperature=0) | StrOutputParser(),
)
_context = { "context": itemgetter("standalone_question") | retriever | _combine_documents, "question": lambda x: x["standalone_question"],
}
conversational_qa_chain = _inputs | _context | ANSWER_PROMPT | ChatOpenAI() result = conversational_qa_chain.invoke( { "question": "where did harrison work?", "chat_history": [], }
)
print(result)
In diesem Beispiel bearbeitet die Kette eine Folgefrage in einem Gesprächskontext.
Mit Speicher und zurückkehrenden Quelldokumenten
LCEL unterstützt auch die Speicherung und Rückgabe von Quelldokumenten. So können Sie Speicher in einer Kette verwenden:
from operator import itemgetter
from langchain.memory import ConversationBufferMemory # Create a memory instance
memory = ConversationBufferMemory( return_messages=True, output_key="answer", input_key="question"
) # Define steps for the chain
loaded_memory = RunnablePassthrough.assign( chat_history=RunnableLambda(memory.load_memory_variables) | itemgetter("history"),
) standalone_question = { "standalone_question": { "question": lambda x: x["question"], "chat_history": lambda x: _format_chat_history(x["chat_history"]), } | CONDENSE_QUESTION_PROMPT | ChatOpenAI(temperature=0) | StrOutputParser(),
} retrieved_documents = { "docs": itemgetter("standalone_question") | retriever, "question": lambda x: x["standalone_question"],
} final_inputs = { "context": lambda x: _combine_documents(x["docs"]), "question": itemgetter("question"),
} answer = { "answer": final_inputs | ANSWER_PROMPT | ChatOpenAI(), "docs": itemgetter("docs"),
} # Create the final chain by combining the steps
final_chain = loaded_memory | standalone_question | retrieved_documents | answer inputs = {"question": "where did harrison work?"}
result = final_chain.invoke(inputs)
print(result)
In diesem Beispiel wird der Speicher zum Speichern und Abrufen des Gesprächsverlaufs und der Quelldokumente verwendet.
Mehrere Ketten
Mithilfe von Runnables können Sie mehrere Ketten aneinanderreihen. Hier ist ein Beispiel:
from operator import itemgetter from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser prompt1 = ChatPromptTemplate.from_template("what is the city {person} is from?")
prompt2 = ChatPromptTemplate.from_template( "what country is the city {city} in? respond in {language}"
) model = ChatOpenAI() chain1 = prompt1 | model | StrOutputParser() chain2 = ( {"city": chain1, "language": itemgetter("language")} | prompt2 | model | StrOutputParser()
) result = chain2.invoke({"person": "obama", "language": "spanish"})
print(result)
In diesem Beispiel werden zwei Ketten kombiniert, um Informationen über eine Stadt und ihr Land in einer bestimmten Sprache zu generieren.
Verzweigen und Zusammenführen
Mit LCEL können Sie Ketten mithilfe von RunnableMaps teilen und zusammenführen. Hier ist ein Beispiel für Verzweigung und Zusammenführung:
from operator import itemgetter from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema import StrOutputParser planner = ( ChatPromptTemplate.from_template("Generate an argument about: {input}") | ChatOpenAI() | StrOutputParser() | {"base_response": RunnablePassthrough()}
) arguments_for = ( ChatPromptTemplate.from_template( "List the pros or positive aspects of {base_response}" ) | ChatOpenAI() | StrOutputParser()
)
arguments_against = ( ChatPromptTemplate.from_template( "List the cons or negative aspects of {base_response}" ) | ChatOpenAI() | StrOutputParser()
) final_responder = ( ChatPromptTemplate.from_messages( [ ("ai", "{original_response}"), ("human", "Pros:n{results_1}nnCons:n{results_2}"), ("system", "Generate a final response given the critique"), ] ) | ChatOpenAI() | StrOutputParser()
) chain = ( planner | { "results_1": arguments_for, "results_2": arguments_against, "original_response": itemgetter("base_response"), } | final_responder
) result = chain.invoke({"input": "scrum"})
print(result)
In diesem Beispiel wird eine Verzweigungs- und Zusammenführungskette verwendet, um ein Argument zu generieren und seine Vor- und Nachteile zu bewerten, bevor eine endgültige Antwort generiert wird.
Python-Code mit LCEL schreiben
Eine der leistungsstarken Anwendungen der LangChain Expression Language (LCEL) ist das Schreiben von Python-Code zur Lösung von Benutzerproblemen. Nachfolgend finden Sie ein Beispiel für die Verwendung von LCEL zum Schreiben von Python-Code:
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain_experimental.utilities import PythonREPL template = """Write some python code to solve the user's problem. Return only python code in Markdown format, e.g.: ```python
....
```"""
prompt = ChatPromptTemplate.from_messages([("system", template), ("human", "{input}")]) model = ChatOpenAI() def _sanitize_output(text: str): _, after = text.split("```python") return after.split("```")[0] chain = prompt | model | StrOutputParser() | _sanitize_output | PythonREPL().run result = chain.invoke({"input": "what's 2 plus 2"})
print(result)
In diesem Beispiel gibt ein Benutzer Eingaben ein und LCEL generiert Python-Code, um das Problem zu lösen. Der Code wird dann mit einem Python REPL ausgeführt und der resultierende Python-Code wird im Markdown-Format zurückgegeben.
Bitte beachten Sie, dass bei Verwendung einer Python-REPL beliebiger Code ausgeführt werden kann. Verwenden Sie diese daher mit Vorsicht.
Speicher zu einer Kette hinzufügen
Der Speicher ist in vielen Konversations-KI-Anwendungen unerlässlich. So fügen Sie Speicher zu einer beliebigen Kette hinzu:
from operator import itemgetter
from langchain.chat_models import ChatOpenAI
from langchain.memory import ConversationBufferMemory
from langchain.schema.runnable import RunnablePassthrough, RunnableLambda
from langchain.prompts import ChatPromptTemplate, MessagesPlaceholder model = ChatOpenAI()
prompt = ChatPromptTemplate.from_messages( [ ("system", "You are a helpful chatbot"), MessagesPlaceholder(variable_name="history"), ("human", "{input}"), ]
) memory = ConversationBufferMemory(return_messages=True) # Initialize memory
memory.load_memory_variables({}) chain = ( RunnablePassthrough.assign( history=RunnableLambda(memory.load_memory_variables) | itemgetter("history") ) | prompt | model
) inputs = {"input": "hi, I'm Bob"}
response = chain.invoke(inputs)
response # Save the conversation in memory
memory.save_context(inputs, {"output": response.content}) # Load memory to see the conversation history
memory.load_memory_variables({})
In diesem Beispiel wird der Speicher zum Speichern und Abrufen des Gesprächsverlaufs verwendet, sodass der Chatbot den Kontext beibehalten und angemessen reagieren kann.
Verwendung externer Tools mit Runnables
Mit LCEL können Sie externe Tools nahtlos in Runnables integrieren. Hier ist ein Beispiel für die Verwendung des DuckDuckGo-Suchtools:
from langchain.chat_models import ChatOpenAI
from langchain.prompts import ChatPromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain.tools import DuckDuckGoSearchRun search = DuckDuckGoSearchRun() template = """Turn the following user input into a search query for a search engine: {input}"""
prompt = ChatPromptTemplate.from_template(template) model = ChatOpenAI() chain = prompt | model | StrOutputParser() | search search_result = chain.invoke({"input": "I'd like to figure out what games are tonight"})
print(search_result)
In diesem Beispiel integriert LCEL das Suchtool DuckDuckGo in die Kette, sodass es aus Benutzereingaben eine Suchabfrage generieren und Suchergebnisse abrufen kann.
Die Flexibilität von LCEL erleichtert die Integration verschiedener externer Tools und Dienste in Ihre Sprachverarbeitungspipelines und verbessert so deren Fähigkeiten und Funktionalität.
Hinzufügen einer Moderation zu einer LLM-Anwendung
Um sicherzustellen, dass Ihre LLM-Anwendung den Inhaltsrichtlinien entspricht und Moderationsschutzmaßnahmen umfasst, können Sie Moderationsprüfungen in Ihre Kette integrieren. So fügen Sie Moderation mit LangChain hinzu:
from langchain.chains import OpenAIModerationChain
from langchain.llms import OpenAI
from langchain.prompts import ChatPromptTemplate moderate = OpenAIModerationChain() model = OpenAI()
prompt = ChatPromptTemplate.from_messages([("system", "repeat after me: {input}")]) chain = prompt | model # Original response without moderation
response_without_moderation = chain.invoke({"input": "you are stupid"})
print(response_without_moderation) moderated_chain = chain | moderate # Response after moderation
response_after_moderation = moderated_chain.invoke({"input": "you are stupid"})
print(response_after_moderation)
In diesem Beispiel OpenAIModerationChain
wird verwendet, um die vom LLM generierte Antwort zu moderieren. Die Moderationskette prüft die Antwort auf Inhalte, die gegen die Inhaltsrichtlinie von OpenAI verstoßen. Wenn Verstöße festgestellt werden, wird die Antwort entsprechend gekennzeichnet.
Routing durch semantische Ähnlichkeit
Mit LCEL können Sie eine benutzerdefinierte Routing-Logik basierend auf der semantischen Ähnlichkeit der Benutzereingaben implementieren. Hier ist ein Beispiel dafür, wie die Kettenlogik basierend auf Benutzereingaben dynamisch bestimmt wird:
from langchain.chat_models import ChatOpenAI
from langchain.embeddings import OpenAIEmbeddings
from langchain.prompts import PromptTemplate
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnableLambda, RunnablePassthrough
from langchain.utils.math import cosine_similarity physics_template = """You are a very smart physics professor. You are great at answering questions about physics in a concise and easy to understand manner. When you don't know the answer to a question you admit that you don't know. Here is a question:
{query}""" math_template = """You are a very good mathematician. You are great at answering math questions. You are so good because you are able to break down hard problems into their component parts, answer the component parts, and then put them together to answer the broader question. Here is a question:
{query}""" embeddings = OpenAIEmbeddings()
prompt_templates = [physics_template, math_template]
prompt_embeddings = embeddings.embed_documents(prompt_templates) def prompt_router(input): query_embedding = embeddings.embed_query(input["query"]) similarity = cosine_similarity([query_embedding], prompt_embeddings)[0] most_similar = prompt_templates[similarity.argmax()] print("Using MATH" if most_similar == math_template else "Using PHYSICS") return PromptTemplate.from_template(most_similar) chain = ( {"query": RunnablePassthrough()} | RunnableLambda(prompt_router) | ChatOpenAI() | StrOutputParser()
) print(chain.invoke({"query": "What's a black hole"}))
print(chain.invoke({"query": "What's a path integral"}))
In diesem Beispiel prompt_router
Die Funktion berechnet die Kosinusähnlichkeit zwischen Benutzereingaben und vordefinierten Eingabeaufforderungsvorlagen für Physik- und Mathematikfragen. Basierend auf dem Ähnlichkeitswert wählt die Kette dynamisch die relevanteste Eingabeaufforderungsvorlage aus und stellt so sicher, dass der Chatbot angemessen auf die Frage des Benutzers reagiert.
Verwendung von Agenten und Runnables
Mit LangChain können Sie Agenten erstellen, indem Sie Runnables, Eingabeaufforderungen, Modelle und Tools kombinieren. Hier ist ein Beispiel für die Erstellung und Verwendung eines Agenten:
from langchain.agents import XMLAgent, tool, AgentExecutor
from langchain.chat_models import ChatAnthropic model = ChatAnthropic(model="claude-2") @tool
def search(query: str) -> str: """Search things about current events.""" return "32 degrees" tool_list = [search] # Get prompt to use
prompt = XMLAgent.get_default_prompt() # Logic for going from intermediate steps to a string to pass into the model
def convert_intermediate_steps(intermediate_steps): log = "" for action, observation in intermediate_steps: log += ( f"<tool>{action.tool}</tool><tool_input>{action.tool_input}" f"</tool_input><observation>{observation}</observation>" ) return log # Logic for converting tools to a string to go in the prompt
def convert_tools(tools): return "n".join([f"{tool.name}: {tool.description}" for tool in tools]) agent = ( { "question": lambda x: x["question"], "intermediate_steps": lambda x: convert_intermediate_steps( x["intermediate_steps"] ), } | prompt.partial(tools=convert_tools(tool_list)) | model.bind(stop=["</tool_input>", "</final_answer>"]) | XMLAgent.get_default_output_parser()
) agent_executor = AgentExecutor(agent=agent, tools=tool_list, verbose=True) result = agent_executor.invoke({"question": "What's the weather in New York?"})
print(result)
In diesem Beispiel wird ein Agent durch die Kombination eines Modells, Tools, einer Eingabeaufforderung und einer benutzerdefinierten Logik für Zwischenschritte und Toolkonvertierung erstellt. Anschließend wird der Agent ausgeführt und gibt eine Antwort auf die Anfrage des Benutzers.
Abfragen einer SQL-Datenbank
Mit LangChain können Sie eine SQL-Datenbank abfragen und SQL-Abfragen basierend auf Benutzerfragen generieren. Hier ist ein Beispiel:
from langchain.prompts import ChatPromptTemplate template = """Based on the table schema below, write a SQL query that would answer the user's question:
{schema} Question: {question}
SQL Query:"""
prompt = ChatPromptTemplate.from_template(template) from langchain.utilities import SQLDatabase # Initialize the database (you'll need the Chinook sample DB for this example)
db = SQLDatabase.from_uri("sqlite:///./Chinook.db") def get_schema(_): return db.get_table_info() def run_query(query): return db.run(query) from langchain.chat_models import ChatOpenAI
from langchain.schema.output_parser import StrOutputParser
from langchain.schema.runnable import RunnablePassthrough model = ChatOpenAI() sql_response = ( RunnablePassthrough.assign(schema=get_schema) | prompt | model.bind(stop=["nSQLResult:"]) | StrOutputParser()
) result = sql_response.invoke({"question": "How many employees are there?"})
print(result) template = """Based on the table schema below, question, SQL query, and SQL response, write a natural language response:
{schema} Question: {question}
SQL Query: {query}
SQL Response: {response}"""
prompt_response = ChatPromptTemplate.from_template(template) full_chain = ( RunnablePassthrough.assign(query=sql_response) | RunnablePassthrough.assign( schema=get_schema, response=lambda x: db.run(x["query"]), ) | prompt_response | model
) response = full_chain.invoke({"question": "How many employees are there?"})
print(response)
In diesem Beispiel wird LangChain verwendet, um SQL-Abfragen basierend auf Benutzerfragen zu generieren und Antworten aus einer SQL-Datenbank abzurufen. Die Eingabeaufforderungen und Antworten sind so formatiert, dass sie Interaktionen in natürlicher Sprache mit der Datenbank ermöglichen.
Automatisieren Sie manuelle Aufgaben und Arbeitsabläufe mit unserem KI-gesteuerten Workflow-Builder, der von Nanonets für Sie und Ihre Teams entwickelt wurde.
LangServe & LangSmith
LangServe hilft Entwicklern bei der Bereitstellung von LangChain-Runables und -Ketten als REST-API. Diese Bibliothek ist in FastAPI integriert und verwendet Pydantic zur Datenvalidierung. Darüber hinaus bietet es einen Client, der zum Aufrufen von auf einem Server bereitgestellten Runnables verwendet werden kann, und in LangChainJS ist ein JavaScript-Client verfügbar.
Eigenschaften
- Eingabe- und Ausgabeschemata werden automatisch aus Ihrem LangChain-Objekt abgeleitet und bei jedem API-Aufruf mit umfangreichen Fehlermeldungen erzwungen.
- Eine API-Dokumentationsseite mit JSONSchema und Swagger ist verfügbar.
- Effiziente /invoke-, /batch- und /stream-Endpunkte mit Unterstützung für viele gleichzeitige Anforderungen auf einem einzelnen Server.
- /stream_log-Endpunkt zum Streamen aller (oder einiger) Zwischenschritte von Ihrer Kette/Ihrem Agenten.
- Playground-Seite unter /playground mit Streaming-Ausgabe und Zwischenschritten.
- Integrierte (optionale) Rückverfolgung nach LangSmith; Fügen Sie einfach Ihren API-Schlüssel hinzu (siehe Anweisungen).
- Alle wurden mit kampferprobten Open-Source-Python-Bibliotheken wie FastAPI, Pydantic, uvloop und asyncio erstellt.
Einschränkungen
- Client-Rückrufe werden für Ereignisse, die ihren Ursprung auf dem Server haben, noch nicht unterstützt.
- Bei Verwendung von Pydantic V2 werden keine OpenAPI-Dokumente generiert. FastAPI unterstützt das Mischen von pydantic v1- und v2-Namespaces nicht. Weitere Einzelheiten finden Sie im folgenden Abschnitt.
Verwenden Sie die LangChain-CLI, um ein LangServe-Projekt schnell zu booten. Um die langchain-CLI zu verwenden, stellen Sie sicher, dass Sie eine aktuelle Version von langchain-cli installiert haben. Sie können es mit pip install -U langchain-cli installieren.
langchain app new ../path/to/directory
Starten Sie Ihre LangServe-Instanz schnell mit LangChain-Vorlagen. Weitere Beispiele finden Sie im Vorlagenindex oder im Beispielverzeichnis.
Hier ist ein Server, der ein OpenAI-Chat-Modell, ein Anthropic-Chat-Modell und eine Kette bereitstellt, die das Anthropic-Modell verwendet, um einen Witz zu einem Thema zu erzählen.
#!/usr/bin/env python
from fastapi import FastAPI
from langchain.prompts import ChatPromptTemplate
from langchain.chat_models import ChatAnthropic, ChatOpenAI
from langserve import add_routes app = FastAPI( title="LangChain Server", version="1.0", description="A simple api server using Langchain's Runnable interfaces",
) add_routes( app, ChatOpenAI(), path="/openai",
) add_routes( app, ChatAnthropic(), path="/anthropic",
) model = ChatAnthropic()
prompt = ChatPromptTemplate.from_template("tell me a joke about {topic}")
add_routes( app, prompt | model, path="/chain",
) if __name__ == "__main__": import uvicorn uvicorn.run(app, host="localhost", port=8000)
Sobald Sie den oben genannten Server bereitgestellt haben, können Sie die generierten OpenAPI-Dokumente anzeigen, indem Sie Folgendes verwenden:
curl localhost:8000/docs
Stellen Sie sicher, dass Sie das Suffix /docs hinzufügen.
from langchain.schema import SystemMessage, HumanMessage
from langchain.prompts import ChatPromptTemplate
from langchain.schema.runnable import RunnableMap
from langserve import RemoteRunnable openai = RemoteRunnable("http://localhost:8000/openai/")
anthropic = RemoteRunnable("http://localhost:8000/anthropic/")
joke_chain = RemoteRunnable("http://localhost:8000/chain/") joke_chain.invoke({"topic": "parrots"}) # or async
await joke_chain.ainvoke({"topic": "parrots"}) prompt = [ SystemMessage(content='Act like either a cat or a parrot.'), HumanMessage(content='Hello!')
] # Supports astream
async for msg in anthropic.astream(prompt): print(msg, end="", flush=True) prompt = ChatPromptTemplate.from_messages( [("system", "Tell me a long story about {topic}")]
) # Can define custom chains
chain = prompt | RunnableMap({ "openai": openai, "anthropic": anthropic,
}) chain.batch([{ "topic": "parrots" }, { "topic": "cats" }])
In TypeScript (erfordert LangChain.js Version 0.0.166 oder höher):
import { RemoteRunnable } from "langchain/runnables/remote"; const chain = new RemoteRunnable({ url: `http://localhost:8000/chain/invoke/`,
});
const result = await chain.invoke({ topic: "cats",
});
Python verwendet Anfragen:
import requests
response = requests.post( "http://localhost:8000/chain/invoke/", json={'input': {'topic': 'cats'}}
)
response.json()
Sie können auch Curl verwenden:
curl --location --request POST 'http://localhost:8000/chain/invoke/' --header 'Content-Type: application/json' --data-raw '{ "input": { "topic": "cats" } }'
Der folgende Code:
...
add_routes( app, runnable, path="/my_runnable",
)
Fügt diese Endpunkte zum Server hinzu:
- POST /my_runnable/invoke – Rufen Sie das Runnable für eine einzelne Eingabe auf
- POST /my_runnable/batch – Rufen Sie das Runnable für einen Batch von Eingaben auf
- POST /my_runnable/stream – Aufruf für eine einzelne Eingabe und Streamen der Ausgabe
- POST /my_runnable/stream_log – Aufruf für eine einzelne Eingabe und Streamen der Ausgabe, einschließlich der Ausgabe von Zwischenschritten bei deren Generierung
- GET /my_runnable/input_schema – JSON-Schema für die Eingabe in das Runnable
- GET /my_runnable/output_schema – JSON-Schema für die Ausgabe des Runnable
- GET /my_runnable/config_schema – JSON-Schema für die Konfiguration des Runnable
Eine Playground-Seite für Ihr Runnable finden Sie unter /my_runnable/playground. Dadurch wird eine einfache Benutzeroberfläche zum Konfigurieren und Aufrufen Ihrer ausführbaren Datei mit Streaming-Ausgabe und Zwischenschritten bereitgestellt.
Für Client und Server:
pip install "langserve[all]"
oder pip install „langserve[client]“ für Clientcode und pip install „langserve[server]“ für Servercode.
Wenn Sie Ihrem Server eine Authentifizierung hinzufügen müssen, lesen Sie bitte die Sicherheitsdokumentation und Middleware-Dokumentation von FastAPI.
Sie können die Bereitstellung auf GCP Cloud Run mit dem folgenden Befehl durchführen:
gcloud run deploy [your-service-name] --source . --port 8001 --allow-unauthenticated --region us-central1 --set-env-vars=OPENAI_API_KEY=your_key
LangServe bietet mit einigen Einschränkungen Unterstützung für Pydantic 2. Bei Verwendung von Pydantic V2 werden keine OpenAPI-Dokumente für invoke/batch/stream/stream_log generiert. Die Fast API unterstützt das Mischen von pydantic v1- und v2-Namespaces nicht. LangChain verwendet den v1-Namespace in Pydantic v2. Bitte lesen Sie die folgenden Richtlinien, um die Kompatibilität mit LangChain sicherzustellen. Abgesehen von diesen Einschränkungen gehen wir davon aus, dass die API-Endpunkte, der Spielplatz und alle anderen Funktionen wie erwartet funktionieren.
LLM-Anwendungen arbeiten oft mit Dateien. Es gibt verschiedene Architekturen, die zur Implementierung der Dateiverarbeitung erstellt werden können. auf hohem Niveau:
- Die Datei kann über einen dedizierten Endpunkt auf den Server hochgeladen und über einen separaten Endpunkt verarbeitet werden.
- Die Datei kann entweder über einen Wert (Bytes der Datei) oder eine Referenz (z. B. S3-URL zum Dateiinhalt) hochgeladen werden.
- Der Verarbeitungsendpunkt kann blockierend oder nicht blockierend sein.
- Wenn eine erhebliche Verarbeitung erforderlich ist, kann die Verarbeitung in einen dedizierten Prozesspool ausgelagert werden.
Sie sollten bestimmen, welche Architektur für Ihre Anwendung geeignet ist. Um Dateien nach Wert in eine ausführbare Datei hochzuladen, verwenden Sie derzeit die Base64-Codierung für die Datei (multipart/form-data wird noch nicht unterstützt).
Hier ist ein Beispiel Hier wird gezeigt, wie mithilfe der Base64-Codierung eine Datei an ein Remote-Ausführungsobjekt gesendet wird. Denken Sie daran, dass Sie Dateien jederzeit per Referenz (z. B. S3-URL) oder als Multipart-/Formulardaten auf einen dedizierten Endpunkt hochladen können.
Eingabe- und Ausgabetypen werden auf allen Runnables definiert. Sie können über die Eigenschaften „input_schema“ und „output_schema“ darauf zugreifen. LangServe verwendet diese Typen zur Validierung und Dokumentation. Wenn Sie die standardmäßig abgeleiteten Typen überschreiben möchten, können Sie die Methode with_types verwenden.
Hier ist ein Spielzeugbeispiel, um die Idee zu veranschaulichen:
from typing import Any
from fastapi import FastAPI
from langchain.schema.runnable import RunnableLambda app = FastAPI() def func(x: Any) -> int: """Mistyped function that should accept an int but accepts anything.""" return x + 1 runnable = RunnableLambda(func).with_types( input_schema=int,
) add_routes(app, runnable)
Erben Sie von CustomUserType, wenn Sie möchten, dass die Daten in ein pydantisches Modell und nicht in die entsprechende Diktdarstellung deserialisiert werden. Dieser Typ funktioniert derzeit nur serverseitig und dient der Festlegung des gewünschten Dekodierungsverhaltens. Wenn von diesem Typ geerbt wird, behält der Server den dekodierten Typ als pydantisches Modell bei, anstatt ihn in ein Diktat umzuwandeln.
from fastapi import FastAPI
from langchain.schema.runnable import RunnableLambda
from langserve import add_routes
from langserve.schema import CustomUserType app = FastAPI() class Foo(CustomUserType): bar: int def func(foo: Foo) -> int: """Sample function that expects a Foo type which is a pydantic model""" assert isinstance(foo, Foo) return foo.bar add_routes(app, RunnableLambda(func), path="/foo")
Auf dem Spielplatz können Sie vom Backend aus benutzerdefinierte Widgets für Ihr Runable definieren. Ein Widget wird auf Feldebene angegeben und als Teil des JSON-Schemas des Eingabetyps geliefert. Ein Widget muss einen Schlüssel namens „type“ enthalten, dessen Wert einer aus einer bekannten Liste von Widgets ist. Andere Widget-Schlüssel werden Werten zugeordnet, die Pfade in einem JSON-Objekt beschreiben.
Allgemeines Schema:
type JsonPath = number | string | (number | string)[];
type NameSpacedPath = { title: string; path: JsonPath }; // Using title to mimic json schema, but can use namespace
type OneOfPath = { oneOf: JsonPath[] }; type Widget = { type: string // Some well-known type (e.g., base64file, chat, etc.) [key: string]: JsonPath | NameSpacedPath | OneOfPath;
};
Ermöglicht die Erstellung einer Datei-Upload-Eingabe im UI-Playground für Dateien, die als Base64-codierte Zeichenfolgen hochgeladen werden. Hier ist das vollständige Beispiel.
try: from pydantic.v1 import Field
except ImportError: from pydantic import Field from langserve import CustomUserType # ATTENTION: Inherit from CustomUserType instead of BaseModel otherwise
# the server will decode it into a dict instead of a pydantic model.
class FileProcessingRequest(CustomUserType): """Request including a base64 encoded file.""" # The extra field is used to specify a widget for the playground UI. file: str = Field(..., extra={"widget": {"type": "base64file"}}) num_chars: int = 100
Automatisieren Sie manuelle Aufgaben und Arbeitsabläufe mit unserem KI-gesteuerten Workflow-Builder, der von Nanonets für Sie und Ihre Teams entwickelt wurde.
Einführung in LangSmith
Mit LangChain können Sie ganz einfach Prototypen für LLM-Anwendungen und -Agenten erstellen. Die Bereitstellung von LLM-Anwendungen in der Produktion kann jedoch trügerisch schwierig sein. Sie müssen Ihre Eingabeaufforderungen, Ketten und andere Komponenten wahrscheinlich stark anpassen und iterieren, um ein qualitativ hochwertiges Produkt zu erstellen.
Um diesen Prozess zu unterstützen, wurde LangSmith eingeführt, eine einheitliche Plattform zum Debuggen, Testen und Überwachen Ihrer LLM-Anwendungen.
Wann könnte sich das als nützlich erweisen? Sie können es nützlich finden, wenn Sie schnell eine neue Kette, einen neuen Agenten oder einen Satz von Tools debuggen, visualisieren möchten, wie Komponenten (Ketten, LMs, Retriever usw.) zusammenhängen und verwendet werden, verschiedene Eingabeaufforderungen und LLMs für eine einzelne Komponente bewerten möchten, Führen Sie eine bestimmte Kette mehrmals über einen Datensatz aus, um sicherzustellen, dass er konsistent eine Qualitätsvorgabe erfüllt, oder erfassen Sie Nutzungsspuren und nutzen Sie LLMs oder Analysepipelines, um Erkenntnisse zu generieren.
Voraussetzungen:
- Erstellen Sie ein LangSmith-Konto und erstellen Sie einen API-Schlüssel (siehe untere linke Ecke).
- Machen Sie sich mit der Plattform vertraut, indem Sie die Dokumente durchsehen.
Jetzt fangen wir an!
Konfigurieren Sie zunächst Ihre Umgebungsvariablen, um LangChain anzuweisen, Spuren zu protokollieren. Dies geschieht durch Setzen der Umgebungsvariablen LANGCHAIN_TRACING_V2 auf true. Sie können LangChain mitteilen, bei welchem Projekt protokolliert werden soll, indem Sie die Umgebungsvariable LANGCHAIN_PROJECT festlegen (wenn diese nicht festgelegt ist, werden Ausführungen im Standardprojekt protokolliert). Dadurch wird das Projekt automatisch für Sie erstellt, falls es nicht vorhanden ist. Sie müssen außerdem die Umgebungsvariablen LANGCHAIN_ENDPOINT und LANGCHAIN_API_KEY festlegen.
HINWEIS: Sie können auch einen Kontextmanager in Python verwenden, um Ablaufverfolgungen zu protokollieren, indem Sie Folgendes verwenden:
from langchain.callbacks.manager import tracing_v2_enabled with tracing_v2_enabled(project_name="My Project"): agent.run("How many people live in canada as of 2023?")
In diesem Beispiel werden wir jedoch Umgebungsvariablen verwenden.
%pip install openai tiktoken pandas duckduckgo-search --quiet import os
from uuid import uuid4 unique_id = uuid4().hex[0:8]
os.environ["LANGCHAIN_TRACING_V2"] = "true"
os.environ["LANGCHAIN_PROJECT"] = f"Tracing Walkthrough - {unique_id}"
os.environ["LANGCHAIN_ENDPOINT"] = "https://api.smith.langchain.com"
os.environ["LANGCHAIN_API_KEY"] = "<YOUR-API-KEY>" # Update to your API key # Used by the agent in this tutorial
os.environ["OPENAI_API_KEY"] = "<YOUR-OPENAI-API-KEY>"
Erstellen Sie den LangSmith-Client für die Interaktion mit der API:
from langsmith import Client client = Client()
Erstellen Sie eine LangChain-Komponente und protokollieren Sie Ausführungen auf der Plattform. In diesem Beispiel erstellen wir einen Agenten im ReAct-Stil mit Zugriff auf ein allgemeines Suchtool (DuckDuckGo). Die Aufforderung des Agenten kann hier im Hub eingesehen werden:
from langchain import hub
from langchain.agents import AgentExecutor
from langchain.agents.format_scratchpad import format_to_openai_function_messages
from langchain.agents.output_parsers import OpenAIFunctionsAgentOutputParser
from langchain.chat_models import ChatOpenAI
from langchain.tools import DuckDuckGoSearchResults
from langchain.tools.render import format_tool_to_openai_function # Fetches the latest version of this prompt
prompt = hub.pull("wfh/langsmith-agent-prompt:latest") llm = ChatOpenAI( model="gpt-3.5-turbo-16k", temperature=0,
) tools = [ DuckDuckGoSearchResults( name="duck_duck_go" ), # General internet search using DuckDuckGo
] llm_with_tools = llm.bind(functions=[format_tool_to_openai_function(t) for t in tools]) runnable_agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai_function_messages( x["intermediate_steps"] ), } | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser()
) agent_executor = AgentExecutor( agent=runnable_agent, tools=tools, handle_parsing_errors=True
)
Wir führen den Agenten gleichzeitig auf mehreren Eingaben aus, um die Latenz zu reduzieren. Ausführungen werden im Hintergrund bei LangSmith protokolliert, sodass die Ausführungslatenz davon nicht betroffen ist:
inputs = [ "What is LangChain?", "What's LangSmith?", "When was Llama-v2 released?", "What is the langsmith cookbook?", "When did langchain first announce the hub?",
] results = agent_executor.batch([{"input": x} for x in inputs], return_exceptions=True) results[:2]
Vorausgesetzt, Sie haben Ihre Umgebung erfolgreich eingerichtet, sollten Ihre Agent-Traces im Abschnitt „Projekte“ der App angezeigt werden. Glückwunsch!
Es sieht jedoch so aus, als ob der Agent die Tools nicht effektiv nutzt. Lassen Sie uns dies auswerten, damit wir eine Ausgangslage haben.
Neben der Protokollierung von Läufen ermöglicht Ihnen LangSmith auch das Testen und Bewerten Ihrer LLM-Anwendungen.
In diesem Abschnitt nutzen Sie LangSmith, um einen Benchmark-Datensatz zu erstellen und KI-gestützte Evaluatoren für einen Agenten auszuführen. Sie werden dies in wenigen Schritten tun:
- Erstellen Sie einen LangSmith-Datensatz:
Im Folgenden verwenden wir den LangSmith-Client, um einen Datensatz aus den Eingabefragen von oben und einer Liste mit Beschriftungen zu erstellen. Sie werden diese später verwenden, um die Leistung eines neuen Agenten zu messen. Ein Datensatz ist eine Sammlung von Beispielen, bei denen es sich lediglich um Eingabe-Ausgabe-Paare handelt, die Sie als Testfälle für Ihre Anwendung verwenden können:
outputs = [ "LangChain is an open-source framework for building applications using large language models. It is also the name of the company building LangSmith.", "LangSmith is a unified platform for debugging, testing, and monitoring language model applications and agents powered by LangChain", "July 18, 2023", "The langsmith cookbook is a github repository containing detailed examples of how to use LangSmith to debug, evaluate, and monitor large language model-powered applications.", "September 5, 2023",
] dataset_name = f"agent-qa-{unique_id}" dataset = client.create_dataset( dataset_name, description="An example dataset of questions over the LangSmith documentation.",
) for query, answer in zip(inputs, outputs): client.create_example( inputs={"input": query}, outputs={"output": answer}, dataset_id=dataset.id )
- Initialisieren Sie einen neuen Agenten zum Benchmarking:
Mit LangSmith können Sie jedes LLM, jede Kette, jeden Agenten oder sogar eine benutzerdefinierte Funktion evaluieren. Konversationsagenten sind zustandsbehaftet (sie haben ein Gedächtnis); Um sicherzustellen, dass dieser Status nicht zwischen Datensatzläufen geteilt wird, übergeben wir eine chain_factory (
(auch bekannt als Konstruktor)-Funktion, die für jeden Aufruf initialisiert wird:
# Since chains can be stateful (e.g. they can have memory), we provide
# a way to initialize a new chain for each row in the dataset. This is done
# by passing in a factory function that returns a new chain for each row.
def agent_factory(prompt): llm_with_tools = llm.bind( functions=[format_tool_to_openai_function(t) for t in tools] ) runnable_agent = ( { "input": lambda x: x["input"], "agent_scratchpad": lambda x: format_to_openai_function_messages( x["intermediate_steps"] ), } | prompt | llm_with_tools | OpenAIFunctionsAgentOutputParser() ) return AgentExecutor(agent=runnable_agent, tools=tools, handle_parsing_errors=True)
- Auswertung konfigurieren:
Der manuelle Vergleich der Ergebnisse von Ketten in der Benutzeroberfläche ist effektiv, kann jedoch zeitaufwändig sein. Es kann hilfreich sein, automatisierte Metriken und KI-gestütztes Feedback zu verwenden, um die Leistung Ihrer Komponente zu bewerten:
from langchain.evaluation import EvaluatorType
from langchain.smith import RunEvalConfig evaluation_config = RunEvalConfig( evaluators=[ EvaluatorType.QA, EvaluatorType.EMBEDDING_DISTANCE, RunEvalConfig.LabeledCriteria("helpfulness"), RunEvalConfig.LabeledScoreString( { "accuracy": """
Score 1: The answer is completely unrelated to the reference.
Score 3: The answer has minor relevance but does not align with the reference.
Score 5: The answer has moderate relevance but contains inaccuracies.
Score 7: The answer aligns with the reference but has minor errors or omissions.
Score 10: The answer is completely accurate and aligns perfectly with the reference.""" }, normalize_by=10, ), ], custom_evaluators=[],
)
- Führen Sie den Agenten und die Evaluatoren aus:
Verwenden Sie die Funktion run_on_dataset (oder die asynchrone Funktion arun_on_dataset), um Ihr Modell auszuwerten. Dieser Wille:
- Rufen Sie Beispielzeilen aus dem angegebenen Datensatz ab.
- Führen Sie Ihren Agenten (oder eine beliebige benutzerdefinierte Funktion) für jedes Beispiel aus.
- Wenden Sie Evaluatoren auf die resultierenden Laufspuren und entsprechenden Referenzbeispiele an, um automatisiertes Feedback zu generieren.
Die Ergebnisse werden in der LangSmith-App sichtbar:
chain_results = run_on_dataset( dataset_name=dataset_name, llm_or_chain_factory=functools.partial(agent_factory, prompt=prompt), evaluation=evaluation_config, verbose=True, client=client, project_name=f"runnable-agent-test-5d466cbc-{unique_id}", tags=[ "testing-notebook", "prompt:5d466cbc", ],
)
Nachdem wir nun die Ergebnisse unseres Testlaufs haben, können wir Änderungen an unserem Agenten vornehmen und ihn einem Benchmarking unterziehen. Versuchen wir es noch einmal mit einer anderen Eingabeaufforderung und sehen uns die Ergebnisse an:
candidate_prompt = hub.pull("wfh/langsmith-agent-prompt:39f3bbd0") chain_results = run_on_dataset( dataset_name=dataset_name, llm_or_chain_factory=functools.partial(agent_factory, prompt=candidate_prompt), evaluation=evaluation_config, verbose=True, client=client, project_name=f"runnable-agent-test-39f3bbd0-{unique_id}", tags=[ "testing-notebook", "prompt:39f3bbd0", ],
)
Mit LangSmith können Sie Daten direkt in der Web-App in gängige Formate wie CSV oder JSONL exportieren. Sie können den Client auch verwenden, um Läufe zur weiteren Analyse abzurufen, in Ihrer eigenen Datenbank zu speichern oder mit anderen zu teilen. Rufen wir die Laufspuren des Evaluierungslaufs ab:
runs = client.list_runs(project_name=chain_results["project_name"], execution_order=1) # After some time, these will be populated.
client.read_project(project_name=chain_results["project_name"]).feedback_stats
Dies war eine Kurzanleitung für den Einstieg, aber es gibt noch viele weitere Möglichkeiten, LangSmith zu nutzen, um Ihren Entwicklerfluss zu beschleunigen und bessere Ergebnisse zu erzielen.
Weitere Informationen dazu, wie Sie LangSmith optimal nutzen können, finden Sie in der LangSmith-Dokumentation.
Steigen Sie mit Nanonets auf
Während LangChain ein wertvolles Tool für die Integration von Sprachmodellen (LLMs) in Ihre Anwendungen ist, kann es bei Unternehmensanwendungsfällen auf Einschränkungen stoßen. Lassen Sie uns untersuchen, wie Nanonets über LangChain hinausgeht, um diese Herausforderungen zu bewältigen:
1. Umfassende Datenkonnektivität:
LangChain bietet Konnektoren, deckt jedoch möglicherweise nicht alle Workspace-Apps und Datenformate ab, auf die Unternehmen angewiesen sind. Nanonets bietet Datenkonnektoren für über 100 weit verbreitete Workspace-Apps, darunter Slack, Notion, Google Suite, Salesforce, Zendesk und viele mehr. Es unterstützt außerdem alle unstrukturierten Datentypen wie PDFs, TXTs, Bilder, Audiodateien und Videodateien sowie strukturierte Datentypen wie CSVs, Tabellenkalkulationen, MongoDB und SQL-Datenbanken.
2. Aufgabenautomatisierung für Workspace-Apps:
Während die Text-/Antwortgenerierung hervorragend funktioniert, sind die Fähigkeiten von LangChain begrenzt, wenn es darum geht, natürliche Sprache zur Ausführung von Aufgaben in verschiedenen Anwendungen zu verwenden. Nanonets bietet Trigger-/Aktionsagenten für die gängigsten Workspace-Apps und ermöglicht Ihnen die Einrichtung von Workflows, die auf Ereignisse warten und Aktionen ausführen. Sie können beispielsweise E-Mail-Antworten, CRM-Einträge, SQL-Abfragen und mehr automatisieren, alles über Befehle in natürlicher Sprache.
3. Echtzeit-Datensynchronisierung:
LangChain ruft statische Daten mit Datenkonnektoren ab, die möglicherweise nicht mit Datenänderungen in der Quelldatenbank Schritt halten. Im Gegensatz dazu sorgt Nanonets für die Echtzeitsynchronisierung mit Datenquellen und stellt so sicher, dass Sie immer mit den neuesten Informationen arbeiten.
3. Vereinfachte Konfiguration:
Das Konfigurieren der Elemente der LangChain-Pipeline, wie etwa Retriever und Synthesizer, kann ein komplexer und zeitaufwändiger Prozess sein. Nanonets rationalisiert dies, indem es für jeden Datentyp eine optimierte Datenaufnahme und -indizierung bereitstellt, die alles im Hintergrund vom AI Assistant durchgeführt wird. Dies reduziert den Aufwand für die Feinabstimmung und erleichtert die Einrichtung und Verwendung.
4. Einheitliche Lösung:
Im Gegensatz zu LangChain, das möglicherweise für jede Aufgabe einzigartige Implementierungen erfordert, dient Nanonets als Komplettlösung für die Verbindung Ihrer Daten mit LLMs. Ganz gleich, ob Sie LLM-Anwendungen oder KI-Workflows erstellen müssen, Nanonets bietet eine einheitliche Plattform für Ihre vielfältigen Anforderungen.
Nanonets KI-Workflows
Nanonets Workflows ist ein sicherer, vielseitiger KI-Assistent, der die Integration Ihres Wissens und Ihrer Daten in LLMs vereinfacht und die Erstellung von No-Code-Anwendungen und Workflows erleichtert. Es bietet eine benutzerfreundliche Benutzeroberfläche und macht es sowohl für Einzelpersonen als auch für Organisationen zugänglich.
Um zu beginnen, können Sie einen Anruf mit einem unserer KI-Experten vereinbaren, der Ihnen eine personalisierte Demo und Testversion der Nanonets-Workflows anbieten kann, die auf Ihren spezifischen Anwendungsfall zugeschnitten ist.
Nach der Einrichtung können Sie mithilfe natürlicher Sprache komplexe Anwendungen und Arbeitsabläufe auf Basis von LLMs entwerfen und ausführen und sich dabei nahtlos in Ihre Anwendungen und Daten integrieren.
Stärken Sie Ihre Teams mit der KI von Nanonets, um Apps zu erstellen und Ihre Daten in KI-gesteuerte Anwendungen und Arbeitsabläufe zu integrieren, damit sich Ihre Teams auf das konzentrieren können, was wirklich wichtig ist.
Automatisieren Sie manuelle Aufgaben und Arbeitsabläufe mit unserem KI-gesteuerten Workflow-Builder, der von Nanonets für Sie und Ihre Teams entwickelt wurde.
- SEO-gestützte Content- und PR-Distribution. Holen Sie sich noch heute Verstärkung.
- PlatoData.Network Vertikale generative KI. Motiviere dich selbst. Hier zugreifen.
- PlatoAiStream. Web3-Intelligenz. Wissen verstärkt. Hier zugreifen.
- PlatoESG. Kohlenstoff, CleanTech, Energie, Umwelt, Solar, Abfallwirtschaft. Hier zugreifen.
- PlatoHealth. Informationen zu Biotechnologie und klinischen Studien. Hier zugreifen.
- Quelle: https://nanonets.com/blog/langchain/
- :hast
- :Ist
- :nicht
- :Wo
- $UP
- 1
- 10
- 100
- 114
- 13
- 15%
- 2000
- 2012
- 2023
- 25
- 30
- 32
- 36
- 40
- 400
- 408
- 50
- 500
- 7
- 8
- a
- ABC
- Fähigkeit
- Fähig
- LiveBuzz
- darüber
- oben
- Akzeptieren
- Akzeptiert
- Zugang
- zugänglich
- Zugriff
- erreichen
- entsprechend
- Konto
- Genauigkeit
- genau
- genau
- Erreichen
- erreicht
- Erreicht
- über
- Handlung
- Action
- Aktionen
- aktiv
- sich anpassen
- adaptiv
- hinzufügen
- hinzugefügt
- Hinzufügen
- Zusatz
- Zusätzliche
- zusätzlich
- Adresse
- Fügt
- eingestehen
- advanced
- Abenteuer
- Nach der
- aufs Neue
- Alter
- Makler
- Agenten
- AI
- AI-Assistent
- KI-Modelle
- Hilfe
- Anvisieren
- Algorithmen
- ausrichten
- Richtet sich aus
- Alle
- erlauben
- Zulassen
- erlaubt
- allein
- entlang
- neben
- bereits
- ebenfalls
- Obwohl
- immer
- an
- Analyse
- Analytische
- Analytik
- und
- Angeles
- Bekannt geben
- jährlich
- Ein anderer
- beantworten
- Antworten
- Hymne
- Anthropisch
- jedem
- etwas
- Bienen
- API-SCHLÜSSEL
- APIs
- App
- anwendbar
- Anwendung
- Anwendungsentwicklung
- Anwendungen
- angewandt
- gilt
- Ansatz
- Ansätze
- angemessen
- passend
- Apps
- Architektur
- SIND
- Argument
- Argumente
- Armstrong
- um
- Feld
- Künstler
- AS
- fragen
- Aussehen
- Aspekte
- helfen
- Assistentin
- damit verbundenen
- At
- anhängen
- Aufmerksamkeit
- Audio-
- Augmented
- Authentifizierung
- automatisieren
- Automatisiert
- Automatisches Erfassen:
- Im Prinzip so, wie Sie es von Google Maps kennen.
- Automation
- verfügbar
- durchschnittlich
- – warten auf Sie!
- bewusst
- AWS
- Zurück
- Backbone (Rückgrat)
- Backend
- Hintergrund
- schlecht
- Balance
- Bar
- Base
- basierend
- Baseline
- bash
- basic
- Grundlagen
- BCG
- BE
- Beach
- Bären
- weil
- war
- Bevor
- beginnen
- Verhalten
- hinter
- hinter den Kulissen
- Sein
- unten
- Benchmark
- vorteilhaft
- BESTE
- Besser
- zwischen
- Beyond
- Größte
- Bill
- Bill Gates
- binden
- Bing
- Bit
- Schwarz
- Schwarzes Loch
- Blockieren
- Sperrung
- Blockiert
- Blog
- Getreide
- Bootstrap
- geboren
- Wander- und Outdoorschuhen
- beide
- Boden
- Filiale
- Break
- Brise
- kurz
- breiteres
- braun
- Browser
- puffern
- bauen
- Baumeister
- Building
- erbaut
- Last
- Unternehmen
- aber
- by
- Berechnen
- berechnet
- Berechnung
- Berechnung
- rufen Sie uns an!
- Rückrufe
- namens
- Aufruf
- Aufrufe
- CAN
- Kann bekommen
- Kanada
- Fähigkeiten
- fähig
- Kapazität
- Erfassung
- Capturing
- Häuser
- Fälle
- CAT
- sorgen
- Catering
- Kümmert sich
- Katzen
- Vorsicht
- vorsichtig
- zentriert
- sicher
- Kette
- Ketten
- Herausforderungen
- Änderungen
- Charakter
- Chatbot
- Chatbots
- aus der Ferne überprüfen
- Schecks
- Auswählen
- gewählt
- Umstände
- Stadt
- Klasse
- Unterricht
- Auftraggeber
- Cloud
- Code
- Programmierung
- Kaffee
- KOHÄRENT
- zusammenhängend
- zusammenarbeiten
- Zusammenbruch
- Sammlung
- bunt
- Kolonne
- Spalten
- COM
- kombinieren
- kombiniert
- vereint
- Vereinigung
- wie die
- kommt
- komfortabel
- gemeinsam
- Kommunikation
- Unternehmen
- vergleichen
- Vergleich
- Kompatibilität
- kompatibel
- abschließen
- uneingeschränkt
- Abschluss
- Komplex
- Komplexität
- Komponente
- Komponenten
- zusammengesetzt
- Zusammensetzung
- umfassend
- umfassend
- konzept
- prägnant
- Wettbewerber
- Zustand
- Konfiguration
- Zusammenfluss
- Vernetz Dich
- Sich zusammenschliessen
- Konnektivität
- Nachteile
- Geht davon
- konsequent
- besteht
- Konsul (Console)
- ständig
- Konstrukte
- enthalten
- enthält
- Inhalt
- Kontext
- Kontexte
- kontextuelle
- fortsetzen
- ständig
- Kontrast
- Smartgeräte App
- Steuerung
- Praktische
- Gespräch
- Konversations
- Konversations-KI
- Gespräche
- Umwandlung (Conversion)
- umgewandelt
- Umwandlung
- Kernbereich
- Ecke
- und beseitigen Muskelschwäche
- Dazugehörigen
- könnte
- Zählen
- Land
- Paar
- Abdeckung
- bedeckt
- erstellen
- erstellt
- schafft
- Erstellen
- Schaffung
- Referenzen
- Kriterien
- Kritiker
- CRM
- wichtig
- Strom
- Zur Zeit
- Original
- Kunden
- Anpassung
- anpassen
- maßgeschneiderte
- innovativ, auf dem neuesten Stand
- technische Daten
- Datenstruktur
- Datenbase
- Datenbanken
- Datum
- datetime
- Deal
- Behandlung
- Dezember
- entscheidet
- Entscheiden
- Decision Making
- Decoding
- gewidmet
- tiefer
- Standard
- definieren
- definiert
- Definition
- Definitionen
- liefern
- liefert
- vertiefen
- Demo
- zeigen
- Synergie
- demonstrieren
- abhängen
- Abhängig
- hängt
- einsetzen
- Einsatz
- Bereitstellen
- Einsatz
- setzt ein
- beschreiben
- Beschreibung
- Design
- bezeichnet
- entworfen
- erwünscht
- Detail
- detailliert
- Details
- Bestimmen
- entschlossen
- entwickeln
- Entwickler:in / Unternehmen
- Entwickler
- Entwicklung
- Entwicklung
- Diagramme
- DICT
- DID
- abweichen
- anders
- anders
- schwer
- Abmessungen
- Größe
- Richtlinien
- Direkt
- diskutieren
- diskutiert
- Anzeige
- deutlich
- tauchen
- verschieden
- DM
- do
- Dokument
- Dokumentation
- Unterlagen
- die
- doesn
- Dabei
- Don
- erledigt
- doppelt
- nach unten
- herunterladen
- Downloads
- Lüftung
- Antrieb
- zwei
- im
- dynamisch
- dynamisch
- e
- jeder
- Früher
- Früh
- erleichtern
- Benutzerfreundlichkeit
- einfacher
- leicht
- Einfache
- einfach zu bedienende
- Echo
- Ökosystem
- Effektiv
- effektiv
- Effizienz
- effizient
- effizient
- mühelos
- entweder
- Element
- Elemente
- Elon
- Elon Musk
- sonst
- einbetten
- eingebettet
- Einbettung
- beschäftigt
- Mitarbeiter
- beschäftigt
- ermächtigen
- ermöglichen
- ermöglicht
- ermöglichen
- kapselt
- Begegnung
- End-to-End
- Endpunkt
- Eingriff
- Motor
- Motor (en)
- England
- Englisch
- Englisch Premier League
- zu steigern,
- verbesserte
- Eine Verbesserung der
- gewährleisten
- sorgt
- Gewährleistung
- Unternehmen
- Entitäten
- Einheit
- Arbeitsumfeld
- Umgebungen
- Äquivalent
- Era
- Fehler
- Fehler
- insbesondere
- essential
- entfremdet
- etc
- bewerten
- Auswertung
- Sogar
- Veranstaltungen
- Jedes
- Beispiel
- Beispiele
- überschreiten
- Außer
- ausführen
- ausgeführt
- Führt aus
- Ausführung
- Ausführung
- beispielhaft
- Training
- existieren
- erwarten
- Erwartungen
- erwartet
- erwartet
- ERFAHRUNGEN
- experimentell
- Experten
- erklärt
- Erklärt
- explizit
- Exploration
- ERKUNDEN
- Erkundet
- exportieren
- Ausdruck
- erweitern
- Verlängerung
- umfangreiche
- extern
- extra
- Extrakt
- Extraktion
- KONZENTRAT
- Gesicht
- erleichtern
- erleichtert
- Fabrik
- Fakten
- weit
- FAST
- Favorit
- Merkmal
- Eigenschaften
- Feedback
- wenige
- Feld
- Felder
- Figur
- Abbildung
- Reichen Sie das
- Mappen
- füllen
- gefüllt
- Füllung
- Filter
- Filterung
- Finale
- Endlich
- Finden Sie
- Suche nach
- Vorname
- fünf
- Flexibilität
- flexibel
- Fluss
- Setzen Sie mit Achtsamkeit
- konzentriert
- konzentriert
- Fokussierung
- folgen
- Folgende
- folgt
- Nahrung,
- Aussichten für
- unten stehende Formular
- Format
- gebildet
- Zum Glück
- gefunden
- Unser Ansatz
- Gerüste
- häufig
- Freund
- Freunde
- für
- voller
- vollwertig
- Funktion
- Funktionsumfang
- Funktionalität
- Funktionen
- fundamental
- komisch
- weiter
- Zukunft
- Gewinnen
- Games
- Gates
- Allgemeines
- allgemein
- erzeugen
- erzeugt
- erzeugt
- Erzeugung
- Generation
- Geschlecht
- Deutschland
- bekommen
- bekommen
- gif
- GitHub
- gegeben
- GMT
- Go
- Goes
- gehen
- gut
- körnig
- Graph
- groß
- mehr
- die Vermittlung von Kompetenzen,
- Guide
- Richtlinien
- hackathon
- Griff
- Griffe
- Handling
- praktisch
- hart
- schaden
- Gurte
- Haben
- mit
- schwer
- Statt
- Hilfe
- hilfreich
- hilft
- hier (auf dänisch)
- hier
- hi
- GUTE
- High-Level
- hochwertige
- höchste
- hoch
- historisch
- Geschichte
- Loch
- Haube
- Gastgeber
- Ultraschall
- Hilfe
- aber
- HTML
- http
- HTTPS
- Nabe
- human
- hunderte
- i
- ID
- Idee
- ideal
- ids
- if
- ii
- iii
- veranschaulichen
- zeigt
- Bilder
- unmittelbar
- implementieren
- Implementierung
- Realisierungen
- umgesetzt
- importieren
- Verbesserungen
- Verbesserung
- in
- eingehende
- das
- inklusive
- Dazu gehören
- Einschließlich
- integrieren
- einarbeiten
- unglaublich
- Index
- Indizes
- zeigen
- zeigt
- Individuell
- Einzelpersonen
- Information
- Anfangs-
- initiieren
- innovativ
- Varianten des Eingangssignals:
- Eingänge
- Einblicke
- installieren
- installiert
- Installieren
- Instanz
- sofortig
- beantragen müssen
- Anleitung
- Integral
- integrieren
- integriert
- Integriert
- Integration
- Integration
- Integrationen
- Intelligent
- beabsichtigt
- interagieren
- Interaktion
- Interaktionen
- interaktive
- interagiert
- Schnittstelle
- Schnittstellen
- innen
- Internet
- in
- eingeführt
- Stellt vor
- intuitiv
- Beteiligung
- isn
- Problem
- Probleme
- IT
- Artikel
- Iterationen
- SEINE
- selbst
- Jackson
- JavaScript
- Job
- Jordanien
- Reise
- JSON
- Juli
- nur
- Justiz
- Behalten
- hält
- Wesentliche
- Tasten
- Art
- Wissen
- Wissen
- Wissen Graph
- bekannt
- Label
- Etiketten
- Land
- Sprache
- Sprachen
- grosse
- größer
- Nachname
- Latency
- später
- neueste
- Liga
- LERNEN
- lernen
- links
- Legacy
- Länge
- weniger
- lassen
- Lasst uns
- Brief
- Niveau
- Cholesterinspiegel
- Hebelwirkung
- Hebelwirkungen
- Nutzung
- Bibliotheken
- Bibliothek
- Gefällt mir
- wahrscheinlich
- LIMIT
- Einschränkungen
- Limitiert
- Begrenzung
- Grenzen
- Links
- Liste
- hören
- Listen
- leben
- ll
- LLM
- Belastung
- Ladeprogramm
- located
- Standorte
- Log
- protokolliert
- Protokollierung
- Logik
- Lang
- länger
- aussehen
- suchen
- SIEHT AUS
- Nachschlagen
- die
- Los Angeles
- Sneaker
- Maschine
- Maschinelles Lernen
- gemacht
- halten
- Wartbar
- Aufrechterhaltung
- unterhält
- um
- MACHT
- Making
- verwalten
- Management
- Manager
- flächendeckende Gesundheitsprogramme
- Manchester
- Manchester United
- Manipulation
- Weise
- manuell
- Hersteller
- viele
- viele Leute
- Karte
- Mapping
- Landkarten
- Spiel
- Abstimmung
- Mathe
- mathematisch
- Angelegenheiten
- maximal
- Kann..
- me
- bedeuten
- Bedeutung
- Mittel
- messen
- Medien
- Treffen
- Trifft
- Memories
- Memory
- erwähnt
- Merge
- Verschmelzung
- Nachricht
- Nachrichten
- Messaging
- Metadaten
- Methode
- Methoden
- Metrik
- könnte
- Millionen
- minimal
- Moll
- Kommt demnächst...
- Fehler
- Vermischung
- MLB
- Mobil
- Modell
- für
- Mäßigung
- Modul
- Module
- Moment
- MongoDB
- Überwachen
- Überwachung
- Mond
- mehr
- vor allem warme
- Am beliebtesten
- schlauer bewegen
- Film
- viel
- mehrere
- mehrere Ketten
- Moschus
- sollen
- my
- Name
- Namens
- Namen
- National
- Natürliche
- Verarbeitung natürlicher Sprache
- Navigieren
- navigieren
- In der Nähe von
- notwendig,
- Need
- erforderlich
- Bedürfnisse
- Negativ
- Neu
- New York
- New York Times
- weiter
- nicht
- Andere
- nichts
- Notion
- jetzt an
- Anzahl
- Obama
- Objekt
- Ziel
- Objekte
- Beobachtung
- erhalten
- beschaffen
- OCR
- of
- bieten
- bieten
- Angebote
- vorgenommen,
- oh
- OK
- Olympiade
- on
- einmal
- EINEM
- einzige
- Open-Source-
- OpenAI
- Einkauf & Prozesse
- Operator
- optimiert
- Verbessert
- Option
- or
- Auftrag
- bio
- Organisationen
- Original
- OS
- Andere
- Anders
- Andernfalls
- UNSERE
- Möglichkeiten für das Ausgangssignal:
- Ausgänge
- übrig
- Override
- Überblick
- besitzen
- Paket
- Pakete
- Seite
- Seiten
- Paare
- Pandas
- Papier
- Parallel
- Parameter
- Parameter
- Park
- Teil
- besonders
- Teile
- passieren
- Bestanden
- leitet
- Bestehen
- passt
- Weg
- Pfade
- Muster
- Payroll
- Personen
- für
- perfekt
- perfekt
- Ausführen
- Leistung
- Durchführung
- führt
- Berechtigungen
- Beharrlichkeit
- person
- Personalisiert
- Perspektive
- Physik
- Stück
- Pipeline
- Pizza
- Platzhalter
- Plattform
- Plato
- Datenintelligenz von Plato
- PlatoData
- Play
- Spielplatz
- spielt
- Bitte
- erfahren
- Points
- Politik durchzulesen
- Datenschutzrichtlinien
- politisch
- Pool
- Beliebt
- besiedelt
- positiv
- möglich
- Post
- BLOG-POSTS
- Potenzial
- Werkzeuge
- angetriebene
- größte treibende
- Praktisch
- Praxis
- bevorzugen
- Premier
- Gegenwart
- Präsident
- verhindern
- Verhütung
- früher
- in erster Linie
- primär
- Prime
- privat
- Aufgabenstellung:
- Probleme
- vorgehen
- Prozessdefinierung
- Verarbeitet
- anpassen
- Verarbeitung
- produziert
- Produkt
- Produktion
- Professor
- Programmierung
- Programmiersprachen
- Projekt
- Projekte
- immobilien
- Resorts
- PROS
- Prototyp
- Prototyping
- die
- vorausgesetzt
- Versorger
- Anbieter
- bietet
- Bereitstellung
- Öffentlichkeit
- Zweck
- Zwecke
- setzen
- Python
- F&A
- Qualität
- Abfragen
- Frage
- Fragen
- Direkt
- schnell
- Zitate
- R
- erhöhen
- Angebot
- Bereich
- lieber
- Wertung
- Roh
- RE
- erreichen
- Reagieren
- Lesen Sie mehr
- Lesebrillen
- bereit
- echt
- Echtzeit
- Echtzeitdaten
- Reich
- Grund
- Gründe
- kürzlich
- empfohlen
- aufgezeichnet
- Aufzeichnungen
- Entspannung
- Veteran
- reduziert
- Reduzierung
- Reduktion
- Referenz
- Referenzierung
- verfeinern
- Verfeinerung
- Regionen
- Beziehungen
- freigegeben
- Relevanz
- relevant
- Zuverlässigkeit
- zuverlässig
- verlassen
- sich auf
- bleibt bestehen
- merken
- Erinnerung
- entfernt
- Ausbeute
- wiederholen
- WIEDERHOLT
- umformulieren
- ersetzen
- berichten
- Quelle
- Darstellung
- Darstellen
- representiert
- Anforderung
- Zugriffe
- erfordern
- falls angefordert
- Voraussetzungen:
- erfordert
- retten
- Forschungsprojekte
- lösen
- Ressourcen
- Reagieren
- reagiert
- Antwort
- Antworten
- für ihren Verlust verantwortlich.
- ansprechbar
- REST
- Folge
- was zu
- Die Ergebnisse
- Halte
- Beibehaltung
- Rückkehr
- Rückkehr
- Rückgabe
- wiederverwendbar
- Überprüfen
- dreht sich
- Reis
- Reiches
- Roboter
- Rollen
- Rollen
- Wurzel
- Routing
- REIHE
- Führen Sie
- Laufen
- läuft
- Laufzeit
- s
- Schutzmaßnahmen
- Vertrieb
- salesforce
- Sam
- gleich
- Speichern
- sagt
- skalierbaren
- Skalieren
- Szenario
- Szenarien
- Szenen
- Zeitplan
- Ergebnis
- kratzen
- nahtlos
- nahtlos
- Suche
- Suchmaschine
- Suchbegriffe
- Suche
- Abschnitt
- Abschnitte
- Verbindung
- Sicherheitdienst
- sehen
- ausgewählt
- Auswahl
- in XNUMX Minuten
- senden
- empfindlich
- Gefühl
- Gefühle
- getrennte
- September
- Reihenfolge
- Modellreihe
- brauchen
- Server
- dient
- Lösungen
- kompensieren
- Sets
- Einstellung
- Einstellungen
- Setup
- sieben
- mehrere
- Teilen
- von Locals geführtes
- Schale
- scheint
- ausgeliefert
- sollte
- erklären
- Vitrine
- gezeigt
- Konzerte
- Sigma
- signifikant
- ähnlich
- Einfacher
- vereinfachte
- vereinfachen
- Vereinfachung
- einfach
- da
- Single
- Größe
- locker
- klein
- kleinere
- smart
- Schnipsel
- So
- bis jetzt
- Fußball
- Social Media
- Social Media
- Social Media Beiträge
- allein
- solide
- Lösung
- LÖSEN
- einige
- etwas
- manchmal
- anspruchsvoll
- Geräusche
- Quelle
- Quellen
- Raumfahrt
- Spanisch
- spezialisiert
- spezifisch
- speziell
- Besonderheiten
- angegeben
- Geschwindigkeit
- verbrachte
- gespalten
- Spagat
- Sport
- quadratisch
- Stand
- standalone
- Standard
- Anfang
- begonnen
- Beginnen Sie
- Bundesstaat
- Aussagen
- statisch
- Schritt
- Shritte
- Immer noch
- Stoppen
- Einstellung
- Stoppt
- Lagerung
- speichern
- gelagert
- Läden
- Speicherung
- Geschichte
- einfach
- Strom
- Streaming
- rationalisieren
- gestrafft
- Stärken
- Strikes
- Schnur
- Struktur
- strukturierte
- Strukturen
- Strukturierung
- Stil
- Fach
- Folge
- Erfolgreich
- so
- Anzug
- geeignet
- Suite
- zusammenfassen
- ZUSAMMENFASSUNG
- Sonnenuntergang
- Support
- Unterstützte
- Unterstützt
- sicher
- Nachhaltigkeit
- Synchronisation
- synopsis
- Syntax
- System
- Systeme und Techniken
- Tabelle
- Tailor
- zugeschnitten
- Nehmen
- nimmt
- Ziele
- Aufgabe
- und Aufgaben
- Team
- Teams
- erzählen
- Vorlage
- Vorlagen
- Terminal
- Terminologie
- AGB
- Test
- Testen
- Text
- als
- Vielen Dank
- zur Verbesserung der Gesundheitsgerechtigkeit
- Das
- Die Grundlagen
- der Hub
- die Informationen
- Die New York Times
- Die Projekte
- Die Quelle
- die Welt
- ihr
- Sie
- dann
- Dort.
- Diese
- vom Nutzer definierten
- fehlen uns die Worte.
- diejenigen
- obwohl?
- Durch
- während
- Zeit
- Zeitaufwendig
- mal
- Titel
- zu
- gemeinsam
- Zeichen
- Tokenisierung
- Tokens
- auch
- Werkzeug
- Toolkit
- Werkzeuge
- Top
- Thema
- Themen
- Gesamt
- Stadt
- Tracing
- verfolgen sind
- traditionell
- Ausbildung
- Transformieren
- Transformationen
- Transformator
- Transformer
- Übergang
- Versuch
- was immer dies auch sein sollte.
- wirklich
- versuchen
- Abstimmung
- WENDE
- Drehung
- Lernprogramm
- Twice
- XNUMX
- tippe
- Typen
- Typoskript
- typisch
- ui
- Letztlich
- unberührt
- für
- zugrunde liegen,
- verstehen
- Verständnis
- versteht
- einheitlich
- einzigartiges
- Vereinigt
- Universal-
- nicht wie
- bis
- Aktualisierung
- Updates
- hochgeladen
- URL
- us
- Nutzbarkeit
- Anwendungsbereich
- -
- Anwendungsfall
- benutzt
- Mitglied
- Benutzerschnittstelle
- Nutzer
- verwendet
- Verwendung von
- Dienstprogramme
- Nutzen
- seit
- die
- Verwendung
- v1
- Bestätigung
- Validierer
- wertvoll
- Wert
- Werte
- Variable
- Vielfalt
- verschiedene
- Ve
- vielseitig
- Version
- sehr
- Video
- Anzeigen
- Verstöße
- sichtbar
- visualisieren
- lebenswichtig
- vs
- Spaziergang
- Walkthrough
- wollen
- wurde
- Ansehen
- Weg..
- Wege
- we
- Wetter
- Netz
- Web-Browser
- Web-Services
- Webseiten
- GUT
- bekannt
- waren
- Was
- Was ist
- was ist
- wann
- ob
- welche
- während
- WHO
- ganze
- warum
- breit
- weit
- Widget
- Wikipedia
- werden wir
- Fenster
- Gewinnt
- mit
- .
- ohne
- Word
- Arbeiten
- gearbeitet
- Arbeitsablauf.
- Workflows
- arbeiten,
- Werk
- weltweit wie ausgehandelt und gekauft ausgeführt wird.
- würde
- schreiben
- Schreiben
- X
- noch
- York
- Du
- Ihr
- sich selbst
- Youtube
- Zendesk
- Zephyrnet
- PLZ