You are viewing the v1 docs for LangChain, which is currently under active development. Learn more.

Overview

Messages are the fundamental unit of context for models in LangChain. They represent the input and output of models, carrying both the content and metadata needed to represent the state of a conversation when interacting with an LLM. Messages are objects that contain:
  • Role - Identifies the message type (e.g. system, user)
  • Content - Represents the actual content of the message (like text, images, audio, documents, etc.)
  • Metadata - Optional fields such as response information, message IDs, and token usage
LangChain provides a standard message type that works across all model providers, ensuring consistent behavior regardless of the model being called.

Message types

Basic usage

The simplest way to use messages is to create message objects and pass them to a model when invoking.
from langchain.chat_models import init_chat_model
from langchain_core.messages import HumanMessage, AIMessage, SystemMessage

model = init_chat_model("openai:gpt-5-nano")

system_msg = SystemMessage("You are a helpful assistant.")
human_msg = HumanMessage("Hello, how are you?")

# Use with chat models
messages = [system_msg, human_msg]
response = model.invoke(messages)  # Returns AIMessage

Text prompts

Text prompts are strings - ideal for straightforward generation tasks where you don’t need to retain conversation history.
response = model.invoke("Write a haiku about spring")
Use text prompts when:
  • You have a single, standalone request
  • You don’t need conversation history
  • You want minimal code complexity

Message prompts

Alternatively, you can pass in a list of messages to the model by providing a list of message objects.
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage

messages = [
    SystemMessage("You are a poetry expert"),
    HumanMessage("Write a haiku about spring"),
    AIMessage("Cherry blossoms bloom...")
]
response = model.invoke(messages)
Use message prompts when:
  • Managing multi-turn conversations
  • Working with multimodal content (images, audio, files)
  • Including system instructions

Dictionary format

You can also specify messages directly in OpenAI chat completions format.
from langchain_core.messages import SystemMessage, HumanMessage, AIMessage

messages = [
    {"role": "system", "content": "You are a poetry expert"},
    {"role": "user", "content": "Write a haiku about spring"},
    {"role": "assistant", "content": "Cherry blossoms bloom..."}
]
response = model.invoke(messages)

Message types

System Message

A SystemMessage represent an initial set of instructions that primes the model’s behavior. You can use a system message to set the tone, define the model’s role, and establish guidelines for responses.
Basic instructions
system_msg = SystemMessage("You are a helpful coding assistant.")

messages = [
    system_msg,
    HumanMessage("How do I create a REST API?")
]
response = model.invoke(messages)
Detailed persona
from langchain_core.messages import SystemMessage, HumanMessage

system_msg = SystemMessage("""
You are a senior Python developer with expertise in web frameworks.
Always provide code examples and explain your reasoning.
Be concise but thorough in your explanations.
""")

messages = [
    system_msg,
    HumanMessage("How do I create a REST API?")
]
response = model.invoke(messages)

Human Message

A HumanMessage represents user input and interactions. They can contain text, images, audio, files, and any other amount of multimodal content.

Text content

human_msg = HumanMessage("What is machine learning?")
response = model.invoke([human_msg])

Message metadata

Add metadata
human_msg = HumanMessage(
    content="Hello!",
    name="alice",  # Optional: identify different users
    id="msg_123",  # Optional: unique identifier for tracing
)
The name field behavior varies by provider - some use it for user identification, others ignore it. To check, refer to the model provider’s reference.

AI Message

An AIMessage represents the output of a model invocation. They can include multimodal data, tool calls, and provider-specific metadata that you can later access.
response = model.invoke("Explain AI")
print(type(response))  # <class 'langchain_core.messages.AIMessage'>
AIMessage objects are returned by the model when calling it, which contains all of the associated metadata in the response. However, that doesn’t mean that’s the only place they can be created/ modified from. Providers weight/contextualize types of messages differently, which means it is sometimes helpful to create a new AIMessage object and insert it into the message history as if it came from the model.
from langchain_core.messages import AIMessage, SystemMessage, HumanMessage

# Create an AI message manually (e.g., for conversation history)
ai_msg = AIMessage("I'd be happy to help you with that question!")

# Add to conversation history
messages = [
    SystemMessage("You are a helpful assistant"),
    HumanMessage("Can you help me?"),
    ai_msg,  # Insert as if it came from the model
    HumanMessage("Great! What's 2+2?")
]

response = model.invoke(messages)

Tool calling responses

When models make tool calls, they’re included in the AI message:
Tool calling
model_with_tools = model.bind_tools([GetWeather])
response = model_with_tools.invoke("What's the weather in Paris?")

for tool_call in response.tool_calls:
    print(f"Tool: {tool_call['name']}")
    print(f"Args: {tool_call['args']}")
    print(f"ID: {tool_call['id']}")

Streaming and chunks

During streaming, you’ll receive AIMessageChunk objects that can be combined:
chunks = []
for chunk in model.stream("Write a poem"):
    chunks.append(chunk)
    print(chunk.text)

Tool Message

For models that support tool calling, AI messages can contain tool calls. Tool messages are used to pass the results of a single tool execution back to the model.
# After a model makes a tool call
ai_message = AIMessage(
    content=[],
    tool_calls=[{
        "name": "get_weather",
        "args": {"location": "San Francisco"},
        "id": "call_123"
    }]
)

# Execute tool and create result message
weather_result = "Sunny, 72°F"
tool_message = ToolMessage(
    content=weather_result,
    tool_call_id="call_123"  # Must match the call ID
)

# Continue conversation
messages = [
    HumanMessage("What's the weather in San Francisco?"),
    ai_message,  # Model's tool call
    tool_message,  # Tool execution result
]
response = model.invoke(messages)  # Model processes the result

Content

You can think of a message’s content as the payload of data that gets sent to the model. Messages have a content attribute that is loosely-typed, supporting strings and lists of untyped objects (e.g., dictionaries). This allows support for provider-native structures directly in LangChain chat models, such as multimodal content and other data. Separately, LangChain provides dedicated content types for text, reasoning, citations, multi-modal data, server-side tool calls, and other message content. See content blocks below. LangChain chat models accept message content in the .content attribute, and can contain:
  1. A string
  2. A list of content blocks in a provider-native format
  3. A list of LangChain’s standard content blocks
See below for an example using multimodal inputs:
from langchain_core.messages import HumanMessage

# String content
human_message = HumanMessage("Hello, how are you?")

# Provider-native format (e.g., OpenAI)
human_message = HumanMessage(content=[
    {"type": "text", "text": "Hello, how are you?"},
    {"type": "image_url", "image_url": {"url": "https://example.com/image.jpg"}}
])

# List of standard content blocks
human_message = HumanMessage(content_blocks=[
    {"type": "text", "text": "Hello, how are you?"},
    {"type": "image", "url": "https://example.com/image.jpg"},
])
Specifying content_blocks when initializing a message will still populate message content, but provides a type-safe interface for doing so.

Standard content blocks

LangChain maintains a standard set of types for message content that works across providers (see the reference section below). Messages also implement a content_blocks property that will lazily parse the content attribute into this standard, type-safe representation. For example, messages generated from ChatAnthropic or ChatOpenAI will include thinking or reasoning blocks in the format of the respective provider, but these can be lazily parsed into a consistent ReasoningContentBlock representation:
from langchain_core.messages import AIMessage

message = AIMessage(
    content=[
        {"type": "thinking", "thinking": "...", "signature": "WaUjzkyp..."},
        {"type": "text", "text": "..."},
    ],
    response_metadata={"model_provider": "anthropic"}
)
message.content_blocks
[{'type': 'reasoning',
  'reasoning': '...',
  'extras': {'signature': 'WaUjzkyp...'}},
 {'type': 'text', 'text': '...'}]
See the integrations guides to get started with the inference provider of your choice.
Serializing standard contentIf an application outside of LangChain needs access to the standard content block representation, you can opt-in to storing content blocks in message content.To do this, you can set the LC_OUTPUT_VERSION environment variable to v1. Or, initialize any chat model with output_version="v1":
from langchain.chat_models import init_chat_model

model = init_chat_model("openai:gpt-5-nano", output_version="v1")

Multimodal

Multimodality refers to the ability to work with data that comes in different forms, such as text, audio, images, and video. LangChain includes standard types for these data that can be used across providers. Chat models can accept multimodal data as input and generate it as output. Below we show short examples of input messages featuring multimodal data:
# From URL
response = model.invoke([
    {"type": "text", "text": "Describe the content of this image."},
    {"type": "image", "url": "https://example.com/path/to/image.jpg"},
])

# From base64 data
response = model.invoke([
    {"type": "text", "text": "Describe the content of this image."},
    {
        "type": "image",
        "base64": "AAAAIGZ0eXBtcDQyAAAAAGlzb21tcDQyAAACAGlzb2...",
        "mime_type": "image/jpeg",
    },
])

# From provider-managed File ID
response = model.invoke([
    {"type": "text", "text": "Describe the content of this image."},
    {"type": "image", "file_id": "file-abc123"},
])
Not all models support all file types. Check the model provider’s reference for supported formats and size limits.

Content block reference

Content blocks are represented (either when creating a message or accessing the content_blocks property) as a list of typed dictionaries. Each item in the list must adhere to one of the following block types:
Content blocks were introduced as a new property on messages in LangChain v1 to standardize content formats across providers while maintaining backward compatibility with existing code. Content blocks are not a replacement for the content property, but rather a new property that can be used to access the content of a message in a standardized format.

Examples

Multi-turn conversations

Building conversational applications requires managing message history and context:
from langchain_core.messages import HumanMessage, AIMessage

# Initialize conversation
messages = [
    SystemMessage("You are a helpful assistant specializing in Python programming")
]

# Simulate multi-turn conversation
while True:
    user_input = input("You: ")
    if user_input.lower() == "quit":
        break

    # Add user message
    messages.append(HumanMessage(user_input))

    # Get model response
    response = model.invoke(messages)

    # Add assistant response to history
    messages.append(response)

    print(f"Assistant: {response.content}")