client.messages.create() call. This tutorial walks through every major feature with working code, from your first "Hello!" to a full tool-use loop.
Prerequisites
You need Python 3.8 or later and an Anthropic API key. If you do not have a key yet, follow the step-by-step guide at How to Get a Claude API Key — it takes about two minutes.
export ANTHROPIC_API_KEY="sk-ant-..." # add to ~/.bashrc or ~/.zshrc
Installation and First Call
pip install anthropic
Make your first API call — the SDK reads ANTHROPIC_API_KEY automatically:
from anthropic import Anthropic
client = Anthropic()
msg = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Hello!"}],
)
print(msg.content[0].text)
The Messages API
Every call to client.messages.create() accepts the same core parameters:
-
model — the Claude model to use (e.g. "claude-sonnet-4-6")
-
max_tokens — the upper limit on output tokens
-
messages — a list of turn objects with role ("user" or "assistant") and content
-
system — an optional system prompt string
The content field can be a plain string or a list of content blocks — objects with a type field ("text", "image", "tool_use", "tool_result"). The response exposes msg.content[0].text, msg.stop_reason, and msg.usage for token counts.
Your First Chat App
The Messages API is stateless. Append each exchange to the messages list to maintain conversation history:
from anthropic import Anthropic
client = Anthropic()
conversation = []
print("Chat with Claude (type 'quit' to exit)\n")
while True:
user_input = input("You: ").strip()
if user_input.lower() in ("quit", "exit", "q"):
break
if not user_input:
continue
conversation.append({"role": "user", "content": user_input})
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=conversation,
)
assistant_text = response.content[0].text
conversation.append({"role": "assistant", "content": assistant_text})
print(f"Claude: {assistant_text}\n")
Streaming Responses
Use client.messages.stream() to display tokens as they arrive:
from anthropic import Anthropic
client = Anthropic()
with client.messages.stream(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[{"role": "user", "content": "Explain quantum entanglement simply."}],
) as stream:
for text in stream.text_stream:
print(text, end="", flush=True)
print()
Call stream.get_final_message() after the loop if you need the complete Message object.
Analyzing Images with Vision
Pass images as base64-encoded content blocks:
import base64
from anthropic import Anthropic
client = Anthropic()
with open("screenshot.png", "rb") as f:
image_data = base64.standard_b64encode(f.read()).decode("utf-8")
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
messages=[
{
"role": "user",
"content": [
{
"type": "image",
"source": {
"type": "base64",
"media_type": "image/png",
"data": image_data,
},
},
{
"type": "text",
"text": "Describe what you see in this image.",
},
],
}
],
)
print(response.content[0].text)
Supported types: image/jpeg, image/png, image/gif, image/webp. You can also pass images by URL using "type": "url".
Tool Use (Function Calling)
Define tools with JSON Schema, handle stop_reason == "tool_use", and return results as tool_result blocks:
from anthropic import Anthropic
client = Anthropic()
tools = [
{
"name": "get_weather",
"description": "Get the current weather for a city.",
"input_schema": {
"type": "object",
"properties": {
"city": {"type": "string", "description": "City name, e.g. 'Kyiv'"},
},
"required": ["city"],
},
}
]
def get_weather(city: str) -> str:
return f"The weather in {city} is 22°C and sunny."
messages = [{"role": "user", "content": "What's the weather in Kyiv?"}]
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
tools=tools,
messages=messages,
)
if response.stop_reason == "tool_use":
tool_block = next(b for b in response.content if b.type == "tool_use")
tool_result = get_weather(**tool_block.input)
messages.append({"role": "assistant", "content": response.content})
messages.append({
"role": "user",
"content": [
{
"type": "tool_result",
"tool_use_id": tool_block.id,
"content": tool_result,
}
],
})
final = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
tools=tools,
messages=messages,
)
print(final.content[0].text)
else:
print(response.content[0].text)
System Prompts
The system parameter sets a persistent instruction outside the turn list:
from anthropic import Anthropic
client = Anthropic()
response = client.messages.create(
model="claude-sonnet-4-6",
max_tokens=1024,
system=(
"You are a senior Python engineer. "
"Always respond with concise, production-quality code. "
"Prefer explicit error handling and type hints."
),
messages=[{"role": "user", "content": "Write a function to retry a failed HTTP request."}],
)
print(response.content[0].text)
Tips: be specific about format, state constraints positively, keep the system prompt stable across turns, and use prompt caching on long system prompts to cut costs.
Choosing a Model
-
claude-opus-4-7 — most capable; best for complex reasoning and multi-step agentic tasks
-
claude-sonnet-4-6 — balanced quality, cost, and speed; the right default for most apps
-
claude-haiku-4-5 — fastest and cheapest; ideal for high-volume, real-time, or extraction tasks
All three support the same API surface. Start with claude-sonnet-4-6 and adjust from there.
Summary
- Install with
pip install anthropic; the SDK reads ANTHROPIC_API_KEY automatically
- Every feature goes through
client.messages.create()
- Multi-turn chat: append each exchange to the
messages list
- Streaming: use
client.messages.stream() and iterate stream.text_stream
- Vision: pass base64-encoded images as content blocks
- Tool use: define tools with JSON Schema, handle
tool_use stop reason, return tool_result blocks
- System prompts: use the
system parameter outside the messages list
- Default to
claude-sonnet-4-6; upgrade to Opus for quality, downgrade to Haiku for speed
Further reading: