Types de messages LangChain
Dans LangChain, toutes les conversations passent par des objets Message. Comprendre l'objectif des différents types de messages est le fondement pour écrire des Agents.
Quatre types de messages principaux
LangChain définit quatre types de messages principaux, correspondant à différents rôles dans une conversation :
| Type | Rôle | Description | Contenu typique |
|---|---|---|---|
| HumanMessage | Utilisateur | Message envoyé par l'utilisateur | "Quel temps fait-il aujourd'hui ?" |
| AIMessage | Assistant IA | Réponse du modèle, peut inclure tool_calls | "Il y a du soleil à Hangzhou aujourd'hui, 25°C" |
| SystemMessage | Système | Instruction système, définissant le rôle et les règles de comportement de l'IA | "Vous êtes un assistant météorologique professionnel" |
| ToolMessage | Outil | Renvoyer le résultat après exécution de l'outil | "Ensoleillé, 25°C, humidité 60%" |
HumanMessage — Message utilisateur
HumanMessage représente un message envoyé par l'utilisateur à l'IA. C'est le type de message le plus courant et le point de départ d'une conversation.
Exemple
from langchain.chat_models import init_chat_model
# Créer un message utilisateur
msg = HumanMessage(content="Qu'est-ce que Python ?")
print(f"Type : {msg.type}") # humain
print(f"Contenu : {msg.content}") # Qu'est-ce que Python ?
print(f"Rôle : {msg.role}") # utilisateur
# Créer une liste de messages (représentant l'historique d'une conversation à plusieurs tours)
messages = [
HumanMessage(content="Bonjour"),
HumanMessage(content="Quels cours Example propose-t-il ?"),
HumanMessage(content="Le cours Python est-il adapté aux débutants sans aucune base ?"),
]
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
response = model.invoke(messages)
print(f"\n"Réponse du modèle : {response.content}")
Sortie :
Type: human Content: What is Python? Role: user Model reply: Python is a high-level, interpreted programming language known for its clear and readable syntax, widely used across many fields. Its rich ecosystem and beginner-friendly design make it an excellent choice for those starting from zero.
Méthodes de création rapide pour HumanMessage
Lors de la construction de listes de messages, vous pouvez utiliser des tuples ou des dictionnaires comme raccourcis :
Exemple
# Méthode 1 : construction standard
msg1 = HumanMessage(content="Hello")
# Méthode 2 : Raccourci tuple (rôle, contenu)
msg2 = ("user", "Hello")
msg3 = ("human", "Hello")
# Méthode 3 : Raccourci dictionnaire
msg4 = {"role": "user", "content": "Hello"}
# Les quatre méthodes sont équivalentes et seront converties en HumanMessage en interne dans l'Agent.
print(type(msg1)) # <class 'langchain_core.messages.human.HumanMessage'>
AIMessage — Réponse de l'IA
AIMessage représente la réponse du modèle. Contrairement au texte ordinaire, AIMessage peut incluretool_calls(demandes d'appel d'outil).
Exemple
# Réponse IA normale (sans appel d'outil)
ai_msg = AIMessage(content="Example is a programming learning platform")
# Réponse de l'IA contenant un appel d'outil
ai_with_tools = AIMessage(
content="", # Lors de l'appel d'un outil, content est généralement vide
tool_calls=[
{
"name": "get_weather",
"args": {"city": "Hangzhou"},
"id": "call_abc123",
"type": "tool_call",
}
]
)
print("=== Message IA normal ===")
print(f"contenu : {ai_msg.content}")
print(f"appels d'outils : {ai_msg.tool_calls}") # []
print("\n"=== Message IA avec appel d'outil ===")
print(f"contenu : {ai_with_tools.content}")
print(f"appels d'outils : {ai_with_tools.tool_calls}")
# [{'name': 'get_weather', 'args': {'city': 'Hangzhou'}, ...}]
Informations supplémentaires pour AIMessage
Exemple
model = init_chat_model("deepseek:deepseek-v4-flash")
response = model.invoke("Présentez Python")
# AIMessage contient des métadonnées riches
print(f"Contenu : {response.content}")
print(f"ID du message : {response.id}")
print(f"Nom du modèle : {response.response_metadata.get('model_name')}")
print(f"Raison de fin : {response.response_metadata.get('finish_reason')}")
# usage_metadata contient des informations sur l'utilisation des tokens
if response.usage_metadata:
print(f"Tokens d'entrée : {response.usage_metadata.get('input_tokens')}")
print(f"Tokens de sortie : {response.usage_metadata.get('output_tokens')}")
print(f"Total des tokens : {response.usage_metadata.get('total_tokens')}")
Sortie :
Content: Example is a free programming learning platform for beginners... Message ID: msg_abc123def456 Model name: deepseek-v4-flash Finish reason: stop Input tokens: 19 Output tokens: 47 Total tokens: 66
SystemMessage — Instruction système
SystemMessage est utilisé pour définir le comportement, le rôle et les contraintes de l'IA. Il est placé au début de la liste de messages et guide la façon dont le modèle répond.
Exemple
from langchain.chat_models import init_chat_model
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0.7)
# Répondre sans instruction système
messages_no_system = [HumanMessage(content="Présentez Python")]
response = model.invoke(messages_no_system)
print(f"Aucune instruction système : {response.content[:80]}...")
# Répondre avec une instruction système
messages_with_system = [
SystemMessage(content="Vous êtes un blogueur de style Xiaohongshu ; les réponses doivent être vivantes, utiliser des émojis et inclure des tags de sujet."),
HumanMessage(content="Présentez Python")
]
response = model.invoke(messages_with_system)
print(f"\n"Avec l'instruction système : {response.content}")
Sortie :
Without system prompt: Example is an online programming learning platform for beginners, offering rich tutorials and examples... With system prompt: Amazing site! Recommending Example to every beginner who wants to learn programming! Comprehensive free tutorials covering everything from HTML to Python! Plenty of examples and quick to get started - a perfect entry point for programming novices! #ProgrammingLearning #FreeTutorials #ZeroBasics #Example
ToolMessage — Résultat renvoyé par l'outil
ToolMessage contient le résultat renvoyé après l'exécution de l'outil. Il doit être associé au tool_call correspondant.
Exemple
from langchain.chat_models import init_chat_model
# Simuler un cycle complet de conversation avec appel d'outils
messages = [
HumanMessage(content="Quel temps fait-il à Hangzhou ?"),
# Le modèle demande à appeler un outil
AIMessage(
content="",
tool_calls=[
{"name": "get_weather", "args": {"city": "Hangzhou"},
"id": "call_abc", "type": "tool_call"}
]
),
# Résultat renvoyé par l'outil (doit inclure tool_call_id correspondant à l'id ci-dessus)
ToolMessage(
content="Ensoleillé, 25°C, humidité 60%",
tool_call_id="call_abc", # Correspond à l'id de tool_call
name="get_weather", # Nom de l'outil
),
]
model = init_chat_model("deepseek:deepseek-v4-flash")
response = model.invoke(messages)
print(f"Réponse du modèle basée sur le résultat de l'outil : {response.content}")
Sortie :
Model reply based on tool result: Hangzhou is sunny today, 25 C, humidity 60%, great for outdoor activities.
L'attribut tool_call_id de ToolMessage doit exactement correspondre à l'id de tool_call dans l'AIMessage. S'ils ne correspondent pas, le modèle peut ignorer le résultat de l'outil ou produire un comportement confus.
AIMessageChunk — Fragment de message de sortie en streaming
Lorsque vous utilisez stream() pour la sortie en streaming, chaque fragment qui arrive est un AIMessageChunk plutôt qu'un AIMessage complet :
Exemple
model = init_chat_model("deepseek:deepseek-v4-flash")
print("Processus de sortie en streaming :")
# stream() renvoie un itérateur AIMessageChunk
for chunk in model.stream("Présentez Python en une phrase"):
# Chaque fragment est un petit morceau de texte
print(chunk.content, end="", flush=True)
print() # Saut de ligne
Sortie :
Streaming output: Example is a free online learning platform for programming beginners, offering rich tutorials and examples.
Table de référence rapide des types de messages
| Type de message | attribut type | attribut role | Champs clés | Quand l'utiliser |
|---|---|---|---|---|
| HumanMessage | human | user | content | Entrée utilisateur |
| AIMessage | ai | assistant | content, tool_calls, usage_metadata | Réponse du modèle |
| AIMessageChunk | ai | assistant | content (delta) | Fragment de sortie en streaming |
| SystemMessage | system | system | content | Définir le rôle de l'IA |
| ToolMessage | tool | tool | content, tool_call_id, name | Résultat de l'exécution de l'outil |
ContentBlock — Contenu de message structuré
Jusqu'à présent, le contenu des messages que nous avons utilisé était composé de simples chaînes de caractères. Mais en réalité, le contenu de chaque message peut être constitué de plusieursContentBlock(blocs de contenu) formant une liste.
Les trois types de blocs de contenu les plus courants :
| Type | Description | Objectif |
|---|---|---|
| PlainTextContentBlock | Contenu en texte brut | Message texte ordinaire |
| ImageContentBlock | Contenu de l'image (base64 ou URL) | Entrée image pour modèles multimodaux |
| ToolCall | Demande d'appel d'outil | L'IA demande d'appeler un outil |
Exemple
from langchain.messages import PlainTextContentBlock, ImageContentBlock
# Construire des messages à l'aide de blocs de contenu
# le contenu peut être une chaîne de caractères simple (scénario simple)
simple_msg = HumanMessage(content=Bonjour)
# le contenu peut aussi être une liste de ContentBlock (scénario complexe)
complex_msg = HumanMessage(content=[
PlainTextContentBlock(text="Qu'y a-t-il dans cette image ?"),
# L'image peut être une URL ou un encodage base64
ImageContentBlock(
url="https://example.com/photo.jpg"
),
])
print(f"Type de contenu du message simple : {type(simple_msg.content)}")
# Sortie : <class 'str'>
print(f"Type de contenu du message complexe : {type(complex_msg.content)}")
# Sortie : <class 'list'>
print(f"Nombre de blocs de contenu : {len(complex_msg.content)}")
# Sortie : 2
Lorsque vous n'avez besoin que d'envoyer du texte brut, vous pouvez directement passer une chaîne, et LangChain s'en chargera automatiquement. Ce n'est que lorsque vous devez mélanger du texte et des images dans un seul message que vous devez construire manuellement une liste ContentBlock.
Messages multimodaux — Permettre au modèle de « voir » les images
Si votre modèle prend en charge l'entrée multimodale (comme GPT-4o, Claude 3+), vous pouvez lui faire analyser le contenu d'une image :
Exemple
from pathlib import Path
from langchain.messages import HumanMessage
from langchain.chat_models import init_chat_model
# Encoder l'image locale en base64
def encode_image(image_path: str) -> str:
Lire le fichier image et le convertir en encodage base64
with open(image_path, "rb") as f:
return base64.b64encode(f.read()).decode("utf-8")
# Créer un modèle multimodal (doit prendre en charge l'entrée d'images)
model = init_chat_model("deepseek:deepseek-v4-flash")
# Construire un message contenant une image
# Remarque : content utilise un format de liste, contenant des blocs de texte et des blocs d'image
image_data = encode_image("screenshot.png")
messages = [
HumanMessage(content=[
{"type": "text", "text": Veuillez décrire le contenu de cette capture d'écran du site officiel de Python.},
{
"type": "image_url",
"image_url": {
"url": f"data:image/png;base64,{image_data}",
"detail": "auto" # Facultatif : low, high, auto
}
}
])
]
response = model.invoke(messages)
print(fRésultat de l'analyse d'image : {response.content})
Si votre message contient uniquement une image et aucun texte, vous pouvez directement utiliser :
Exemple
model = init_chat_model("deepseek:deepseek-v4-flash")
# Utiliser une URL pour référencer directement une image en ligne
messages = [
{
"role": "user",
"content": [
{"type": "text", "text": Que décrit cette image ?},
{
"type": "image_url",
"image_url": {"url": "https://www.example.com/wp-content/uploads/2024/01/logo.png"}
}
]
}
]
response = model.invoke(messages)
print(response.content)
Tous les modèles ne prennent pas en charge l'entrée multimodale. La série GPT-4o d'OpenAI, Claude 3+ d'Anthropic et la série Gemini de Google la prennent en charge. Si vous envoyez une image en utilisant un modèle non pris en charge, vous obtiendrez une erreur.
ToolCall — Message d'appel d'outil
Le champ tool_calls dans AIMessage est une liste d'objets ToolCall, où chaque ToolCall représente une requête du modèle pour appeler un outil :
Exemple
from langchain.messages.tool import ToolCall
# Construire manuellement un ToolCall
tool_call = ToolCall(
name="get_weather", # Nom de l'outil
args={"city": Hangzhou}, # Arguments d'appel
id="call_abc123", # Identifiant unique
type="tool_call", # Valeur fixe
)
# Créer un AIMessage contenant tool_calls
ai_message = AIMessage(
content="", # Lorsque tool_calls est présent, content est généralement vide
tool_calls=[tool_call],
)
print(fNom de l'outil : {ai_message.tool_calls)
print(fParamètres d'appel : {ai_message.tool_calls)
print(fID d'appel : {ai_message.tool_calls)
Vérifier si AIMessage contient des appels d'outils
Exemple
model = init_chat_model("deepseek:deepseek-v4-flash", temperature=0)
# Après avoir lié des outils, le modèle peut renvoyer tool_calls
tools = [{
"type": "function",
"function": {
"name": "get_weather",
"description": Interroger la météo,
"parameters": {
"type": "object",
"properties": {
"city": {"type": "string", "description": Nom de la ville}
},
"required": ["city"]
}
}
}]
model_with_tools = model.bind_tools(tools)
# Question qui déclenche un appel d'outil
response = model_with_tools.invoke(Quel temps fait-il à Hangzhou ?)
# Deux façons de déterminer s'il y a un appel d'outil
# Méthode 1 : Vérifier si la liste tool_calls est non vide
if response.tool_calls:
print(Le modèle demande un appel d'outil)
# Méthode 2 : Vérifier si content est vide
# (Pour la plupart des modèles, content est vide lorsque tool_calls est présent)
if not response.content:
print(Le contenu du modèle est vide, ce qui indique qu'il souhaite appeler un outil au lieu de répondre directement.)
trim_messages() — Troncature de l'historique des messages
Lorsque la conversation s'allonge, la liste des messages peut dépasser la fenêtre de contexte du modèle.trim_messages()Cette fonction vous aide à tronquer intelligemment l'historique des messages.
Exemple
HumanMessage, AIMessage, SystemMessage, trim_messages
)
from langchain.chat_models import init_chat_model
# Simuler un long historique de conversation
messages = [
SystemMessage(content=Vous êtes l'assistant IA du tutoriel EXAMPLE.),
HumanMessage(content=Comment débuter avec Python ?),
AIMessage(content=Pour débuter avec Python, on peut commencer par des connaissances de base...),
HumanMessage(content=Un IDE recommandé ?),
AIMessage(content=Je recommande VS Code ou PyCharm...),
HumanMessage(content=Comment installer des bibliothèques tierces ?),
AIMessage(content=Utilisez la commande pip install...),
HumanMessage(content=Qu'est-ce que NumPy ?),
AIMessage(content=NumPy est une bibliothèque de calcul scientifique...),
HumanMessage(content=Quelle est la différence entre pandas et NumPy ?),
]
model = init_chat_model("deepseek:deepseek-v4-flash")
# Tronquer les messages pour qu'ils tiennent dans la fenêtre de contexte du modèle (au plus 1000 tokens)
# strategy="last" conserve le dernier message système et la conversation la plus récente
trimmed = trim_messages(
messages,
max_tokens=1000, # Conserver au maximum 1000 tokens
strategy="last", # Conserver le dernier message système + la conversation la plus récente
token_counter=model, # Utiliser la méthode de comptage de tokens du modèle
include_system=True, # Toujours conserver SystemMessage
start_on="human", # Après l'élagage, commencer par un message humain
)
print(fAvant l'élagage : {len(messages)} messages)
print(fAprès l'élagage : {len(trimmed)} messages)
for msg in trimmed:
snippet = msg.content[:50] if isinstance(msg.content, str) else str(msg.content)[:50]
print(f" [{msg.type}] {snippet}...")
Résultat de l'exécution :
Before trimming: 10 messages After trimming: 5 messages [system] You are the AI assistant of Example... [human] How do I install third-party libraries?... [ai] Use the pip install command... [human] What is NumPy?... [ai] NumPy is a scientific computing library...
| Stratégie | Description | Scénarios applicables |
|---|---|---|
| strategy="last" | Conserver le message système + la conversation la plus récente | Dans les longues conversations, seul le contexte le plus récent compte |
| strategy="first" | Conserver le message système + la conversation la plus ancienne | Veiller à ce que le contexte clé ne soit pas tronqué |
start_on="human" garantit que la liste de messages tronquée commence par un message utilisateur (plutôt qu'un message IA), empêchant le modèle de recevoir une liste commençant par une réponse IA isolée.
RemoveMessage — Suppression de messages spécifiques
Dans certains scénarios avancés, vous devrez peut-être supprimer des messages spécifiques de l'historique des messages (comme nettoyer du contenu sensible, régénérer des réponses, etc.) :
Exemple
# Supposons qu'il y ait une conversation
messages = [
HumanMessage(content=Bonjour, id="msg_1"),
AIMessage(content=Bonjour ! Comment puis-je vous aider ?, id="msg_2"),
HumanMessage(content=Vérifie la météo pour moi, id="msg_3"),
]
# Utiliser RemoveMessage pour supprimer un message spécifique (par ID)
# RemoveMessage est utilisé avec le reducer add_messages
# Lors de la mise à jour de l'état de l'Agent, RemoveMessage supprime de la liste le message avec l'ID correspondant
removal = RemoveMessage(id="msg_3")
print(fID du message à supprimer : {removal.id})
print(fType : {removal.type}) # supprimer
RemoveMessage est généralement utilisé avec le reducer add_messages d'AgentState. Renvoyer RemoveMessage dans middleware ou les hooks after_model peut nettoyer dynamiquement l'historique des messages.
Méthodes courantes pour les propriétés des messages
Tous les types de messages héritent de BaseMessage et partagent certaines méthodes courantes :
Exemple
msg = HumanMessage(content=Bonjour, Exemple)
# Attributs de base
print(f"content: {msg.content}") # Contenu du message
print(f"type: {msg.type}") # Type de message (human/ai/system/tool)
print(f"id: {msg.id}") # ID unique généré automatiquement
# attribut text : s'il s'agit de contenu textuel, retourner le texte ; sinon retourner ""
print(f"text: {msg.text}")
# pretty_repr() : affichage formaté, adapté au débogage
print(f"Sortie formatée :\n{msg.pretty_repr()}")
Résultat de l'exécution:
content: Hello, world type: human id: 00000000-0000-4000-8000-000000000000 text: Hello, world Pretty output: ================================ Human Message ================================= Hello, worldAutres extensions