Utilisation avancée du modèle de chat LangChain

Cette section présente deux fonctionnalités avancées du modèle de chat : bind_tools() (liaison d'outils) et with_structured_output() (sortie structurée). Elles constituent la base des Agents et de l'extraction de données structurées.


bind_tools() — Indiquer au modèle quels outils sont disponibles

Les modèles ordinaires ne peuvent générer que du texte. Mais après avoir appelébind_tools()le modèle peut renvoyer dans sa réponsetool_call, indiquant au programme "Je dois appeler cet outil".

Exemple

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)

# Décrire l'outil avec un dictionnaire (format d'appel de fonction OpenAI)
tools = [
    {
        "type": "function",
        "function": {
            "name": "get_weather",
            "description": "Interroger la météo d'une ville spécifiée",
            "parameters": {
                "type": "object",
                "properties": {
                    "city": {
                        "type": "string",
                        "description": "Nom de la ville, par ex., Hangzhou, Beijing"
                    }
                },
                "required": ["city"]
            }
        }
    }
]

# bind_tools() lie l'outil au modèle
# Le modèle "sait" maintenant que l'outil get_weather est disponible
model_with_tools = model.bind_tools(tools)

# Poser une question qui nécessite l'outil
response = model_with_tools.invoke("Quel temps fait-il à Hangzhou aujourd'hui ?")

# Vérifier si le modèle a demandé un appel d'outil
if response.tool_calls:
    print("Le modèle a demandé d'appeler les outils suivants :")
    for tc in response.tool_calls:
        print(f" Nom de l'outil : {tc['name']}")
        print(f" Arguments : {tc['args']}")
        print(f" ID d'appel : {tc['id']}")
else:
    print(f"Réponse directe du modèle : {response.content}")

Résultat de l'exécution :

模型请求调用以下工具:
  工具名: get_weather
  Arguments: {'city': '杭州'}
  Call ID: call_abc123def456

Notez que le modèle n'exécute pas réellement la fonction get_weather. bind_tools() indique seulement au modèle "vous avez un outil disponible", et le modèle renvoie une demande d'appel d'outil. L'exécution réelle est effectuée par l'Agent ou le code que vous écrivez vous-même.


Décrire des outils avec les modèles Pydantic

Pour les outils complexes, utiliser des modèles Pydantic pour définir les structures de paramètres est plus clair que d'écrire des dictionnaires à la main :

Exemple

from pydantic import BaseModel, Field
from langchain.chat_models import init_chat_model

# Définir la structure des paramètres de l'outil avec Pydantic
class WeatherInput(BaseModel):
    """Interroger la météo d'une ville spécifiée"""
    city: str = Field(description="Nom de la ville, par ex. Hangzhou, Beijing")
    unit: str = Field(
        default="celsius",
        description="Unité de température, celsius ou fahrenheit"
    )

class CalculatorInput(BaseModel):
    """Effectuer un calcul mathématique"""
    expression: str = Field(
        description="Expression mathématique à calculer, par ex. '(3 + 5) * 2'"
    )

model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)

# Passez des modèles Pydantic, LangChain les convertit automatiquement en descriptions d'outils
model_with_tools = model.bind_tools([WeatherInput, CalculatorInput])

# Tester un scénario complexe
response = model_with_tools.invoke(
    "Quelle est la température à Pékin aujourd'hui ? Au fait, aidez-moi à calculer 123 * 456"
)

print(f"Le modèle a demandé {len(response.tool_calls)} appels d'outils :")
for tc in response.tool_calls:
    print(f" {tc['name']}({tc['args']})")

Résultat de l'exécution :

模型请求了 2 个工具调用:
  get_weather({'city': '北京', 'unit': 'celsius'})
  calculate({'expression': '123 * 456'})

Utiliser Pydantic pour définir les paramètres d'outil est la pratique recommandée. Cela assure la sécurité de type, une validation automatique, et LangChain génère automatiquement les descriptions d'outils à partir des noms de classe et des descriptions de Field.


with_structured_output() — Faire en sorte que le modèle renvoie des données structurées

with_structured_output()C'est une approche plus directe que tool_calling. Elle fait en sorte que le modèle renvoie des données selon le format (Schema) que vous spécifiez, au lieu de renvoyer un tool_call.

Exemple

from pydantic import BaseModel, Field
from langchain.chat_models import init_chat_model

# Définir la structure de sortie attendue
class PersonInfo(BaseModel):
    """Informations sur la personne extraites du texte"""
    name: str = Field(description="Nom de la personne")
    age: int = Field(description="Âge")
    occupation: str = Field(description="Profession")
    skills: list[str] = Field(description="Liste des compétences")

model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)

# with_structured_output() fait que le modèle renvoie selon le format PersonInfo
structured_model = model.with_structured_output(PersonInfo)

# Passer un texte non structuré, obtenir des données structurées
text = "Zhang San a 28 ans cette année, un ingénieur full-stack maîtrisant Python, React et Docker"
result = structured_model.invoke(text)

print(f"Nom : {result.name}")
print(f"Âge : {result.age}")
print(f"Profession : {result.occupation}")
print(f"Compétences : {', '.join(result.skills)}")
print(f"Type : {type(result)}")

Résultat de l'exécution :

姓名: 张三
年龄: 28
职业: 全栈工程师
技能: Python, React, Docker
Type: <class '__main__.PersonInfo'>

La valeur de retour est directementune instance de modèle Pydantic, et vous pouvez accéder directement aux propriétés telles que .name et .age.


with_structured_output() vs bind_tools()

Ces deux méthodes se ressemblent, mais elles ont des objectifs différents :

Critère de comparaisonwith_structured_output()bind_tools()
ObjectifExtraire des données structurées à partir de texteIndiquer au modèle la liste des outils disponibles
Format de retourRenvoie directement un objet PydanticRenvoie un AIMessage contenant tool_calls
Scénarios applicablesExtraction d'informations, analyse de donnéesAppel d'outils par l'agent, scénarios nécessitant une exécution externe
Prise en charge du modèleNécessite que le modèle prenne en charge la sortie structurée nativeTous les modèles qui prennent en charge l'appel de fonctions

Sortie structurée imbriquée

with_structured_output() prend en charge les structures imbriquées complexes :

Exemple

from pydantic import BaseModel, Field
from langchain.chat_models import init_chat_model


class Ingredient(BaseModel):
    """Informations sur l'ingrédient"""
    name: str = Field(description="Nom de l'ingrédient")
    amount: str = Field(description="Quantité, par ex. : '200g', '2 pièces'")


class CookingStep(BaseModel):
    """Étapes de cuisson"""
    step_number: int = Field(description="Numéro d'étape")
    description: str = Field(description="Description de l'étape")
    duration_minutes: int = Field(description="Temps requis pour cette étape (minutes)")


class Recipe(BaseModel):
    """Recette"""
    dish_name: str = Field(description="Nom du plat")
    difficulty: str = Field(description="Difficulté : facile, moyen, difficile")
    ingredients: list[Ingredient] = Field(description="Liste des ingrédients")
    steps: list[CookingStep] = Field(description="Étapes de cuisson")


model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
structured_model = model.with_structured_output(Recipe)

# Saisir une description de recette
recipe_text = """
Aujourd'hui, je vais vous apprendre à préparer des œufs brouillés classiques aux tomates. Ce plat est très simple.
Vous devez préparer : 2 tomates, 3 œufs, un peu d'oignon vert haché, un peu de sel, un peu de sucre.
Étapes:
1. D'abord, coupez les tomates en morceaux et battez les œufs, environ 5 minutes
2. Faites chauffer la poêle, ajoutez l'huile, brouillez les œufs et retirez-les, environ 3 minutes
3. Ajoutez à nouveau de l'huile, faites sauter les tomates jusqu'à ce qu'elles rendent leur jus, ajoutez le sel et le sucre, environ 5 minutes
4. Ajoutez les œufs brouillés, faites sauter uniformément, parsemez d'oignon vert haché, environ 2 minutes
"""


result = structured_model.invoke(recipe_text)

print(f"Nom du plat : {result.dish_name}")
print(f"Difficulté : {result.difficulty}")
print(f"Ingrédients ({len(result.ingredients)} types) :")
for ing in result.ingredients:
    print(f" - {ing.name}: {ing.amount}")
print(f"Étapes ({len(result.steps)} étapes) :")
for step in result.steps:
    print(f" {step.step_number}. {step.description} ({step.duration_minutes} minutes)")

Résultat de l'exécution :

菜名: 番茄炒蛋
Difficulty: 简单
食材 (5 种):
  - 番茄: 2个
  - 鸡蛋: 3个
  - 葱花: 少许
  - 盐: 适量
  - 糖: 少许
步骤 (4 步):
  1. 番茄切块,鸡蛋打散 (5分钟)
  2. 热锅放油,鸡蛋炒熟盛出 (3分钟)
  3. 炒番茄至出汁,加盐和糖 (5分钟)
  4. 倒入鸡蛋翻炒均匀,撒上葱花 (2分钟)

Mode JSON Schema

Outre les modèles Pydantic, vous pouvez également passer directement un JSON Schema :

Exemple

from langchain.chat_models import init_chat_model

model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)

# Passer directement un JSON Schema
json_schema = {
    "title": "SentimentAnalysis",
    "description": "Résultat de l'analyse des sentiments",
    "type": "object",
    "properties": {
        "sentiment": {
            "type": "string",
            "enum": ["positive", "negative", "neutral"],
            "description": "Tendance sentimentale"
        },
        "confiance": {
            "type": "number",
            "description": "Confiance, 0~1"
        },
        "keywords": {
            "type": "array",
            "items": {"type": "string"},
            "description": "Mots-clés sentimentaux"
        }
    },
    "required": ["sentiment", "confidence"]
}

structured_model = model.with_structured_output(json_schema)
result = structured_model.invoke("Le tutoriel d'exemple EXAMPLE est vraiment génial, je le recommande vivement à tous les débutants en programmation!")

print(f"Sentiment: {result['sentiment']}")
print(f"Confiance: {result['confidence']}")
print(f"Mots-clés: {result['keywords']}")

Résultat de l'exécution :

Sentiment: positive
Confidence: 0.95
Keywords: ['太棒了', '强烈推荐']

bind_tools et with_structured_output sur ConfigurableModel

Les modèles configurables prennent également en charge ces deux méthodes, avec exactement la même utilisation:

Exemple

from pydantic import BaseModel, Field
from langchain.chat_models import init_chat_model

# Créer un modèle configurable
configurable_model = init_chat_model(
    "deepseek-v4-flash",
    configurable_fields=("model", "model_provider"),
    temperature=0,
)

# Appel chaîné: lier d'abord les outils, puis invoquer
configurable_with_tools = configurable_model.bind_tools([...])

# Différents modèles peuvent être utilisés à l'exécution
result = configurable_with_tools.invoke(
    "Interroger la météo",
    config={"configurable": {"model": "claude-sonnet-4-5"}}
)

Lorsque l'on chaîne bind_tools ou with_structured_output sur ConfigurableModel, l'opération réelle est différée — elle n'est réellement liée que lorsque le modèle est instancié, donc cela n'affecte pas la capacité de changer dynamiquement de modèle au moment de l'exécution.

Autres extensions