安装

pip install claude-agent-sdk

query()ClaudeSDKClient 之间选择

Python SDK 提供两种与 Claude Code 交互的方式:

快速比较

功能query()ClaudeSDKClient
会话每次创建新会话重用同一会话
对话单次交换同一上下文中的多次交换
连接自动管理手动控制
流式输入✅ 支持✅ 支持
中断❌ 不支持✅ 支持
钩子❌ 不支持✅ 支持
自定义工具❌ 不支持✅ 支持
继续聊天❌ 每次新会话✅ 维护对话
使用场景一次性任务持续对话

何时使用 query()(每次新会话)

最适合:
  • 不需要对话历史的一次性问题
  • 不需要先前交换上下文的独立任务
  • 简单的自动化脚本
  • 当你希望每次都重新开始时

何时使用 ClaudeSDKClient(持续对话)

最适合:
  • 继续对话 - 当你需要 Claude 记住上下文时
  • 后续问题 - 基于先前回应构建
  • 交互式应用 - 聊天界面、REPL
  • 响应驱动逻辑 - 当下一个动作依赖于 Claude 的响应时
  • 会话控制 - 明确管理对话生命周期

函数

query()

为每次与 Claude Code 的交互创建新会话。返回一个异步迭代器,在消息到达时产生消息。每次调用 query() 都会重新开始,不记住先前的交互。
async def query(
    *,
    prompt: str | AsyncIterable[dict[str, Any]],
    options: ClaudeAgentOptions | None = None
) -> AsyncIterator[Message]

参数

参数类型描述
promptstr | AsyncIterable[dict]输入提示,作为字符串或用于流式模式的异步可迭代对象
optionsClaudeAgentOptions | None可选配置对象(如果为 None,默认为 ClaudeAgentOptions()

返回值

返回一个 AsyncIterator[Message],产生对话中的消息。

示例 - 带选项


import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    options = ClaudeAgentOptions(
        system_prompt="你是一个专业的 Python 开发者",
        permission_mode='acceptEdits',
        cwd="/home/user/project"
    )

    async for message in query(
        prompt="创建一个 Python Web 服务器",
        options=options
    ):
        print(message)


asyncio.run(main())

tool()

用于定义具有类型安全的 MCP 工具的装饰器。
def tool(
    name: str,
    description: str,
    input_schema: type | dict[str, Any]
) -> Callable[[Callable[[Any], Awaitable[dict[str, Any]]]], SdkMcpTool[Any]]

参数

参数类型描述
namestr工具的唯一标识符
descriptionstr工具功能的人类可读描述
input_schematype | dict[str, Any]定义工具输入参数的模式(见下文)

输入模式选项

  1. 简单类型映射(推荐):
    {"text": str, "count": int, "enabled": bool}
    
  2. JSON 模式格式(用于复杂验证):
    {
        "type": "object",
        "properties": {
            "text": {"type": "string"},
            "count": {"type": "integer", "minimum": 0}
        },
        "required": ["text"]
    }
    

返回值

一个装饰器函数,包装工具实现并返回 SdkMcpTool 实例。

示例

from claude_agent_sdk import tool
from typing import Any

@tool("greet", "问候用户", {"name": str})
async def greet(args: dict[str, Any]) -> dict[str, Any]:
    return {
        "content": [{
            "type": "text",
            "text": f"你好,{args['name']}!"
        }]
    }

create_sdk_mcp_server()

创建一个在 Python 应用程序内运行的进程内 MCP 服务器。
def create_sdk_mcp_server(
    name: str,
    version: str = "1.0.0",
    tools: list[SdkMcpTool[Any]] | None = None
) -> McpSdkServerConfig

参数

参数类型默认值描述
namestr-服务器的唯一标识符
versionstr"1.0.0"服务器版本字符串
toolslist[SdkMcpTool[Any]] | NoneNone使用 @tool 装饰器创建的工具函数列表

返回值

返回一个 McpSdkServerConfig 对象,可以传递给 ClaudeAgentOptions.mcp_servers

示例

from claude_agent_sdk import tool, create_sdk_mcp_server

@tool("add", "两数相加", {"a": float, "b": float})
async def add(args):
    return {
        "content": [{
            "type": "text",
            "text": f"和:{args['a'] + args['b']}"
        }]
    }

@tool("multiply", "两数相乘", {"a": float, "b": float})
async def multiply(args):
    return {
        "content": [{
            "type": "text",
            "text": f"积:{args['a'] * args['b']}"
        }]
    }

calculator = create_sdk_mcp_server(
    name="calculator",
    version="2.0.0",
    tools=[add, multiply]  # 传递装饰的函数
)

# 与 Claude 一起使用
options = ClaudeAgentOptions(
    mcp_servers={"calc": calculator},
    allowed_tools=["mcp__calc__add", "mcp__calc__multiply"]
)

ClaudeSDKClient

在多次交换中维护对话会话。 这是 TypeScript SDK 的 query() 函数内部工作方式的 Python 等价物 - 它创建一个可以继续对话的客户端对象。

主要功能

  • 会话连续性:在多次 query() 调用中维护对话上下文
  • 同一对话:Claude 记住会话中的先前消息
  • 中断支持:可以在执行过程中停止 Claude
  • 显式生命周期:你控制会话何时开始和结束
  • 响应驱动流程:可以对响应做出反应并发送后续消息
  • 自定义工具和钩子:支持自定义工具(使用 @tool 装饰器创建)和钩子
class ClaudeSDKClient:
    def __init__(self, options: ClaudeAgentOptions | None = None)
    async def connect(self, prompt: str | AsyncIterable[dict] | None = None) -> None
    async def query(self, prompt: str | AsyncIterable[dict], session_id: str = "default") -> None
    async def receive_messages(self) -> AsyncIterator[Message]
    async def receive_response(self) -> AsyncIterator[Message]
    async def interrupt(self) -> None
    async def disconnect(self) -> None

方法

方法描述
__init__(options)使用可选配置初始化客户端
connect(prompt)连接到 Claude,可选择初始提示或消息流
query(prompt, session_id)在流式模式下发送新请求
receive_messages()作为异步迭代器接收来自 Claude 的所有消息
receive_response()接收消息直到并包括 ResultMessage
interrupt()发送中断信号(仅在流式模式下工作)
disconnect()断开与 Claude 的连接

上下文管理器支持

客户端可以用作异步上下文管理器以自动管理连接:
async with ClaudeSDKClient() as client:
    await client.query("你好 Claude")
    async for message in client.receive_response():
        print(message)
重要: 在迭代消息时,避免使用 break 提前退出,因为这可能导致 asyncio 清理问题。相反,让迭代自然完成或使用标志来跟踪何时找到所需内容。

示例 - 继续对话

import asyncio
from claude_agent_sdk import ClaudeSDKClient, AssistantMessage, TextBlock, ResultMessage

async def main():
    async with ClaudeSDKClient() as client:
        # 第一个问题
        await client.query("法国的首都是什么?")
        
        # 处理响应
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"Claude:{block.text}")
        
        # 后续问题 - Claude 记住先前的上下文
        await client.query("那个城市的人口是多少?")
        
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"Claude:{block.text}")
        
        # 另一个后续问题 - 仍在同一对话中
        await client.query("那里有哪些著名的地标?")
        
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"Claude:{block.text}")

asyncio.run(main())

示例 - 使用 ClaudeSDKClient 的流式输入

import asyncio
from claude_agent_sdk import ClaudeSDKClient

async def message_stream():
    """动态生成消息。"""
    yield {"type": "text", "text": "分析以下数据:"}
    await asyncio.sleep(0.5)
    yield {"type": "text", "text": "温度:25°C"}
    await asyncio.sleep(0.5)
    yield {"type": "text", "text": "湿度:60%"}
    await asyncio.sleep(0.5)
    yield {"type": "text", "text": "你看到了什么模式?"}

async def main():
    async with ClaudeSDKClient() as client:
        # 向 Claude 流式输入
        await client.query(message_stream())
        
        # 处理响应
        async for message in client.receive_response():
            print(message)
        
        # 在同一会话中的后续问题
        await client.query("我们应该担心这些读数吗?")
        
        async for message in client.receive_response():
            print(message)

asyncio.run(main())

示例 - 使用中断

import asyncio
from claude_agent_sdk import ClaudeSDKClient, ClaudeAgentOptions

async def interruptible_task():
    options = ClaudeAgentOptions(
        allowed_tools=["Bash"],
        permission_mode="acceptEdits"
    )
    
    async with ClaudeSDKClient(options=options) as client:
        # 开始一个长时间运行的任务
        await client.query("慢慢地从 1 数到 100")
        
        # 让它运行一会儿
        await asyncio.sleep(2)
        
        # 中断任务
        await client.interrupt()
        print("任务已中断!")
        
        # 发送新命令
        await client.query("改为只说你好")
        
        async for message in client.receive_response():
            # 处理新响应
            pass

asyncio.run(interruptible_task())

示例 - 高级权限控制

from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions
)

async def custom_permission_handler(
    tool_name: str,
    input_data: dict,
    context: dict
):
    """工具权限的自定义逻辑。"""

    # 阻止写入系统目录
    if tool_name == "Write" and input_data.get("file_path", "").startswith("/system/"):
        return {
            "behavior": "deny",
            "message": "不允许写入系统目录",
            "interrupt": True
        }

    # 重定向敏感文件操作
    if tool_name in ["Write", "Edit"] and "config" in input_data.get("file_path", ""):
        safe_path = f"./sandbox/{input_data['file_path']}"
        return {
            "behavior": "allow",
            "updatedInput": {**input_data, "file_path": safe_path}
        }

    # 允许其他所有操作
    return {
        "behavior": "allow",
        "updatedInput": input_data
    }

async def main():
    options = ClaudeAgentOptions(
        can_use_tool=custom_permission_handler,
        allowed_tools=["Read", "Write", "Edit"]
    )
    
    async with ClaudeSDKClient(options=options) as client:
        await client.query("更新系统配置文件")
        
        async for message in client.receive_response():
            # 将使用沙盒路径
            print(message)

asyncio.run(main())

类型

SdkMcpTool

使用 @tool 装饰器创建的 SDK MCP 工具的定义。
@dataclass
class SdkMcpTool(Generic[T]):
    name: str
    description: str
    input_schema: type[T] | dict[str, Any]
    handler: Callable[[T], Awaitable[dict[str, Any]]]
属性类型描述
namestr工具的唯一标识符
descriptionstr人类可读的描述
input_schematype[T] | dict[str, Any]输入验证的模式
handlerCallable[[T], Awaitable[dict[str, Any]]]处理工具执行的异步函数

ClaudeAgentOptions

Claude Code 查询的配置数据类。
@dataclass
class ClaudeAgentOptions:
    allowed_tools: list[str] = field(default_factory=list)
    max_thinking_tokens: int = 8000
    system_prompt: str | None = None
    mcp_servers: dict[str, McpServerConfig] | str | Path = field(default_factory=dict)
    permission_mode: PermissionMode | None = None
    continue_conversation: bool = False
    resume: str | None = None
    fork_session: bool = False
    max_turns: int | None = None
    disallowed_tools: list[str] = field(default_factory=list)
    model: str | None = None
    permission_prompt_tool_name: str | None = None
    cwd: str | Path | None = None
    settings: str | None = None
    add_dirs: list[str | Path] = field(default_factory=list)
    env: dict[str, str] = field(default_factory=dict)
    extra_args: dict[str, str | None] = field(default_factory=dict)
属性类型默认值描述
allowed_toolslist[str][]允许的工具名称列表
max_thinking_tokensint8000思考过程的最大令牌数
system_promptstr | NoneNone系统提示配置。传递字符串用于自定义提示,或使用 Claude Code 系统提示的预设格式
mcp_serversdict[str, McpServerConfig] | str | Path{}MCP 服务器配置或配置文件路径
permission_modePermissionMode | NoneNone工具使用的权限模式
continue_conversationboolFalse继续最近的对话
resumestr | NoneNone要恢复的会话 ID
fork_sessionboolFalse使用 resume 恢复时,分叉到新会话 ID 而不是继续原始会话
max_turnsint | NoneNone最大对话轮数
disallowed_toolslist[str][]不允许的工具名称列表
modelstr | NoneNone要使用的 Claude 模型
permission_prompt_tool_namestr | NoneNone权限提示的 MCP 工具名称
cwdstr | Path | NoneNone当前工作目录
settingsstr | NoneNone设置文件路径
add_dirslist[str | Path][]Claude 可以访问的其他目录
extra_argsdict[str, str | None]{}直接传递给 CLI 的其他 CLI 参数
can_use_toolCanUseTool | NoneNone工具权限回调函数
hooksdict[HookEvent, list[HookMatcher]] | NoneNone拦截事件的钩子配置
agentsdict[str, AgentDefinition] | NoneNone程序化定义的子代理
setting_sourceslist[SettingSource] | NoneNone(无设置)控制 SDK 从哪些文件系统设置加载设置。省略时,不加载任何设置

SettingSource

控制 SDK 从哪些基于文件系统的配置源加载设置。
SettingSource = Literal["user", "project", "local"]
描述位置
"user"全局用户设置~/.claude/settings.json
"project"共享项目设置(版本控制).claude/settings.json
"local"本地项目设置(gitignored).claude/settings.local.json

默认行为

setting_sources省略或为 None 时,SDK 不会加载任何文件系统设置。这为 SDK 应用程序提供了隔离。

为什么使用 setting_sources?

加载所有文件系统设置(遗留行为):
# 像 SDK v0.0.x 那样加载所有设置
from claude_agent_sdk import query, ClaudeAgentOptions

async for message in query(
    prompt="分析这段代码",
    options=ClaudeAgentOptions(
        setting_sources=["user", "project", "local"]  # 加载所有设置
    )
):
    print(message)
仅加载特定设置源:
# 仅加载项目设置,忽略用户和本地设置
async for message in query(
    prompt="运行 CI 检查",
    options=ClaudeAgentOptions(
        setting_sources=["project"]  # 仅 .claude/settings.json
    )
):
    print(message)
测试和 CI 环境:
# 通过排除本地设置确保 CI 中的一致行为
async for message in query(
    prompt="运行测试",
    options=ClaudeAgentOptions(
        setting_sources=["project"],  # 仅团队共享设置
        permission_mode="bypassPermissions"
    )
):
    print(message)
仅 SDK 应用程序:
# 程序化定义所有内容(默认行为)
# 无文件系统依赖 - setting_sources 默认为 None
async for message in query(
    prompt="审查这个 PR",
    options=ClaudeAgentOptions(
        # setting_sources=None 是默认值,无需指定
        agents={ /* ... */ },
        mcp_servers={ /* ... */ },
        allowed_tools=["Read", "Grep", "Glob"]
    )
):
    print(message)

设置优先级

当加载多个源时,设置按以下优先级合并(从高到低):
  1. 本地设置(.claude/settings.local.json
  2. 项目设置(.claude/settings.json
  3. 用户设置(~/.claude/settings.json
程序化选项(如 agentsallowed_tools)总是覆盖文件系统设置。

AgentDefinition

程序化定义的子代理配置。
@dataclass
class AgentDefinition:
    description: str
    prompt: str
    tools: list[str] | None = None
    model: Literal["sonnet", "opus", "haiku", "inherit"] | None = None
字段必需描述
description何时使用此代理的自然语言描述
tools允许的工具名称数组。如果省略,继承所有工具
prompt代理的系统提示
model此代理的模型覆盖。如果省略,使用主模型

PermissionMode

控制工具执行的权限模式。
PermissionMode = Literal[
    "default",           # 标准权限行为
    "acceptEdits",       # 自动接受文件编辑
    "plan",              # 规划模式 - 不执行
    "bypassPermissions"  # 绕过所有权限检查(谨慎使用)
]

McpSdkServerConfig

使用 create_sdk_mcp_server() 创建的 SDK MCP 服务器配置。
class McpSdkServerConfig(TypedDict):
    type: Literal["sdk"]
    name: str
    instance: Any  # MCP 服务器实例

McpServerConfig

MCP 服务器配置的联合类型。
McpServerConfig = McpStdioServerConfig | McpSSEServerConfig | McpHttpServerConfig | McpSdkServerConfig

McpStdioServerConfig

class McpStdioServerConfig(TypedDict):
    type: NotRequired[Literal["stdio"]]  # 为向后兼容性可选
    command: str
    args: NotRequired[list[str]]
    env: NotRequired[dict[str, str]]

McpSSEServerConfig

class McpSSEServerConfig(TypedDict):
    type: Literal["sse"]
    url: str
    headers: NotRequired[dict[str, str]]

McpHttpServerConfig

class McpHttpServerConfig(TypedDict):
    type: Literal["http"]
    url: str
    headers: NotRequired[dict[str, str]]

消息类型

Message

所有可能消息的联合类型。
Message = UserMessage | AssistantMessage | SystemMessage | ResultMessage

UserMessage

用户输入消息。
@dataclass
class UserMessage:
    content: str | list[ContentBlock]

AssistantMessage

带有内容块的助手响应消息。
@dataclass
class AssistantMessage:
    content: list[ContentBlock]
    model: str

SystemMessage

带有元数据的系统消息。
@dataclass
class SystemMessage:
    subtype: str
    data: dict[str, Any]

ResultMessage

带有成本和使用信息的最终结果消息。
@dataclass
class ResultMessage:
    subtype: str
    duration_ms: int
    duration_api_ms: int
    is_error: bool
    num_turns: int
    session_id: str
    total_cost_usd: float | None = None
    usage: dict[str, Any] | None = None
    result: str | None = None

内容块类型

ContentBlock

所有内容块的联合类型。
ContentBlock = TextBlock | ThinkingBlock | ToolUseBlock | ToolResultBlock

TextBlock

文本内容块。
@dataclass
class TextBlock:
    text: str

ThinkingBlock

思考内容块(用于具有思考能力的模型)。
@dataclass
class ThinkingBlock:
    thinking: str
    signature: str

ToolUseBlock

工具使用请求块。
@dataclass
class ToolUseBlock:
    id: str
    name: str
    input: dict[str, Any]

ToolResultBlock

工具执行结果块。
@dataclass
class ToolResultBlock:
    tool_use_id: str
    content: str | list[dict[str, Any]] | None = None
    is_error: bool | None = None

错误类型

ClaudeSDKError

所有 SDK 错误的基础异常类。
class ClaudeSDKError(Exception):
    """Claude SDK 的基础错误。"""

CLINotFoundError

当 Claude Code CLI 未安装或未找到时引发。
class CLINotFoundError(CLIConnectionError):
    def __init__(self, message: str = "未找到 Claude Code", cli_path: str | None = None):
        """
        参数:
            message: 错误消息(默认:"未找到 Claude Code")
            cli_path: 未找到的 CLI 的可选路径
        """

CLIConnectionError

当连接到 Claude Code 失败时引发。
class CLIConnectionError(ClaudeSDKError):
    """连接到 Claude Code 失败。"""

ProcessError

当 Claude Code 进程失败时引发。
class ProcessError(ClaudeSDKError):
    def __init__(self, message: str, exit_code: int | None = None, stderr: str | None = None):
        self.exit_code = exit_code
        self.stderr = stderr

CLIJSONDecodeError

当 JSON 解析失败时引发。
class CLIJSONDecodeError(ClaudeSDKError):
    def __init__(self, line: str, original_error: Exception):
        """
        参数:
            line: 解析失败的行
            original_error: 原始 JSON 解码异常
        """
        self.line = line
        self.original_error = original_error

钩子类型

HookEvent

支持的钩子事件类型。注意,由于设置限制,Python SDK 不支持 SessionStart、SessionEnd 和 Notification 钩子。
HookEvent = Literal[
    "PreToolUse",      # 工具执行前调用
    "PostToolUse",     # 工具执行后调用
    "UserPromptSubmit", # 用户提交提示时调用
    "Stop",            # 停止执行时调用
    "SubagentStop",    # 子代理停止时调用
    "PreCompact"       # 消息压缩前调用
]

HookCallback

钩子回调函数的类型定义。
HookCallback = Callable[
    [dict[str, Any], str | None, HookContext],
    Awaitable[dict[str, Any]]
]
参数:
  • input_data:钩子特定的输入数据(参见钩子文档
  • tool_use_id:可选的工具使用标识符(用于工具相关钩子)
  • context:带有附加信息的钩子上下文
返回一个可能包含以下内容的字典:
  • decision"block" 阻止操作
  • systemMessage:要添加到记录中的系统消息
  • hookSpecificOutput:钩子特定的输出数据

HookContext

传递给钩子回调的上下文信息。
@dataclass
class HookContext:
    signal: Any | None = None  # 未来:中止信号支持

HookMatcher

将钩子匹配到特定事件或工具的配置。
@dataclass
class HookMatcher:
    matcher: str | None = None        # 要匹配的工具名称或模式(例如,"Bash"、"Write|Edit")
    hooks: list[HookCallback] = field(default_factory=list)  # 要执行的回调列表

钩子使用示例

from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher, HookContext
from typing import Any

async def validate_bash_command(
    input_data: dict[str, Any],
    tool_use_id: str | None,
    context: HookContext
) -> dict[str, Any]:
    """验证并可能阻止危险的 bash 命令。"""
    if input_data['tool_name'] == 'Bash':
        command = input_data['tool_input'].get('command', '')
        if 'rm -rf /' in command:
            return {
                'hookSpecificOutput': {
                    'hookEventName': 'PreToolUse',
                    'permissionDecision': 'deny',
                    'permissionDecisionReason': '危险命令已阻止'
                }
            }
    return {}

async def log_tool_use(
    input_data: dict[str, Any],
    tool_use_id: str | None,
    context: HookContext
) -> dict[str, Any]:
    """记录所有工具使用以进行审计。"""
    print(f"使用的工具:{input_data.get('tool_name')}")
    return {}

options = ClaudeAgentOptions(
    hooks={
        'PreToolUse': [
            HookMatcher(matcher='Bash', hooks=[validate_bash_command]),
            HookMatcher(hooks=[log_tool_use])  # 适用于所有工具
        ],
        'PostToolUse': [
            HookMatcher(hooks=[log_tool_use])
        ]
    }
)

async for message in query(
    prompt="分析这个代码库",
    options=options
):
    print(message)

工具输入/输出类型

所有内置 Claude Code 工具的输入/输出模式文档。虽然 Python SDK 不将这些导出为类型,但它们表示消息中工具输入和输出的结构。

Task

工具名称: Task 输入:
{
    "description": str,      # 任务的简短(3-5 个词)描述
    "prompt": str,           # 代理要执行的任务
    "subagent_type": str     # 要使用的专门代理类型
}
输出:
{
    "result": str,                    # 子代理的最终结果
    "usage": dict | None,             # 令牌使用统计
    "total_cost_usd": float | None,  # 总成本(美元)
    "duration_ms": int | None         # 执行持续时间(毫秒)
}

Bash

工具名称: Bash 输入:
{
    "command": str,                  # 要执行的命令
    "timeout": int | None,           # 可选超时(毫秒)(最大 600000)
    "description": str | None,       # 清晰、简洁的描述(5-10 个词)
    "run_in_background": bool | None # 设置为 true 以在后台运行
}
输出:
{
    "output": str,              # 合并的 stdout 和 stderr 输出
    "exitCode": int,            # 命令的退出代码
    "killed": bool | None,      # 命令是否因超时而被终止
    "shellId": str | None       # 后台进程的 Shell ID
}

Edit

工具名称: Edit 输入:
{
    "file_path": str,           # 要修改的文件的绝对路径
    "old_string": str,          # 要替换的文本
    "new_string": str,          # 要替换为的文本
    "replace_all": bool | None  # 替换所有出现(默认 False)
}
输出:
{
    "message": str,      # 确认消息
    "replacements": int, # 进行的替换次数
    "file_path": str     # 被编辑的文件路径
}

MultiEdit

工具名称: MultiEdit 输入:
{
    "file_path": str,     # 要修改的文件的绝对路径
    "edits": [            # 编辑操作数组
        {
            "old_string": str,          # 要替换的文本
            "new_string": str,          # 要替换为的文本
            "replace_all": bool | None  # 替换所有出现
        }
    ]
}
输出:
{
    "message": str,       # 成功消息
    "edits_applied": int, # 应用的编辑总数
    "file_path": str      # 被编辑的文件路径
}

Read

工具名称: Read 输入:
{
    "file_path": str,       # 要读取的文件的绝对路径
    "offset": int | None,   # 开始读取的行号
    "limit": int | None     # 要读取的行数
}
输出(文本文件):
{
    "content": str,         # 带行号的文件内容
    "total_lines": int,     # 文件中的总行数
    "lines_returned": int   # 实际返回的行数
}
输出(图像):
{
    "image": str,       # Base64 编码的图像数据
    "mime_type": str,   # 图像 MIME 类型
    "file_size": int    # 文件大小(字节)
}

Write

工具名称: Write 输入:
{
    "file_path": str,  # 要写入的文件的绝对路径
    "content": str     # 要写入文件的内容
}
输出:
{
    "message": str,        # 成功消息
    "bytes_written": int,  # 写入的字节数
    "file_path": str       # 被写入的文件路径
}

Glob

工具名称: Glob 输入:
{
    "pattern": str,       # 匹配文件的 glob 模式
    "path": str | None    # 要搜索的目录(默认为 cwd)
}
输出:
{
    "matches": list[str],  # 匹配的文件路径数组
    "count": int,          # 找到的匹配数
    "search_path": str     # 使用的搜索目录
}

Grep

工具名称: Grep 输入:
{
    "pattern": str,                    # 正则表达式模式
    "path": str | None,                # 要搜索的文件或目录
    "glob": str | None,                # 过滤文件的 Glob 模式
    "type": str | None,                # 要搜索的文件类型
    "output_mode": str | None,         # "content"、"files_with_matches" 或 "count"
    "-i": bool | None,                 # 不区分大小写搜索
    "-n": bool | None,                 # 显示行号
    "-B": int | None,                  # 每个匹配前显示的行数
    "-A": int | None,                  # 每个匹配后显示的行数
    "-C": int | None,                  # 前后显示的行数
    "head_limit": int | None,          # 将输出限制为前 N 行/条目
    "multiline": bool | None           # 启用多行模式
}
输出(内容模式):
{
    "matches": [
        {
            "file": str,
            "line_number": int | None,
            "line": str,
            "before_context": list[str] | None,
            "after_context": list[str] | None
        }
    ],
    "total_matches": int
}
输出(files_with_matches 模式):
{
    "files": list[str],  # 包含匹配的文件
    "count": int         # 有匹配的文件数
}

NotebookEdit

工具名称: NotebookEdit 输入:
{
    "notebook_path": str,                     # Jupyter 笔记本的绝对路径
    "cell_id": str | None,                    # 要编辑的单元格的 ID
    "new_source": str,                        # 单元格的新源代码
    "cell_type": "code" | "markdown" | None,  # 单元格的类型
    "edit_mode": "replace" | "insert" | "delete" | None  # 编辑操作类型
}
输出:
{
    "message": str, # 成功消息
    "edit_type": "replaced" | "inserted" | "deleted",  # 执行的编辑类型
    "cell_id": str | None,                       # 受影响的单元格 ID
    "total_cells": int                           # 编辑后笔记本中的总单元格数
}

WebFetch

工具名称: WebFetch 输入:
{
    "url": str,     # 要获取内容的 URL
    "prompt": str   # 在获取的内容上运行的提示
}
输出:
{
    "response": str,           # AI 模型对提示的响应
    "url": str,                # 被获取的 URL
    "final_url": str | None,   # 重定向后的最终 URL
    "status_code": int | None  # HTTP 状态码
}

WebSearch

工具名称: WebSearch 输入:
{
    "query": str,                        # 要使用的搜索查询
    "allowed_domains": list[str] | None, # 仅包含来自这些域的结果
    "blocked_domains": list[str] | None  # 永不包含来自这些域的结果
}
输出:
{
    "results": [
        {
            "title": str,
            "url": str,
            "snippet": str,
            "metadata": dict | None
        }
    ],
    "total_results": int,
    "query": str
}

TodoWrite

工具名称: TodoWrite 输入:
{
    "todos": [
        {
            "content": str, # 任务描述
            "status": "pending" | "in_progress" | "completed",  # 任务状态
            "activeForm": str                            # 描述的活动形式
        }
    ]
}
输出:
{
    "message": str,  # 成功消息
    "stats": {
        "total": int,
        "pending": int,
        "in_progress": int,
        "completed": int
    }
}

BashOutput

工具名称: BashOutput 输入:
{
    "bash_id": str,       # 后台 shell 的 ID
    "filter": str | None  # 过滤输出行的可选正则表达式
}
输出:
{
    "output": str, # 自上次检查以来的新输出
    "status": "running" | "completed" | "failed",       # 当前 shell 状态
    "exitCode": int | None # 完成时的退出代码
}

KillBash

工具名称: KillBash 输入:
{
    "shell_id": str  # 要终止的后台 shell 的 ID
}
输出:
{
    "message": str,  # 成功消息
    "shell_id": str  # 被终止的 shell 的 ID
}

ExitPlanMode

工具名称: ExitPlanMode 输入:
{
    "plan": str  # 用户要运行以获得批准的计划
}
输出:
{
    "message": str,          # 确认消息
    "approved": bool | None  # 用户是否批准了计划
}

ListMcpResources

工具名称: ListMcpResources 输入:
{
    "server": str | None  # 可选的服务器名称以按资源过滤
}
输出:
{
    "resources": [
        {
            "uri": str,
            "name": str,
            "description": str | None,
            "mimeType": str | None,
            "server": str
        }
    ],
    "total": int
}

ReadMcpResource

工具名称: ReadMcpResource 输入:
{
    "server": str,  # MCP 服务器名称
    "uri": str      # 要读取的资源 URI
}
输出:
{
    "contents": [
        {
            "uri": str,
            "mimeType": str | None,
            "text": str | None,
            "blob": str | None
        }
    ],
    "server": str
}

ClaudeSDKClient 的高级功能

构建持续对话界面

from claude_agent_sdk import ClaudeSDKClient, ClaudeCodeOptions, AssistantMessage, TextBlock
import asyncio

class ConversationSession:
    """与 Claude 维护单个对话会话。"""
    
    def __init__(self, options: ClaudeCodeOptions = None):
        self.client = ClaudeSDKClient(options)
        self.turn_count = 0
    
    async def start(self):
        await self.client.connect()
        print("开始对话会话。Claude 将记住上下文。")
        print("命令:'exit' 退出,'interrupt' 停止当前任务,'new' 新会话")
        
        while True:
            user_input = input(f"\n[轮次 {self.turn_count + 1}] 你:")
            
            if user_input.lower() == 'exit':
                break
            elif user_input.lower() == 'interrupt':
                await self.client.interrupt()
                print("任务已中断!")
                continue
            elif user_input.lower() == 'new':
                # 断开连接并重新连接以获得新会话
                await self.client.disconnect()
                await self.client.connect()
                self.turn_count = 0
                print("开始新对话会话(先前上下文已清除)")
                continue
            
            # 发送消息 - Claude 记住此会话中的所有先前消息
            await self.client.query(user_input)
            self.turn_count += 1
            
            # 处理响应
            print(f"[轮次 {self.turn_count}] Claude:", end="")
            async for message in self.client.receive_response():
                if isinstance(message, AssistantMessage):
                    for block in message.content:
                        if isinstance(block, TextBlock):
                            print(block.text, end="")
            print()  # 响应后换行
        
        await self.client.disconnect()
        print(f"对话在 {self.turn_count} 轮后结束。")

async def main():
    options = ClaudeCodeOptions(
        allowed_tools=["Read", "Write", "Bash"],
        permission_mode="acceptEdits"
    )
    session = ConversationSession(options)
    await session.start()

# 示例对话:
# 轮次 1 - 你:"创建一个名为 hello.py 的文件"
# 轮次 1 - Claude:"我将为你创建一个 hello.py 文件..."
# 轮次 2 - 你:"那个文件里有什么?"  
# 轮次 2 - Claude:"我刚创建的 hello.py 文件包含..."(记住了!)
# 轮次 3 - 你:"给它添加一个主函数"
# 轮次 3 - Claude:"我将给 hello.py 添加一个主函数..."(知道是哪个文件!)

asyncio.run(main())

使用钩子进行行为修改

from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    HookMatcher,
    HookContext
)
import asyncio
from typing import Any

async def pre_tool_logger(
    input_data: dict[str, Any],
    tool_use_id: str | None,
    context: HookContext
) -> dict[str, Any]:
    """在执行前记录所有工具使用。"""
    tool_name = input_data.get('tool_name', 'unknown')
    print(f"[PRE-TOOL] 即将使用:{tool_name}")

    # 你可以在这里修改或阻止工具执行
    if tool_name == "Bash" and "rm -rf" in str(input_data.get('tool_input', {})):
        return {
            'hookSpecificOutput': {
                'hookEventName': 'PreToolUse',
                'permissionDecision': 'deny',
                'permissionDecisionReason': '危险命令已阻止'
            }
        }
    return {}

async def post_tool_logger(
    input_data: dict[str, Any],
    tool_use_id: str | None,
    context: HookContext
) -> dict[str, Any]:
    """工具执行后记录结果。"""
    tool_name = input_data.get('tool_name', 'unknown')
    print(f"[POST-TOOL] 已完成:{tool_name}")
    return {}

async def user_prompt_modifier(
    input_data: dict[str, Any],
    tool_use_id: str | None,
    context: HookContext
) -> dict[str, Any]:
    """为用户提示添加上下文。"""
    original_prompt = input_data.get('prompt', '')

    # 为所有提示添加时间戳
    from datetime import datetime
    timestamp = datetime.now().strftime("%Y-%m-%d %H:%M:%S")

    return {
        'hookSpecificOutput': {
            'hookEventName': 'UserPromptSubmit',
            'updatedPrompt': f"[{timestamp}] {original_prompt}"
        }
    }

async def main():
    options = ClaudeAgentOptions(
        hooks={
            'PreToolUse': [
                HookMatcher(hooks=[pre_tool_logger]),
                HookMatcher(matcher='Bash', hooks=[pre_tool_logger])
            ],
            'PostToolUse': [
                HookMatcher(hooks=[post_tool_logger])
            ],
            'UserPromptSubmit': [
                HookMatcher(hooks=[user_prompt_modifier])
            ]
        },
        allowed_tools=["Read", "Write", "Bash"]
    )
    
    async with ClaudeSDKClient(options=options) as client:
        await client.query("列出当前目录中的文件")
        
        async for message in client.receive_response():
            # 钩子将自动记录工具使用
            pass

asyncio.run(main())

实时进度监控

from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    AssistantMessage,
    ToolUseBlock,
    ToolResultBlock,
    TextBlock
)
import asyncio

async def monitor_progress():
    options = ClaudeAgentOptions(
        allowed_tools=["Write", "Bash"],
        permission_mode="acceptEdits"
    )
    
    async with ClaudeSDKClient(options=options) as client:
        await client.query(
            "创建 5 个包含不同排序算法的 Python 文件"
        )
        
        # 实时监控进度
        files_created = []
        async for message in client.receive_messages():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, ToolUseBlock):
                        if block.name == "Write":
                            file_path = block.input.get("file_path", "")
                            print(f"🔨 创建中:{file_path}")
                    elif isinstance(block, ToolResultBlock):
                        print(f"✅ 工具执行完成")
                    elif isinstance(block, TextBlock):
                        print(f"💭 Claude 说:{block.text[:100]}...")
            
            # 检查是否收到最终结果
            if hasattr(message, 'subtype') and message.subtype in ['success', 'error']:
                print(f"\n🎯 任务完成!")
                break

asyncio.run(monitor_progress())

使用示例

基本文件操作(使用 query)

from claude_agent_sdk import query, ClaudeAgentOptions, AssistantMessage, ToolUseBlock
import asyncio

async def create_project():
    options = ClaudeAgentOptions(
        allowed_tools=["Read", "Write", "Bash"],
        permission_mode='acceptEdits',
        cwd="/home/user/project"
    )
    
    async for message in query(
        prompt="创建一个带有 setup.py 的 Python 项目结构",
        options=options
    ):
        if isinstance(message, AssistantMessage):
            for block in message.content:
                if isinstance(block, ToolUseBlock):
                    print(f"使用工具:{block.name}")

asyncio.run(create_project())

错误处理

from claude_agent_sdk import (
    query,
    CLINotFoundError,
    ProcessError,
    CLIJSONDecodeError
)

try:
    async for message in query(prompt="你好"):
        print(message)
except CLINotFoundError:
    print("请安装 Claude Code:npm install -g @anthropic-ai/claude-code")
except ProcessError as e:
    print(f"进程失败,退出代码:{e.exit_code}")
except CLIJSONDecodeError as e:
    print(f"解析响应失败:{e}")

使用客户端的流式模式

from claude_agent_sdk import ClaudeSDKClient
import asyncio

async def interactive_session():
    async with ClaudeSDKClient() as client:
        # 发送初始消息
        await client.query("天气怎么样?")
        
        # 处理响应
        async for msg in client.receive_response():
            print(msg)
        
        # 发送后续消息
        await client.query("告诉我更多相关信息")
        
        # 处理后续响应
        async for msg in client.receive_response():
            print(msg)

asyncio.run(interactive_session())

使用 ClaudeSDKClient 的自定义工具

from claude_agent_sdk import (
    ClaudeSDKClient,
    ClaudeAgentOptions,
    tool,
    create_sdk_mcp_server,
    AssistantMessage,
    TextBlock
)
import asyncio
from typing import Any

# 使用 @tool 装饰器定义自定义工具
@tool("calculate", "执行数学计算", {"expression": str})
async def calculate(args: dict[str, Any]) -> dict[str, Any]:
    try:
        result = eval(args["expression"], {"__builtins__": {}})
        return {
            "content": [{
                "type": "text",
                "text": f"结果:{result}"
            }]
        }
    except Exception as e:
        return {
            "content": [{
                "type": "text",
                "text": f"错误:{str(e)}"
            }],
            "is_error": True
        }

@tool("get_time", "获取当前时间", {})
async def get_time(args: dict[str, Any]) -> dict[str, Any]:
    from datetime import datetime
    current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
    return {
        "content": [{
            "type": "text",
            "text": f"当前时间:{current_time}"
        }]
    }

async def main():
    # 使用自定义工具创建 SDK MCP 服务器
    my_server = create_sdk_mcp_server(
        name="utilities",
        version="1.0.0",
        tools=[calculate, get_time]
    )

    # 使用服务器配置选项
    options = ClaudeAgentOptions(
        mcp_servers={"utils": my_server},
        allowed_tools=[
            "mcp__utils__calculate",
            "mcp__utils__get_time"
        ]
    )
    
    # 使用 ClaudeSDKClient 进行交互式工具使用
    async with ClaudeSDKClient(options=options) as client:
        await client.query("123 * 456 等于多少?")
        
        # 处理计算响应
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"计算:{block.text}")
        
        # 跟进时间查询
        await client.query("现在几点了?")
        
        async for message in client.receive_response():
            if isinstance(message, AssistantMessage):
                for block in message.content:
                    if isinstance(block, TextBlock):
                        print(f"时间:{block.text}")

asyncio.run(main())

另请参阅