Skip to content
FunCoding

Search

Search docs, agents, posts, Skills and MCP servers

Python SDK 参考:消息、内容块与错误

Agent SDK Python 的 Message 联合类型、UserMessage、AssistantMessage、ResultMessage(含 usage、model_usage 字段)、StreamEvent、RateLimitEvent、后台任务消息、内容块类型以及错误类型(ClaudeSDKError、ProcessError、ResultError 等)。

本页是 Python Agent SDK 参考的第三部分:query() 和 ClaudeSDKClient 产出的消息类型、内容块,以及你的代码要捕获的错误类型。

消息类型

Message

所有可能消息的联合类型。

Message = (
    UserMessage
    | AssistantMessage
    | SystemMessage
    | ResultMessage
    | StreamEvent
    | RateLimitEvent
    | ConversationResetMessage
)

UserMessage

用户输入消息。

@dataclass
class UserMessage:
    content: str | list[ContentBlock]
    uuid: str | None = None
    parent_tool_use_id: str | None = None
    tool_use_result: dict[str, Any] | None = None
    origin: MessageOrigin | None = None
字段类型说明
contentstr | list[ContentBlock]消息内容,文本或内容块
uuidstr | None唯一的消息标识
parent_tool_use_idstr | None该消息是工具结果响应时的工具使用 ID
tool_use_resultdict[str, Any] | None工具结果数据(如适用)
originMessageOrigin | None该消息的来源,在注入的轮次(如任务通知和对等消息)上填充;CLI 没有归属时为 None(需要 Python Agent SDK 0.2.137 及以上)

SDK 原样透传来自 CLI 的 tool_use_result。对外部 MCP 服务器上、结果含 resource_link 块的工具,该字典有一个 resourceLinks 键,持有字典列表,键与 TypeScript 的 SDKMcpResourceLink 类型相同。Claude 把每个链接作为工具结果里的一行文本收到;要渲染服务器返回的文件,读 resourceLinks,而不是解析那段文本(resourceLinks 键需要 Python Agent SDK 0.2.150 及以上)。结果没有链接时以及子智能体的结果上,CLI 省略该键;CLI 每个结果最多保留 50 个链接,列表达到 64 KiB 序列化 JSON 后停止添加链接;你用 tool() 在进程内定义的工具从不产生该键,因为 SDK 在 CLI 看到结果之前就把它的 resource_link 块展平成了文本。

AssistantMessage

带内容块的助手响应消息。

@dataclass
class AssistantMessage:
    content: list[ContentBlock]
    model: str
    parent_tool_use_id: str | None = None
    error: AssistantMessageError | None = None
    usage: dict[str, Any] | None = None
    message_id: str | None = None
    stop_reason: str | None = None
    session_id: str | None = None
    uuid: str | None = None
字段类型说明
contentlist[ContentBlock]响应里的内容块列表
modelstr生成响应的模型
parent_tool_use_idstr | None这是嵌套响应时的工具使用 ID
errorAssistantMessageError | None响应遇到错误时的错误类型
usagedict[str, Any] | None每条消息的 token 用量(键与 ResultMessage.usage 相同)
message_idstr | NoneAPI 消息 ID;同一轮次的多条消息共享同一个 ID
stop_reasonstr | None来自 API 的停止原因(例如 end_turn、tool_use)
session_idstr | None该消息所属会话的 ID
uuidstr | None会话记录内的唯一消息标识

AssistantMessageError

助手消息可能的错误类型。

AssistantMessageError = Literal[
    "authentication_failed",
    "billing_error",
    "rate_limit",
    "invalid_request",
    "server_error",
    "unknown",
]

底层 CLI 进程可能发出这个 Literal 没有列出的错误类型,如 max_output_tokens;SDK 原样透传该值,所以要把列表之外的字符串当作 unknown 处理。TypeScript 的 SDKAssistantMessageError 类型列出了 CLI 能发出的全部值。

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
    stop_reason: str | None = None
    total_cost_usd: float | None = None
    usage: dict[str, Any] | None = None
    result: str | None = None
    structured_output: Any = None
    model_usage: dict[str, ModelUsage] | None = None
    permission_denials: list[Any] | None = None
    deferred_tool_use: DeferredToolUse | None = None
    errors: list[str] | None = None
    api_error_status: int | None = None
    uuid: str | None = None
    terminal_reason: str | None = None
    origin: MessageOrigin | None = None

subtype 字段决定其他哪些字段被填充,取值之一:"success"、"error_during_execution"、"error_max_turns"、"error_max_budget_usd" 或 "error_max_structured_output_retries"。Python dataclass 把所有变体展平成一个形状,所以不适用于所返回 subtype 的字段为 None。若干字段携带关于对话如何结束的诊断细节:

  • is_error:对话以错误状态结束时为 True;在 error_* subtype 上总是 True;在 subtype="success" 上,最后一次模型请求失败时为 True,即智能体循环完成了但最后一次 API 调用返回了错误。
  • api_error_status:终止的 API 错误的 HTTP 状态码;轮次没有这类错误地结束时为 None;只在 subtype="success" 上填充。
  • result:subtype="success" 上最终助手消息的文本,error_* subtype 上为 None;当 subtype="success" 且 is_error=True 时,它持有 API 错误字符串(如果有的话,但可能为空),所以要查看 api_error_status 和前面的 AssistantMessage 内容来了解细节。
  • errors:循环级的错误字符串,如最大轮次消息;只在 error_* subtype 上填充。
  • terminal_reason:查询循环为何结束,如 "completed"、"max_turns"、"api_error"、"aborted_streaming" 或 "aborted_tools";"aborted_streaming" 或 "aborted_tools" 表示轮次在完成前被中止,常见原因是 interrupt() 和权限回调返回带 interrupt=True 的 PermissionResultDeny;在早于该字段的 CLI 版本上、以及绕过智能体循环的本地命令(如 /voice 或 /usage)的结果上为 None。
  • origin:触发这个轮次的用户消息的来源。在流式输入模式下,检查它来区分你自己提示的结果(origin 为 None 或 {"kind": "human"})与注入轮次(如后台任务通知)的结果(需要 Python Agent SDK 0.2.137 及以上)。

usage 字典只涵盖主智能体循环,不含子智能体以及其他嵌套或辅助的模型调用;在流式输入模式下,值是按轮次的。做 token 和成本核算时优先用 model_usage。usage 字典存在时含这些键:

键类型说明
input_tokensint顶层智能体循环消耗的输入 token;不含子智能体 token,整棵树的核算要用 model_usage
output_tokensint顶层智能体循环生成的输出 token;不含子智能体 token
cache_creation_input_tokensint用于创建新缓存条目的 token
cache_read_input_tokensint从现有缓存条目读取的 token

model_usage 字典把模型名映射到按模型的用量,涵盖经查询管道发出的每个模型调用:主循环、子智能体,以及压缩和 Workflow 智能体等内部调用;管道之外的辅助调用(如权限分类器和 token 计数请求)被排除在 model_usage 之外。把 model_usage 视为估算,不是账单。在流式输入模式下,model_usage 和 total_cost_usd 跨轮次累计,所以要读最新的结果而不是跨结果求和;恢复会话的调用还会计入从会话先前调用还原的总数。model_usage 的每个值是 ModelUsage TypedDict(通过 from claude_agent_sdk.types import ModelUsage 导入),它的键用 camelCase,因为 SDK 原样透传来自底层 CLI 进程的值,与 TypeScript 的 ModelUsage 类型一致:

键类型说明
inputTokensint该模型的输入 token
outputTokensint该模型的输出 token
cacheReadInputTokensint该模型的缓存读取 token
cacheCreationInputTokensint该模型的缓存创建 token
webSearchRequestsint该模型发出的网页搜索请求数
thinkingTokensint该模型生成的思考 token,已计入 outputTokens;在某个轮次于记录它的 Claude Code 版本上运行之前不存在,也没有在 TypedDict 上声明,所以要用 .get() 读取(需要 Python Agent SDK 0.2.150 及以上,其捆绑的 CLI 会记录它)
costUSDfloat该模型估算的美元成本,在客户端计算
contextWindowint该模型的上下文窗口大小
maxOutputTokensint该模型的最大输出 token 限制
canonicalModelstr价格查找使用的规范模型 ID,可能与作为条目键的原始模型字符串不同(如提供商专有 ID 或别名);不一定存在
providerstr服务该模型的 API 提供商,如 firstParty、bedrock、vertex、foundry、anthropicAws、mantle 或 gateway;不一定存在

StreamEvent

流式传输期间部分消息更新的流事件。只有在 ClaudeAgentOptions 里设了 include_partial_messages=True 时才会收到。通过 from claude_agent_sdk.types import StreamEvent 导入。

@dataclass
class StreamEvent:
    uuid: str
    session_id: str
    event: dict[str, Any]  # 原始的 Claude API 流事件
    parent_tool_use_id: str | None = None
字段类型说明
uuidstr该事件的唯一标识
session_idstr会话标识
eventdict[str, Any]原始的 Claude API 流事件数据
parent_tool_use_idstr | None总是 None:流事件只为主会话发出;要做子智能体归属,用 AssistantMessage 这类完整消息

RateLimitEvent

速率限制状态变化时发出(例如从 "allowed" 变为 "allowed_warning")。用它在用户触及硬限制之前警告他们,或在状态为 "rejected" 时退避。

@dataclass
class RateLimitEvent:
    rate_limit_info: RateLimitInfo
    uuid: str
    session_id: str

RateLimitInfo

RateLimitEvent 携带的速率限制状态。

RateLimitStatus = Literal["allowed", "allowed_warning", "rejected"]
RateLimitType = Literal[
    "five_hour", "seven_day", "seven_day_opus", "seven_day_sonnet", "overage"
]


@dataclass
class RateLimitInfo:
    status: RateLimitStatus
    resets_at: int | None = None
    rate_limit_type: RateLimitType | None = None
    utilization: float | None = None
    overage_status: RateLimitStatus | None = None
    overage_resets_at: int | None = None
    overage_disabled_reason: str | None = None
    raw: dict[str, Any] = field(default_factory=dict)
字段类型说明
statusRateLimitStatus当前状态,"allowed"、"allowed_warning" 或 "rejected" 之一;"allowed_warning" 表示接近限制,"rejected" 表示已触及限制
resets_atint | None速率限制窗口重置时的 Unix 时间戳
rate_limit_typeRateLimitType | None适用哪个速率限制窗口
utilizationfloat | None已消耗的速率限制比例(0.0 到 1.0)
overage_statusRateLimitStatus | None按量付费超额用量的状态(如适用)
overage_resets_atint | None超额窗口重置时的 Unix 时间戳
overage_disabled_reasonstr | None状态为 "rejected" 时,超额为何不可用
rawdict[str, Any]来自 CLI 的完整原始字典,包含上面没有建模的字段

ConversationResetMessage

对话被替换而不结束连接时发出,如 /clear 之后(重置如何影响之后 ResultMessage 对象上的累计总数,见「在流式输入模式下跟踪成本」)。需要 Python Agent SDK 0.2.137 及以上。

@dataclass
class ConversationResetMessage:
    new_conversation_id: str
    uuid: str
    session_id: str
字段类型说明
new_conversation_idstr新对话的不透明标识;不是后续消息的 session_id,那个要从下一条消息读取
uuidstr唯一的消息标识
session_idstr被重置的会话的 ID;重置之后的消息带新的 session_id

TaskStartedMessage、TaskUsage、TaskProgressMessage、TaskNotificationMessage

后台任务是在主轮次之外跟踪的任何东西:转入后台的 Bash 命令、Monitor 监视、经 Agent 工具派生的子智能体或远程智能体;task_type 字段告诉你是哪一种(这个命名与 Task 到 Agent 的工具重命名无关)。

@dataclass
class TaskStartedMessage(SystemMessage):
    task_id: str
    description: str
    uuid: str
    session_id: str
    tool_use_id: str | None = None
    task_type: str | None = None


class TaskUsage(TypedDict):
    total_tokens: int
    tool_uses: int
    duration_ms: int


@dataclass
class TaskProgressMessage(SystemMessage):
    task_id: str
    description: str
    usage: TaskUsage
    uuid: str
    session_id: str
    tool_use_id: str | None = None
    last_tool_name: str | None = None


@dataclass
class TaskNotificationMessage(SystemMessage):
    task_id: str
    status: TaskNotificationStatus  # "completed" | "failed" | "stopped"
    output_file: str
    summary: str
    uuid: str
    session_id: str
    tool_use_id: str | None = None
    usage: TaskUsage | None = None

TaskStartedMessage 在后台任务开始时发出:task_id 是任务唯一标识,description 是任务描述,tool_use_id 是关联的工具使用 ID,task_type 说明哪种后台任务:"local_bash"(后台 Bash 和 Monitor 监视)、"local_agent" 或 "remote_agent"。TaskProgressMessage 在运行中的后台任务上定期发出进度更新:description 是当前状态描述,usage 是该任务到目前为止的 token 用量,last_tool_name 是任务用过的最后一个工具名。TaskNotificationMessage 在后台任务完成、失败或被停止时发出(后台任务包括 run_in_background 的 Bash 命令、Monitor 监视和后台子智能体):status 是 "completed"、"failed" 或 "stopped" 之一,output_file 是任务输出文件的路径,summary 是任务结果的摘要,usage 是任务最终的 token 用量。当 CLI 把长时间的 MCP 工具调用转入后台时,该调用的工具结果只含占位符,调用的真实结果在这条消息里到达;对这类调用的 "completed" 通知,CLI 会加一个 resource_links 键,列出工具按引用返回的文件,条目和限制与 UserMessage.tool_use_result 上的 resourceLinks 键相同(resource_links 键需要 Python Agent SDK 0.2.150 及以上)。dataclass 没有 resource_links 字段,要从消息继承自 SystemMessage 的 data 字典读取:message.data.get("resource_links");用 tool_use_id 把通知与调用匹配;结果没有链接时以及不是 MCP 工具调用的任务通知上,CLI 省略该键。

内容块类型

ContentBlock

所有内容块的联合类型。

ContentBlock = (
    TextBlock
    | ThinkingBlock
    | ToolUseBlock
    | ToolResultBlock
    | ServerToolUseBlock
    | ServerToolResultBlock
)

各内容块:

@dataclass
class TextBlock:
    text: str


@dataclass
class ThinkingBlock:  # 用于具备思考能力的模型
    thinking: str
    signature: str


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


@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):
    """Base error for Claude SDK."""

单次 query() 以错误结果结束时(例如轮次上限错误),SDK 在产出最终结果消息之后抛出 ResultError;Python Agent SDK 0.2.140 之前,抛出的是一个不是 ClaudeSDKError 子类的普通 Exception。

CLINotFoundError 与 CLIConnectionError

未安装或找不到 Claude Code CLI 时抛出 CLINotFoundError;连接 Claude Code 失败时抛出 CLIConnectionError。

class CLINotFoundError(CLIConnectionError):
    def __init__(
        self, message: str = "Claude Code not found", cli_path: str | None = None
    ):
        """
        Args:
            message: 错误消息(默认:"Claude Code not found")
            cli_path: 找不到的 CLI 的可选路径
        """


class CLIConnectionError(ClaudeSDKError):
    """Failed to connect to 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

ResultError

在最终的 ResultMessage 之后抛出,当 Claude Code 进程因运行以错误结果结束(如轮次上限错误或 API 错误)而退出时。ResultError 是 ProcessError 的子类,所以现有的 except ProcessError 处理程序也会捕获它。它的属性携带该结果消息的字段,所以你能按运行失败的原因分支,而不必解析消息文本(需要 Python Agent SDK 0.2.140 及以上)。

class ResultError(ProcessError):
    subtype: str | None  # "error_max_turns"、"error_during_execution" 等;运行因失败的请求而结束时为 "success"
    errors: list[str]  # 结果消息没报告任何错误时为空列表
    result: str | None
    api_error_status: int | None
    terminal_reason: str | None  # "max_turns"、"api_error" 等;先检查它,再看 subtype
    session_id: str | None
    data: dict[str, Any]  # 原始的结果消息载荷

要区分各种失败,先检查 terminal_reason 再看 subtype:最终请求失败(如 API 错误)时,Claude Code 报告 subtype 为 "success",原因在 terminal_reason 里,例如 "api_error";你设置的限制(如 max_turns 或 max_budget_usd)结束运行时,它报告 error_* subtype。

CLIJSONDecodeError

JSON 解析失败时抛出。

class CLIJSONDecodeError(ClaudeSDKError):
    def __init__(self, line: str, original_error: Exception):
        """
        Args:
            line: 解析失败的那一行
            original_error: 原始的 JSON 解码异常
        """
        self.line = line
        self.original_error = original_error