HomeAgents & OrchestrationClaude Agent SDK Overview
intermediate15 min read· Module 9, Lesson 2

🧰Claude Agent SDK Overview

Build custom agents with Claude's official Agent SDK

What Is the Claude Agent SDK?

The Claude Agent SDK is Anthropic's official framework for building autonomous AI agents powered by Claude. Instead of writing raw API calls and manually managing conversation loops, the SDK gives you a structured, production-ready way to create agents that can use tools, maintain memory, handle errors, and run multi-turn conversations — all out of the box.

Think of it this way: the Claude API gives you the engine. The Agent SDK gives you the entire vehicle — steering, brakes, dashboard, and GPS included.


Why Use the Agent SDK Instead of Raw API Calls?

You can absolutely build agents using the Claude API directly. But here is what you would need to handle yourself:

  • Conversation loop management — tracking messages, sending them back, and deciding when to stop
  • Tool call parsing — extracting tool calls from responses, executing them, and feeding results back
  • Error recovery — retrying failed tool calls, handling rate limits, managing timeouts
  • Memory and state — persisting context across turns and sessions
  • Configuration — managing model selection, token limits, system prompts, and safety settings

The Agent SDK handles all of this for you. It provides a clean, declarative interface where you define your agent's behavior and the SDK manages the execution loop.

AspectRaw APIAgent SDK
Conversation loopYou build it manuallyBuilt-in agent loop
Tool executionYou parse and executeAutomatic dispatch
Error handlingCustom retry logicConfigurable retry policies
MemoryYou manage contextPluggable memory providers
Multi-turnManual message trackingAutomatic turn management
Setup timeHours to daysMinutes

Installation

The Agent SDK is available for both Python and TypeScript. Install it using your preferred package manager.

Python Installation

Terminal
# Using pip pip install claude-agent-sdk # Using poetry poetry add claude-agent-sdk # Using uv (recommended for new projects) uv add claude-agent-sdk

TypeScript Installation

Terminal
# Using npm npm install @anthropic-ai/agent-sdk # Using yarn yarn add @anthropic-ai/agent-sdk # Using pnpm pnpm add @anthropic-ai/agent-sdk

Environment Setup

Both installations require an Anthropic API key. Set it as an environment variable:

Terminal
export ANTHROPIC_API_KEY="sk-ant-your-key-here"

Or pass it directly when creating the agent (not recommended for production):

Python
# Python — passing the key directly from claude_agent_sdk import Agent agent = Agent(api_key="sk-ant-your-key-here")

Creating Your First Agent

Let us start with the simplest possible agent — one that takes a prompt and returns a response, with no tools and no memory.

Python — Basic Agent

Python
from claude_agent_sdk import Agent # Create a basic agent agent = Agent( model="claude-sonnet-4-20250514", system_prompt="You are a helpful assistant that answers questions concisely.", max_turns=1 ) # Run the agent with a single prompt result = agent.run("What is the capital of France?") print(result.output) # Output: The capital of France is Paris.

TypeScript — Basic Agent

TypeScript
const agent = new Agent({ model: "claude-sonnet-4-20250514", systemPrompt: "You are a helpful assistant that answers questions concisely.", maxTurns: 1, }); const result = await agent.run("What is the capital of France?"); console.log(result.output); // Output: The capital of France is Paris.

This is the foundation. Every agent you build starts here and adds capabilities on top.


Registering Tools

Tools are what make agents powerful. A tool is a function that the agent can call to interact with the outside world — search the web, read a file, query a database, call an API, or perform calculations.

Python — Defining and Registering Tools

Python
from claude_agent_sdk import Agent, tool @tool( name="get_weather", description="Get the current weather for a given city.", parameters={ "city": { "type": "string", "description": "The city name, e.g. 'London'" } } ) def get_weather(city: str) -> str: # In production, call a real weather API return f"The weather in {city} is 22C and sunny." @tool( name="calculate", description="Evaluate a mathematical expression and return the result.", parameters={ "expression": { "type": "string", "description": "A math expression like '2 + 2' or '144 ** 0.5'" } } ) def calculate(expression: str) -> str: import ast try: # Use ast.literal_eval for safe evaluation result = ast.literal_eval(expression) return str(result) except (ValueError, SyntaxError) as e: return f"Error: {e}" # Create agent with tools agent = Agent( model="claude-sonnet-4-20250514", system_prompt="You are a helpful assistant with access to weather and math tools.", tools=[get_weather, calculate], max_turns=10 ) result = agent.run("What is the weather in Tokyo, and what is 15% of 230?") print(result.output)

TypeScript — Defining and Registering Tools

TypeScript
const getWeather = defineTool({ name: "get_weather", description: "Get the current weather for a given city.", parameters: { type: "object", properties: { city: { type: "string", description: "The city name" }, }, required: ["city"], }, execute: async ({ city }) => { return `The weather in ${city} is 22C and sunny.`; }, }); const calculate = defineTool({ name: "calculate", description: "Evaluate a mathematical expression and return the result.", parameters: { type: "object", properties: { expression: { type: "string", description: "A math expression" }, }, required: ["expression"], }, execute: async ({ expression }) => { try { // Parse and compute safely const result = Number(expression); return String(result); } catch (e) { return `Error: ${e}`; } }, }); const agent = new Agent({ model: "claude-sonnet-4-20250514", systemPrompt: "You are a helpful assistant with weather and math tools.", tools: [getWeather, calculate], maxTurns: 10, }); const result = await agent.run("What is the weather in Tokyo, and what is 15% of 230?"); console.log(result.output);

The agent automatically decides when to use each tool, calls them, reads the results, and continues reasoning until it has a complete answer.


The Agent Loop

The agent loop is the core execution cycle of every agent. Understanding it is essential for debugging and optimizing your agents.

Here is how the loop works:

  1. Receive input — the user sends a message or the loop continues from a previous step
  2. Think — Claude processes the input and decides what to do next
  3. Act — if Claude decides to use a tool, the SDK executes the tool call automatically
  4. Observe — the tool result is fed back into the conversation
  5. Repeat — steps 2-4 repeat until Claude produces a final text response or the max turns limit is reached

Python — Observing the Agent Loop

Python
from claude_agent_sdk import Agent, tool @tool(name="search_docs", description="Search documentation.", parameters={ "query": {"type": "string", "description": "Search query"} }) def search_docs(query: str) -> str: return f"Found 3 results for '{query}': [Doc A, Doc B, Doc C]" agent = Agent( model="claude-sonnet-4-20250514", system_prompt="You are a documentation assistant.", tools=[search_docs], max_turns=5, verbose=True # Enables detailed logging of each loop iteration ) result = agent.run("Find documentation about authentication") # Access loop metadata print(f"Total turns used: {result.turns_used}") print(f"Tool calls made: {result.tool_calls_count}") print(f"Tokens used: {result.total_tokens}")

When verbose=True is set, you will see output like:

[Turn 1] User: Find documentation about authentication [Turn 1] Assistant: I will search the docs for authentication. [Turn 1] Tool call: search_docs(query="authentication") [Turn 1] Tool result: Found 3 results for 'authentication': [Doc A, Doc B, Doc C] [Turn 2] Assistant: I found 3 relevant documents about authentication... [Loop complete] Final response delivered in 2 turns.

Memory Integration

By default, agents are stateless — each call to agent.run() starts a fresh conversation. To maintain context across interactions, you can use the SDK's memory providers.

Python — Conversation Memory

Python
from claude_agent_sdk import Agent, ConversationMemory # Create a memory provider memory = ConversationMemory(max_messages=50) agent = Agent( model="claude-sonnet-4-20250514", system_prompt="You are a helpful assistant. Remember previous conversations.", memory=memory, max_turns=5 ) # First interaction result1 = agent.run("My name is Sarah and I work at Acme Corp.") print(result1.output) # Second interaction — the agent remembers result2 = agent.run("What is my name and where do I work?") print(result2.output) # Output: Your name is Sarah and you work at Acme Corp.

TypeScript — Conversation Memory

TypeScript
const memory = new ConversationMemory({ maxMessages: 50 }); const agent = new Agent({ model: "claude-sonnet-4-20250514", systemPrompt: "You are a helpful assistant. Remember previous conversations.", memory, maxTurns: 5, }); const result1 = await agent.run("My name is Sarah and I work at Acme Corp."); console.log(result1.output); const result2 = await agent.run("What is my name and where do I work?"); console.log(result2.output); // Output: Your name is Sarah and you work at Acme Corp.

Persistent Memory with File Storage

For production agents that need to persist memory across restarts:

Python
from claude_agent_sdk import Agent, FileMemory # Memory is saved to disk and survives restarts memory = FileMemory( path="./agent_memory.json", max_messages=200 ) agent = Agent( model="claude-sonnet-4-20250514", system_prompt="You are a project manager assistant.", memory=memory, max_turns=10 )

Multi-Turn Conversations

Multi-turn conversations allow you to have interactive, back-and-forth sessions with your agent — similar to a chat interface but with full tool access and memory.

Python — Interactive Multi-Turn Session

Python
from claude_agent_sdk import Agent, ConversationMemory agent = Agent( model="claude-sonnet-4-20250514", system_prompt="You are a code review assistant.", memory=ConversationMemory(), max_turns=5 ) # Simulate a multi-turn conversation conversation = [ "Review this function: def add(a, b): return a + b", "Can you suggest type hints for it?", "Now write unit tests for the improved version.", ] for message in conversation: result = agent.run(message) print(f"User: {message}") print(f"Agent: {result.output}") print("---")

TypeScript — Streaming Multi-Turn Session

TypeScript
const agent = new Agent({ model: "claude-sonnet-4-20250514", systemPrompt: "You are a code review assistant.", memory: new ConversationMemory(), maxTurns: 5, }); const messages = [ "Review this function: function add(a, b) { return a + b; }", "Can you suggest TypeScript types for it?", "Now write unit tests for the improved version.", ]; for (const message of messages) { const result = await agent.run(message, { stream: true }); process.stdout.write(`Agent: `); for await (const chunk of result.stream) { process.stdout.write(chunk); } console.log("\n---"); }

Error Handling

Production agents must handle errors gracefully. The SDK provides multiple layers of error handling.

Python — Error Handling Strategies

Python
from claude_agent_sdk import Agent, AgentError, ToolError, RateLimitError agent = Agent( model="claude-sonnet-4-20250514", system_prompt="You are a data analyst.", max_turns=10, retry_config={ "max_retries": 3, "retry_delay": 1.0, # seconds between retries "backoff_factor": 2.0, # exponential backoff multiplier "retryable_errors": [RateLimitError], } ) try: result = agent.run("Analyze the Q4 sales data.") print(result.output) except RateLimitError as e: print(f"Rate limited after retries: {e}") print(f"Retry after: {e.retry_after} seconds") except ToolError as e: print(f"Tool execution failed: {e.tool_name}{e.message}") except AgentError as e: print(f"Agent error: {e}")

TypeScript — Error Handling Strategies

TypeScript
Agent, AgentError, ToolError, RateLimitError, } from "@anthropic-ai/agent-sdk"; const agent = new Agent({ model: "claude-sonnet-4-20250514", systemPrompt: "You are a data analyst.", maxTurns: 10, retryConfig: { maxRetries: 3, retryDelay: 1000, backoffFactor: 2.0, retryableErrors: [RateLimitError], }, }); try { const result = await agent.run("Analyze the Q4 sales data."); console.log(result.output); } catch (error) { if (error instanceof RateLimitError) { console.error(`Rate limited. Retry after: ${error.retryAfter}s`); } else if (error instanceof ToolError) { console.error(`Tool ${error.toolName} failed: ${error.message}`); } else if (error instanceof AgentError) { console.error(`Agent error: ${error.message}`); } }

Configuration Options

The Agent SDK provides a wide range of configuration options to control agent behavior.

OptionPythonTypeScriptDefaultDescription
modelmodelmodelRequiredThe Claude model to use
system_promptsystem_promptsystemPromptNoneInstructions for the agent
toolstoolstools[]List of tools the agent can use
max_turnsmax_turnsmaxTurns10Maximum loop iterations
memorymemorymemoryNoneMemory provider for state persistence
max_tokensmax_tokensmaxTokens4096Maximum tokens per response
temperaturetemperaturetemperature1.0Response randomness (0.0 - 1.0)
verboseverboseverboseFalseEnable detailed logging
timeouttimeouttimeout120Timeout per API call in seconds
retry_configretry_configretryConfigDefault policyRetry behavior for errors
stop_sequencesstop_sequencesstopSequences[]Custom stop sequences
metadatametadatametadata{}Custom metadata for tracking

Full Working Example: Research Assistant Agent

Let us put everything together into a complete, working example — a research assistant that can search the web, take notes, and compile findings.

Python — Full Example

Python
from claude_agent_sdk import Agent, tool, ConversationMemory, AgentError # Define tools @tool( name="web_search", description="Search the web for information on a topic.", parameters={ "query": {"type": "string", "description": "The search query"} } ) def web_search(query: str) -> str: # In production, integrate with a real search API return f"Search results for '{query}': [Result 1: Overview of {query}, Result 2: Deep dive into {query}, Result 3: Latest news about {query}]" @tool( name="save_note", description="Save a research note for later reference.", parameters={ "title": {"type": "string", "description": "Note title"}, "content": {"type": "string", "description": "Note content"} } ) def save_note(title: str, content: str) -> str: # In production, save to a database or file print(f" [Note saved] {title}") return f"Note '{title}' saved successfully." @tool( name="read_notes", description="Read all saved research notes.", parameters={} ) def read_notes() -> str: return "Notes: [1] Topic overview, [2] Key findings, [3] Open questions" # Create the research assistant research_agent = Agent( model="claude-sonnet-4-20250514", system_prompt="""You are a thorough research assistant. When given a topic: 1. Search for information using web_search 2. Save important findings as notes using save_note 3. Review your notes using read_notes 4. Compile a structured summary with key findings, sources, and open questions. Always be thorough and cite your sources.""", tools=[web_search, save_note, read_notes], memory=ConversationMemory(max_messages=100), max_turns=15, max_tokens=4096, temperature=0.7, verbose=True, retry_config={ "max_retries": 3, "retry_delay": 1.0, "backoff_factor": 2.0, } ) # Run the agent try: result = research_agent.run( "Research the current state of quantum computing in 2025. " "Focus on recent breakthroughs, major players, and practical applications." ) print("\n=== Research Report ===") print(result.output) print(f"\nTurns used: {result.turns_used}") print(f"Tool calls: {result.tool_calls_count}") print(f"Total tokens: {result.total_tokens}") except AgentError as e: print(f"Research failed: {e}")

TypeScript — Full Example

TypeScript
Agent, defineTool, ConversationMemory, AgentError, } from "@anthropic-ai/agent-sdk"; const webSearch = defineTool({ name: "web_search", description: "Search the web for information on a topic.", parameters: { type: "object", properties: { query: { type: "string", description: "The search query" }, }, required: ["query"], }, execute: async ({ query }) => { return `Search results for '${query}': [Result 1, Result 2, Result 3]`; }, }); const saveNote = defineTool({ name: "save_note", description: "Save a research note for later reference.", parameters: { type: "object", properties: { title: { type: "string", description: "Note title" }, content: { type: "string", description: "Note content" }, }, required: ["title", "content"], }, execute: async ({ title }) => { console.log(` [Note saved] ${title}`); return `Note '${title}' saved successfully.`; }, }); const readNotes = defineTool({ name: "read_notes", description: "Read all saved research notes.", parameters: { type: "object", properties: {} }, execute: async () => { return "Notes: [1] Topic overview, [2] Key findings, [3] Open questions"; }, }); const researchAgent = new Agent({ model: "claude-sonnet-4-20250514", systemPrompt: `You are a thorough research assistant. When given a topic: 1. Search for information using web_search 2. Save important findings as notes using save_note 3. Review your notes using read_notes 4. Compile a structured summary.`, tools: [webSearch, saveNote, readNotes], memory: new ConversationMemory({ maxMessages: 100 }), maxTurns: 15, maxTokens: 4096, temperature: 0.7, verbose: true, retryConfig: { maxRetries: 3, retryDelay: 1000, backoffFactor: 2.0, }, }); async function main() { try { const result = await researchAgent.run( "Research the current state of quantum computing in 2025." ); console.log("\n=== Research Report ==="); console.log(result.output); console.log(`Turns used: ${result.turnsUsed}`); console.log(`Tool calls: ${result.toolCallsCount}`); } catch (error) { if (error instanceof AgentError) { console.error(`Research failed: ${error.message}`); } } } main();

Key Takeaways

  • The Claude Agent SDK is the official framework for building agents — it handles the loop, tools, memory, and errors for you
  • Installation is straightforward with pip or npm — just set your API key and you are ready
  • Tools are simple functions you register with the agent — the SDK handles calling them automatically
  • The agent loop (think, act, observe, repeat) runs until the agent has a final answer or hits the turn limit
  • Memory providers let you maintain context across conversations — in-memory for development, file-based for production
  • Error handling is built in with configurable retry policies and typed exceptions
  • Start simple (basic agent, no tools) and add capabilities incrementally — tools, then memory, then error handling