Originally published at kalyna.pro
The Claude API gives you direct access to Anthropic's language models from any Python application. Whether you want to generate text, analyze images, stream responses token by token, or wire up tools so Claude can call your own functions — all of it goes through the same 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 withrole("user"or"assistant") andcontent -
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 readsANTHROPIC_API_KEYautomatically - Every feature goes through
client.messages.create() - Multi-turn chat: append each exchange to the
messageslist - Streaming: use
client.messages.stream()and iteratestream.text_stream - Vision: pass base64-encoded images as content blocks
- Tool use: define tools with JSON Schema, handle
tool_usestop reason, returntool_resultblocks - System prompts: use the
systemparameter outside the messages list - Default to
claude-sonnet-4-6; upgrade to Opus for quality, downgrade to Haiku for speed
Further reading:
Top comments (0)