Skip to content

Agent SDK

用 @anthropic-ai/claude-agent-sdk 在自己代码里跑 Claude Code 同款循环。

Claude Agent SDK 是 Anthropic 官方发布的包,作用可以一句话说清:把 Claude Code 那套 agent loop 内核抽出来,让你的程序也能调用。终端里 claude 命令背后跑的工具循环、上下文压缩、subagent 调度、MCP 连接、权限决策,SDK 里全都有,只是把用户界面换成了函数调用。

如果你之前接触过 OpenAI 的 Assistants API 或者 LangChain 那种 agent 框架,Agent SDK 大致上占同一个生态位——都是把"让 LLM 自主用工具解决问题"这套循环封装好交给你。区别是 Agent SDK 深度绑定 Claude Code 生态,你在 CLI 里辛苦攒下的 skills、commands、agents、hooks 配置一行代码不改就能被 SDK 复用,这是它相比通用框架最实在的好处。

SDK 和 CLI 是什么关系

一个直接的比喻:CLI 是给人敲键盘用的前台,SDK 是给程序调用的后台。两者共享同一个 agent 引擎,所以你在 CLI 里配的 CLAUDE.md.claude/skills/.claude/commands/.claude/agents/ 这些约定,SDK 都能读,跑起来行为是一致的。

区别在于 SDK 拿到的是一个结构化的消息流,而不是终端里那种边打字边渲染的界面。你调用 query(...),SDK 返回一个异步迭代器,一条一条把 Claude 生成的消息(文本、tool_use、tool_result、system 事件、最终 result)推给你,你自己决定怎么处理。

这套结构化流是 SDK 相比直接调 API 最大的优势。你不用自己维护 tool 循环、不用自己写权限判定、也不用自己拼上下文,只关心"用户想要什么"和"结果怎么用",中间那一堆脏活 SDK 全接了。

安装

TypeScript 用 npm:

bash
npm install @anthropic-ai/claude-agent-sdk

Python 有两种主流方式,推荐用 uv:

bash
uv init
uv add claude-agent-sdk

或者传统 venv:

bash
python3 -m venv .venv
source .venv/bin/activate
pip install claude-agent-sdk

Windows PowerShell 里激活虚拟环境是 .venv\Scripts\Activate.ps1,遇到执行策略拒绝时先 Set-ExecutionPolicy -Scope Process RemoteSigned

装完之后设置 API key:

bash
export ANTHROPIC_API_KEY=sk-ant-xxxxx

除了直连 Anthropic,SDK 也支持云厂商托管:Amazon Bedrock 走 CLAUDE_CODE_USE_BEDROCK=1,Google Vertex 走 CLAUDE_CODE_USE_VERTEX=1,Azure Foundry 走 CLAUDE_CODE_USE_FOUNDRY=1,各自再配好厂商凭证即可。

最小示例

Python 版本,一段 8 行的代码就能跑起来:

python
import asyncio
from claude_agent_sdk import query, ClaudeAgentOptions

async def main():
    async for message in query(
        prompt="列一下当前目录有哪些文件",
        options=ClaudeAgentOptions(allowed_tools=["Bash", "Glob"]),
    ):
        if hasattr(message, "result"):
            print(message.result)

asyncio.run(main())

TypeScript 版本更短:

ts
import { query } from "@anthropic-ai/claude-agent-sdk";

for await (const message of query({
  prompt: "列一下当前目录有哪些文件",
  options: { allowedTools: ["Bash", "Glob"] },
})) {
  if ("result" in message) console.log(message.result);
}

这两段代码等价于你在终端里打开 claude 然后输入那句提问,只不过输出被你程序捕获而不是渲染在屏幕上。SDK 会自动加载当前目录的 CLAUDE.md.claude/settings.json,处理工具调用循环,最后把结果推给 async for 循环。

消息类型

query() 迭代出来的 message 有多种类型:SystemMessage(会话开始、上下文压缩等系统事件)、AssistantMessage(模型生成的一轮回复,可能包含文本块或 tool_use 块)、UserMessage(工具返回的 tool_result)、ResultMessage(这次任务的最终结果)。写业务代码时最常用的是过滤 ResultMessage 拿最终答案,或者对 AssistantMessage 里的 text 做流式渲染。

Node 和 Python 该选哪个

两个语言版本的能力完全对齐,选哪个纯看你的技术栈。Node 版本的优势在于跟前端工具链、Serverless 部署(Vercel、Cloudflare Workers)粘合更自然,异步语法更贴近 API 特性。Python 版本的优势在于数据处理生态(pandas、numpy)和 AI 领域大量现成的工具库能直接引用。写脚本、和其他 LLM 框架混用,Python 更顺手;做 SaaS 后端、加进现有 Web 服务,Node 更省事。

常用配置项

ClaudeAgentOptions(或 TS 里的 options 对象)是控制这次 agent 行为的核心开关,几个最常用的字段:

  • allowed_tools / allowedTools:允许 Claude 调用的内置工具白名单,比如 ReadWriteEditBashGlobGrepAgent。不写就是允许全部内置工具。
  • system_prompt / systemPrompt:覆盖或追加系统提示词,往里塞项目背景、身份约束、输出格式。
  • model:指定模型,比如 claude-opus-4-7claude-sonnet-5claude-haiku-4-5-20251001。省略走默认。
  • max_turns / maxTurns:agent loop 最多跑几轮,超了就停。防止死循环烧钱的兜底。
  • permission_mode / permissionMode:权限模式,比如 acceptEdits 表示自动接受文件修改,适合无人值守。
  • hooks:在 PreToolUsePostToolUseStopSessionStartSessionEndUserPromptSubmit 这些时机插自定义回调。
  • agents:注册 subagent 类型,供主 loop 通过 Agent 工具派发独立任务。
  • mcp_servers / mcpServers:连接外部 MCP server,比如给它接一个 playwright 或者你自研的内部工具网关。
  • resume:传上一次会话的 session_id,接着上次的上下文继续跑。

中等复杂例子:日志分析定时脚本

假设你想每天早上自动分析昨天的 nginx 错误日志,把 500 错误的模式总结成 markdown 存到 reports/ 目录。用 SDK 加 cron(或 Windows 计划任务)就够了。

python
import asyncio
from datetime import date, timedelta
from claude_agent_sdk import query, ClaudeAgentOptions, HookMatcher

async def audit_hook(input_data, tool_use_id, context):
    # 每次工具调用记录一行审计,方便后期排查
    tool = input_data.get("tool_name", "?")
    print(f"[audit] {tool} at {tool_use_id}")
    return {}

async def main():
    yesterday = (date.today() - timedelta(days=1)).isoformat()
    prompt = f"""
读取 /var/log/nginx/error.log,筛选日期为 {yesterday} 的 500 错误。
按 URL 模式分组,统计出现次数最多的前 5 类。
将结果写入 reports/{yesterday}.md,格式为 markdown 表格。
"""
    async for message in query(
        prompt=prompt,
        options=ClaudeAgentOptions(
            allowed_tools=["Read", "Write", "Bash", "Grep"],
            model="claude-sonnet-5",
            permission_mode="acceptEdits",
            max_turns=20,
            hooks={
                "PreToolUse": [HookMatcher(matcher="*", hooks=[audit_hook])],
            },
        ),
    ):
        if hasattr(message, "result"):
            print(message.result)

asyncio.run(main())

这段脚本的几个要点:permission_mode="acceptEdits" 让它无人值守;max_turns=20 防止陷入无限循环;PreToolUse hook 把每次工具调用打印出来,事后能查是谁干的。丢进 cron 每天 06:00 跑一遍,报告就自动出来了。

生产落地注意

无人值守跑 Claude Code 有几条硬红线要守住:一是权限最小化,allowed_tools 里只放这次任务真正需要的工具,不要一股脑给全部;二是把结果落盘到你能审计的位置,别让它随便写系统关键路径;三是加上超时和 max_turns,防止一次意外的 prompt 让它跑到明天;四是订阅告警,一旦脚本失败你要能第一时间知道。

Hook 的常见用法

上面例子里用到的 hook 机制不只是打日志。几个常见的落地场景值得单独说:

  • PreToolUse:在工具真正执行前拦截。可以做参数校验(不许 Bash 删 /)、可以做二次确认、可以直接返回一个 deny 阻止执行。这是把安全规则从 CLAUDE.md 提示词层面下沉到代码层面的关键机制。
  • PostToolUse:工具跑完记录审计日志、上报指标、触发下游 webhook。上文的 audit_hook 就是这一类。
  • SessionStart / SessionEnd:会话级别的生命周期钩子,可以在开始时预热缓存、结束时刷新指标或者关闭连接池。
  • UserPromptSubmit:用户输入进来之前拦一道,用来做敏感词检查、把简写扩展成完整问题、或者根据当前项目动态注入上下文。
  • Stop:模型主动结束一次回合时触发,适合把中间产物落盘。

Subagent 和 MCP 也能在 SDK 里注册

Agent SDK 完整继承了 Claude Code 的 subagent 和 MCP 机制,写法上一目了然。注册一个代码评审 subagent:

python
from claude_agent_sdk import query, ClaudeAgentOptions, AgentDefinition

options = ClaudeAgentOptions(
    allowed_tools=["Read", "Glob", "Grep", "Agent"],
    agents={
        "code-reviewer": AgentDefinition(
            description="专业代码评审员,看质量和安全",
            prompt="分析代码质量,指出可读性、正确性、安全问题",
            tools=["Read", "Glob", "Grep"],
        )
    },
)

主 loop 只要在提示词里说"用 code-reviewer 评审这份代码",SDK 就会自动派出子 agent 独立跑一轮。这一套跟你在 .claude/agents/ 里定义子 agent 的效果一致,区别只是入口一个是文件一个是代码。

MCP 也一样,mcp_servers 字段直接传一个 dict:

python
options = ClaudeAgentOptions(
    mcp_servers={
        "playwright": {"command": "npx", "args": ["@playwright/mcp@latest"]}
    }
)

Claude 就能通过 mcp__playwright__* 系列工具去驱动浏览器。

Session 恢复

SDK 支持会话恢复,用于连续的多次对话。第一次调用时捕获 session_id,下一次把它塞进 resume

python
from claude_agent_sdk import query, ClaudeAgentOptions, SystemMessage, ResultMessage

session_id = None

async for message in query(
    prompt="先读一下认证模块",
    options=ClaudeAgentOptions(allowed_tools=["Read", "Glob"]),
):
    if isinstance(message, SystemMessage) and message.subtype == "init":
        session_id = message.data["session_id"]

async for message in query(
    prompt="现在找出所有调用它的地方",
    options=ClaudeAgentOptions(resume=session_id),
):
    if isinstance(message, ResultMessage):
        print(message.result)

第二次调用不用重新解释"它"是谁,因为整个上下文还在。这个能力对于做交互式 agent 服务、或者让脚本分阶段推进任务都很关键。

什么时候选 Agent SDK

选 SDK 而不是自己撸 Messages API 的 tool 循环,标准很简单:你要让 Claude 自主用工具解决多步问题。SDK 已经把工具循环、错误重试、上下文压缩、subagent 调度、MCP 集成、hook 机制全都封装好了,你只管写业务逻辑。

反过来如果你只是想调一次模型拿一段文本回来(翻译、摘要、分类),不涉及工具,那用底层的 Messages API 更轻。下一节讲 Messages API 时会给出这两种选择的对照。

本教程为社区中文学习整理,非官方发布。Claude Code 属于 Anthropic。