Agent SDK Quickstart: Build AI Agents in Python & TypeScript
The Anthropic Agent SDK transforms Claude from a chat interface into a production agent that manages its own loop, handles tool calls, and persists state across sessions. In this guide, you'll go from installation to a running GitHub PR analyzer in 5 minutes—then deepen into streaming, tool design, and deployment.
Understanding how the SDK dispatches on tool responses, maintains session context, and gates tool execution is the foundation for every production agent you'll build. We'll trace one request end-to-end, show the failure points, and give you a deployment checklist that catches the top 3 gotchas before production.
Messages API Fundamentals
The Agent SDK wraps the Anthropic Messages API—a simple contract: you send a list of messages, Claude sends back a single response object that may contain text, tool use, or an error. Tool use is not automatic; you read the response, call the tool in your own runtime, append the result to the message list, and send again.
The key insight: Claude does not have side effects. Your agent decides whether to accept tool outputs, retry, branch, or terminate. This is why the SDK is stateless by default and why session persistence requires you to store and restore the full message history.
Each request has a fixed context window, token limits, and token cost. Tools count toward the cost. Streaming reduces perceived latency but does not reduce actual token usage.
Quick reference
- Messages are stateful—order matters. A reordered history changes Claude's behavior.
- Tool use is explicit in the response; you handle the decision logic.
- Token cost is fixed per request; streaming only distributes it over time.
- Each session is independent; no memory shared between conversations.
- Errors (invalid tools, rate limits, timeouts) are your responsibility to catch and retry.
Remember this
The Messages API is a stateless request-response contract. Your agent owns the loop: read response, call tools, append results, repeat.
Running Your First Agent in 5 Minutes
Install the SDK, create a simple agent that echoes back the user's input with tool support, and run it locally. This is the minimal working agent—a foundation for everything else.
The flow is: user input → Claude response → check for tool use → if tool, call it → append result → loop. When Claude stops emitting tool use (stop_reason is 'end_turn'), the agent conversation ends. Your agent always respects stop_reason and never overrides Claude's decision to stop.
Quick reference
- Install:
pip install anthropic(Python) ornpm install @anthropic-ai/sdk(TypeScript). - Initialize a client with your API key from environment variables.
- Create a system prompt that describes the agent's role and available tools.
- Send the first user message and read the response in a loop.
- Respect stop_reason='end_turn'—never force more tool calls.
Remember this
A working agent: initialize client, set up tools, loop on messages, append tool results, exit on 'end_turn'.
Streaming Responses in Real-Time
Streaming distributes token emission over time, so the user sees Claude's response character-by-character instead of waiting for the full response. Streaming does not reduce token cost, but it feels faster and unblocks UI updates.
With streaming, tool use detection is the same: you collect events, assemble the response, check for tool_use blocks, and handle them. The difference is that text appears before you know if a tool follows. Streaming is compatible with tool calling but requires event aggregation.
Quick reference
- Use
stream=Truein Python orstream: truein TypeScript. - Collect events in a buffer; do not assume the stream order.
- Assemble the full response before checking for tool_use.
- Streaming works with tool calling; tools execute after the stream ends.
- Error handling: stream events can include error indicators; always validate the final response.
Remember this
Streaming makes responses feel instant but requires buffering to detect and handle tool calls. Always use get_final_message() to get the complete response.
Adding Custom Tools to Your Agent
Tools are how agents interact with the outside world: databases, APIs, file systems, or custom business logic. You define the tool contract (name, description, input schema), implement the handler, and ensure that tool outputs are valid JSON strings.
The key mechanism: Claude generates a tool_use block with the tool name and input. You match the name, call your handler, validate the output, and append it to messages. Claude cannot retry a failed tool call; you retry in your code and send the result back.
Tool names and descriptions must be clear and specific. If Claude picks the wrong tool, improve the description. If the input schema is ambiguous, Claude may call with missing fields; add defaults or catch the error.
Quick reference
- Define tools in an array with name, description, and JSON Schema for input_schema.
- Tool output must be a string (JSON-serializable for structured results).
- Match tool_use.name exactly; use a dict lookup for robustness.
- Always wrap tool execution in try-catch; errors become tool_result content.
- Tool descriptions are hints to Claude; specific descriptions = better tool selection.
Remember this
Tool handlers wrap your business logic. Treat Claude's tool request as a contract: if the request is valid, return a result; if not, return an error—never crash.
Session Persistence Patterns
A session is the full message history from start to finish. To resume an agent, you restore the history, append a new user message, and loop again. Persistence requires storing messages in a database or cache—not just in memory.
The pattern: serialize messages to JSON, store by session ID, retrieve on resume. Sessions are independent; they don't share context. If you need cross-session memory, you maintain a separate knowledge store and include relevant facts in the system prompt or a new message.
For long-running agents, checkpoint the message history after each tool call. This lets you resume from the last tool result, not the last message. It's also a recovery point if the agent fails mid-execution.
Quick reference
- Serialize messages with json.dumps() or JSON.stringify().
- Store by session ID in Redis, PostgreSQL, or S3.
- On resume, retrieve the full message history and continue.
- Session expiration: set a TTL or archive after N days.
- Checkpoints: save after tool execution for recovery.
Remember this
Persistence is: serialize → store by ID → retrieve on resume. Use a database or cache, set a TTL, and checkpoint after tool calls.
Real Example: GitHub PR Analyzer Agent
Put it all together: build an agent that analyzes a GitHub pull request by fetching the PR, diff, comments, and commits, then outputs a summary.
The agent has two tools: fetch_pr (gets PR metadata and diff) and fetch_comments (gets review comments). The system prompt tells Claude to analyze code quality, suggest improvements, and flag issues. After both tools return, Claude synthesizes the analysis and stops.
This example shows error handling (invalid PR ID), tool chaining (fetch PR, then comments), and how Claude naturally decides which tools to call and in what order. It's the pattern for any multi-tool agent.
Quick reference
- Define clear tool descriptions so Claude knows when to use each.
- Fetch data from real APIs; parse JSON responses carefully.
- If a tool fails, let Claude see the error and decide next steps.
- Include metadata (PR author, labels, draft status) to give Claude context.
- Stop criteria: when Claude has enough info and emits 'end_turn'.
Remember this
Multi-tool agents use tool chaining: Claude calls tools in sequence, you append results, and Claude synthesizes. Keep tool outputs small and focused.
Deployment Checklist
Before running your agent in production, verify these 5 items. Most outages come from missing API keys, unbounded message history, and no timeout handling.
1. API key: use environment variables, never hardcode. 2. Message history size: add a hard limit (e.g., max 100 messages or 50k tokens). If the agent runs too long, truncate old messages or create a new session. 3. Tool timeout: wrap tool calls in a timeout handler (e.g., 30 seconds). If the tool hangs, return an error to Claude. 4. Error recovery: catch rate limits (429), timeouts (408), and invalid responses (500). Retry with exponential backoff or fail gracefully. 5. Cost visibility: log token usage per request. Set a hard limit (e.g., stop if cumulative cost exceeds $1).
Quick reference
- Use
export ANTHROPIC_API_KEY=sk-...or.envfiles; never commit keys. - Implement a message history limit: if len(messages) > 100, remove the oldest user-assistant pair.
- Wrap tool calls: try/except with a timeout (Python:
signal.alarm(), TypeScript:Promise.race()). - Retry logic: exponential backoff (2s, 4s, 8s) up to 3 retries; then fail with context.
- Log usage:
response.usage.input_tokens + response.usage.output_tokensper request; track cumulative cost.
Remember this
Production readiness: env-based config, bounded history, timeouts, error recovery, and cost tracking. Test all 5 in staging before go-live.
Key takeaway
You now have a working agent that calls tools, persists state, and handles errors. The next level is adding tool validation (Claude is sometimes wrong), multi-modal inputs (images in the PR), and orchestration (multiple agents, each specialized). For those patterns, read the worktrees guide and dynamic workflows guide. Start with a simple agent, measure token usage and latency in production, then add complexity only when needed.
Polo Khan
Lead Author & Systems ArchitectSoftware engineer and distributed systems architect specializing in backend scalability, cloud-native infrastructure, databases, and AI engineering workflows. Author and maintainer of Core Concept Learning.
Related Articles
Explore this topic