返回专栏
Agent SDK/03 · Claude/3.3

Claude Agent SDK

Claude Agent SDK 就是把 Claude Code 当作一个库来用:它提供与 Claude Code 相同的工具、agent loop 和上下文管理,支持 Python 和 TypeScript。

预计阅读
23分钟
全文字数
3,000字
资料截至
2026-10-09
Agent SDK · Claude3.3
版本与时效声明
  • 本文基于 claude-agent-sdk(Python)0.2.164(仓库 commit f7b0b62,2026-10-07)。安装包里自带 Claude Code CLI 2.1.2921。TS 版 @anthropic-ai/claude-agent-sdk 的最新版本为 0.3.293,与 Claude Code v2.1.293 对齐2。
  • 该 SDK 的版本号仍是 0.x,几乎每天都会随 Claude Code 一起发版,行为细节变化很快。文中代码已用 pyright 对照 0.2.164 做过类型检查;没有 API Key,因此没有实际运行。
  • 资料截至 2026-10-09,本文不随官方同步更新,请对照 Agent SDK 文档 以及 Python 和 TS 的 CHANGELOG 使用。
本文要点
  1. Claude Agent SDK 就是把 Claude Code 当作一个库来用:它提供与 Claude Code 相同的工具、agent loop 和上下文管理,支持 Python 和 TypeScript3。
  2. 从架构上看,你的代码调用 query() 时,SDK 会启动一个 claude CLI 子进程,通过 stdio 与它通信。这个子进程持有 shell、工作目录和本地磁盘上的会话记录4。
  3. 开箱即用:Read、Edit、Write、Bash、Glob、Grep、WebSearch、WebFetch 等内置工具,加上权限、hooks、subagents、MCP、sessions、skills、plugins35。
  4. 它原名 Claude Code SDK,2025-09-29 更名为 Claude Agent SDK,因为同一套 harness 也适用于编码以外的 agent6。

1. 定位:harness,而不是“又一个 API 封装”#

  • 分层位置:L4 Harness,运行在你自己的基础设施上。
  • 它和 Tool Runner 的区别:Tool Runner 只循环你自己定义的工具;Agent SDK 自带一整套编码和文件系统工具,还有权限系统,见 3.2 Anthropic 客户端 SDK 与 Messages API。
  • 它和 Managed Agents 的区别:Agent SDK 由你来部署;Managed Agents 由 Anthropic 托管运行,见 3.4 Claude Managed Agents。
  • 官方说明:Agent SDK 是一个运行 Claude Code 二进制的库,具备 Claude Code 的内置工具、权限、会话和 hooks 等能力3。
关于品牌与登录方式
  • 官方规定:除非事先获得批准,第三方开发者不得在基于 Agent SDK 的产品中提供 claude.ai 账号登录或沿用其额度,请使用 API Key 认证3。
  • 产品可以叫 “Claude Agent” 或 “{你的产品名} Powered by Claude”,但不能叫 “Claude Code”3。

2. 架构:子进程模型#

claude CLI 子进程(随 SDK 打包的二进制)

你的进程(Python / Node)

stdio:JSON 消息流

HTTPS

你的应用代码

Agent SDK

query() / ClaudeSDKClient

hooks 回调

can_use_tool 回调

进程内 MCP 工具

agent loop + 上下文管理 + compaction

内置工具

Read / Edit / Write / Bash / Glob / Grep / Web…

Claude API

工作目录 / shell

~/.claude/projects/

JSONL 会话记录

claude CLI 子进程(随 SDK 打包的二进制)

你的进程(Python / Node)

stdio:JSON 消息流

HTTPS

你的应用代码

Agent SDK

query() / ClaudeSDKClient

hooks 回调

can_use_tool 回调

进程内 MCP 工具

agent loop + 上下文管理 + compaction

内置工具

Read / Edit / Write / Bash / Glob / Grep / Web…

Claude API

工作目录 / shell

~/.claude/projects/

JSONL 会话记录

官方文档中与托管部署相关的几个事实4:

  • 调用 query() 时,SDK 会启动一个独立的 claude CLI 进程,通过 stdio 与它通信。这个子进程持有 shell、工作目录,以及本地磁盘上的 JSONL 会话记录。
  • 一个会话对应一个子进程。N 个并发会话就是 N 个子进程。不同会话需要隔离文件系统时,给每个会话传入不同的 cwd。
  • 默认情况下,会话记录、CLAUDE.md 和工作目录里的产物都存放在本地磁盘上,容器重启后就会丢失。如果要跨主机恢复会话,需要配置 SessionStore 适配器。
这个架构决定了部署方式

托管 Agent SDK 和托管一个无状态的 API 封装完全不同:每个运行中的 agent 都是一个绑定本地状态的长生命周期进程4。官方给出了四种会话模式(比如每个任务一个临时容器),以及 Docker、Modal、Kubernetes 的部署示例。


3. 安装与第一个 Agent#

Terminal window
pip install claude-agent-sdk # 安装包里已经自带 Claude Code 二进制
export ANTHROPIC_API_KEY=sk-ant-...
import asyncio
from claude_agent_sdk import (
AssistantMessage,
ClaudeAgentOptions,
ResultMessage,
TextBlock,
ToolUseBlock,
query,
)
async def main() -> None:
options = ClaudeAgentOptions(
cwd=".", # agent 在哪个目录里工作
allowed_tools=["Read", "Glob", "Grep"], # 列在这里的工具会被自动批准,不弹审批
max_turns=20, # 防止失控
)
async for message in query(prompt="找出这个项目里所有的 TODO 注释,并按文件汇总", options=options):
if isinstance(message, AssistantMessage):
for block in message.content: # 每个 AssistantMessage 只带一个内容块
if isinstance(block, TextBlock):
print("Claude:", block.text)
elif isinstance(block, ToolUseBlock):
print("调用工具:", block.name)
elif isinstance(message, ResultMessage): # 循环结束的标志
print("结果类型:", message.subtype, "| 费用:", message.total_cost_usd)
if message.subtype == "success":
print(message.result)
asyncio.run(main())
注意

单次调用 query() 时,如果循环以错误结束(比如 error_max_turns),SDK 会先把错误结果作为消息输出,然后再抛出异常。如果你的程序需要在出错后继续运行,记得用 try 包住5。


4. 循环与消息类型#

循环的过程5:

  1. 接收 prompt,SDK 输出一条 SystemMessage(init);
  2. Claude 评估当前状态并给出回应,可能是文本、工具调用,或者两者都有;
  3. SDK 执行工具;
  4. 重复第 2、3 步;
  5. 输出最后的 AssistantMessage(只有文本,没有工具调用),然后输出 ResultMessage。
ClaudeAgent SDK你的代码ClaudeAgent SDK你的代码……多个 turn……query("修复 auth 模块里失败的测试")SystemMessage(init)prompt + 系统提示词 + 工具定义tool_use: Bash("npm test")AssistantMessage(工具调用)执行 BashUserMessage(工具结果:3 个失败)tool_use: Read / Edit / Bash只有文本:“已修复,3 个测试全部通过”AssistantMessage(最终文本)ResultMessage(result / 费用 / usage / session_id)
ClaudeAgent SDK你的代码ClaudeAgent SDK你的代码……多个 turn……query("修复 auth 模块里失败的测试")SystemMessage(init)prompt + 系统提示词 + 工具定义tool_use: Bash("npm test")AssistantMessage(工具调用)执行 BashUserMessage(工具结果:3 个失败)tool_use: Read / Edit / Bash只有文本:“已修复,3 个测试全部通过”AssistantMessage(最终文本)ResultMessage(result / 费用 / usage / session_id)
消息类型含义
SystemMessage会话生命周期事件。subtype 有 init、compact_boundary(发生了压缩)、informational 等
AssistantMessageClaude 响应中的每一个内容块都对应一条,比如文本或工具调用
UserMessage工具执行后的结果,也包括你在循环中途发送的输入
StreamEvent原始的流式事件,需要开启 include_partial_messages
ResultMessage循环结束。包含最终文本、token 用量、费用和 session ID

以上取自官方文档5。ResultMessage.subtype 的取值有:success、error_max_turns、error_max_budget_usd、error_during_execution、error_max_structured_output_retries。只有 success 时 result 字段才有值5。


5. 内置工具与权限#

类别工具
文件操作Read、Edit、Write
搜索Glob、Grep
执行Bash
WebWebSearch、WebFetch
发现ToolSearch(按需加载工具)
编排Agent(subagent)、Skill、AskUserQuestion、TaskCreate、TaskUpdate

以上取自官方文档5。

5.1 权限是怎么判定的#

工具调用的审批按固定顺序判定,前一步就能做出决定时,后面的步骤不再执行7:

deny

放行

命中

未命中

命中

未命中

bypassPermissions / acceptEdits

等模式放行

未决定

命中

未命中

allow

deny

Claude 请求调用工具

1. Hooks

拒绝

2. deny 规则

(disallowed_tools / settings)

3. ask 规则

6. can_use_tool 回调

4. 权限模式

执行

5. allow 规则

(allowed_tools / settings)

deny

放行

命中

未命中

命中

未命中

bypassPermissions / acceptEdits

等模式放行

未决定

命中

未命中

allow

deny

Claude 请求调用工具

1. Hooks

拒绝

2. deny 规则

(disallowed_tools / settings)

3. ask 规则

6. can_use_tool 回调

4. 权限模式

执行

5. allow 规则

(allowed_tools / settings)

两个容易误解的点
  • deny 规则的优先级最高,即使在 bypassPermissions 模式下也照样生效。
  • hook 返回 allow 并不会跳过后面的 deny 和 ask 规则7。
权限模式行为
default需要审批的调用交给 can_use_tool 回调;没有提供回调时直接拒绝
acceptEdits自动批准文件编辑和常见的文件系统命令,例如 mkdir、mv
plan只探索和规划;写操作一律交给回调审批
dontAsk从不询问:没有预先批准的调用一律拒绝
auto由模型分类器逐个审查每次调用,决定放行或拦截
bypassPermissions不询问,直接运行所有允许的工具。只建议在 CI、容器等隔离环境中使用

以上取自官方文档57。

5.2 用回调做人工审批#

import asyncio
from claude_agent_sdk import (
ClaudeAgentOptions,
HookContext,
HookInput,
HookJSONOutput,
HookMatcher,
PermissionResultAllow,
PermissionResultDeny,
ResultMessage,
ToolPermissionContext,
query,
)
async def can_use_tool(
tool_name: str, input_data: dict, context: ToolPermissionContext
) -> PermissionResultAllow | PermissionResultDeny:
print(f"\n工具:{tool_name},参数:{input_data}")
if input("允许吗?(y/n) ").lower() == "y":
return PermissionResultAllow(updated_input=input_data) # 也可以修改参数后再放行
return PermissionResultDeny(message="用户拒绝了这个操作") # Claude 能看到这条信息,会换个办法
async def keep_stream_open(
input_data: HookInput, tool_use_id: str | None, context: HookContext
) -> HookJSONOutput:
return {"continue_": True} # 官方给出的变通写法:靠一个 hook 让流保持打开
async def prompt_stream():
yield {"type": "user", "message": {"role": "user", "content": "在 /tmp 里创建一个测试文件,然后删掉它"}}
async def main() -> None:
async for message in query(
prompt=prompt_stream(), # Python 中使用 can_use_tool 时需要“流式输入”
options=ClaudeAgentOptions(
can_use_tool=can_use_tool,
hooks={"PreToolUse": [HookMatcher(matcher=None, hooks=[keep_stream_open])]},
),
):
if isinstance(message, ResultMessage) and message.subtype == "success":
print(message.result)
asyncio.run(main())

这个例子改编自官方示例8。注意:如果某个工具已经被前面的规则自动批准,回调根本不会被调用8。


6. 自定义工具:进程内 MCP Server#

Agent SDK 用 in-process MCP server 承载自定义工具,也就是一个运行在你自己进程里的 MCP 服务器。工具的完整名称格式是 mcp__{server_name}__{tool_name}9。

import asyncio
from typing import Annotated, Any
from claude_agent_sdk import ClaudeAgentOptions, ResultMessage, create_sdk_mcp_server, query, tool
@tool(
"get_weather",
"查询城市今天的天气",
{"city": Annotated[str, "城市名,例如 北京"]}, # dict 写法:SDK 会转换成 JSON Schema
)
async def get_weather(args: dict[str, Any]) -> dict[str, Any]:
data = {"北京": "晴,25°C", "上海": "小雨,22°C"}
return {"content": [{"type": "text", "text": data.get(args["city"], "暂无数据")}]}
weather_server = create_sdk_mcp_server(name="weather", version="1.0.0", tools=[get_weather])
async def main() -> None:
options = ClaudeAgentOptions(
mcp_servers={"weather": weather_server}, # 这里的 key 就是 server_name
allowed_tools=["mcp__weather__get_weather"], # 预先批准,不弹审批
)
async for message in query(prompt="北京今天适合跑步吗?", options=options):
if isinstance(message, ResultMessage) and message.subtype == "success":
print(message.result)
asyncio.run(main())
要点说明
返回值必须包含 content 数组(text、image、resource 等块);可选 structuredContent(机器可读的 JSON)和 isError(标记失败)
可选参数dict 写法要求所有 key 都是必填。需要可选参数时,改用完整的 JSON Schema,并在处理函数里用 args.get() 读取
并行执行自定义工具默认串行执行。设置 readOnlyHint 注解后,可以和其他只读工具并行
只保留部分内置工具传 tools=[...] 指定要保留的内置工具

以上取自官方文档95。


7. Hooks:在循环的关键节点插入你的代码#

import asyncio
from claude_agent_sdk import (
AssistantMessage,
ClaudeAgentOptions,
ClaudeSDKClient,
HookContext,
HookInput,
HookJSONOutput,
HookMatcher,
ResultMessage,
)
async def protect_env_files(
input_data: HookInput, tool_use_id: str | None, context: HookContext
) -> HookJSONOutput:
if input_data["hook_event_name"] != "PreToolUse": # HookInput 是按事件名区分的联合类型
return {}
file_path = str(input_data["tool_input"].get("file_path", ""))
if file_path.split("/")[-1] == ".env":
return {
"hookSpecificOutput": {
"hookEventName": "PreToolUse",
"permissionDecision": "deny",
"permissionDecisionReason": "不允许修改 .env 文件",
}
}
return {} # 返回空对象表示放行
async def main() -> None:
options = ClaudeAgentOptions(
hooks={"PreToolUse": [HookMatcher(matcher="Write|Edit", hooks=[protect_env_files])]}
)
async with ClaudeSDKClient(options=options) as client:
await client.query("创建一个 .env 文件,写入本地开发数据库配置")
async for message in client.receive_response():
if isinstance(message, (AssistantMessage, ResultMessage)):
print(message)
asyncio.run(main())

这个例子改编自官方示例10。

关于类型注解

官方文档里的 hook 示例没有写类型注解。用 pyright 检查时会报错,因为 HookMatcher.hooks 要求的类型是 HookCallback,即参数为 (HookInput, str | None, HookContext)、返回 HookJSONOutput 的异步函数。上面的写法按照 SDK 源码中的类型定义补上了注解,并且能通过 0.2.164 的类型检查。

Hook什么时候触发常见用途
PreToolUse工具执行前校验输入、拦截危险命令
PostToolUse工具返回后审计输出、触发后续动作
UserPromptSubmit提交 prompt 时注入额外的上下文
Stopagent 结束时校验结果、保存状态
SubagentStart / SubagentStopsubagent 启动或结束时汇总并行任务的结果
PreCompact上下文压缩之前归档完整的对话记录

以上取自官方文档5。hooks 在你的进程里运行,不占用 agent 的上下文窗口5。


8. Subagents:隔离上下文、并行处理#

import asyncio
from claude_agent_sdk import AgentDefinition, ClaudeAgentOptions, ResultMessage, query
async def main() -> None:
options = ClaudeAgentOptions(
allowed_tools=["Read", "Grep", "Glob", "Agent"], # 主 agent 通过 Agent 工具调用 subagent
agents={
"code-reviewer": AgentDefinition(
description="代码审查专家,负责质量、安全和可维护性审查。", # Claude 根据它决定何时调用
prompt="你是代码审查专家,关注安全漏洞、性能问题和编码规范,给出具体的改进建议。",
tools=["Read", "Grep", "Glob"], # 只读:只能分析,不能修改
model="sonnet",
),
},
)
async for message in query(prompt="审查 auth 模块的安全问题", options=options):
if isinstance(message, ResultMessage) and message.subtype == "success":
print(message.result)
asyncio.run(main())

这个例子改编自官方示例11。官方总结的四个好处11:

  1. 上下文隔离:中间的工具调用都留在 subagent 内部,只有最终结论返回给父 agent。
  2. 并行:互不依赖的子任务可以同时执行。
  3. 专门的指令:每个 subagent 有自己的系统提示词。
  4. 工具限制:例如只给读权限。

9. 会话:continue、resume、fork#

场景做法
一次性任务调用一次 query() 即可
同一个进程里的多轮对话使用 ClaudeSDKClient,它会自动沿用同一个会话
进程重启后接着上次继续continue_conversation=True,自动接续当前目录下最近的一次会话
恢复某个指定的会话resume=session_id
在不改动原会话的前提下尝试别的方案resume=session_id 加上 fork_session=True

以上取自官方文档12。

import asyncio
from claude_agent_sdk import ClaudeAgentOptions, ClaudeSDKClient, ResultMessage
async def main() -> None:
async with ClaudeSDKClient(options=ClaudeAgentOptions(allowed_tools=["Read", "Glob"])) as client:
await client.query("分析一下 utils 目录是做什么的")
async for msg in client.receive_response():
if isinstance(msg, ResultMessage):
print(msg.result)
await client.query("基于刚才的分析,列出三个可以重构的点") # 自动沿用同一个会话的上下文
async for msg in client.receive_response():
if isinstance(msg, ResultMessage):
print(msg.result)
asyncio.run(main())

会话持久化保存的是对话,而不是文件系统。如果要回滚 agent 对文件做的改动,需要使用 file checkpointing12。


10. 系统提示词与项目配置#

选项作用
system_prompt可以传一个字符串,完全自定义;也可以传 {"type": "preset", "preset": "claude_code", "append": "..."},在 Claude Code 默认提示词的基础上追加内容13
setting_sources控制加载哪些文件系统配置:user、project、local。默认值 None 表示全部加载,与 CLI 行为一致;传 [] 进入隔离模式;必须包含 project 才会加载 CLAUDE.md13
skills为主会话启用哪些 skills。它是一个上下文过滤器,不是沙箱:未启用的 skill 文件仍然可以通过 Read 或 Bash 读到13
max_turns / max_budget_usd限制轮数和花费,subagent 的花费也会计入预算5
effortlow / medium / high / xhigh / max5
写给 CLAUDE.md 的建议

自动压缩会把较早的历史替换成摘要,所以写在初始 prompt 里的规则可能在压缩后丢失。官方建议:需要长期遵守的规则写进 CLAUDE.md,因为它在每次请求时都会重新注入5。


11. 与其他方案的对比#

维度Claude Agent SDKOpenAI Agents SDKpi SDK
运行方式启动 Claude Code CLI 子进程纯 Python 库,在你的进程内运行纯 TS 库,在你的进程内运行
内置工具一整套编码工具默认没有,需要另外加 Sandbox agentsread、bash、edit、write
模型ClaudeOpenAI 为主,可以接入其他厂商数十家提供方
权限多层权限系统needs_approval 加护栏默认不提供,用扩展自己实现
适合场景需要一个能力完整的编码或办公 agent业务流程编排、多 agent 协作需要深度定制、多模型的 agent

这张表是笔者根据各篇笔记的内容归纳的,并非官方对比。


小结#

  • Agent SDK = Claude Code 的 harness 加上一套编程接口。你拿到的是一个“开箱即用的 Claude Code”,而不是一组需要自己组装的原语。
  • 理解它的关键在于子进程架构:一个会话对应一个 CLI 进程,状态默认保存在本地磁盘上,这决定了它该怎么部署和扩展。
  • 安全相关的工具有:权限判定顺序、can_use_tool、hooks、disallowed_tools;在生产环境中,还应该放进容器隔离运行。

相关笔记#

参考资料#

注释与出处#

  1. claude-agent-sdk 0.2.164 安装包中 claude_agent_sdk/_cli_version.py(__cli_version__ = "2.1.292")。仓库地址:https://github.com/anthropics/claude-agent-sdk-python/tree/f7b0b62c2a8d110d4da0eec0aa70cf795ec3afc4 ↩

  2. anthropics/claude-agent-sdk-typescript,CHANGELOG.md,https://github.com/anthropics/claude-agent-sdk-typescript/blob/799dc78749f5568e2965699c6ed4d2542031082d/CHANGELOG.md ↩

  3. Anthropic,Agent SDK overview,https://code.claude.com/docs/en/agent-sdk/overview ↩ ↩2 ↩3 ↩4 ↩5

  4. Anthropic,Hosting the Agent SDK(The subprocess model 一节),https://code.claude.com/docs/en/agent-sdk/hosting ↩ ↩2 ↩3

  5. Anthropic,How the agent loop works,https://code.claude.com/docs/en/agent-sdk/agent-loop ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13

  6. Anthropic Engineering,Building agents with the Claude Agent SDK(2025-09-29),https://www.anthropic.com/engineering/building-agents-with-the-claude-agent-sdk ↩

  7. Anthropic,Configure permissions(How permissions are evaluated 一节),https://code.claude.com/docs/en/agent-sdk/permissions ↩ ↩2 ↩3

  8. Anthropic,Handle approvals and user input,https://code.claude.com/docs/en/agent-sdk/user-input ↩ ↩2

  9. Anthropic,Give Claude custom tools,https://code.claude.com/docs/en/agent-sdk/custom-tools ↩ ↩2

  10. Anthropic,Intercept and control agent behavior with hooks,https://code.claude.com/docs/en/agent-sdk/hooks ↩

  11. Anthropic,Subagents in the SDK,https://code.claude.com/docs/en/agent-sdk/subagents ↩ ↩2

  12. Anthropic,Work with sessions,https://code.claude.com/docs/en/agent-sdk/sessions ↩ ↩2

  13. anthropics/claude-agent-sdk-python,src/claude_agent_sdk/types.py 中 ClaudeAgentOptions 的字段文档(system_prompt、setting_sources、skills),https://github.com/anthropics/claude-agent-sdk-python/blob/f7b0b62c2a8d110d4da0eec0aa70cf795ec3afc4/src/claude_agent_sdk/types.py ↩ ↩2 ↩3

输入关键词开始搜索。多个关键词用空格分隔。