Syllabus Lesson 113 of 239 · Calling a Real LLM
Calling a Real LLM

Build the Messages Payload

Every call to a chat model is just an HTTP request carrying a JSON body, and getting that body right is the first thing real code does. Across this module you will build the exact dicts and lists the Anthropic API consumes and returns, by hand, with plain Python -> so the whole thing runs offline and can be graded. Each lesson also shows you the one real line you would run with an API key on your own machine. The shapes you build here ARE the shapes that go over the wire.

With the SDK installed, sending a message looks like this (illustrative only -> we do not call the network here):

import anthropic
client = anthropic.Anthropic()   # reads ANTHROPIC_API_KEY from the environment
resp = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=1024,
    system="You are a terse assistant.",
    messages=[{"role": "user", "content": "Hello"}],
)

Notice the shape: system is its own top-level field (it is NOT a message), and messages is a list of turns, each a dict with a role and content. The only valid roles inside messages are "user" and "assistant", alternating like a conversation. A common bug is trying to smuggle the instructions in as a {"role": "system", ...} turn the way some other APIs allow -> the Anthropic API rejects that, because the system prompt has its own slot.

You are building build_request(system, messages, model="claude-sonnet-4-6", max_tokens=1024). It returns the request dict:

{"model": ..., "max_tokens": ..., "system": ..., "messages": [...]}
  • Copy model and max_tokens straight through, and put system in its own key.
  • For each turn in messages, validate the role is exactly "user" or "assistant". Anything else (a "system" turn, a typo like "User", a missing role) must raise a ValueError -> fail loudly before you ever hit the API and waste a round trip.
  • Return the turns in messages unchanged (same order, same content).

That last **req below is the real call you would make with the dict you just built:

resp = client.messages.create(**build_request("Be brief.", history))

Build it so two different (system, messages) pairs produce two different request dicts, and a turn with a role other than user or assistant raises.

Your turn

Write build_request(system, messages, model="claude-sonnet-4-6", max_tokens=1024) that returns the Anthropic-shape request dict {"model", "max_tokens", "system", "messages"}. messages is a list of {"role", "content"} turns. Validate every role is exactly "user" or "assistant" and raise a ValueError on anything else (including a smuggled "system" turn). Return the turns unchanged.

Spotted a problem in this lesson? Report it

Code · runs in your browser
Output