API Beginner easy · 4 min

user role: the human turn

What you will learn
The <code>user</code> role in OpenAI messages represents input from the human interacting with the model.

Why this matters

Every conversation with GPT models requires you to structure messages with roles. The <code>user</code> role is where your actual questions and prompts go: getting this wrong breaks the entire conversation flow.

Skip if: Don't use <code>user</code> role for system instructions (use <code>system</code> instead) or for continuing the model's own outputs (use <code>assistant</code> instead). If you're building a retrieval-augmented generation (RAG) system, you'll still use <code>user</code> for the query, but pair it with <code>system</code> context containing your documents.

Explanation

What it does: The user role tells the OpenAI API that a message is input from a human. It's one of three standard roles in chat completions: system (instructions), user (human input), and assistant (model output).

How it works: When you call client.chat.completions.create(), you pass a messages list containing dictionaries with a role field set to "user" and a content field with your actual text. The API reads this role to understand conversation context: it knows user messages are prompts it should respond to, not previous responses to repeat.

When to use it: Use user for every question, instruction, or request you want the model to process. In multi-turn conversations, every human input is a user message. This is the only role you control directly in most interactions.

Request code

python
import os
from openai import OpenAI

client = OpenAI(api_key=os.environ.get("OPENAI_API_KEY"))

response = client.chat.completions.create(
    model="gpt-4.1",
    messages=[
        {
            "role": "user",
            "content": "What is the capital of France?"
        }
    ]
)

print(response.choices[0].message.content)

Response shape

FieldDescription
choices [{choice_0}, ...]
choices[0].message.role "assistant"
choices[0].message.content "Paris is the capital of France."
usage.prompt_tokens 10
usage.completion_tokens 9

Field guide

choices[0].message.content

The text response from the model: this is what the model generated in reply to your user message

usage.prompt_tokens

Count of tokens in your user message (and any system/assistant messages): useful for cost tracking and understanding what counts toward your context window

Setup trap

Setting OPENAI_API_KEY in environment after instantiating the client won't work. The OpenAI() constructor reads the environment variable at instantiation time. Set your API key in the environment *before* importing or creating the client, or pass it explicitly: OpenAI(api_key="sk-...").

Cost

Each token in your <code>user</code> message counts toward prompt token costs (typically $0.50 per 1M tokens for GPT-4.1). Verbose user messages cost more. A 100-word question costs roughly 130 tokens; keep this in mind for high-volume applications.

Rate limits

Not typically hit on per-message basis, but if you're sending thousands of user messages per minute, you'll hit rate limits. Standard tier allows ~3,500 requests per minute.

Common gotcha

Forgetting that role is a required field. New developers often pass {"content": "question"} without "role": "user" and get a validation error. Every message dict must have both role and content.

Error recovery

pydantic_core._pydantic_core.ValidationError: 'role' field required
You omitted the 'role' key in your message dict. Change {"content": ".."} to {"role": "user", "content": "..."}
TypeError: 'NoneType' object is not subscriptable on response.choices[0]
The request succeeded but returned no choices (rare). Verify your message wasn't filtered by safety policies: check response.choices length before indexing.

Experienced dev note

The user role is stateless from the API perspective: each request is independent. If you want a multi-turn conversation, you must reconstruct the *entire* message history yourself and send it with every request. This means storing user/assistant exchanges in your application layer (database, session, vector store). Many junior developers expect the API to remember previous turns; it doesn't. You're building the conversation memory, not the API.

Check your understanding

You're building a chatbot. A user sends Message A, the model responds. Then the user sends Message B. In your next API call, what messages list structure do you send to maintain conversation context?

Show answer hint

You need to send all previous user and assistant messages, in order, plus the new user message. The API has no memory of your first request.

VERSION This pattern is stable in openai 1.0+. The deprecated 0.x SDK used openai.ChatCompletion.create() with identical message structure, so migration is mostly import changes.

Community Notes

No notes yetBe the first to share a version-specific fix or tip.