Eine handgefertigte LangChain-Tool-Schleife zur Vergleich von Echtzeit-Bestandsmetriken
Erstellen Sie schrittweise einen kleinen LangChain-Assistenten zur Aktienvergleich, und lernen Sie den Zyklus aus Erstellen, Binden, Aufrufen und Ausführen kennen, der es einem LLM ermöglicht, aktuelle Daten anzufragen, anstatt zu raten.
Ein Sprachmodell kennt nur das, was in seinen Trainingsdaten enthalten ist, weshalb eine Anfrage nach dem heutigen Aktienkurs lediglich eine zuversichtliche Schätzung liefert und nicht einen Fakt. Für finanzielle Angelegenheiten ist das ein ernstes Problem. Die durch Tool-Calling ermöglichte Lösung lässt das Modell Ihren Code anweisen, aktuelle Daten abzurufen, und anschließend auf den Ergebnissen zu verarbeiten. In dieser Anleitung wird ein kompakter Assistent erstellt, der zwei Aktien hinsichtlich Preis und Kurs-Gewinn-Verhältnis vergleicht, wobei dabei jede Phase des Tool-Calling-Arbeitsablaufs von LangChain klar dargestellt wird: Erstellen, Binden, Aufrufen, Ausführen.
Warum ein Modell ohne Tools nur raten kann
Stellen Sie sich einen Verkäufer vor, der jedes Produkt und jede Richtlinie auswendig kennt, aber keinen Zugang zum Lagerverwaltungssystem hat. Wenn Sie fragen, ob eine Jacke in Größe M auf Lager ist, erhalten Sie eine zuversichtliche Antwort, die auf den Daten der letzten Woche beruht. Das ist ein reines LLM: klar ausdrucksfähig, aber blind für die Gegenwart.
Geben Sie dem Mitarbeiter einen Barcode-Scanner, damit er die Informationen überprüfen kann anstelle zu raten. In LangChain ist der Scanner ein Tool: eine gewöhnliche Funktion, die das Modell anfordern kann, um sie auszuführen – beispielsweise eine Preisabfrage, eine Datenbankanfrage oder einen API-Aufruf. Die Aufrufung von Tools ist das Mechanismus, der dem Modell ermöglicht zu entscheiden, wann es den Scanner verwenden soll, welchen Gegenstand gescannt werden muss und wie das Ergebnis genutzt werden kann.
Der vierstufige Zyklus
Die Aufrufung von Tools (oft als Funktionsaufruf bezeichnet) folgt stets dem gleichen Ablauf:
- Erstellen Sie das Tool. Schreiben Sie eine Python-Funktion mit einer beschreibenden Bezeichnung, typisierten Parametern sowie einer Dokumentation, die erklärt, was sie tut.
- Binden Sie es an das Modell. Rufen Sie
.bind_tools()beim Chat-Modell auf, damit es weiß, welche Tools vorhanden sind und welche Argumente sie benötigen.
get_stock_price with ticker='MSFT'".Die wichtige Eigenschaft ist, dass das Modell – und nicht Ihr Code – entscheidet, wann ein Tool benötigt wird. Eine Frage wie „Was ist 2+2?“ erhält eine direkte Antwort, während „Vergleiche MSFT und AAPL“ in einer einzigen Antwort zwei Toolaufrufe erzeugen kann. Das Modell beantragt lediglich die Aufrufe; deren Ausführung bleibt Ihre Aufgabe. Wie Frameworks diesen Prozess automatisieren, erfahren Sie unter was LangChain tatsächlich automatisiert, sobald Sie einen Agenten-Loop erstellt haben.
Schritt 1: Installieren Sie bei der ersten Ausführung die Abhängigkeiten
Das Skript beginnt damit, nach seinen Paketen zu suchen und alle fehlenden zu installieren, sodass es ohne einen separaten pip install-Schritt ausgeführt werden kann. Es wandelt jeden Paketnamen in seinen Importnamen um, indem es Bindestriche durch Unterstriche ersetzt (langchain-groq wird zu langchain_groq), und fällt bei Problemen zurück auf den Aufruf von pip über den aktuellen Interpreter:
import sys
import subprocess
required_packages = ["langchain-groq", "langchain-core", "yfinance"]
for package in required_packages:
try:
__import__(package.replace("-", "_"))
except ImportError:
print(f"📦 Package '{package}' not found. Installing now...")
subprocess.check_call([sys.executable, "-m", "pip", "install", package])
Das eignet sich für Demos, doch echte Projekte sollten Abhängigkeiten in requirements.txt oder pyproject.toml festlegen; laufzeitbasierte Installationen machen die Builds nicht reproduzierbar.
Schritt 2: API-Schlüssel bereitstellen
Das Modell läuft auf Groq, daher benötigt der Groq-Client einen API-Schlüssel in der Umgebung. In der Demo wird dieser als Platzhalter direkt zugewiesen:
import os
os.environ["GROQ_API_KEY"] = "Your-API"
Echte Schlüssel sollten in einer .env-Datei liegen, die aus dem Versionskontrollsystem ausgeschlossen ist, oder in einem Secrets-Manager – niemals im kommitierten Code.
Schritt 3: Definieren des Tools für Aktiendaten
Das Tool verwendet yfinance, um einen Aktienkürzel zu suchen, den neuesten Schlusskurs eines Tages aus der Historie abzurufen sowie die Marktkapitalisierung und das Kurs-Gewinn-Verhältnis aus den Informationen zum Aktienkürzel zu lesen:
from langchain_core.tools import tool
import yfinance as yf
@tool
def get_stock_price(ticker: str) -> str:
"""Fetches the current stock price and key statistics for a given ticker symbol."""
try:
stock = yf.Ticker(ticker)
todays_data = stock.history(period='1d')
if todays_data.empty:
return f"Could not find data for ticker {ticker}."
price = todays_data['Close'].iloc[-1]
info = stock.info
market_cap = info.get('marketCap', 'N/A')
pe_ratio = info.get('trailingPE', 'N/A')
return f"{ticker} Current Price: ${price:.2f}, Market Cap: {market_cap}, P/E Ratio: {pe_ratio}"
except Exception as e:
return f"Error fetching data for {ticker}: {str(e)}"
Drei Aspekte machen diese Funktion zu einem guten Tool:
- Der
@tool-Decorator verwandelt die Funktion in ein LangChain-Tool und leitet ein Eingabeschema aus ihren Typangaben ab. - Die Dokumentation ist keine Dekoration. Das Modell liest sie zusammen mit dem Namen, um zu entscheiden, wann das Tool angewendet werden soll; daher sollte sie klar angeben, was das Tool zurückgibt.
- Fehler werden als beschreibende Zeichenketten zurückgegeben anstatt ausgelöst zu werden. Ein unbekanntes Aktienkürzel oder ein fehlgeschlagener Anfragen führt zu einer Nachricht, über die das Modell nachdenken kann (“Daten konnten nicht gefunden werden”), anstatt zu einer Ausnahme, die den gesamten Ablauf abbricht.
Bemerken Sie, dass yfinance ein inoffizieller Wrapper für Yahoo Finance ist: Die Kursangaben können verzögert sein und einige Felder fehlen, weshalb als Ersatz 'N/A' verwendet wird.
Schritt 4: Erstellen Sie das Modell und verknüpfen Sie die Tools
Danach wird das Chat-Modell erstellt und mit der Liste der Tools verknüpft:
from langchain_groq import ChatGroq
llm = ChatGroq(
model="openai/gpt-oss-120b",
temperature=0
)
tools = [get_stock_price]
llm_with_tools = llm.bind_tools(tools)
bind_tools() sendet bei jeder Anfrage die Namen, Beschreibungen sowie Argumentstrukturen der Tools an das Modell, damit dieses weiß, nach was es fragen kann. Beachten Sie außerdem, dass das noch nicht verknüpfte llm ebenfalls beibehalten wird; es wird später für die endgültige Zusammenfassung wiederverwendet. Der Modellname spiegelt wider, was Groq zum Zeitpunkt der Erstellung anbot – überprüfen Sie daher vor dem Ausführen die aktuelle Modellliste des Anbieters.
Durch das Setzen von temperature=0 bleibt die Ausgabe fokussiert und konsistent, allerdings wird dadurch nur die Zufälligkeit verringert, keine identischen Antworten garantiert.
Schritt 5: Erstellen Sie eine Prompt-Kette
Ein Prompt-Muster liefert eine Systemanweisung und fügt die Frage des Benutzers in die menschliche Nachricht ein. Der Pipe-Operator verbindet anschließend den Prompt mit dem toolbewussten Modell zu einer ausführbaren Einheit, ähnlich wie eine Unix-Pipeline:
from langchain_core.prompts import ChatPromptTemplate
from IPython.display import display, Markdown
prompt = ChatPromptTemplate.from_messages([
("system", "You are an expert financial analyst. Use the tools provided to pull real-time data before comparing or concluding."),
("human", "{input}")
])
chain = prompt | llm_with_tools
Die Systemnachricht erledigt hier die eigentliche Arbeit: Sie weist das Modell an, vor jeder Vergleichserstellung Daten mit den Tools abzurufen. Ohne sie könnte das Modell auf veraltete Trainingsdaten antworten.
Schritt 6: Die Schleife ausführen und mehrere Tool-Aufrufe verarbeiten
Der Hauptblock bindet alles zusammen. Er ruft die Kette auf, prüft, ob die Antwort tool_calls enthält, führt jede angeforderte Abfrage aus, sammelt die Ausgaben und bittet schließlich das einfache Modell, auf der gesammelten Datenbasis einen Vergleich zu erstellen. Wenn keine Tools angefordert wurden, gibt er die direkte Antwort des Modells aus:
if __name__ == "__main__":
query = "Compare the current stock price and P/E ratio of Microsoft (MSFT) AND Apple (AAPL). Which one looks cheaper based on P/E?"
print(f"🚀 Invoking Financial Pipeline with query: '{query}'\n")
# 1. Ask the model what tools it wants to use
ai_message = chain.invoke({"input": query})
# 2. Check if the model requested tool use
if ai_message.tool_calls:
print(f"🛠️ Model requesting {len(ai_message.tool_calls)} real-time tool lookups...\n")
tool_outputs = []
# 3. Execute ALL generated tool calls
for tool_call in ai_message.tool_calls:
if tool_call["name"] == "get_stock_price":
ticker_symbol = tool_call["args"]["ticker"]
print(f" -> Executing tool lookup for: {ticker_symbol}")
result = get_stock_price.invoke(tool_call["args"])
print(f" [Tool Output] {result}")
tool_outputs.append(result)
# 4. Supply the full collective data back to the LLM
summary_prompt = f"""
User Query: {query}
Real-time Data Harvested: {'; '.join(tool_outputs)}
Synthesize a final response evaluating which asset looks cheaper.
"""
final_answer = llm.invoke(summary_prompt)
print("\n--- Final Analysis Output ---")
display(Markdown(final_answer.content))
else:
print("\n--- Final Analysis Output ---")
print(ai_message.content)
Für eine Frage bezüglich sowohl Microsoft als auch Apple gibt das Modell in der Regel zwei Tool-Aufrufe pro Antwort zurück, einen pro Ticker. Der Loop führt sie alle aus, bevor er fortfährt, sodass im letzten Schritt beide Datensätze gleichzeitig verfügbar sind. Das Modell beantragt die Aufrufe parallel, doch dieser Code führt sie nacheinander aus; bei langsamen APIs könnte man sie koncurrent ausführen.
Zwei Verbesserungen sind wichtig zu kennen, sobald dies funktioniert. Erstens dient die Namenkontrolle innerhalb der Schleife dazu, zwischen mehreren Tools zu wählen; ein Wörterbuch, das Toolnamen mit Tool-Objekten verknüpft, ist effizienter als eine Kette von if-Anweisungen. Zweitens gibt diese Version die Ergebnisse zurück, indem sie einen neuen Textaufruf erstellt. Der übliche Ansatz von LangChain fügt jedes Ergebnis als ToolMessage mit der entsprechenden tool_call_id zum Gespräch hinzu und ruft das dem Tool zugeordnete Modell erneut auf, wodurch der gesamte Austausch beibehalten wird und das Modell weitere Aufrufe anfordern kann, falls die ersten Ergebnisse unzureichend sind.
Die Erweiterung des Assistenten erfolgt schrittweise: Ein Tool wie get_financial_news oder calculate_valuation wird über denselben Aufruf von bind_tools() eingebunden, und das Modell wählt die Tools anhand ihrer Beschreibungen aus.
Haupterkenntnisse
- Ein Tool ist eine Funktion mit einem klaren Namen, Typhinweisen und einer Dokumentation; der
@tool-Decorator erledigt den Rest. .bind_tools()verbindet Ihre Funktionen mit dem Modell, indem sie in jeder Anfrage beschrieben werden.- Das Modell fordert nur Aufrufe von Tools an. Ihr Code führt diese aus und gibt die Ergebnisse zurück – diese Kontrolle ist nützlich, keine Einschränkung.
- Geben Sie Fehler von Tools als lesbare Zeichenketten zurück, damit ein einziger fehlerhafter Abruf den Ablauf nicht beendet.
- Fangen Sie mit einem Tool und einer Schleife an, fügen Sie dann nach Bedarf weitere Tools, über Nachrichten erfolgende Ergebnisübertragung sowie Konkurrenzfähigkeit hinzu.
Das gleiche Muster gilt überall dort, wo ein Modell aktuelle Informationen benötigt – von Wetter- und Lagerdaten bis zu CRM-Einträgen oder Ihrer eigenen Datenbank – sodass Assistenten über laufende Systeme statt über eingefrorene Snapshots entscheiden können.