You know the model runs on a server, you talk to it through an API, and you prove who pays with an API key.
Now the full trip in detail: what your program sends, what comes back, and how to read it.
What a turn is
Imagine your program wants the model to answer: What is 2 + 2?
One full trip looks like this:
- Your program builds a request — the text for the model, plus a few settings
- It sends that request to the server, with your API key as proof
- The server runs the model
- Your program gets a response — the reply text, plus a little extra info
That full trip is one turn.
Think of a turn like one back-and-forth: you ask once, you get one answer package back. Later you will stack many turns. First lock this single trip in your head.
Your program Server
┌──────────────┐ request ┌──────────────┐
│ prompt + key │ ──────────────▶ │ model runs │
│ │ ◀────────────── │ │
└──────────────┘ response └──────────────┘Request and response as JSON
Your program does not “talk” to the server in casual English over the wire.
It sends structured text — labeled fields the server can read. That format is usually JSON: text shaped like a form, with names and values.
Request — what you send
Here is a small, complete request for our 2 + 2 question:
{
"model": "some-model",
"messages": [
{
"role": "user",
"content": "What is 2 + 2?"
}
]
}
Walk each field:
| Field | In this example | What it means |
|---|---|---|
model |
"some-model" |
Which brain / size to run on the server |
messages |
an array (a list) | The text the model should see for this turn |
role |
"user" |
Who this piece of text is from — here, you |
content |
"What is 2 + 2?" |
The actual words |
Your API key travels with the request too, but usually outside this JSON — in a separate header the server checks first. The JSON is the prompt. The API key is the proof.
Companies rename fields (messages vs contents, and so on). The jobs stay the same: pick a model, send text, say who said it.
Response — what comes back
The server does not return only a bare string. It returns another JSON object. A simplified shape:
{
"message": {
"role": "assistant",
"content": "2 + 2 is 4."
},
"finish_reason": "stop",
"usage": {
"input_tokens": 10,
"output_tokens": 6
}
}
Walk each part:
| Field | In this example | What it means |
|---|---|---|
role |
"assistant" |
This text is from the model, not from you |
content |
"2 + 2 is 4." |
The reply you usually show or use in your program |
finish_reason |
"stop" |
Why the model stopped writing |
usage |
10 in, 6 out |
How much work this turn used (in tokens — more below) |
Real company responses wrap these ideas in slightly different nesting. Your job as a reader of the response is always the same: find the reply text, why it stopped, and usage.
Put the whole turn in one glance:
REQUEST (JSON) RESPONSE (JSON)
model + messages ──────▶ assistant content
(+ API key beside it) ◀── finish_reason + usage
For this chapter, role: "user" means your question and role: "assistant" means the model’s reply. That is enough. (More roles come later when conversations get longer.)
Limits and dials
The tiny request above is enough for a first mental model. Real requests often add limits and dials, for example:
{
"model": "some-model",
"messages": [
{ "role": "user", "content": "Explain gravity in two sentences." }
],
"max_tokens": 60
}
max_tokens (names vary) means: do not let the reply grow past this much work.
Why it matters: without a limit, a long reply can cost more and take longer. With a limit that is too small, the reply can stop mid-thought — and finish_reason will often tell you that happened.
You do not need every dial today. Remember the pattern: prompt + settings, not the question alone.
Reading the response
Most beginners only print message.content. That works until it doesn’t.
Take two different finish reasons with the same kind of question:
Finished normally
{
"message": { "role": "assistant", "content": "Gravity pulls masses together." },
"finish_reason": "stop"
}
Hit a length limit
{
"message": { "role": "assistant", "content": "Gravity pulls masses together. On Earth, it make" },
"finish_reason": "length"
}
Same request idea. Different endings. If you only read the text, the second one looks like a weird half-sentence. If you also read finish_reason, you know the model was cut off.
Usage is the other field to notice. It is how billing and limits connect to this single turn.
Tokens and cost
You already know the model works in tokens — small pieces of text.
On a turn, usage usually splits into:
- Input tokens — pieces in what you sent (your prompt, and any other text in the request)
- Output tokens — pieces in what the model wrote
You usually pay for both.
Use the first example’s numbers:
"usage": {
"input_tokens": 10,
"output_tokens": 6
}
Rough story:
- Sending
"What is 2 + 2?"(plus a little overhead) cost about 10 input tokens - Writing
"2 + 2 is 4."cost about 6 output tokens - This turn’s work is 16 tokens total
Now change the question to a long paragraph, or ask for a long essay back. Both numbers climb. Longer prompts and longer replies cost more.
You do not need to count tokens by hand. You do need to know why usage exists in the response: it is the meter for this turn.
Each call forgets
Most model APIs start fresh every time.
The server does not keep a private memory of your last request. If you want the model to use earlier text, you must send that text again in the next request.
See it with two separate turns.
Turn 1 — you introduce a name
{
"model": "some-model",
"messages": [
{ "role": "user", "content": "My cat is named Mango." }
]
}
Turn 1 — reply (shortened)
{
"message": {
"role": "assistant",
"content": "Got it — your cat is named Mango."
}
}
Turn 2 — a new call, only the new question
{
"model": "some-model",
"messages": [
{ "role": "user", "content": "What is my cat's name?" }
]
}
Turn 2 did not include the Mango sentence. The server has no leftover memory from Turn 1. The model may guess, invent, or say it does not know — because that fact was never in this request.
So for one turn: there is no memory. Conversation memory is something you build later by sending history on purpose.
Ready for a real call
You now have the full picture for one turn: build a request, send it with your API key, read the response (text, finish reason, usage).
Next you will do that from a real program — same shape, live server.