Erweiterte Nutzung des LangChain-Chat-Modells
Dieser Abschnitt stellt zwei erweiterte Funktionen des Chat Model vor: bind_tools() (Binden von Tools) und with_structured_output() (strukturierte Ausgabe). Sie sind die Grundlage für Agents und die Extraktion strukturierter Daten.
bind_tools() — Dem Modell mitteilen, welche Tools verfügbar sind
Gewöhnliche Modelle können nur Text generieren. Aber nach dem Aufruf vonbind_tools()kann das Modell in seiner Antworttool_callzurückgeben und dem Programm mitteilen: "Ich muss dieses Tool aufrufen".
Beispiel
load_dotenv()
from langchain.chat_models import init_chat_model
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# Beschreibe das Tool mit einem Dictionary (OpenAI-Function-Calling-Format)
tools = [
{
"type": "function",
"function": {
"name": "get_weather",
"description": "Das Wetter einer angegebenen Stadt abfragen",
"parameters": {
"type": "object",
"properties": {
"city": {
"type": "string",
"description": "Stadtname, z. B. Hangzhou, Beijing"
}
},
"required": ["city"]
}
}
}
]
# bind_tools() bindet das Tool an das Modell
# Das Modell "weiß" jetzt, dass das Tool get_weather verfügbar ist
model_with_tools = model.bind_tools(tools)
# Stellen Sie eine Frage, die das Tool erfordert
response = model_with_tools.invoke("Wie ist das Wetter heute in Hangzhou?")
# Prüfen Sie, ob das Modell einen Tool-Aufruf angefordert hat
if response.tool_calls:
print("Das Modell hat angefordert, die folgenden Tools aufzurufen:")
for tc in response.tool_calls:
print(f" Tool-Name: {tc['name']}")
print(f" Argumente: {tc['args']}")
print(f" Aufruf-ID: {tc['id']}")
else:
print(f"Direkte Antwort des Modells: {response.content}")
Run result:
模型请求调用以下工具:
工具名: get_weather
Arguments: {'city': '杭州'}
Call ID: call_abc123def456
Beachten Sie, dass das Modell die Funktion get_weather nicht tatsächlich ausführt. bind_tools() teilt dem Modell nur mit "Sie haben ein Tool verfügbar", und das Modell gibt eine Tool-Aufruf-Anfrage zurück. Die tatsächliche Ausführung erfolgt durch den Agenten oder den Code, den Sie selbst schreiben.
Tools mit Pydantic-Modellen beschreiben
Für komplexe Tools ist die Verwendung von Pydantic-Modellen zur Definition von Parameterstrukturen klarer als das manuelle Schreiben von Dictionaries:
Beispiel
from langchain.chat_models import init_chat_model
# Parameterstruktur des Tools mit Pydantic definieren
class WeatherInput(BaseModel):
"""Wetter einer angegebenen Stadt abfragen"""
city: str = Field(description="Stadtname, z. B. Hangzhou, Beijing")
unit: str = Field(
default="celsius",
description="Temperatureinheit, Celsius oder Fahrenheit"
)
class CalculatorInput(BaseModel):
"""Eine mathematische Berechnung durchführen"""
expression: str = Field(
description="Mathematischer Ausdruck zum Berechnen, z. B. '(3 + 5) * 2'"
)
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# Übergeben Sie Pydantic-Modelle, LangChain konvertiert sie automatisch in Tool-Beschreibungen
model_with_tools = model.bind_tools([WeatherInput, CalculatorInput])
# Testen Sie ein komplexes Szenario
response = model_with_tools.invoke(
"Wie ist heute die Temperatur in Peking? Übrigens, hilf mir, 123 * 456 zu berechnen"
)
print(f"Das Modell hat {len(response.tool_calls)} Tool-Aufrufe angefordert:")
for tc in response.tool_calls:
print(f" {tc['name']}({tc['args']})")
Run result:
模型请求了 2 个工具调用:
get_weather({'city': '北京', 'unit': 'celsius'})
calculate({'expression': '123 * 456'})
Die Verwendung von Pydantic zur Definition von Tool-Parametern ist die empfohlene Vorgehensweise. Sie bietet Typsicherheit, automatische Validierung, und LangChain generiert automatisch Tool-Beschreibungen aus Klassennamen und Field-Beschreibungen.
with_structured_output() — Das Modell dazu bringen, strukturierte Daten zurückzugeben
with_structured_output()Es ist ein direkterer Ansatz als tool_calling. Es bringt das Modell dazu, Daten gemäß dem von Ihnen angegebenen Format (Schema) zurückzugeben, anstatt einen tool_call zurückzugeben.
Beispiel
from langchain.chat_models import init_chat_model
# Definiere die erwartete Ausgabestruktur
class PersonInfo(BaseModel):
"""Aus dem Text extrahierte Personeninformationen"""
name: str = Field(description="Name der Person")
age: int = Field(description="Alter")
occupation: str = Field(description="Beruf")
skills: list[str] = Field(description="Liste der Fähigkeiten")
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# with_structured_output() bewirkt, dass das Modell gemäß dem PersonInfo-Format zurückgibt
structured_model = model.with_structured_output(PersonInfo)
# Unstrukturierten Text übergeben, strukturierte Daten erhalten
text = "Zhang San ist dieses Jahr 28 Jahre alt, ein Full-Stack-Engineer, versiert in Python, React und Docker"
result = structured_model.invoke(text)
print(f"Name: {result.name}")
print(f"Age: {result.age}")
print(f"Occupation: {result.occupation}")
print(f"Skills: {', '.join(result.skills)}")
print(f"Type: {type(result)}")
Run result:
姓名: 张三 年龄: 28 职业: 全栈工程师 技能: Python, React, Docker Type: <class '__main__.PersonInfo'>
Der Rückgabewert ist direkteine Pydantic-Modellinstanz, und Sie können direkt auf Eigenschaften wie .name und .age zugreifen.
with_structured_output() vs bind_tools()
Diese beiden Methoden sehen ähnlich aus, erfüllen aber unterschiedliche Zwecke:
| Vergleichsdimension | with_structured_output() | bind_tools() |
|---|---|---|
| Zweck | Strukturierte Daten aus Text extrahieren | Dem Modell die verfügbare Tool-Liste mitteilen |
| Rückgabeformat | Gibt direkt ein Pydantic-Objekt zurück | Gibt eine AIMessage zurück, die tool_calls enthält |
| Anwendbare Szenarien | Informationsextraktion, Datenparsing | Agent-Tool-Aufruf, Szenarien, die eine externe Ausführung erfordern |
| Modellunterstützung | Erfordert, dass das Modell native strukturierte Ausgabe unterstützt | Alle Modelle, die Funktionsaufrufe unterstützen |
Verschachtelte strukturierte Ausgabe
with_structured_output() unterstützt komplexe verschachtelte Strukturen:
Beispiel
from langchain.chat_models import init_chat_model
class Ingredient(BaseModel):
"""Zutateninformationen"""
name: str = Field(description="Name der Zutat")
amount: str = Field(description="Menge, z. B. '200g', '2 Stück'")
class CookingStep(BaseModel):
"""Kochschritte"""
step_number: int = Field(description="Schrittnummer")
description: str = Field(description="Schrittbeschreibung")
duration_minutes: int = Field(description="Für diesen Schritt benötigte Zeit (Minuten)")
class Recipe(BaseModel):
"""Rezept"""
dish_name: str = Field(description="Name des Gerichts")
difficulty: str = Field(description="Schwierigkeit: einfach, mittel, schwer")
ingredients: list[Ingredient] = Field(description="Zutatenliste")
steps: list[CookingStep] = Field(description="Kochschritte")
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
structured_model = model.with_structured_output(Recipe)
# Eine Rezeptbeschreibung eingeben
recipe_text = """
Heute bringe ich dir bei, wie man ein klassisches Rührei mit Tomaten zubereitet. Dieses Gericht ist sehr einfach.
Du musst vorbereiten: 2 Tomaten, 3 Eier, ein wenig gehackte Frühlingszwiebeln, etwas Salz, etwas Zucker.
Schritte:
1. Zuerst die Tomaten in Stücke schneiden und die Eier verquirlen, etwa 5 Minuten
2. Die Pfanne erhitzen, Öl hinzufügen, die Eier anbraten und herausnehmen, etwa 3 Minuten
3. Wieder Öl hinzufügen, die Tomaten anbraten, bis sie Saft abgeben, Salz und Zucker hinzufügen, etwa 5 Minuten
4. Das Rührei hinzufügen, gleichmäßig anbraten, mit gehackten Frühlingszwiebeln bestreuen, etwa 2 Minuten
"""
result = structured_model.invoke(recipe_text)
print(f"Name des Gerichts: {result.dish_name}")
print(f"Schwierigkeit: {result.difficulty}")
print(f"Zutaten ({len(result.ingredients)} Sorten):")
for ing in result.ingredients:
print(f" - {ing.name}: {ing.amount}")
print(f"Schritte ({len(result.steps)} Schritte):")
for step in result.steps:
print(f" {step.step_number}. {step.description} ({step.duration_minutes} Minuten)")
Run result:
菜名: 番茄炒蛋 Difficulty: 简单 食材 (5 种): - 番茄: 2个 - 鸡蛋: 3个 - 葱花: 少许 - 盐: 适量 - 糖: 少许 步骤 (4 步): 1. 番茄切块,鸡蛋打散 (5分钟) 2. 热锅放油,鸡蛋炒熟盛出 (3分钟) 3. 炒番茄至出汁,加盐和糖 (5分钟) 4. 倒入鸡蛋翻炒均匀,撒上葱花 (2分钟)
JSON-Schema-Modus
Neben Pydantic-Modellen können Sie auch direkt JSON Schema übergeben:
Beispiel
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# JSON Schema direkt übergeben
json_schema = {
"title": "SentimentAnalysis",
"description": "Ergebnis der Sentimentanalyse",
"type": "object",
"properties": {
"sentiment": {
"type": "string",
"enum": ["positive", "negative", "neutral"],
"description": "Sentiment-Tendenz"
},
"Konfidenz": {
"type": "number",
"description": "Konfidenz, 0~1"
},
"keywords": {
"type": "array",
"items": {"type": "string"},
"description": "Wichtige Sentiment-Wörter"
}
},
"required": ["sentiment", "confidence"]
}
structured_model = model.with_structured_output(json_schema)
result = structured_model.invoke("Beispiel-Tutorial EXAMPLE ist wirklich großartig, sehr empfehlenswert für alle Programmieranfänger!")
print(f"Stimmung: {result['sentiment']}")
print(f"Konfidenz: {result['confidence']}")
print(f"Schlüsselwörter: {result['keywords']}")
Run result:
Sentiment: positive Confidence: 0.95 Keywords: ['太棒了', '强烈推荐']
bind_tools und with_structured_output auf ConfigurableModel
Konfigurierbare Modelle unterstützen diese beiden Methoden ebenfalls, mit genau derselben Verwendung:
Beispiel
from langchain.chat_models import init_chat_model
# Ein konfigurierbares Modell erstellen
configurable_model = init_chat_model(
"deepseek-v4-flash",
configurable_fields=("model", "model_provider"),
temperature=0,
)
# Verketteter Aufruf: zuerst Tools binden, dann invoke aufrufen
configurable_with_tools = configurable_model.bind_tools([...])
# Verschiedene Modelle können zur Laufzeit für die Ausführung verwendet werden
result = configurable_with_tools.invoke(
"Das Wetter abfragen",
config={"configurable": {"model": "claude-sonnet-4-5"}}
)
Weitere ErweiterungenWenn bind_tools oder with_structured_output auf ConfigurableModel verkettet werden, wird die eigentliche Operation aufgeschoben — sie wird erst dann wirklich gebunden, wenn das Modell instanziiert wird, sodass sie die Fähigkeit, Modelle zur Laufzeit dynamisch zu wechseln, nicht beeinträchtigt.