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
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 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 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 comparaison | with_structured_output() | bind_tools() |
|---|---|---|
| Objectif | Extraire des données structurées à partir de texte | Indiquer au modèle la liste des outils disponibles |
| Format de retour | Renvoie directement un objet Pydantic | Renvoie un AIMessage contenant tool_calls |
| Scénarios applicables | Extraction d'informations, analyse de données | Appel d'outils par l'agent, scénarios nécessitant une exécution externe |
| Prise en charge du modèle | Nécessite que le modèle prenne en charge la sortie structurée native | Tous 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 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
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 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"}}
)
Autres extensionsLorsque 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.