参考数据:Agent SDK 模式 — Python
Data: Agent SDK patterns — Python
v2.1.63Python Agent SDK patterns including custom tools, hooks, subagents, MCP integration, and session resumption
Agent SDK 模式 — Python
基础 Agent
python
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
async for message in query(
prompt="Explain what this repository does",
options=ClaudeAgentOptions(
cwd="/path/to/project",
allowed_tools=["Read", "Glob", "Grep"]
)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)自定义工具
自定义工具需要一个 MCP 服务器。使用 ClaudeSDKClient 以获得完全控制,或者通过 mcp_servers 将服务器传递给 query()。
python
import anyio
from claude_agent_sdk import (
tool,
create_sdk_mcp_server,
ClaudeSDKClient,
ClaudeAgentOptions,
AssistantMessage,
TextBlock,
)
@tool("get_weather", "Get the current weather for a location", {"location": str})
async def get_weather(args):
location = args["location"]
return {"content": [{"type": "text", "text": f"The weather in {location} is sunny and 72°F."}]}
server = create_sdk_mcp_server("weather-tools", tools=[get_weather])
async def main():
options = ClaudeAgentOptions(mcp_servers={"weather": server})
async with ClaudeSDKClient(options=options) as client:
await client.query("What's the weather in Paris?")
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(block.text)
anyio.run(main)Hooks
工具使用后 Hook
在任何编辑后记录文件更改:
python
import anyio
from datetime import datetime
from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher, ResultMessage
async def log_file_change(input_data, tool_use_id, context):
file_path = input_data.get('tool_input', {}).get('file_path', 'unknown')
with open('./audit.log', 'a') as f:
f.write(f"{datetime.now()}: modified {file_path}\n")
return {}
async def main():
async for message in query(
prompt="Refactor utils.py to improve readability",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Write"],
permission_mode="acceptEdits",
hooks={
"PostToolUse": [HookMatcher(matcher="Edit|Write", hooks=[log_file_change])]
}
)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)子 Agent
python
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition, ResultMessage
async def main():
async for message in query(
prompt="Use the code-reviewer agent to review this codebase",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Glob", "Grep", "Agent"],
agents={
"code-reviewer": AgentDefinition(
description="Expert code reviewer for quality and security reviews.",
prompt="Analyze code quality and suggest improvements.",
tools=["Read", "Glob", "Grep"]
)
}
)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)MCP 服务器集成
浏览器自动化 (Playwright)
python
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
async for message in query(
prompt="Open example.com and describe what you see",
options=ClaudeAgentOptions(
mcp_servers={
"playwright": {"command": "npx", "args": ["@playwright/mcp@latest"]}
}
)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)数据库访问 (PostgreSQL)
python
import os
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
async for message in query(
prompt="Show me the top 10 users by order count",
options=ClaudeAgentOptions(
mcp_servers={
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {"DATABASE_URL": os.environ["DATABASE_URL"]}
}
}
)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)权限模式
python
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
# 默认:在执行危险操作前提示
async for message in query(
prompt="Delete all test files",
options=ClaudeAgentOptions(
allowed_tools=["Bash"],
permission_mode="default" # 删除前会提示
)
):
pass
# 计划模式:agent 在做出更改前创建一个计划
async for message in query(
prompt="Refactor the auth system",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit"],
permission_mode="plan"
)
):
pass
# 接受编辑:自动接受文件编辑
async for message in query(
prompt="Refactor this module",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit"],
permission_mode="acceptEdits"
)
):
pass
# 绕过模式:跳过所有提示(谨慎使用)
async for message in query(
prompt="Set up the development environment",
options=ClaudeAgentOptions(
allowed_tools=["Bash", "Write"],
permission_mode="bypassPermissions",
allow_dangerously_skip_permissions=True
)
):
pass
anyio.run(main)错误恢复
python
import anyio
from claude_agent_sdk import (
query,
ClaudeAgentOptions,
CLINotFoundError,
CLIConnectionError,
ProcessError,
ResultMessage,
)
async def run_with_recovery():
try:
async for message in query(
prompt="Fix the failing tests",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Bash"],
max_turns=10
)
):
if isinstance(message, ResultMessage):
print(message.result)
except CLINotFoundError:
print("Claude Code CLI not found. Install with: pip install claude-agent-sdk")
except CLIConnectionError as e:
print(f"Connection error: {e}")
except ProcessError as e:
print(f"Process error: {e}")
anyio.run(run_with_recovery)会话恢复
python
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage, SystemMessage
async def main():
session_id = None
# 首次查询:捕获会话 ID
async for message in query(
prompt="Read the authentication module",
options=ClaudeAgentOptions(allowed_tools=["Read", "Glob"])
):
if isinstance(message, SystemMessage) and message.subtype == "init":
session_id = message.session_id
# 使用首次查询的完整上下文恢复会话
async for message in query(
prompt="Now find all places that call it", # "it" 指代 auth 模块
options=ClaudeAgentOptions(resume=session_id)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)自定义系统提示
python
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
async for message in query(
prompt="Review this code",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Glob", "Grep"],
system_prompt="""You are a senior code reviewer focused on:
1. Security vulnerabilities
2. Performance issues
3. Code maintainability
Always provide specific line numbers and suggestions for improvement."""
)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)英文原文 / English Original
Agent SDK Patterns — Python
Basic Agent
python
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
async for message in query(
prompt="Explain what this repository does",
options=ClaudeAgentOptions(
cwd="/path/to/project",
allowed_tools=["Read", "Glob", "Grep"]
)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)Custom Tools
Custom tools require an MCP server. Use ClaudeSDKClient for full control, or pass the server to query() via mcp_servers.
python
import anyio
from claude_agent_sdk import (
tool,
create_sdk_mcp_server,
ClaudeSDKClient,
ClaudeAgentOptions,
AssistantMessage,
TextBlock,
)
@tool("get_weather", "Get the current weather for a location", {"location": str})
async def get_weather(args):
location = args["location"]
return {"content": [{"type": "text", "text": f"The weather in {location} is sunny and 72°F."}]}
server = create_sdk_mcp_server("weather-tools", tools=[get_weather])
async def main():
options = ClaudeAgentOptions(mcp_servers={"weather": server})
async with ClaudeSDKClient(options=options) as client:
await client.query("What's the weather in Paris?")
async for message in client.receive_response():
if isinstance(message, AssistantMessage):
for block in message.content:
if isinstance(block, TextBlock):
print(block.text)
anyio.run(main)Hooks
After Tool Use Hook
Log file changes after any edit:
python
import anyio
from datetime import datetime
from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher, ResultMessage
async def log_file_change(input_data, tool_use_id, context):
file_path = input_data.get('tool_input', {}).get('file_path', 'unknown')
with open('./audit.log', 'a') as f:
f.write(f"{datetime.now()}: modified {file_path}\\n")
return {}
async def main():
async for message in query(
prompt="Refactor utils.py to improve readability",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Write"],
permission_mode="acceptEdits",
hooks={
"PostToolUse": [HookMatcher(matcher="Edit|Write", hooks=[log_file_change])]
}
)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)Subagents
python
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition, ResultMessage
async def main():
async for message in query(
prompt="Use the code-reviewer agent to review this codebase",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Glob", "Grep", "Agent"],
agents={
"code-reviewer": AgentDefinition(
description="Expert code reviewer for quality and security reviews.",
prompt="Analyze code quality and suggest improvements.",
tools=["Read", "Glob", "Grep"]
)
}
)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)MCP Server Integration
Browser Automation (Playwright)
python
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
async for message in query(
prompt="Open example.com and describe what you see",
options=ClaudeAgentOptions(
mcp_servers={
"playwright": {"command": "npx", "args": ["@playwright/mcp@latest"]}
}
)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)Database Access (PostgreSQL)
python
import os
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
async for message in query(
prompt="Show me the top 10 users by order count",
options=ClaudeAgentOptions(
mcp_servers={
"postgres": {
"command": "npx",
"args": ["-y", "@modelcontextprotocol/server-postgres"],
"env": {"DATABASE_URL": os.environ["DATABASE_URL"]}
}
}
)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)Permission Modes
python
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions
async def main():
# Default: prompt for dangerous operations
async for message in query(
prompt="Delete all test files",
options=ClaudeAgentOptions(
allowed_tools=["Bash"],
permission_mode="default" # Will prompt before deleting
)
):
pass
# Plan: agent creates a plan before making changes
async for message in query(
prompt="Refactor the auth system",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit"],
permission_mode="plan"
)
):
pass
# Accept edits: auto-accept file edits
async for message in query(
prompt="Refactor this module",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit"],
permission_mode="acceptEdits"
)
):
pass
# Bypass: skip all prompts (use with caution)
async for message in query(
prompt="Set up the development environment",
options=ClaudeAgentOptions(
allowed_tools=["Bash", "Write"],
permission_mode="bypassPermissions",
allow_dangerously_skip_permissions=True
)
):
pass
anyio.run(main)Error Recovery
python
import anyio
from claude_agent_sdk import (
query,
ClaudeAgentOptions,
CLINotFoundError,
CLIConnectionError,
ProcessError,
ResultMessage,
)
async def run_with_recovery():
try:
async for message in query(
prompt="Fix the failing tests",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Edit", "Bash"],
max_turns=10
)
):
if isinstance(message, ResultMessage):
print(message.result)
except CLINotFoundError:
print("Claude Code CLI not found. Install with: pip install claude-agent-sdk")
except CLIConnectionError as e:
print(f"Connection error: {e}")
except ProcessError as e:
print(f"Process error: {e}")
anyio.run(run_with_recovery)Session Resumption
python
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage, SystemMessage
async def main():
session_id = None
# First query: capture the session ID
async for message in query(
prompt="Read the authentication module",
options=ClaudeAgentOptions(allowed_tools=["Read", "Glob"])
):
if isinstance(message, SystemMessage) and message.subtype == "init":
session_id = message.session_id
# Resume with full context from the first query
async for message in query(
prompt="Now find all places that call it", # "it" = auth module
options=ClaudeAgentOptions(resume=session_id)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)Custom System Prompt
python
import anyio
from claude_agent_sdk import query, ClaudeAgentOptions, ResultMessage
async def main():
async for message in query(
prompt="Review this code",
options=ClaudeAgentOptions(
allowed_tools=["Read", "Glob", "Grep"],
system_prompt="""You are a senior code reviewer focused on:
1. Security vulnerabilities
2. Performance issues
3. Code maintainability
Always provide specific line numbers and suggestions for improvement."""
)
):
if isinstance(message, ResultMessage):
print(message.result)
anyio.run(main)