In meinem Grundlagenartikel zu LangChain habe ich das Thema LangSmith nur kurz angeschnitten. In diesem Artikel werden wir uns näher mit dieser Plattform befassen, die auch im Tandem mit anderen Large-Language-Model (LLM)-Frameworks funktioniert.
LangSmith definiert
LangSmith ist - in aller Kürze - ein Tool, um LLM-Applikationen und intelligente Agenten zu tracen, zu evaluieren und vom Prototypenstatus in die Produktion zu überführen.
Oder, wie es die LangSmith-Dokumentation ausdrückt: "LangSmith ist eine Plattform, um produktionsreife LLM-Anwendungen zu erstellen. Sie ermöglicht es, Chains und intelligente Agenten - die auf einem beliebigen LLM-Framework aufgebaut sind - zu debuggen, zu testen, zu bewerten und zu überwachen. LangSmith lässt sich dabei nahtlos mit dem führenden Open-Source-Framework LangChain integrieren."
Wie das konkret vonstattengeht, erfahren Sie in diesem Artikel. Anmerkung: Aktuell ist LangChain in drei Implementierungen verfügbar: Python, JavaScript und Go. Wir verwenden für alle genannten Beispiel die erstgenannte.
LangSmith mit LangChain nutzen
Nachdem Sie Ihr LangSmith-Konto eingerichtet, API-Schlüssel erstellt, die LangChain-Installation mit pip
aktualisiert und die Shell-Umgebungsvariablen eingerichtet haben, können Sie die Python-Quickstart-Applikation ausführen:
from langchain.chat_models import ChatOpenAI
llm = ChatOpenAI()
llm.predict("Hello, world!")
Bevor wir die Ergebnisse betrachten, ein Blick auf den LangSmith-Hub:
Auf der nächsten Registerkarte finden Sie die Trace-Liste des Default-Projekts:
Erst nachdem ich meinen OpenAI-API-Tarif entsprechend angepasst respektive konfiguriert hatte, lief das Python-Programm bis zum Ende durch. Ein Blick auf die Ergebnisse:
Ein Blick auf die zugehörige Metadaten-Registerkarte verriet mir, dass der "Hello, World!"-Prompt mit dem gpt-3.5-turbo
-Modell mit einer Sampling Temperature von 0,7 ausgeführt wurde. Die Skala reicht hier von 0 bis 1, wobei 1 die willkürlichste Einstellung ist und 0 das Modell auffordert, die Temperatur automatisch einzustellen.
Wie LangSmith funktioniert
LangSmith protokolliert sämtliche LLM-, Chain-, Agent-, Tool- und Retriever-Calls in einer LangChain - oder einem anderen LLM-Programm. Das kann Sie dabei unterstützen,
unerwartete Endergebnisse zu debuggen,
festzustellen, warum ein Agent "loopt",
herauszufinden, warum eine Chain langsamer als erwartet ist und
zu ermitteln, wie viele Token ein Agent verwendet hat.
Dabei bietet LangSmith eine unkomplizierte Visualisierung der genauen In- und Outputs aller LLM-Calls. Wenn Sie jetzt denken, die Input-Seite wäre trivial, irren Sie: Zusätzlich zu den Eingabevariablen (Prompt) verwendet ein LLM-Call ein Template und oft auch Hilfsfunktionen, die den Kontext für das Sprachmodell festlegen - etwa Informationen aus dem Web abrufen oder Dateien hochladen.
Ganz allgemeinen empfehle ich Ihnen, LangSmith für alle Arbeiten mit LangChain eingeschaltet zu lassen - die Protokolle müssen Sie lediglich dann einsehen, wenn es relevant ist. Sollte ein Prompt dabei nicht die gewünschten Ergebnisse liefern, haben Sie die Möglichkeit, diesen in den "Playground" zu verfrachten:
Vergessen Sie dabei nicht, Ihre API-Keys über die entsprechende Schaltfläche "Secrets & API Keys" hinzuzufügen.
LangSmith LLMChain-Beispiel
In meiner LangChain-Einführung habe ich das Beispiel einer LLMChain genutzt, die einen ChatOpenAI-Call mit einem einfachen Parser für kommagetrennte Listen kombiniert. Ein Blick auf das LangSmith-Protokoll für diesen Python-Code hilft zu verstehen, was in dem Programm passiert.
Der Parser ist eine Unterklasse von BaseOutputParser
. Das System Message Template für den ChatOpenAI-Aufruf ist relativ einfaches Prompt Engineering.
from langchain.chat_models import ChatOpenAI
from langchain.prompts.chat import (
ChatPromptTemplate,
SystemMessagePromptTemplate,
HumanMessagePromptTemplate,
)
from langchain.chains import LLMChain
from langchain.schema import BaseOutputParser
class CommaSeparatedListOutputParser(BaseOutputParser):
"""Parse the output of an LLM call to a comma-separated list."""
def parse(self, text: str):
"""Parse the output of an LLM call."""
return text.strip().split(", ")
template = """You are a helpful assistant who generates comma separated lists.
A user will pass in a category, and you should generate 5 objects in that category in a comma separated list.
ONLY return a comma separated list, and nothing more."""
system_message_prompt = SystemMessagePromptTemplate.from_template(template)
human_template = "{text}"
human_message_prompt = HumanMessagePromptTemplate.from_template(human_template)
chat_prompt = ChatPromptTemplate.from_messages([system_message_prompt, human_message_prompt])
chain = LLMChain(
llm=ChatOpenAI(),
prompt=chat_prompt,
output_parser=CommaSeparatedListOutputParser()
)
chain.run("colors")
Mit LangSmith evaluieren
Dieser Quickstart-Walkthrough evaluiert eine Chain unter Einsatz eines beispielhaften Datensatzes. Ist das Dataset erstellt, wird ein LLM, eine Chain oder ein Agent für die Evaluierung definiert. Ist der Vorgang abgeschlossen, werden die Traces und das Feedback innerhalb von LangSmith überprüft.
from langsmith import Client
example_inputs = [
"a rap battle between Atticus Finch and Cicero",
"a rap battle between Barbie and Oppenheimer",
"a Pythonic rap battle between two swallows: one European and one African",
"a rap battle between Aubrey Plaza and Stephen Colbert",
]
client = Client()
dataset_name = "Rap Battle Dataset"
# Storing inputs in a dataset lets us
# run chains and LLMs over a shared set of examples.
dataset = client.create_dataset(
dataset_name=dataset_name, description="Rap battle prompts.",
)
for input_prompt in example_inputs:
# Each example must be unique and have inputs defined.
# Outputs are optional
client.create_example(
inputs={"question": input_prompt},
outputs=None,
dataset_id=dataset.id,
)
from langchain.chat_models import ChatOpenAI
from langchain.chains import LLMChain
# Since chains and agents can be stateful (they can have memory),
# create a constructor to pass in to the run_on_dataset method.
def create_chain():
llm = ChatOpenAI(temperature=0)
return LLMChain.from_string(llm, "Spit some bars about {input}.")
from langchain.smith import RunEvalConfig, run_on_dataset
eval_config = RunEvalConfig(
evaluators=[
# You can specify an evaluator by name/enum.
# In this case, the default criterion is "helpfulness"
"criteria",
# Or you can configure the evaluator
RunEvalConfig.Criteria("harmfulness"),
RunEvalConfig.Criteria(
{"cliche": "Are the lyrics cliche?"
" Respond Y if they are, N if they're entirely unique."}
)
]
)
run_on_dataset(
client=client,
dataset_name=dataset_name,
llm_or_chain_factory=create_chain,
evaluation=eval_config,
verbose=True,
project_name="llmchain-test-1",
)
Bei diesem Beispiel gibt es wesentlich mehr zu beachten. Der obenstehende Code verwendet einen Datensatz, führt das Modell gegen vier Prompts aus dem Datensatz aus und führt mehrere Evaluierungen jedes erzeugten Rap-Battle-Ergebnisses.
Hier die zugehörigen Statistiken, die während des Laufs über das Terminal ausgegeben wurden:
Eval quantiles:
0.25 0.5 0.75 mean mode
harmfulness 0.00 0.0 0.0 0.00 0.0
helpfulness 0.75 1.0 1.0 0.75 1.0
cliche 1.00 1.0 1.0 1.00 1.0
Wie der nachfolgende Datensatz zeigt, hatte jemand Spaß daran, die Rap-Battle-Prompts aufzusetzen:
Der Code verwendet einen eigenen Projektnamen - llmchain-test-1
- daher sind dort auch die Ergebnisse zu finden:
Im Folgenden das "Barbie vs. Oppenheimer" Rap-Battle, wie es von gpt-3.5-turbo
generiert wurde:
Das LangSmith Cookbook
Die Standarddokumentation von LangSmith deckt alle Grundlagen der Plattform ab. In gängige Patterns und Anwendungsfälle aus der echten Welt dürfen Sie hingegen mit dem LangSmith Cookbook abtauchen (um den Code auszuführen, sollten Sie das Repository clonen oder forken).
Das Cookbook deckt dabei folgende Bereiche ab:
Code-Tracing mit LangChain;
Prompts mit LangChain Hub entdecken und teilen;
Testing und Benchmarking für LLM-Systeme;
Applikationen mit Hilfe von User Feedback optimieren, monitoren und personalisieren;
Daten exportieren zu Feintuning-Zwecken;
explorative Datenanalysen.
Dieser Beitrag basiert auf einem Artikel unserer US-Schwesterpublikation Infoworld.