LangChain/Core Concepts
Intermediate12 min

Messages

Messages are LangChain's transport layer — every model call is a list of typed messages in, one message out. This article covers what each message type carries, how content blocks handle multimodal I/O, and how to manage message growth before it blows your context budget.

Quick Reference

  • Four types: SystemMessage, HumanMessage, AIMessage, ToolMessage
  • AIMessage.content can be a string OR a list of dicts — never assume string
  • AIMessage.text is the safe accessor: always returns concatenated text
  • ToolMessage.tool_call_id must match the AIMessage tool call id exactly
  • HumanMessage accepts images, audio, and files via content blocks
  • trim_messages() is the production solution to unbounded context growth
  • LangGraph users: RemoveMessage prunes specific messages from graph state

Message Anatomy

Every model interaction in LangChain is a list of messages passed to model.invoke(). Each message has a role, content, and optional metadata. LangChain maps four roles to typed classes that work across all providers.

TypeRoleContentExtra fields
SystemMessagesystemInstructions, persona, constraints
HumanMessageuserText, images, audio, files
AIMessageassistantText, tool calls, reasoning blockstool_calls, usage_metadata
ToolMessagetoolTool execution result (stringified)tool_call_id, artifact
SystemMessage"You are a helpful assistant..."HumanMessage"What's the weather in Tokyo?"AIMessagetool_calls"I'll look up the weather..."ToolMessage{ "temp": "22°C", "condition": "Sunny" }AIMessage"It's 22°C and sunny in Tokyo today!"

Messages flow through the conversation: System sets context, Human asks, AI reasons, Tools execute

LangChain accepts messages in three equivalent forms. A plain string becomes a HumanMessage. A dict with 'role' and 'content' is OpenAI-compatible. A typed class gives you autocompletion and explicit metadata control.

Three equivalent input forms