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| 字段 | 类型 | 说明 |
|---|---|---|
content | str | list[ContentBlock] | 消息内容,文本或内容块 |
uuid | str | None | 唯一的消息标识 |
parent_tool_use_id | str | None | 该消息是工具结果响应时的工具使用 ID |
tool_use_result | dict[str, Any] | None | 工具结果数据(如适用) |
origin | MessageOrigin | 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| 字段 | 类型 | 说明 |
|---|---|---|
content | list[ContentBlock] | 响应里的内容块列表 |
model | str | 生成响应的模型 |
parent_tool_use_id | str | None | 这是嵌套响应时的工具使用 ID |
error | AssistantMessageError | None | 响应遇到错误时的错误类型 |
usage | dict[str, Any] | None | 每条消息的 token 用量(键与 ResultMessage.usage 相同) |
message_id | str | None | API 消息 ID;同一轮次的多条消息共享同一个 ID |
stop_reason | str | None | 来自 API 的停止原因(例如 end_turn、tool_use) |
session_id | str | None | 该消息所属会话的 ID |
uuid | str | 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 = Nonesubtype 字段决定其他哪些字段被填充,取值之一:"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_tokens | int | 顶层智能体循环消耗的输入 token;不含子智能体 token,整棵树的核算要用 model_usage |
output_tokens | int | 顶层智能体循环生成的输出 token;不含子智能体 token |
cache_creation_input_tokens | int | 用于创建新缓存条目的 token |
cache_read_input_tokens | int | 从现有缓存条目读取的 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 类型一致:
| 键 | 类型 | 说明 |
|---|---|---|
inputTokens | int | 该模型的输入 token |
outputTokens | int | 该模型的输出 token |
cacheReadInputTokens | int | 该模型的缓存读取 token |
cacheCreationInputTokens | int | 该模型的缓存创建 token |
webSearchRequests | int | 该模型发出的网页搜索请求数 |
thinkingTokens | int | 该模型生成的思考 token,已计入 outputTokens;在某个轮次于记录它的 Claude Code 版本上运行之前不存在,也没有在 TypedDict 上声明,所以要用 .get() 读取(需要 Python Agent SDK 0.2.150 及以上,其捆绑的 CLI 会记录它) |
costUSD | float | 该模型估算的美元成本,在客户端计算 |
contextWindow | int | 该模型的上下文窗口大小 |
maxOutputTokens | int | 该模型的最大输出 token 限制 |
canonicalModel | str | 价格查找使用的规范模型 ID,可能与作为条目键的原始模型字符串不同(如提供商专有 ID 或别名);不一定存在 |
provider | str | 服务该模型的 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| 字段 | 类型 | 说明 |
|---|---|---|
uuid | str | 该事件的唯一标识 |
session_id | str | 会话标识 |
event | dict[str, Any] | 原始的 Claude API 流事件数据 |
parent_tool_use_id | str | None | 总是 None:流事件只为主会话发出;要做子智能体归属,用 AssistantMessage 这类完整消息 |
RateLimitEvent
速率限制状态变化时发出(例如从 "allowed" 变为 "allowed_warning")。用它在用户触及硬限制之前警告他们,或在状态为 "rejected" 时退避。
@dataclass
class RateLimitEvent:
rate_limit_info: RateLimitInfo
uuid: str
session_id: strRateLimitInfo
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)| 字段 | 类型 | 说明 |
|---|---|---|
status | RateLimitStatus | 当前状态,"allowed"、"allowed_warning" 或 "rejected" 之一;"allowed_warning" 表示接近限制,"rejected" 表示已触及限制 |
resets_at | int | None | 速率限制窗口重置时的 Unix 时间戳 |
rate_limit_type | RateLimitType | None | 适用哪个速率限制窗口 |
utilization | float | None | 已消耗的速率限制比例(0.0 到 1.0) |
overage_status | RateLimitStatus | None | 按量付费超额用量的状态(如适用) |
overage_resets_at | int | None | 超额窗口重置时的 Unix 时间戳 |
overage_disabled_reason | str | None | 状态为 "rejected" 时,超额为何不可用 |
raw | dict[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_id | str | 新对话的不透明标识;不是后续消息的 session_id,那个要从下一条消息读取 |
uuid | str | 唯一的消息标识 |
session_id | str | 被重置的会话的 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 = NoneTaskStartedMessage 在后台任务开始时发出: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 = stderrResultError
在最终的 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