Claude Agent SDK 的 Python 版怎么用:与 TypeScript 版对不上的地方

2026-08-18

搜 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_conversationresumeClaudeSDKClient 复用同一会话、连接手工控制、支持 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 inituv 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_modepermissionModestrict_mcp_configstrictMcpConfig,照猜基本不会错。真正会咬人的是不机械的那几处:

事项PythonTypeScript
顶层配置字段snake_case,如 permission_modecamelCase,如 permissionMode
AgentDefinition 字段仍是 camelCase,如 disallowedToolsmaxTurnscamelCase
续聊开关continue_conversationcontinue
指定 CLI 可执行文件cli_pathpathToClaudeCodeExecutable
追加可访问目录add_dirsadditionalDirectories
ModelUsage 的键camelCase,如 inputTokenscamelCase

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 的(如 ResultMessageAgentDefinitionTextBlock)运行时是对象,用属性访问 msg.result;用 TypedDict 定义的(如 ThinkingConfigEnabledMcpStdioServerConfigSyncHookJSONOutput运行时就是普通 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 还有 instructionsalwaysLoad——后两个我们在 Python 参考页的 create_sdk_mcp_server() 参数表里没有找到对应项。

ToolAnnotations 两边都有。这里照抄文档的一句提醒:所有字段都是可选提示,客户端不应依赖它们做安全决策

五、边界:文档明说不一致或明说没有的部分

这一节全部是官方文档写明的限制,不是推断。

  • hook 事件 Python 更少。 Python 参考页的 HookEvent 列出的是 PreToolUsePostToolUsePostToolUseFailureUserPromptSubmitStopSubagentStopPreCompactNotificationSubagentStartPermissionRequest 这些;紧跟着的 Note 直说「TypeScript SDK 支持一些 Python 尚不可用的 hook 事件」,让你去查 hooks 页的按 SDK 支持情况表。TypeScript 参考页的 HookEvent 里确实还有 SessionStartSessionEndPostCompactPermissionDeniedWorktreeCreate 等 Python 侧没列的值。你在 TypeScript 教程里看到的某个 hook,先确认它在不在 Python 这张表里。
  • applyFlagSettings() 是 TypeScript-only。 TypeScript 参考页的 Note 原话是这个方法「Python SDK 不提供等价方法」。Python 的 ClaudeSDKClientset_permission_mode()set_model() 这两个专用 setter,但没有那个通用形式。
  • sandbox 起不来时的默认行为不同。 Python 参考页写明:sandbox 依赖平台支持,Linux 上还依赖 bubblewrapsocat 之类的工具;默认情况下 enabledTrue 但 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

几个能确认「配对了」的判据:

  1. 看是不是根本没读到密钥。 文档给的排查提示很直白:如果出现 “API key not found”,确认 ANTHROPIC_API_KEY 是在你实际运行 agent 的那个 shell 里设的——SDK 不自动加载 .env。Windows 上尤其容易踩:在一个 PowerShell 窗口里 $env: 设的变量,换个窗口就没了。
  2. 确认虚拟环境真的激活了。 如果 pip installerror: externally-managed-environment,说明装到系统 Python 上去了,回到第二节重来。
  3. 拿会话信息做连通性检查。 Python 的 ClaudeSDKClientget_server_info(),文档说它返回包含 session ID 与 capabilities 的服务端信息;MCP 那边可以用 get_mcp_status() 看所有已配置 MCP 服务器的状态。
  4. 验证 camelCase / snake_case 有没有搞混。 由于 AgentDefinition 传 snake_case 关键字会在构造时抛 TypeError,这个错会在调用 Claude 之前就暴露,属于容易定位的一类。
  5. 最小可跑的形态,官方给的上下文管理器写法是这样:
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 的公开内容整理。 该产品闭源,本文只复述官方文档写明的机制,不推断其内部实现我们没有对文中涉及的功能做过实测,因此不涉及界面外观、操作手感与运行速度的任何描述。 该产品迭代频繁,文中涉及的命令、配置项与默认值随版本变动,请以官方文档最新内容为准。 本文不涉及价格、额度与限流的具体数值,相关信息请以官方定价与用量说明页为准。

安全与合规相关做法请结合自身环境评估,本文不构成安全方案建议。

想系统学会用 AI?报名体系课或加入会员,照着学、照着用。