Site

Messages — Conversation Structure

Tutorial 3.0  •  AI / Learn

3.0 What This Teaches

Every call to messages.create takes a list of messages that represents the conversation so far. Understanding the structure of that list is how you build multi-turn conversations and control what the model knows. This tutorial covers:

3.1 The Messages List

The messages parameter is a list of dicts. Each dict has two keys:
messages = [
    {"role": "user",      "content": "What is a Python list?"},
    {"role": "assistant", "content": "A list is an ordered, mutable collection..."},
    {"role": "user",      "content": "How do I append to one?"},
]
The list must start with a user message and roles must strictly alternate: user, assistant, user, assistant, and so on. Sending two consecutive user messages without an assistant turn in between is an API error.

3.2 A Single-Turn Call

A single question is still a list - it just has one element:
# single_turn.py - one question, one answer.
import anthropic

client = anthropic.Anthropic()

response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=256,
    messages=[
        {"role": "user", "content": "What is a Python list?"}
    ]
)

print(response.content[0].text)

3.3 Building a Multi-Turn Conversation

To continue the conversation, append the assistant's reply and your next question, then call messages.create again with the full updated list:
# multi_turn.py - two-turn conversation.
import anthropic

client = anthropic.Anthropic()

messages = [
    {"role": "user", "content": "What is a Python list?"}
]

# First turn
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=256,
    messages=messages
)
answer1 = response.content[0].text
print("Turn 1:", answer1)

# Append assistant reply, then ask a follow-up
messages.append({"role": "assistant", "content": answer1})
messages.append({"role": "user",      "content": "How do I append to one?"})

# Second turn - passes full history so the model has context
response = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=256,
    messages=messages
)
answer2 = response.content[0].text
print("Turn 2:", answer2)
On the second call, the model sees both the original question and its own first answer. That is how it knows what "one" refers to in the follow-up question.

3.4 No Built-In Memory

The API is stateless. Each call is completely independent. If you start a new call without passing the previous messages, the model has no knowledge of prior turns:
# Each of these calls knows nothing about the other.
response1 = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=64,
    messages=[{"role": "user", "content": "My name is Alex."}]
)

response2 = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=64,
    messages=[{"role": "user", "content": "What is my name?"}]
)
# response2 will say it does not know - there is no shared state.
Your application is responsible for storing and replaying the conversation history on every request. This is exactly what the Chat Loop application (Tutorial A1) does.

3.5 Inspecting the History

# Print the conversation so far in a readable format.
for msg in messages:
    role = msg["role"].upper()
    print(f"[{role}] {msg['content'][:80]}")
    print()
This pattern is useful for debugging: it shows exactly what the model receives, which is always the full conversation up to that point.

3.6 Exercise

Exercise Write a script that carries out a three-turn conversation: ask the model to explain recursion, then ask for a code example, then ask it to add a base-case comment to that example. Append each response to the messages list before sending the next turn. Print all three answers.

3.7 Common Mistakes

Two consecutive user messages

messages = [
    {"role": "user", "content": "Hello"},
    {"role": "user", "content": "Are you there?"},  # API error
]
Roles must strictly alternate. Insert an assistant message between two user messages, or merge them into one user message.

Forgetting to append the assistant reply before the next user turn

messages.append({"role": "user", "content": "Follow-up"})  # missing assistant turn
If you skip the assistant append, the messages list has two consecutive user entries, causing an API error. Always append the response text as an assistant message before adding the next user message.

Mutating the messages list across unrelated requests

If you reuse the same messages list for two different conversations, they share history. Start a fresh list for each independent conversation.

3.8 Key Terms

TermMeaning
role"user" for human turns, "assistant" for model turns
contentThe text of one turn in the conversation
multi-turn conversationA call where messages contains more than one exchange
stateless APIEach request is independent; the server stores no session between calls
conversation historyThe full list of prior messages your application maintains and passes on each call
alternating rolesThe required pattern: user, assistant, user, assistant...