Claude Agent SDK 的 Python 版怎么用:与 TypeScript 版对不上的地方
搜 Claude Agent SDK 的用法,翻到的示例十有八九是 TypeScript 的。把它照着改成 Python,第一步通常没问题,改到第三步就开始报错:字段名写成驼峰不认,某个方法在 Python 这边压根没有,沙箱起不来的时候两边行为还不一样。
这类坑里有一部分官方文档其实写明了,只是分散在 Python 参考页的几个 Note 里,不逐段读很容易错过。这篇就把「文档明说的差异」摘出来,并注明哪些是我们在文档里查不到对应说明的——查不到的地方,本文不替它补。
一、这个东西解决什么问题
Agent SDK 的两个语言版本不是同一套代码的机械翻译。官方文档在 Python 参考页(code.claude.com/docs/en/agent-sdk/python)里明确用「TypeScript SDK 不受影响」「TypeScript-only」「这个默认值与 TypeScript SDK 不同」这样的措辞标出了若干处不一致。也就是说,跨语言搬示例出问题不是你写错了,是两边确实不一样。
先说最容易踩的一条:Python 版有两个入口,TypeScript 版只有一个。
文档写明,Python 的 query() 默认为每次交互创建新会话,返回一个异步迭代器;而 ClaudeSDKClient 「在多次交换之间维持同一个会话」,并且原文自述它是「TypeScript SDK 的 query() 函数内部工作方式在 Python 里的等价物」。所以你在 TypeScript 示例里看到的 query() 拿到一个可以继续对话、可以中断的对象,在 Python 里对应的其实是 ClaudeSDKClient,而不是同名的 query()。
Python 参考页给了一张对照表,其中几行值得记住:query() 单次交换、连接自动管理、不支持 interrupts,续聊要手工传 continue_conversation 或 resume;ClaudeSDKClient 复用同一会话、连接手工控制、支持 interrupts、续聊自动。hooks 和自定义工具两边都支持。文档的建议是:聊天界面这类交互式应用,或者下一步动作取决于上一次回答的场景,用 ClaudeSDKClient。
二、前置条件
快速上手页(code.claude.com/docs/en/agent-sdk/quickstart)列的前置条件是 Node.js 18+ 或 Python 3.10+,外加一个 Anthropic 账号。
Python 参考页对安装写得很直接:装进虚拟环境。原文说明,在较新的 Debian、Ubuntu 和 Homebrew 的 Python 上,对系统 Python 跑 pip install 会失败并报 error: externally-managed-environment。
macOS / Linux:
python3 -m venv .venv
source .venv/bin/activate
pip install claude-agent-sdk
Windows(PowerShell),快速上手页给的是另一组命令:
py -m venv .venv
.venv\Scripts\Activate.ps1
pip install claude-agent-sdk
文档还写了一句 Windows 用户大概率会撞上的:如果 PowerShell 因执行策略拦住 Activate.ps1,先跑 Set-ExecutionPolicy -Scope Process RemoteSigned。
用 uv 的话是 uv init 加 uv add claude-agent-sdk。
关于底层 CLI,文档说两个 SDK 都捆绑了原生 Claude Code 二进制,多数安装不需要单独装 Claude Code,但有例外:如果 pip 装到的是 Python SDK 的源码分发而不是平台 wheel(原文举的例子是 ARM64 Windows),就没有捆绑二进制,需要单独原生安装 Claude Code,Python SDK 会从你的 PATH 上找到它。TypeScript 侧的对应例外是 npm 跳过了可选依赖(原文举例 npm ci --omit=optional),这时要重装或改用 pathToClaudeCodeExecutable 指向自己装的二进制。
密钥用环境变量,文档明说 SDK 不会自动加载 .env 文件:
$env:ANTHROPIC_API_KEY = "<YOUR_API_KEY>"
macOS / Linux 侧是 export ANTHROPIC_API_KEY=<YOUR_API_KEY>。文档另外列了通过 Amazon Bedrock、Google Cloud 的 Agent Platform、Microsoft Foundry 等第三方供应商鉴权的开关变量,需要走这条路的按对应设置页配。
三、命名对不上的地方,先看这张表
Python 版顶层配置类是 ClaudeAgentOptions,字段是 snake_case;TypeScript 版是 Options,字段是 camelCase。这一层是机械对应的,permission_mode ↔ permissionMode,strict_mcp_config ↔ strictMcpConfig,照猜基本不会错。真正会咬人的是不机械的那几处:
| 事项 | Python | TypeScript |
|---|---|---|
| 顶层配置字段 | snake_case,如 permission_mode | camelCase,如 permissionMode |
AgentDefinition 字段 | 仍是 camelCase,如 disallowedTools、maxTurns | camelCase |
| 续聊开关 | continue_conversation | continue |
| 指定 CLI 可执行文件 | cli_path | pathToClaudeCodeExecutable |
| 追加可访问目录 | add_dirs | additionalDirectories |
ModelUsage 的键 | camelCase,如 inputTokens | camelCase |
AgentDefinition 那一行是重灾区。Python 参考页专门加了 Note:它的字段名用 camelCase,「这些名字直接对应与 TypeScript SDK 共享的 wire 格式」,与使用 snake_case 的 ClaudeAgentOptions 不同;由于 AgentDefinition 是 dataclass,传 snake_case 关键字会在构造时抛 TypeError。也就是说同一份配置里,外层写 permission_mode,定义 subagent 的内层写 permissionMode,看着别扭但文档就是这么规定的。
ModelUsage 同理:文档说它的键用 camelCase,因为 SDK 把底层 CLI 进程的值原样透传,与 TypeScript 的 ModelUsage 类型一致。
还有一个 Python 独有的取值陷阱,与 TypeScript 无关但同样常见。参考页的 Note 写明:这套 SDK 有两类类型,带 @dataclass 的(如 ResultMessage、AgentDefinition、TextBlock)运行时是对象,用属性访问 msg.result;用 TypedDict 定义的(如 ThinkingConfigEnabled、McpStdioServerConfig、SyncHookJSONOutput)运行时就是普通 dict,必须用键访问 config["budget_tokens"],写成 config.budget_tokens 不行。两类都能用 ClassName(field=value) 的写法构造,只有 dataclass 构造出带属性的对象。
四、自定义工具:装饰器 vs 函数参数
自定义 MCP 工具是两边写法差得最远的一处。Python 用 @tool 装饰器,schema 可以是简单类型映射,也可以是 JSON Schema:
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']}!"}]}
TypeScript 的 tool() 是普通函数,签名里第四个参数就是 handler,inputSchema 收的是 Zod schema(文档写明同时支持 Zod 3 和 Zod 4)。所以 TypeScript 示例里的 Zod 那一套在 Python 这边没有对应物,得改写成类型映射或 JSON Schema。
建服务器的入口也不一样。Python 是位置参数:
def create_sdk_mcp_server(
name: str,
version: str = "1.0.0",
tools: list[SdkMcpTool[Any]] | None = None
) -> McpSdkServerConfig
TypeScript 的 createSdkMcpServer() 收一个对象,除了 name / version / tools 还有 instructions 和 alwaysLoad——后两个我们在 Python 参考页的 create_sdk_mcp_server() 参数表里没有找到对应项。
ToolAnnotations 两边都有。这里照抄文档的一句提醒:所有字段都是可选提示,客户端不应依赖它们做安全决策。
五、边界:文档明说不一致或明说没有的部分
这一节全部是官方文档写明的限制,不是推断。
- hook 事件 Python 更少。 Python 参考页的
HookEvent列出的是PreToolUse、PostToolUse、PostToolUseFailure、UserPromptSubmit、Stop、SubagentStop、PreCompact、Notification、SubagentStart、PermissionRequest这些;紧跟着的 Note 直说「TypeScript SDK 支持一些 Python 尚不可用的 hook 事件」,让你去查 hooks 页的按 SDK 支持情况表。TypeScript 参考页的HookEvent里确实还有SessionStart、SessionEnd、PostCompact、PermissionDenied、WorktreeCreate等 Python 侧没列的值。你在 TypeScript 教程里看到的某个 hook,先确认它在不在 Python 这张表里。 applyFlagSettings()是 TypeScript-only。 TypeScript 参考页的 Note 原话是这个方法「Python SDK 不提供等价方法」。Python 的ClaudeSDKClient有set_permission_mode()和set_model()这两个专用 setter,但没有那个通用形式。- sandbox 起不来时的默认行为不同。 Python 参考页写明:sandbox 依赖平台支持,Linux 上还依赖
bubblewrap、socat之类的工具;默认情况下enabled为True但 sandbox 起不来时,命令会不带沙箱继续执行,只在 stderr 打一条警告。原文紧接着说「这个默认值与 TypeScript SDK 不同,那边failIfUnavailable默认为true」。Python 侧想要「起不来就停」,文档给的做法是在 sandbox 设置里写"failIfUnavailable": True,并明确提示这个键还没有声明在SandboxSettings上,只是 SDK 会把它转发给 Claude Code,后者认这个键。这属于文档明说的过渡态,写代码时值得留一条注释。涉及本机执行外部命令的配置,别把「设了某个开关」当成安全保证。 - 错误类型枚举 Python 不全。
AssistantMessageError这个Literal列的值有限,文档写明底层 CLI 进程可能吐出这个 Literal 没列的类型(原文举例max_output_tokens),SDK 原样透传,遇到列表外的字符串就按unknown处理;完整取值集合要去看 TypeScript 的SDKAssistantMessageError。写分支判断时别把Literal当封闭集合用。 setting_sources=[]在旧版本上不生效。 文档写明:Python SDK 0.1.59 及更早版本把空列表当成没传这个选项,所以setting_sources=[]并不会禁用文件系统设置,需要空列表真正生效就升级;并注明「TypeScript SDK 不受影响」。Transport是低层内部 API。 Python 参考页对Transport抽象基类挂了 Warning:这是低层内部 API,接口在未来版本可能变化,自定义实现必须跟着改。- interrupt 之后缓冲区不会清空。 文档写明
interrupt()只是发停止信号,被中断任务已经产生的消息(包括它的ResultMessage)仍留在流里,必须先用receive_response()排空,否则中断后立刻发新 query 再只读一次receive_response(),你拿到的是上一个任务的消息。另有一条提醒:遍历消息时避免用break提前退出,那会引发 asyncio 清理问题。 startup()/WarmQuery这类预热接口,我们在 Python 参考页上没有找到对应说明,TypeScript 参考页有。这里只陈述两页文档的差异,不推断 Python 侧是否计划支持。
六、怎么验证配对了
按快速上手页,跑起来的命令按安装方式分:uv 装的用 uv run agent.py,pip 装的在虚拟环境仍激活的状态下用 python agent.py。TypeScript 侧是 npx tsx agent.ts。
几个能确认「配对了」的判据:
- 看是不是根本没读到密钥。 文档给的排查提示很直白:如果出现 “API key not found”,确认
ANTHROPIC_API_KEY是在你实际运行 agent 的那个 shell 里设的——SDK 不自动加载.env。Windows 上尤其容易踩:在一个 PowerShell 窗口里$env:设的变量,换个窗口就没了。 - 确认虚拟环境真的激活了。 如果
pip install报error: externally-managed-environment,说明装到系统 Python 上去了,回到第二节重来。 - 拿会话信息做连通性检查。 Python 的
ClaudeSDKClient有get_server_info(),文档说它返回包含 session ID 与 capabilities 的服务端信息;MCP 那边可以用get_mcp_status()看所有已配置 MCP 服务器的状态。 - 验证 camelCase / snake_case 有没有搞混。 由于
AgentDefinition传 snake_case 关键字会在构造时抛TypeError,这个错会在调用 Claude 之前就暴露,属于容易定位的一类。 - 最小可跑的形态,官方给的上下文管理器写法是这样:
import asyncio
from claude_agent_sdk import ClaudeSDKClient
async def main():
async with ClaudeSDKClient() as client:
await client.query("Hello Claude")
async for message in client.receive_response():
print(message)
asyncio.run(main())
参考页另有一条说明:签名块和裸的 async for / async with 片段只是示意,要跑得把函数体包进 async def main(): ... 再用 asyncio.run(main()) 调用。
以上代码块均按官方文档原样引用;若你把多个参数组合到一起使用,属于按官方文档中的参数语义组合的示例,未经实测,以官方文档与 --help 的实际输出为准。
最后提醒一句,本文列出的差异是文档在某一时刻的口径。这类 SDK 迭代频繁,字段增删、默认值调整、某个 TypeScript-only 的方法哪天补到 Python 侧,都不会有人来通知你——真正落地前,还是把对应那一页翻一遍。
本文依据 Claude Code 官方文档(code.claude.com/docs)于 2026-08-17 的公开内容整理。
该产品闭源,本文只复述官方文档写明的机制,不推断其内部实现;
我们没有对文中涉及的功能做过实测,因此不涉及界面外观、操作手感与运行速度的任何描述。
该产品迭代频繁,文中涉及的命令、配置项与默认值随版本变动,请以官方文档最新内容为准。
本文不涉及价格、额度与限流的具体数值,相关信息请以官方定价与用量说明页为准。
安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。