Site

System Prompts — Controlling Model Behavior

Tutorial 6.0  •  AI / Learn

6.0 What This Teaches

The system parameter gives you a way to set ground rules that persist across an entire conversation. This tutorial covers:

6.1 What a System Prompt Is

The system parameter in messages.create() sets persistent instructions that apply to every turn of the conversation. Unlike the messages list, the system prompt is not part of the alternating user/assistant role structure - it is separate, and the model treats it as a higher-level directive. Think of the system prompt as a contract you establish before the conversation starts: "you are this kind of assistant, you always output this format, you never do these things." The messages list then carries the actual conversation within that contract.

6.2 Setting a System Prompt

# system_basic.py - compare output with and without a system prompt.
import anthropic

client = anthropic.Anthropic()

user_message = "Write a function that reads a JSON file."

# Without system prompt - model chooses its own style.
r1 = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=256,
    messages=[{"role": "user", "content": user_message}]
)
print("--- No system prompt ---")
print(r1.content[0].text)

# With system prompt - model follows the constraints.
r2 = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=256,
    system=(
        "You are a senior Python developer. "
        "Always include type hints. "
        "Return only code with no prose."
    ),
    messages=[{"role": "user", "content": user_message}]
)
print("--- With system prompt ---")
print(r2.content[0].text)
The second response should be shorter, contain type hints, and have no surrounding explanation. The exact same user message produces different output because the system prompt changed the model's defaults.

6.3 Persona Setting

The system prompt can establish a persona that changes how the model communicates: technical depth, level of assumed knowledge, tone, and vocabulary all shift.
# persona.py - two personas, same question, different outputs.
import anthropic

client = anthropic.Anthropic()

question = "What is a pointer?"

expert_system = (
    "You are a C++ expert focused on performance and undefined behavior. "
    "Assume the reader is an experienced systems programmer."
)

beginner_system = (
    "You are a patient teacher explaining programming concepts to beginners "
    "who have no prior experience with low-level languages. "
    "Use analogies and avoid jargon."
)

for label, system in [("Expert", expert_system), ("Beginner", beginner_system)]:
    r = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=256,
        system=system,
        messages=[{"role": "user", "content": question}]
    )
    print(f"--- {label} persona ---")
    print(r.content[0].text)
    print()
The expert persona will discuss memory addresses, alignment, and undefined behavior. The beginner persona will use an analogy like "a pointer is like a street address for your data." Same model, same question, fundamentally different output because the audience expectation is different.

6.4 Output Format Constraints

When you need structured output consistently across multiple turns, put the format requirement in the system prompt rather than repeating it in every user message.
# json_system.py - enforce JSON output via system prompt.
import anthropic
import json

client = anthropic.Anthropic()

system = (
    "Always respond with valid JSON. No other text before or after the JSON. "
    "Every response must have exactly two keys: "
    "'answer' (a string) and 'confidence' ('high', 'medium', or 'low')."
)

questions = [
    "What does the `with` statement do in Python?",
    "Is Python dynamically typed?",
]

for q in questions:
    r = client.messages.create(
        model="claude-sonnet-4-6",
        max_tokens=256,
        system=system,
        messages=[{"role": "user", "content": q}]
    )
    data = json.loads(r.content[0].text)
    print(f"Q: {q}")
    print(f"A: {data['answer']}")
    print(f"Confidence: {data['confidence']}")
    print()
Without the system prompt, the model might return JSON for the first question and plain prose for the second. The system prompt makes the format consistent across every turn.

6.5 Scope: System vs User

The system prompt sets ground rules; user messages make individual requests within those rules. The model treats system instructions as higher-priority than user requests in most cases.
LayerPurposePersists across turns?
system Persona, output format, behavioral guardrails Yes - set once, applies to the whole conversation
user message The specific task for this turn No - each message is a new request
assistant message The model's previous reply (for context in multi-turn) Only if you include it in the messages list
If a user message contradicts the system prompt - for example, the system prompt says "return only code" but the user says "explain what the code does" - the model usually follows the user message. Guardrails work best for format and persona, not for preventing the user from overriding them.

6.6 Example: Code Reviewer Persona

# code_reviewer.py - system prompt makes Claude act as a strict code reviewer.
import anthropic

client = anthropic.Anthropic()

system = """\
You are a strict Python code reviewer. When shown code, you always check for:
1. Security issues (e.g., shell injection, hardcoded secrets)
2. Missing type hints on function parameters and return values
3. Missing error handling for I/O operations
For each issue found, state the line number (if visible), the problem, and a fix.
If no issues are found in a category, say "None found."
"""

code_to_review = """\
def load_config(path):
    import json
    f = open(path)
    return json.load(f)
"""

r = client.messages.create(
    model="claude-sonnet-4-6",
    max_tokens=512,
    system=system,
    messages=[{"role": "user", "content": f"Review this code:\n\n{code_to_review}"}]
)

print(r.content[0].text)
The reviewer will flag: missing type hints on path and the return type, the file handle that is never closed (no with statement), and the absence of a FileNotFoundError handler. All of these come from the system prompt's checklist, not from a user request.

6.7 Exercise

Exercise Write a script that sends the same user message - "Write a function to read a JSON file" - twice: once with no system prompt, and once with: system="You are a security-conscious Python developer. Always validate inputs and handle FileNotFoundError." Print both responses and compare them. Note whether the second response includes input validation, a with statement for the file, and a try/except block that catches FileNotFoundError.

6.8 Common Mistakes

Putting format instructions in the user message instead of system

If you write "return only JSON" in the user message on turn 1, the model follows it. On turn 2, you send a new user message without that instruction and the model may revert to prose. Format constraints belong in the system prompt so they apply to every turn automatically.

Contradicting the system prompt in user messages

If the system prompt says "return only code" and the user message says "explain this code line by line", the model faces a conflict. Behavior varies: sometimes the system prompt wins, sometimes the user message does. Keep user messages consistent with the system prompt to get predictable results.

Making the system prompt so long it eats into the context window

The system prompt counts as input tokens on every single call. A 2,000-token system prompt in a 10-turn conversation adds 20,000 tokens to your total input cost. Keep system prompts concise - three to five clear sentences is usually enough to establish persona and format.

6.9 Key Terms

TermMeaning
system promptThe text passed in the system parameter; sets persistent instructions for the whole conversation
system parameterThe system= argument in messages.create()
personaA role description in the system prompt that changes how the model communicates
output constraintA format rule in the system prompt, such as "always return valid JSON"
behavioral guardrailAn instruction that restricts what the model will or will not do
context window budgetThe portion of the context window consumed by the system prompt on every call