通俗版 Claude Code 文档

结构照原 docs,内容改成真能照着做的人话版。

查看原始文档 目录顺序与官方保持一致

SDK references

Python SDK

Python SDK 这一页讲的,就是 Python SDK 这件事在 Claude Code 里到底怎么用。

页面信息

对应原页

Agent SDK reference - Python

页面性质

第三方中文解释页

使用建议

先看人话解释,再对照原页命令和代码

这页不是官方原文,而是顺着官方文档结构做的中文解释版。命令、参数、配置名这些硬东西尽量保留,解释部分则尽量讲成人能照着做的话。

如果你碰到特别敏感的配置、权限或企业环境差异,最好顺手点上面的“查看原始文档”再核一遍。

这一页先讲明白

这页主要讲 Python SDK:Complete API reference for the Python Agent SDK, including all functions, types, and classes.

你可以把它当成"SDK references"这块里专门管这一摊事的说明书。

你可以把"Python SDK"理解成 SDK references 这一栏里的一把专门工具。这页不是让你背书,而是教你什么时候该把这把工具拿出来。

原文这页大多会按 Installation、Choosing between query() and ClaudeSDKClient、Quick comparison、When to use query() (new session each time) 这些环节往下讲。

翻成人话,大概就是:Choosing between query() and ClaudeSDKClient

第一,先别一上来全开全配。先按最小一步试通,确认没跑偏,再继续往下加。

第二,命令、配置名、参数名这些硬东西尽量保留原样。人话解释是帮你听懂,不是帮你改关键字。

第三,照着原文这几个环节挨个过:Installation -> Choosing between query() and ClaudeSDKClient -> Quick comparison -> When to use query() (new session each time)。像下地先看水路、再试机器、再正式开干,一步一步最稳。

终端里敲

原页关键片段:Installation

真到动手的时候了,下面这条直接敲一遍,看它回什么。

pip install claude-agent-sdk
关键片段

原页关键片段:query() 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

async def query(
    *,
    prompt: str | AsyncIterable[dict[str, Any]],
    options: ClaudeAgentOptions | None = None,
    transport: Transport | None = None
) -> AsyncIterator[Message]
关键片段

原页关键片段:query() 2

先看下面这块原始片段,等会儿再回头看解释会顺得多。

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions


async def main():
    options = ClaudeAgentOptions(
        system_prompt="You are an expert Python developer",
        permission_mode="acceptEdits",
        cwd="/home/user/project",
    )

    async for message in query(prompt="Create a Python web server", options=options):
        print(message)


asyncio.run(main())
关键片段

原页关键片段:tool() 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

def tool(
    name: str,
    description: str,
    input_schema: type | dict[str, Any],
    annotations: ToolAnnotations | None = None
) -> Callable[[Callable[[Any], Awaitable[dict[str, Any]]]], SdkMcpTool[Any]]
改配置

原页关键片段:tool() 2

这一段说完,最后还得写到配置里才算真的生效。

{"text": str, "count": int, "enabled": bool}
改配置

原页关键片段:tool() 3

这一段说完,最后还得写到配置里才算真的生效。

{
    "type": "object",
    "properties": {
        "text": {"type": "string"},
        "count": {"type": "integer", "minimum": 0},
    },
    "required": ["text"],
}
关键片段

原页关键片段:create_sdk_mcp_server() 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

def create_sdk_mcp_server(
    name: str,
    version: str = "1.0.0",
    tools: list[SdkMcpTool[Any]] | None = None
) -> McpSdkServerConfig
关键片段

原页关键片段:create_sdk_mcp_server() 2

先看下面这块原始片段,等会儿再回头看解释会顺得多。

from claude_agent_sdk import tool, create_sdk_mcp_server


@tool("add", "Add two numbers", {"a": float, "b": float})
async def add(args):
    return {"content": [{"type": "text", "text": f"Sum: {args['a'] + args['b']}"}]}


@tool("multiply", "Multiply two numbers", {"a": float, "b": float})
async def multiply(args):
    return {"content": [{"type": "text", "text": f"Product: {args['a'] * args['b']}"}]}


calculator = create_sdk_mcp_server(
    name="calculator",
    version="2.0.0",
    tools=[add, multiply],  # Pass decorated functions
)

# Use with Claude
options = ClaudeAgentOptions(
    mcp_servers={"calc": calculator},
    allowed_tools=["mcp__calc__add", "mcp__calc__multiply"],
)
关键片段

原页关键片段:list_sessions() 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

def list_sessions(
    directory: str | None = None,
    limit: int | None = None,
    include_worktrees: bool = True
) -> list[SDKSessionInfo]
关键片段

原页关键片段:list_sessions() 2

先看下面这块原始片段,等会儿再回头看解释会顺得多。

from claude_agent_sdk import list_sessions

for session in list_sessions(directory="/path/to/project", limit=10):
    print(f"{session.summary} ({session.session_id})")
关键片段

原页关键片段:get_session_messages() 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

def get_session_messages(
    session_id: str,
    directory: str | None = None,
    limit: int | None = None,
    offset: int = 0
) -> list[SessionMessage]
关键片段

原页关键片段:get_session_messages() 2

先看下面这块原始片段,等会儿再回头看解释会顺得多。

from claude_agent_sdk import list_sessions, get_session_messages

sessions = list_sessions(limit=1)
if sessions:
    messages = get_session_messages(sessions[0].session_id)
    for msg in messages:
        print(f"[{msg.type}] {msg.uuid}")

预留广告位

正文中段响应式广告 等你后面真接 AdSense,这里再放正式广告。

Documentation Index

这里不是让你背"Documentation Index"这个词,而是让你看它真干活时怎么使。

Installation

这里不是让你背"Installation"这个词,而是让你看它真干活时怎么使。

终端里敲

Installation

真到动手的时候了,下面这条直接敲一遍,看它回什么。

pip install claude-agent-sdk

Choosing between query() and ClaudeSDKClient

这一段不只是挂个标题,它是在说明"Choosing between query() and ClaudeSDKClient"这一块到底负责什么。

Quick comparison

这一段主要是在把"Quick comparison"讲实,不是只摆个标题给你看。

When to use query() (new session each time)

这一段主要是在帮你判断:When to use query() (new session each time) 这种东西到底值不值得现在就上。

When to use ClaudeSDKClient (continuous conversation)

When to use ClaudeSDKClient (continuous conversation) 到底什么时候值得上,这一段就是在算这笔账。

这里还牵扯作用域,意思就是这条规则到底管当前项目、你个人,还是只管这一趟会话。

Functions

这一块主要是在说"Functions"真到手上该怎么用,哪里最容易踩坑。

query()

看到这里,就把"query()"当成一件真要上手的活来看。

这里还牵扯作用域,意思就是这条规则到底管当前项目、你个人,还是只管这一趟会话。

关键片段

query() 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

async def query(
    *,
    prompt: str | AsyncIterable[dict[str, Any]],
    options: ClaudeAgentOptions | None = None,
    transport: Transport | None = None
) -> AsyncIterator[Message]
关键片段

query() 2

先看下面这块原始片段,等会儿再回头看解释会顺得多。

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions


async def main():
    options = ClaudeAgentOptions(
        system_prompt="You are an expert Python developer",
        permission_mode="acceptEdits",
        cwd="/home/user/project",
    )

    async for message in query(prompt="Create a Python web server", options=options):
        print(message)


asyncio.run(main())

tool()

看到这里,就把"tool()"当成一件真要上手的活来看。

看这段时要特别盯工具和权限边界,别为了省事一把全开。

关键片段

tool() 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

def tool(
    name: str,
    description: str,
    input_schema: type | dict[str, Any],
    annotations: ToolAnnotations | None = None
) -> Callable[[Callable[[Any], Awaitable[dict[str, Any]]]], SdkMcpTool[Any]]
改配置

tool() 2

这一段说完,最后还得写到配置里才算真的生效。

{"text": str, "count": int, "enabled": bool}
改配置

tool() 3

这一段说完,最后还得写到配置里才算真的生效。

{
    "type": "object",
    "properties": {
        "text": {"type": "string"},
        "count": {"type": "integer", "minimum": 0},
    },
    "required": ["text"],
}
改配置

tool() 4

这一段说完,最后还得写到配置里才算真的生效。

from claude_agent_sdk import tool
from typing import Any


@tool("greet", "Greet a user", {"name": str})
async def greet(args: dict[str, Any]) -> dict[str, Any]:
    return {"content": [{"type": "text", "text": f"Hello, {args['name']}!"}]}

create_sdk_mcp_server()

这一段是在教你把 an in-process MCP server that runs within your Python application. 真正建出来。文件放哪儿、字段怎么写、建完怎么验,都得跟着看。

如果你打算把外接能力往里挂,这里提到的 hooks、MCP、skills、memory 都要分清各自负责哪一摊。

关键片段

create_sdk_mcp_server() 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

def create_sdk_mcp_server(
    name: str,
    version: str = "1.0.0",
    tools: list[SdkMcpTool[Any]] | None = None
) -> McpSdkServerConfig
关键片段

create_sdk_mcp_server() 2

先看下面这块原始片段,等会儿再回头看解释会顺得多。

from claude_agent_sdk import tool, create_sdk_mcp_server


@tool("add", "Add two numbers", {"a": float, "b": float})
async def add(args):
    return {"content": [{"type": "text", "text": f"Sum: {args['a'] + args['b']}"}]}


@tool("multiply", "Multiply two numbers", {"a": float, "b": float})
async def multiply(args):
    return {"content": [{"type": "text", "text": f"Product: {args['a'] * args['b']}"}]}


calculator = create_sdk_mcp_server(
    name="calculator",
    version="2.0.0",
    tools=[add, multiply],  # Pass decorated functions
)

# Use with Claude
options = ClaudeAgentOptions(
    mcp_servers={"calc": calculator},
    allowed_tools=["mcp__calc__add", "mcp__calc__multiply"],
)

list_sessions()

看到这里,就把"list_sessions()"当成一件真要上手的活来看。

这里还牵扯作用域,意思就是这条规则到底管当前项目、你个人,还是只管这一趟会话。

关键片段

list_sessions() 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

def list_sessions(
    directory: str | None = None,
    limit: int | None = None,
    include_worktrees: bool = True
) -> list[SDKSessionInfo]
关键片段

list_sessions() 2

先看下面这块原始片段,等会儿再回头看解释会顺得多。

from claude_agent_sdk import list_sessions

for session in list_sessions(directory="/path/to/project", limit=10):
    print(f"{session.summary} ({session.session_id})")

get_session_messages()

看到这里,就把"get_session_messages()"当成一件真要上手的活来看。

这里还牵扯作用域,意思就是这条规则到底管当前项目、你个人,还是只管这一趟会话。

关键片段

get_session_messages() 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

def get_session_messages(
    session_id: str,
    directory: str | None = None,
    limit: int | None = None,
    offset: int = 0
) -> list[SessionMessage]
关键片段

get_session_messages() 2

先看下面这块原始片段,等会儿再回头看解释会顺得多。

from claude_agent_sdk import list_sessions, get_session_messages

sessions = list_sessions(limit=1)
if sessions:
    messages = get_session_messages(sessions[0].session_id)
    for msg in messages:
        print(f"[{msg.type}] {msg.uuid}")

get_session_info()

看到这里,就把"get_session_info()"当成一件真要上手的活来看。

这里还牵扯作用域,意思就是这条规则到底管当前项目、你个人,还是只管这一趟会话。

关键片段

get_session_info() 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

def get_session_info(
    session_id: str,
    directory: str | None = None,
) -> SDKSessionInfo | None
关键片段

get_session_info() 2

先看下面这块原始片段,等会儿再回头看解释会顺得多。

from claude_agent_sdk import get_session_info

info = get_session_info("550e8400-e29b-41d4-a716-446655440000")
if info:
    print(f"{info.summary} (branch: {info.git_branch}, tag: {info.tag})")

rename_session()

这一段主要是在把"rename_session()"讲实,不是只摆个标题给你看。

这里还牵扯作用域,意思就是这条规则到底管当前项目、你个人,还是只管这一趟会话。

关键片段

rename_session() 1

这一段要真抓重点,通常就抓下面这块原文。

def rename_session(
    session_id: str,
    title: str,
    directory: str | None = None,
) -> None
关键片段

rename_session() 2

这一段要真抓重点,通常就抓下面这块原文。

from claude_agent_sdk import list_sessions, rename_session

sessions = list_sessions(directory="/path/to/project", limit=1)
if sessions:
    rename_session(sessions[0].session_id, "Refactor auth module")

tag_session()

这一段主要是在把"tag_session()"讲实,不是只摆个标题给你看。

这里还牵扯作用域,意思就是这条规则到底管当前项目、你个人,还是只管这一趟会话。

关键片段

tag_session() 1

这一段要真抓重点,通常就抓下面这块原文。

def tag_session(
    session_id: str,
    tag: str | None,
    directory: str | None = None,
) -> None
关键片段

tag_session() 2

这一段要真抓重点,通常就抓下面这块原文。

from claude_agent_sdk import list_sessions, tag_session

# Tag a session
tag_session("550e8400-e29b-41d4-a716-446655440000", "needs-review")

# Later: find all sessions with that tag
for session in list_sessions(directory="/path/to/project"):
    if session.tag == "needs-review":
        print(session.summary)

Classes

这里不是让你背"Classes"这个词,而是让你看它真干活时怎么使。

ClaudeSDKClient

看到这里,就把"ClaudeSDKClient"当成一件真要上手的活来看。

这里还牵扯作用域,意思就是这条规则到底管当前项目、你个人,还是只管这一趟会话。

关键片段

ClaudeSDKClient 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

class ClaudeSDKClient:
    def __init__(self, options: ClaudeAgentOptions | None = None, transport: Transport | 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 set_permission_mode(self, mode: str) -> None
    async def set_model(self, model: str | None = None) -> None
    async def rewind_files(self, user_message_id: str) -> None
    async def get_mcp_status(self) -> McpStatusResponse
    async def reconnect_mcp_server(self, server_name: str) -> None
    async def toggle_mcp_server(self, server_name: str, enabled: bool) -> None
    async def stop_task(self, task_id: str) -> None
    async def get_server_info(self) -> dict[str, Any] | None
    async def disconnect(self) -> None
关键片段

ClaudeSDKClient 2

先看下面这块原始片段,等会儿再回头看解释会顺得多。

async with ClaudeSDKClient() as client:
    await client.query("Hello Claude")
    async for message in client.receive_response():
        print(message)
关键片段

ClaudeSDKClient 3

先看下面这块原始片段,等会儿再回头看解释会顺得多。

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


async def main():
    async with ClaudeSDKClient() as client:
        # First question
        await client.query("What's the capital of France?")

        # Process response
        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}")

        # Follow-up question - the session retains the previous context
        await client.query("What's the population of that city?")

        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}")

        # Another follow-up - still in the same conversation
        await client.query("What are some famous landmarks there?")

        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 4

先看下面这块原始片段,等会儿再回头看解释会顺得多。

import asyncio
from claude_agent_sdk import ClaudeSDKClient


async def message_stream():
    """Generate messages dynamically."""
    yield {
        "type": "user",
        "message": {"role": "user", "content": "Analyze the following data:"},
    }
    await asyncio.sleep(0.5)
    yield {
        "type": "user",
        "message": {"role": "user", "content": "Temperature: 25°C, Humidity: 60%"},
    }
    await asyncio.sleep(0.5)
    yield {
        "type": "user",
        "message": {"role": "user", "content": "What patterns do you see?"},
    }


async def main():
    async with ClaudeSDKClient() as client:
        # Stream input to Claude
        await client.query(message_stream())

        # Process response
        async for message in client.receive_response():
            print(message)

        # Follow-up in same session
        await client.query("Should we be concerned about these readings?")

        async for message in client.receive_response():
            print(message)


asyncio.run(main())

Types

这一块主要是在说"Types"真到手上该怎么用,哪里最容易踩坑。

如果你打算把外接能力往里挂,这里提到的 hooks、MCP、skills、memory 都要分清各自负责哪一摊。

SdkMcpTool

这一段主要是在把"SdkMcpTool"讲实,不是只摆个标题给你看。

看这段时要特别盯工具和权限边界,别为了省事一把全开。

关键片段

SdkMcpTool

这一段要真抓重点,通常就抓下面这块原文。

@dataclass
class SdkMcpTool(Generic[T]):
    name: str
    description: str
    input_schema: type[T] | dict[str, Any]
    handler: Callable[[T], Awaitable[dict[str, Any]]]
    annotations: ToolAnnotations | None = None

Transport

这一块主要是在说"Transport"真到手上该怎么用,哪里最容易踩坑。

关键片段

Transport

"Transport"这一段里最要紧的原始写法在下面,先看它怎么落地。

from abc import ABC, abstractmethod
from collections.abc import AsyncIterator
from typing import Any


class Transport(ABC):
    @abstractmethod
    async def connect(self) -> None: ...

    @abstractmethod
    async def write(self, data: str) -> None: ...

    @abstractmethod
    def read_messages(self) -> AsyncIterator[dict[str, Any]]: ...

    @abstractmethod
    async def close(self) -> None: ...

    @abstractmethod
    def is_ready(self) -> bool: ...

    @abstractmethod
    async def end_input(self) -> None: ...

ClaudeAgentOptions

这一块主要是在说"ClaudeAgentOptions"真到手上该怎么用,哪里最容易踩坑。

看这段时要特别盯工具和权限边界,别为了省事一把全开。

关键片段

ClaudeAgentOptions 1

"ClaudeAgentOptions"这一段里最要紧的原始写法在下面,先看它怎么落地。

@dataclass
class ClaudeAgentOptions:
    tools: list[str] | ToolsPreset | None = None
    allowed_tools: list[str] = field(default_factory=list)
    system_prompt: str | SystemPromptPreset | None = None
    mcp_servers: dict[str, McpServerConfig] | str | Path = field(default_factory=dict)
    strict_mcp_config: bool = False
    permission_mode: PermissionMode | None = None
    continue_conversation: bool = False
    resume: str | None = None
    max_turns: int | None = None
    max_budget_usd: float | None = None
    disallowed_tools: list[str] = field(default_factory=list)
    model: str | None = None
    fallback_model: str | None = None
    betas: list[SdkBeta] = field(default_factory=list)
    output_format: dict[str, Any] | None = None
    permission_prompt_tool_name: str | None = None
    cwd: str | Path | None = None
    cli_path: 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)
    max_buffer_size: int | None = None
    debug_stderr: Any = sys.stderr  # Deprecated
    stderr: Callable[[str], None] | None = None
    can_use_tool: CanUseTool | None = None
    hooks: dict[HookEvent, list[HookMatcher]] | None = None
    user: str | None = None
    include_partial_messages: bool = False
    include_hook_events: bool = False
    fork_session: bool = False
    agents: dict[str, AgentDefinition] | None = None
    setting_sources: list[SettingSource] | None = None
    sandbox: SandboxSettings | None = None
    plugins: list[SdkPluginConfig] = field(default_factory=list)
    max_thinking_tokens: int | None = None  # Deprecated: use thinking instead
    thinking: ThinkingConfig | None = None
    effort: Literal["low", "medium", "high", "xhigh", "max"] | None = None
    enable_file_checkpointing: bool = False
    session_store: SessionStore | None = None
    session_store_flush: SessionStoreFlushMode = "batched"
关键片段

ClaudeAgentOptions 2

"ClaudeAgentOptions"这一段里最要紧的原始写法在下面,先看它怎么落地。

options = ClaudeAgentOptions(
    env={
        "API_TIMEOUT_MS": "120000",
        "CLAUDE_CODE_MAX_RETRIES": "2",
        "CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS": "120000",
    },
)

OutputFormat

这里不是让你背"OutputFormat"这个词,而是让你看它真干活时怎么使。

关键片段

OutputFormat

下面这块是这一段最值钱的原文样板,先对着看一眼。

# Expected dict shape for output_format
{
    "type": "json_schema",
    "schema": {...},  # Your JSON Schema definition
}

SystemPromptPreset

这里不是让你背"SystemPromptPreset"这个词,而是让你看它真干活时怎么使。

关键片段

SystemPromptPreset

下面这块是这一段最值钱的原文样板,先对着看一眼。

class SystemPromptPreset(TypedDict):
    type: Literal["preset"]
    preset: Literal["claude_code"]
    append: NotRequired[str]
    exclude_dynamic_sections: NotRequired[bool]

SettingSource

看到这里,就把"SettingSource"当成一件真要上手的活来看。

这里还牵扯作用域,意思就是这条规则到底管当前项目、你个人,还是只管这一趟会话。

关键片段

SettingSource 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

SettingSource = Literal["user", "project", "local"]
关键片段

SettingSource 2

先看下面这块原始片段,等会儿再回头看解释会顺得多。

# Do not load user, project, or local settings from disk
from claude_agent_sdk import query, ClaudeAgentOptions

async for message in query(
    prompt="Analyze this code",
    options=ClaudeAgentOptions(
        setting_sources=[]
    ),
):
    print(message)
关键片段

SettingSource 3

先看下面这块原始片段,等会儿再回头看解释会顺得多。

from claude_agent_sdk import query, ClaudeAgentOptions

async for message in query(
    prompt="Analyze this code",
    options=ClaudeAgentOptions(
        setting_sources=["user", "project", "local"]
    ),
):
    print(message)
改配置

SettingSource 4

这一段说完,最后还得写到配置里才算真的生效。

# Load only project settings, ignore user and local
async for message in query(
    prompt="Run CI checks",
    options=ClaudeAgentOptions(
        setting_sources=["project"]  # Only .claude/settings.json
    ),
):
    print(message)

AgentDefinition

这一段主要是在把"AgentDefinition"讲实,不是只摆个标题给你看。

看这段时要特别盯工具和权限边界,别为了省事一把全开。

关键片段

AgentDefinition

这一段要真抓重点,通常就抓下面这块原文。

@dataclass
class AgentDefinition:
    description: str
    prompt: str
    tools: list[str] | None = None
    disallowedTools: list[str] | None = None
    model: str | None = None
    skills: list[str] | None = None
    memory: Literal["user", "project", "local"] | None = None
    mcpServers: list[str | dict[str, Any]] | None = None
    initialPrompt: str | None = None
    maxTurns: int | None = None
    background: bool | None = None
    effort: Literal["low", "medium", "high", "xhigh", "max"] | int | None = None
    permissionMode: PermissionMode | None = None

PermissionMode

这里不是让你背"PermissionMode"这个词,而是让你看它真干活时怎么使。

看这段时要特别盯工具和权限边界,别为了省事一把全开。

关键片段

PermissionMode

下面这块是这一段最值钱的原文样板,先对着看一眼。

PermissionMode = Literal[
    "default",  # Standard permission behavior
    "acceptEdits",  # Auto-accept file edits
    "plan",  # Planning mode - read-only tools only
    "dontAsk",  # Deny anything not pre-approved instead of prompting
    "bypassPermissions",  # Bypass all permission checks (use with caution)
]

CanUseTool

这一块主要是在说"CanUseTool"真到手上该怎么用,哪里最容易踩坑。

看这段时要特别盯工具和权限边界,别为了省事一把全开。

关键片段

CanUseTool

"CanUseTool"这一段里最要紧的原始写法在下面,先看它怎么落地。

CanUseTool = Callable[
    [str, dict[str, Any], ToolPermissionContext], Awaitable[PermissionResult]
]

ToolPermissionContext

这一段主要是在把"ToolPermissionContext"讲实,不是只摆个标题给你看。

看这段时要特别盯工具和权限边界,别为了省事一把全开。

关键片段

ToolPermissionContext

这一段要真抓重点,通常就抓下面这块原文。

@dataclass
class ToolPermissionContext:
    signal: Any | None = None  # Future: abort signal support
    suggestions: list[PermissionUpdate] = field(default_factory=list)
    blocked_path: str | None = None
    decision_reason: str | None = None
    title: str | None = None
    display_name: str | None = None
    description: str | None = None

PermissionResult

这一段主要是在把"PermissionResult"讲实,不是只摆个标题给你看。

看这段时要特别盯工具和权限边界,别为了省事一把全开。

关键片段

PermissionResult

这一段要真抓重点,通常就抓下面这块原文。

PermissionResult = PermissionResultAllow | PermissionResultDeny

PermissionResultAllow

看到这里,就把"PermissionResultAllow"当成一件真要上手的活来看。

看这段时要特别盯工具和权限边界,别为了省事一把全开。

关键片段

PermissionResultAllow

先看下面这块原始片段,等会儿再回头看解释会顺得多。

@dataclass
class PermissionResultAllow:
    behavior: Literal["allow"] = "allow"
    updated_input: dict[str, Any] | None = None
    updated_permissions: list[PermissionUpdate] | None = None

PermissionResultDeny

这一段主要是在把"PermissionResultDeny"讲实,不是只摆个标题给你看。

看这段时要特别盯工具和权限边界,别为了省事一把全开。

关键片段

PermissionResultDeny

这一段要真抓重点,通常就抓下面这块原文。

@dataclass
class PermissionResultDeny:
    behavior: Literal["deny"] = "deny"
    message: str = ""
    interrupt: bool = False

照着做一遍

如果你不想来回翻,就先照这几步顺着做。

每做完一步就看一下结果,再决定要不要继续往下。

终端里敲

第 1 步:Installation

真到动手的时候了,下面这条直接敲一遍,看它回什么。

pip install claude-agent-sdk
关键片段

第 2 步:query() 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

async def query(
    *,
    prompt: str | AsyncIterable[dict[str, Any]],
    options: ClaudeAgentOptions | None = None,
    transport: Transport | None = None
) -> AsyncIterator[Message]
关键片段

第 3 步:query() 2

先看下面这块原始片段,等会儿再回头看解释会顺得多。

import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions


async def main():
    options = ClaudeAgentOptions(
        system_prompt="You are an expert Python developer",
        permission_mode="acceptEdits",
        cwd="/home/user/project",
    )

    async for message in query(prompt="Create a Python web server", options=options):
        print(message)


asyncio.run(main())
关键片段

第 4 步:tool() 1

先看下面这块原始片段,等会儿再回头看解释会顺得多。

def tool(
    name: str,
    description: str,
    input_schema: type | dict[str, Any],
    annotations: ToolAnnotations | None = None
) -> Callable[[Callable[[Any], Awaitable[dict[str, Any]]]], SdkMcpTool[Any]]

一眼看懂这一页

先把这页到底在讲什么看明白,再去碰具体命令和配置,最不容易绕晕。

Python SDK
   |
   v
这是 SDK references 里的一摊要紧活
   |
   v
先弄懂,再下手

文末提醒

这站会按官方 docs 的导航和内容变化继续重生成,原站加页、删页、改页时,这里会跟着更新。

人话解释会尽量顺着原页往下讲,但命令、参数名、配置名这些硬东西还是保留原样,免得你抄过去跑不起来。