Messages are the universal currency between your code, models, tools and agents.
Chat models consume a list of messages, each with a role:
SystemMessage: instructions that set behaviour ("You are a concise assistant").HumanMessage: user input.AIMessage: model output, possibly containingtool_calls.ToolMessage: the result of a tool call, linked to it bytool_call_id.
You can also use plain dicts ({"role": "user", "content": "..."}) or ("human", "...") tuples; LangChain converts them.
Models are stateless: they only see the messages you send. To have a conversation you resend the history each time:
history = [SystemMessage("Be brief."), HumanMessage("Hi, I'm Ana.")]
ai = model.invoke(history)
history += [ai, HumanMessage("What's my name?")]Content can be multimodal: a list of content blocks such as text plus an image URL or base64 data, if the model supports it.
Long histories cost tokens and eventually exceed the context window. Utilities in langchain_core.messages help: trim_messages keeps the most recent messages within a token budget, filter_messages selects by type or name, and count_tokens_approximately estimates size. Agents and LangGraph manage history for you with checkpointers (later lessons), but the underlying representation is always this message list.
Example
from langchain_core.messages import (AIMessage, HumanMessage, SystemMessage,
trim_messages)
from langchain_core.messages.utils import count_tokens_approximately
history = [
SystemMessage("You are a helpful assistant. Be brief."),
HumanMessage("Hi, I'm Ana."),
AIMessage("Hello Ana! How can I help?"),
HumanMessage("What's my name?"),
]
# reply = model.invoke(history) -> AIMessage("Your name is Ana.")
print([m.type for m in history]) # ['system', 'human', 'ai', 'human']
as_dicts = [{"role": "user", "content": "Hello"}] # also accepted by models
recent = trim_messages(history, max_tokens=30, strategy="last",
token_counter=count_tokens_approximately,
include_system=True, start_on="human")
print([m.type for m in recent]) # ['system', 'human'] (oldest turns dropped)Remember
- System, human, AI and tool messages carry roles; dicts and tuples also work
- Models are stateless; send the history you want them to see
- Trim long histories with
trim_messagesto stay within the context window
Watch out for
- Appending only the user's messages to history and forgetting the AI replies, which confuses the model about the conversation.