Claude SDK Essentials
> "Claude SDK" spans two related things: the Anthropic Messages API (for direct model calls) and the Claude Agent SDK (for building custom agents that loop over tools). This notebook covers both — what they're for, and how they differ from just calling an API endpoint.
What is the Claude SDK?
Anthropic ships two layers for building with Claude, and it's worth being precise about which one a task needs:
1. The Messages API — the direct, low-level way to send a conversation to Claude and get a response. This is the primitive: one call in, one response out, with support for tool use, vision, and structured system prompts.
2. The Claude Agent SDK — a higher-level SDK (Python/TypeScript) that wraps the Messages API with an agentic loop: it handles running tools, feeding results back to the model, and repeating until the model produces a final answer, without you hand-writing that loop yourself. It's the same loop that powers Claude Code, made available as a building block for custom agents.
Use the Messages API when you want direct control over a single call or a custom loop. Use the Agent SDK when you're building an agent that needs to plan, call tools repeatedly, and manage that loop's state — and you don't want to reimplement it from scratch.
The Messages API
import anthropic
client = anthropic.Anthropic()
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
system="You are a concise technical writing assistant.",
messages=[
{"role": "user", "content": "Summarize what a message queue does, in two sentences."}
],
)
print(response.content[0].text)
Key parameters worth knowing:
system — a dedicated system prompt field (not part of the messages list), used for role, tone, and constraintsmax_tokens — required; caps the length of the responsemessages — a list of user/assistant turns; Claude has no implicit memory, so the full conversation is sent every callTool Use with the Messages API
Claude can request that your application run a tool, similarly to OpenAI's function calling — you define a tool schema, Claude decides when to call it, and your code executes it and returns the result.
tools = [{
"name": "get_order_status",
"description": "Look up the status of a customer order by ID",
"input_schema": {
"type": "object",
"properties": {"order_id": {"type": "string"}},
"required": ["order_id"],
},
}]
response = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
tools=tools,
messages=[{"role": "user", "content": "Where's my order #A1042?"}],
)
if response.stop_reason == "tool_use":
tool_call = next(b for b in response.content if b.type == "tool_use")
result = get_order_status(tool_call.input["order_id"])
# send the tool result back so Claude can produce a final answer
follow_up = client.messages.create(
model="claude-sonnet-5",
max_tokens=1024,
tools=tools,
messages=[
{"role": "user", "content": "Where's my order #A1042?"},
{"role": "assistant", "content": response.content},
{"role": "user", "content": [{
"type": "tool_result",
"tool_use_id": tool_call.id,
"content": str(result),
}]},
],
)
The Agent SDK: The Same Loop, Pre-Built
Writing that tool-call → execute → feed-back-in loop by hand gets repetitive once an agent needs to call several tools across several turns. The Agent SDK provides that loop out of the box, plus permission handling, file/bash tool access, and hooks for custom behavior — the same architecture behind Claude Code, exposed as a library.
from claude_agent_sdk import query
async for message in query(
prompt="Find and fix the failing test in this repo",
options={"allowed_tools": ["Read", "Edit", "Bash"]},
):
print(message)
This is the right layer when you're building something agent-shaped — a coding assistant, a research agent, an ops bot — rather than a single classification or extraction call.
Common Use Cases
Best Practices
system prompt focused on role and constraints; put task-specific instructions in the user turnmax_tokens deliberately; a low cap can silently truncate a long structured response