LangChain (YT style)LangChain 1.4 · Python 3.12+
0%
1
Curious builder0 XP earned · 300 to level 2
0 daysFinish a lesson to begin
Badge collection0 of 6 unlocked
46 small wins to finish your pathNext lesson →

Messages: a conversation as a list

A LangChain message is a typed object for one turn of a conversation: SystemMessage, HumanMessage and AIMessage each hold one role's words.

Last updated: 27 Sep, 2026 · LangChain 1.4

Text prompts and a list of messages · from the Updated LangChain Version V1 Crash Course · 66:40 to 73:03

Four kinds of message

Whatever you pass to model.invoke goes in as a human message, and the reply comes back as an AI message. A plain string, such as model.invoke("what is langchain"), is a text prompt: fine for a single request that needs no conversation history. A message prompt is a list of message objects, which lets you tell the model how to behave and carry a conversation. There are four types:

  • SystemMessage tells the model how to behave: its role, tone and rules.
  • HumanMessage is the user's input.
  • AIMessage is the model's reply, including any tool calls it makes.
  • ToolMessage carries a tool's result back to the model; you meet it in the bind_tools: asking for a tool lesson.

Import the classes from langchain.messages and build the list. The video's first list has two messages: a system message, "You are a poetry expert", and a human message asking for a poem on artificial intelligence. Both go to the model together, and the poem comes back as an AI message:

python
from langchain.chat_models import init_chat_model
from langchain.messages import SystemMessage, HumanMessage

model = init_chat_model("groq:openai/gpt-oss-120b")   # the model from the setup lesson

messages = [
    SystemMessage("You are a poetry expert"),
    HumanMessage("Write a poem on artificial intelligence"),
]
response = model.invoke(messages)
A detailed system message and an AI message written by hand · from the Updated LangChain Version V1 Crash Course · 73:16 to 78:32

A one-line system message gets a generic answer. With "You are a helpful coding assistant.", the question "How do I create a REST API?" gets a general walkthrough that picks Flask as one example and lists other languages. A detailed system message, "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.", gets a practical Python answer to the same question, with Flask code and steps.

Each message carries a role, which names its type, content, which can be text, audio or documents, and optional metadata. The video's human message carries a name, Alice, and an id; the name tells users apart and the id helps trace the conversation.

Adding the model's side of a conversation

An AIMessage can also be written by hand, as if the model had said it. That is how a conversation's history is passed back in. The video writes "I'd be happy to help you with that question!" as an AI message, places it between "Can you help me?" and "Great! What's 2+2?", and the model answers the last question from the whole list. Here is that example, run on Groq:

ExampleAPI keyFrom the video, run on Groq
from langchain.chat_models import init_chat_model

model = init_chat_model("groq:openai/gpt-oss-120b")

from langchain.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)
print(response.content)
print(response.usage_metadata)

The reply read the whole history, including the AI message written by hand, and answered the last question. usage_metadata reports the tokens: 112 in and 36 out, 17 of them the reasoning the model did before it answered. The video's model reasons first too, which is why its reply opens with its thinking.

Now the shop's conversation, built from the same classes.

Importing the message classes

Import the three classes, one per role.

python
from langchain.messages import AIMessage, HumanMessage, SystemMessage

Building the conversation

Build the conversation as a list of these objects instead of dictionaries.

python
conversation = [
    SystemMessage("You help customers of a small online shop."),
    HumanMessage("Where is my order A17?"),
    AIMessage("Order A17 shipped on 3 March."),
]

Printing each turn

Loop over it. Each message carries a type naming its role, and text holds its words.

python
for message in conversation:
    print(f"{message.type:<7} {message.text}")

Printing a conversation end to end

The same pieces in one file, ready to run.

Example
from langchain.messages import AIMessage, HumanMessage, SystemMessage

conversation = [
    SystemMessage("You help customers of a small online shop."),
    HumanMessage("Where is my order A17?"),
    AIMessage("Order A17 shipped on 3 March."),
]

for message in conversation:
    print(f"{message.type:<7} {message.text}")

Reading the message fields

  • type names the role: a user turn is human, a model turn is ai, the rules turn is system.
  • text returns the words of the message, whatever the provider.

Sending the conversation to a model

The list is the model's memory. Send the whole list, add the reply to it, add the next question, and send it again:

ExampleAPI key
from langchain.chat_models import init_chat_model
from langchain.messages import HumanMessage, SystemMessage

model = init_chat_model("groq:openai/gpt-oss-120b", temperature=0)
conversation = [
    SystemMessage("You help customers of a small online shop. Order A17 shipped on 3 March. Order C40 is waiting for stock. Answer in one short sentence, using only these facts."),
    HumanMessage("Where is my order A17?"),
]
reply = model.invoke(conversation)
print(reply.text)

conversation.append(reply)
conversation.append(HumanMessage("And C40?"))
print(model.invoke(conversation).text)

The second question, "And C40?", makes sense to the model only because the first question and its answer travel with it.

The dictionary form still works

The same conversation as dictionaries prints much the same way. Each turn has a role and content; the classes above are the typed version of exactly this.

Example
conversation = [
    {"role": "system", "content": "You help customers of a small online shop."},
    {"role": "user", "content": "Where is my order A17?"},
]

for turn in conversation:
    print(f"{turn['role']:<7} {turn['content']}")

Printing a message readably

pretty_print shows a message with a header naming its type, which is easier to read once a conversation gets long.

Example
from langchain.messages import HumanMessage

HumanMessage("Where is my order A17?").pretty_print()

Plain dict vs message object

Plain dictMessage object
Role fieldrole: "user"type: "human"
Text fieldcontenttext
Works with every providerConverted firstYes, directly
Has pretty_printNoYes

When to use message objects

  • Holding a chat history you send to a model on every turn.
  • Passing a saved conversation between models without rewriting it.
Watch out. The role name and the type name differ: a user turn is user as a dict but human as a message, and a model turn is assistant versus ai. Match on type, not the dict role, once you switch to objects.
Try it yourself
  • Add a second HumanMessage asking about order B22 and print the list again.
  • Call pretty_print() on the AIMessage and compare its header with the human one.
  • Print SystemMessage("x").type and see which name it uses.

You understood something today that you didn't yesterday.