本页目录22
- SDK 通过 query() 启动独立的 claude CLI 子进程,每个会话对应一个子进程,拥有自己的 shell、工作目录与本地磁盘上的 JSONL 会话记录,容器重启/缩容/迁移节点后这些状态都不会保留
- 四种会话模式可选:Ephemeral(一次性任务)、Long-running(常驻多会话)、Hybrid(空闲缩容+SessionStore 恢复)、Multi-agent container(单容器多子进程协作)
- 生产环境需自行配置会话持久化(SessionStore)、OpenTelemetry 可观测性、密钥管理与出站代理、按 RAM 估算的横向扩容,以及多租户隔离(settingSources、CLAUDE_CODE_DISABLE_AUTO_MEMORY、CLAUDE_CONFIG_DIR、per-tenant cwd)
- 已知限制:无顶层会话超时(需用 maxTurns 控制)、长会话内存会增长、大规模并行子代理易触发限流、子代理无单独 wall-clock 超时(仅有针对后台子代理的 stall watchdog)
- Token 成本通常比容器基础设施成本高一个数量级以上,规划成本时应以此为重点
本文是对 Claude Agent SDK 官方文档「Hosting the Agent SDK」页面的中文整理,完整与最新内容以原文为准:https://code.claude.com/docs/en/agent-sdk/hosting
概述
Agent SDK 会启动并管理一个 claude CLI 子进程,该子进程拥有 shell、工作目录以及磁盘上的会话文件。托管它不同于托管一个无状态的 API 包装器——每个正在运行的 agent 都是绑定本地状态的长生命周期进程,这决定了资源分配、会话持久化和跨租户扩容的方式。
本文覆盖在自有基础设施上的自托管方案。可部署的 Dockerfile 与 Kubernetes manifest 见 hosting cookbook。
如果不需要基础设施控制、自定义隔离或自有数据平面,可考虑使用 Managed Agents:一个由 Anthropic 运行 agent 和沙箱的托管 REST API,应用只需发送事件并流式接收结果,无需运维托管基础设施。
关于基础沙箱之外的安全加固(网络控制、凭证管理、隔离选项),参见 Secure Deployment。
子进程模型
本文的所有托管决策都源于 SDK 运行 agent 的方式。当代码调用 query() 时,SDK 会启动一个独立的 claude CLI 进程,通过 stdio 与其通信。该子进程拥有 shell、工作目录,以及本地磁盘上的 JSONL 会话记录文件。
一个 agent 会话对应一个子进程。运行 N 个并发会话意味着 N 个子进程,每个都有自己的进程树和记录文件。默认情况下它们都继承应用的工作目录,因此当会话需要独立文件系统时,应在每次 query() 调用中传入 cwd:
query({ prompt, options: { cwd: "/work/session-a" } })
query(prompt=prompt, options=ClaudeAgentOptions(cwd="/work/session-a"))
存放在本地磁盘上的状态
默认情况下有三类 agent 状态存放在容器文件系统上。它们都不会在容器重启、缩容或迁移到其他节点后保留。
| 状态 | 默认位置 |
|---|---|
| 会话记录(Session transcripts) | ~/.claude/projects/,若设置了 CLAUDE_CONFIG_DIR 则为其下的 projects/ 目录 |
CLAUDE.md 记忆文件 | user 层级为 ~/.claude/CLAUDE.md,project 层级为会话的工作目录 |
| 工作目录中的产出文件 | 会话的工作目录 |
要跨主机持久化会话记录,需配置 SessionStore 适配器。记忆文件和其他工作目录产出物需要自己的存储策略,例如挂载卷或对象存储同步。
关于会话、恢复(resumption)与分叉(forking)在 API 层面的工作方式,参见 Sessions。
选择会话模式
以下四种模式覆盖会话生命周期问题:容器相对于它所服务的会话存活多久。关于容器运行在何处,hosting cookbook 提供了针对本地 Docker、Modal 与 Kubernetes 的可部署代码。可在此处选定会话模式,再从 cookbook 中选定部署目标。
Ephemeral(一次性)会话
为每个用户任务创建一个容器,任务完成后销毁。适合一次性任务。用户仍可在任务执行期间与 AI 交互,但任务完成后容器即被销毁。
典型工作负载包括 bug 排查修复、发票/收据信息提取、文档翻译、媒体转换。
容器运行一个一次性入口(entrypoint),调用 SDK 后退出。TypeScript 中需将文件保存为 entrypoint.mts,或在 package.json 中设置 "type": "module" 以使用顶层 await。
import { query } from "@anthropic-ai/claude-agent-sdk";
const prompt = process.env.TASK_PROMPT!;
for await (const message of query({ prompt, options: { maxTurns: 20 } })) {
console.log(message);
}
import asyncio
import os
from claude_agent_sdk import ClaudeAgentOptions, query
async def main():
async for message in query(
prompt=os.environ["TASK_PROMPT"],
options=ClaudeAgentOptions(max_turns=20),
):
print(message)
asyncio.run(main())
Long-running(长驻)会话
运行持久化的容器实例,通常每个容器托管多个 SDK 进程,以服务持续进行的工作。适合执行自主行动、持续提供内容或处理高并发消息流的 agent。
典型工作负载包括:对收到的邮件进行分诊和回复的邮件 agent、通过容器端口托管每用户可编辑站点的建站工具、处理来自 Slack 等平台持续流量的聊天机器人。
容器暴露 HTTP 或 WebSocket 端点,将每个活跃会话映射到一个长生命周期的 query 及其背后的子进程。TypeScript 中使用 streamInput() 向活跃会话添加轮次,使用 startup() 在流量到达前预热子进程。Python 中使用 ClaudeSDKClient 在多轮之间保持会话打开。容器规格需能容纳内存中同时保存的最大并发会话数。
Hybrid(混合)会话
容器在启动时从 SessionStore 中恢复状态,并将更新持久化回去,是一种 ephemeral 容器。适合跨越多次交互、但两次交互之间处于空闲状态的会话。容器在空闲期间缩容,用户返回时再重新拉起。
典型工作负载包括:间歇性签到的个人项目管理助手、跨数小时暂停/恢复的深度研究任务、跨交互加载工单历史的客服 agent。
应根据预期用户返回频率调整所用云厂商的空闲超时设置。在没有配置 SessionStore 的情况下关闭容器会连同记录一起丢失,因此该 store 对此模式是必需项,而非可选项。
该模式的核心是通过共享 store,按会话 ID 恢复会话:
import { query, type SessionStore } from "@anthropic-ai/claude-agent-sdk";
declare const userInput: string;
declare const sessionId: string; // looked up from your database by user
declare const sessionStore: SessionStore; // S3, Redis, Postgres, or your own adapter
for await (const message of query({
prompt: userInput,
options: { resume: sessionId, sessionStore },
})) {
// ...
}
from claude_agent_sdk import query, ClaudeAgentOptions, SessionStore
import asyncio
user_input: str = ...
session_id: str = ... # looked up from your database by user
session_store: SessionStore = ... # S3, Redis, Postgres, or your own adapter
async def main():
async for message in query(
prompt=user_input,
options=ClaudeAgentOptions(
resume=session_id,
session_store=session_store,
),
):
...
asyncio.run(main())
完整的 SessionStore 接口与参考适配器见 Session storage。
Multi-agent container(多 agent 容器)
在同一容器内运行多个 SDK 子进程。适合需要紧密协作的 agent,例如多个 agent 在共享环境中互相交互的多智能体模拟。
应为每个 agent 分配独立的工作目录,避免相互覆盖文件;并隔离设置加载,使各 agent 的 CLAUDE.md 不会互相泄漏。具体选项见下文 多租户隔离。
配置容器
基于容器的沙箱
将 SDK 运行在沙箱化容器中,以获得进程隔离、资源限制、网络控制及临时文件系统。多家提供商专注于适配 Agent SDK 模型的沙箱化容器环境。
选型时需回答的问题:
- 谁运维沙箱:沙箱即服务(sandbox-as-a-service)提供商代为运维基础设施;自托管方案则提供软件供自行运行。
- 冷启动延迟:从「创建沙箱」到「可接受第一个请求」耗时多久。Ephemeral 模式需要亚秒级启动,long-running 模式容忍度更高。
- 持久化存储:提供商是否提供持久卷,还是仅有临时磁盘。Hybrid 模式需要在沙箱内或旁侧具备某种持久化存储。
- 计费模型:按秒、按请求或按小时固定计费。按秒计费适合突发性的 ephemeral 负载,按小时计费适合 long-running 会话。
- 网络:是否支持自定义出站规则、出站代理及面向受监管环境的私有 VPC 对等连接。
可评估的提供商:
关于 Docker、gVisor、Firecracker 等自托管方案及详细隔离配置,参见 Isolation Technologies。
运行时依赖
容器需要具备所用 SDK 语言的运行时:
- Python SDK 需要 Python 3.10+,TypeScript SDK 需要 Node.js 18+
- TypeScript 与 Python SDK 在大多数安装方式下都会内置(bundle)原生 Claude Code 二进制文件,被启动的 CLI 无需单独安装 Node.js。需要单独安装原生 Claude Code 的安装方式见 quickstart 的安装说明。
内置二进制文件版本与 SDK 包版本绑定,因此更新 SDK 即是更新 CLI 的方式。SDK 遵循语义化版本(semver):应持续跟进补丁版本(patch),在升级次版本(minor)前先查阅 TypeScript 或 Python 的 changelog。
资源
每个 agent 建议起始配置为 1 GiB 内存、5 GiB 磁盘、1 个 CPU(针对刚启动的实例)。内存占用会随会话长度和工具活跃度增长,应按实际需要的会话时长与并发量来定容量,而非按空闲基线定容量。关于如何计算每台主机可承载的 agent 数量,见下文 扩容与并发。
网络
SDK 需要出站 HTTPS 访问 api.anthropic.com;若运行在 Amazon Bedrock 或 Google Cloud 的 Agent Platform 上,则需访问对应云厂商的区域端点。若 agent 使用 MCP 服务器或外部工具,同样需要相应的出站访问权限。生产环境应将出站流量路由经过一个执行域名白名单、注入凭证、记录请求日志的出站代理。完整方案见 Secure Deployment。
对于入站流量,需在容器上暴露 HTTP 或 WebSocket 端口。应用在该端口处理客户端请求,并在内部调用 SDK;子进程本身不监听网络。
处理生产环境问题
在自托管 agent 上线前需理清以下决策。
会话与状态持久化
默认本地磁盘状态会在重启、缩容或迁移到不同节点时丢失。对于任何用户期望能恢复的会话,应使用 SessionStore 适配器将记录镜像到持久化存储。S3、Redis、Postgres 的参考适配器及针对自建适配器的一致性测试套件见 参考实现。
关于 SessionStore 行为需了解的三点:
- 仅镜像记录(transcripts):
SessionStore只镜像会话记录,不包含CLAUDE.md记忆文件或其他工作目录产出物,这些需另行挂载共享卷或单独同步。 - 是镜像而非替代:子进程始终先写入本地磁盘,SDK 再将每批数据的副本转发给 store。全新会话的本地记录在运行结束后仍会保留;而从 store 恢复(resume)的运行,在结束时会删除其本地副本,因此此时 store 中保存的是唯一的持久化副本。详见 Dual-write architecture。
mirror_error消息:当 SDK 无法将某批数据写入 store 时,会丢弃该批数据,发出一条{ type: "system", subtype: "mirror_error" }消息,并继续该 query。若 store 的持久性对业务重要,应对此类消息设置告警。重试与超时行为见 Mirror writes are best-effort。
可观测性
Agent SDK 的 agent 是长生命周期进程,会跨多次 API 往返触发工具调用。没有遥测数据就无法知道运行了哪些工具、耗时多久,以及会话在何处卡住。
SDK 会从环境中继承 OpenTelemetry 配置。应在容器或编排层设置 OTEL 相关环境变量,使每次 query() 调用都将 span、指标(metrics)与日志事件导出到你的 collector。下例启用了三种信号的 OTLP 导出。CLAUDE_CODE_ENHANCED_TELEMETRY_BETA 仅为 traces 所需;若只导出 metrics 和 logs,可省略该变量。
CLAUDE_CODE_ENABLE_TELEMETRY=1
CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1
OTEL_TRACES_EXPORTER=otlp
OTEL_METRICS_EXPORTER=otlp
OTEL_LOGS_EXPORTER=otlp
OTEL_EXPORTER_OTLP_PROTOCOL=http/protobuf
OTEL_EXPORTER_OTLP_ENDPOINT=http://collector.example.com:4318
默认情况下,导出内容不包含 prompt 文本和工具输入。相关的显式开启选项见 Control sensitive data in exports,完整信号目录见 Observability。
认证与密钥
托管阶段需关注三类认证问题:
- Anthropic API:子进程从其环境中读取
ANTHROPIC_API_KEY。应从密钥管理服务中提供该值,或设置ANTHROPIC_BASE_URL将模型调用路由到一个在容器外注入密钥的代理。代理模式见 Credential management,受支持的认证方式见 SDK quickstart 中的 Setup 部分。 - 入站:应在 agent 容器前设置网关进行身份验证。agent 应接收已完成认证的请求,而不应作为验证用户令牌的组件。
- 出站工具:工具凭证不应存放在 agent 环境中。应将出站调用路由经过一个在请求离开容器后再注入 API 密钥的代理——由 agent 发起调用,由代理添加凭证。
扩容与并发
每个会话运行在自己的子进程中,因此单机并发能力受限于其内存能容纳的子进程数量。
可用以下公式估算每台主机的容量:
agents per host = (host RAM - overhead) / (per-session RAM ceiling)
应通过在预期工具负载下运行一个具代表性、达到目标时长的会话,并记录其内存峰值(peak RSS)来度量单会话内存上限。资源一节中提到的 1 GiB 起始值是下限,而非上限。
横向扩容的路由策略取决于所选模式。对于容器同时持有多个会话的 long-running 模式,应在负载均衡器后运行一个容器池,并基于 sessionId 使用一致性哈希将每个会话固定(pin)到某一容器。被固定的会话会持续命中同一个容器、进而命中同一个正在运行的子进程,直到该会话被驱逐或容器重启。
成本
Anthropic 的 token 成本通常比容器基础设施成本高出一个数量级以上。一个最低配置的容器每小时成本大约为 0.05 美元,而单个长会话在 token 上的花费可达数美元级别。按会话粒度进行 token 核算方法见 Cost tracking。
多租户隔离
SDK 默认行为会从文件系统读取设置与 CLAUDE.md 记忆文件。在为多个租户提供服务的共享容器中,这些文件可能导致一个租户的上下文泄漏到另一个租户的会话中。
在共享容器内隔离租户的做法:
- 在 TypeScript 中传入
settingSources: [],在 Python 中传入setting_sources=[],使系统不加载任何文件系统中的设置。 - 在
env中设置CLAUDE_CODE_DISABLE_AUTO_MEMORY=1。位于~/.claude/projects/<project>/memory/的 Auto memory 无论settingSources如何设置,都会被加载进 system prompt。其他无条件加载的输入见 What settingSources does not control。 - 将
CLAUDE_CONFIG_DIR指向按租户区分的目录,避免各租户共用~/.claude.json全局配置。当每个配置目录只服务一个工作目录时,还可以在env里设置CLAUDE_CODE_PROJECT_DIR_NAME,让该目录下的转录路径更短(需要 TypeScript Agent SDK v0.3.234 或更高版本)。 - 使用按租户区分的工作目录:在每次
query()调用中显式传入cwd。 - 在代理层应用按租户区分的出站规则,例如不同的出站 IP、凭证或域名白名单,防止某个被攻破的租户通过另一租户的出站策略窃取数据。
下例将上述四项 SDK 级选项组合使用。应构造 tenantDir 与 configDir,使每个租户拥有其他租户都无法读取的路径。TypeScript 中 env 会替换子进程的整个环境,因此需展开 ...process.env 以保留继承的变量(如 PATH、ANTHROPIC_API_KEY)。Python 中 env 会合并叠加在继承的环境之上。
import { query } from "@anthropic-ai/claude-agent-sdk";
declare const prompt: string;
declare const tenantDir: string;
declare const configDir: string;
for await (const message of query({
prompt,
options: {
cwd: tenantDir,
settingSources: [],
env: {
...process.env,
CLAUDE_CONFIG_DIR: configDir,
CLAUDE_CODE_DISABLE_AUTO_MEMORY: "1",
},
},
})) {
// ...
}
from claude_agent_sdk import query, ClaudeAgentOptions
import asyncio
prompt: str = ...
tenant_dir: str = ...
config_dir: str = ...
async def main():
async for message in query(
prompt=prompt,
options=ClaudeAgentOptions(
cwd=tenant_dir,
setting_sources=[],
env={
"CLAUDE_CONFIG_DIR": config_dir,
"CLAUDE_CODE_DISABLE_AUTO_MEMORY": "1",
},
),
):
...
asyncio.run(main())
关于按租户的网络控制,参见 Secure Deployment。
已知限制
部署设计时应对以下限制预先规划。
| 限制 | 应对方式 |
|---|---|
| 无顶层会话超时 | 会话不会自行超时。应在 Options 中设置 maxTurns,限制 agent 在停止前可进行的工具调用往返轮次。 |
| 长会话中的内存增长 | 限制会话长度,或定期回收子进程。见 扩容与并发。 |
| 大规模并行子代理扇出(fanout)可能触发限流 | 应将工作拆分为更小批次,而非一次性发出大范围调度。 |
| 子代理无单独的 wall-clock 截止时间 | 应在每个子代理的 AgentDefinition 中通过 maxTurns 加以限制。仅针对后台子代理,CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS 设置了一个停滞看门狗(stall watchdog),当 run_in_background 子代理停止产生输出时触发;它不是总运行时长的截止时间。 |
后续阅读
- Hosting cookbook:notebook 演示,附针对 Docker、Modal、Kubernetes 的可部署代码
- Session storage:通过
SessionStore适配器跨主机持久化会话记录 - Observability:将 OTEL traces、metrics、logs 导出到 collector
- Secure deployment:网络控制、凭证管理与隔离加固
- Cost tracking:按会话进行 token 与成本核算