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

from dotenv import load_dotenv
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 pydantic import BaseModel, Field
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 pydantic import BaseModel, Field
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:

Vergleichsdimensionwith_structured_output()bind_tools()
ZweckStrukturierte Daten aus Text extrahierenDem Modell die verfügbare Tool-Liste mitteilen
RückgabeformatGibt direkt ein Pydantic-Objekt zurückGibt eine AIMessage zurück, die tool_calls enthält
Anwendbare SzenarienInformationsextraktion, DatenparsingAgent-Tool-Aufruf, Szenarien, die eine externe Ausführung erfordern
ModellunterstützungErfordert, dass das Modell native strukturierte Ausgabe unterstütztAlle Modelle, die Funktionsaufrufe unterstützen

Verschachtelte strukturierte Ausgabe

with_structured_output() unterstützt komplexe verschachtelte Strukturen:

Beispiel

from pydantic import BaseModel, Field
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

from langchain.chat_models import init_chat_model

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 pydantic import BaseModel, Field
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"}}
)

Wenn 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.

Weitere Erweiterungen