4 4
5# 托管 Agent SDK5# 托管 Agent SDK
6 6
7> 在生产环境中部署 Agent SDK:子进程架构、会话持久化、扩展、可观测性和 Docker、Kubernetes 及沙箱提供商的多租户隔离。7> 在生产环境中部署 Agent SDK:子进程架构、会话持久化、扩展、可观测性以及针对 Docker、Kubernetes 和沙箱提供商的多租户隔离。
8 8
9Agent SDK 生成并监督一个拥有 shell、工作目录和磁盘上会话文件的 `claude` CLI 子进程。托管它不像托管无状态 API 包装器。每个运行中的代理都是一个与本地状态绑定的长期进程,这决定了你如何分配资源、持久化会话以及跨租户扩展。9Agent SDK 生成并监督一个 `claude` CLI 子进程,该子进程拥有一个 shell、一个工作目录和磁盘上的会话文件。托管它不像托管无状态 API 包装器。每个运行中的代理都是一个与本地状态绑定的长期进程,这决定了你如何分配资源、持久化会话以及跨租户扩展。
10 10
11本页涵盖在你自己的基础设施上自托管:理解[子进程模型](#the-subprocess-model)、[选择会话模式](#choose-a-session-pattern)、[配置容器](#provision-the-container)和[处理生产问题](#handle-production-concerns),如持久化、可观测性、身份验证和多租户隔离。有关可部署的 Dockerfile 和 Kubernetes 清单,请参阅[托管指南](https://github.com/anthropics/claude-cookbooks/tree/main/claude_agent_sdk/hosting)。11本页面涵盖在你自己的基础设施上自托管。有关可部署的 Dockerfile 和 Kubernetes 清单,请参阅[托管指南](https://github.com/anthropics/claude-cookbooks/tree/main/claude_agent_sdk/hosting)。
12 12
13如果你不需要基础设施控制、自定义隔离或自己的数据平面,请考虑改用[托管代理](https://platform.claude.com/docs/zh-CN/managed-agents/overview):一个托管的 REST API,其中 Anthropic 运行代理和沙箱,因此你的应用程序发送事件并流回结果,无需操作任何托管基础设施。13如果你不需要基础设施控制、自定义隔离或自己的数据平面,请考虑改用[托管代理](https://platform.claude.com/docs/en/managed-agents/overview):这是一个托管的 REST API,其中 Anthropic 运行代理和沙箱,因此你的应用程序发送事件并流回结果,无需操作任何托管基础设施。
14
15<Info>
16 有关超越基本 sandboxing 的安全加固(包括网络控制、凭证管理和隔离选项),请参阅 [Secure Deployment](/zh-CN/agent-sdk/secure-deployment)。
17</Info>
18 14
19<h2 id="the-subprocess-model">15<h2 id="the-subprocess-model">
20 子进程模型16 子进程模型
21</h2>17</h2>
22 18
23此页面上的每个托管决策都遵循 SDK 如何运行代理的方式。当您的代码调用 `query()` 时,SDK 会生成一个单独的 `claude` CLI 进程,并通过 stdio 与其通信。该子进程拥有 shell、工作目录和本地磁盘上的 JSONL 会话记录。19本页面上的每个托管决策都遵循 SDK 如何运行代理的方式。当您的代码调用 `query()` 时,SDK 会生成一个单独的 `claude` CLI 进程,并通过 stdio 与其通信。该子进程拥有 shell、工作目录和本地磁盘上的 JSONL 会话记录。
20
21<img src="https://mintcdn.com/claude-code/ikqp3_70mqIahteV/images/agent-sdk/hosting-subprocess.svg?fit=max&auto=format&n=ikqp3_70mqIahteV&q=85&s=9dac857ca9d3b1410c3734900c386004" className="dark:hidden" alt="请求流:从客户端到您的应用,应用在容器内通过 stdio 生成 claude CLI 子进程;子进程写入本地磁盘并通过 HTTPS 调用 api.anthropic.com" width="920" height="220" data-path="images/agent-sdk/hosting-subprocess.svg" />
24 22
25<img src="https://mintcdn.com/claude-code/ikqp3_70mqIahteV/images/agent-sdk/hosting-subprocess.svg?fit=max&auto=format&n=ikqp3_70mqIahteV&q=85&s=9dac857ca9d3b1410c3734900c386004" alt="请求流:客户端到您的应用,应用在容器内通过 stdio 生成 claude CLI 子进程;子进程写入本地磁盘并通过 HTTPS 调用 api.anthropic.com" width="920" height="220" data-path="images/agent-sdk/hosting-subprocess.svg" />23<img src="https://mintcdn.com/claude-code/_xqph1dUOslCOwsj/images/agent-sdk/hosting-subprocess-dark.svg?fit=max&auto=format&n=_xqph1dUOslCOwsj&q=85&s=3fdeff3d7f44b2b67762668acfbb25f5" className="hidden dark:block" alt="请求流:从客户端到您的应用,应用在容器内通过 stdio 生成 claude CLI 子进程;子进程写入本地磁盘并通过 HTTPS 调用 api.anthropic.com" width="920" height="220" data-path="images/agent-sdk/hosting-subprocess-dark.svg" />
26 24
27一个代理会话映射到一个子进程。运行 N 个并发会话意味着 N 个子进程,每个都有自己的进程树和记录文件。默认情况下,它们都继承您应用程序的工作目录,因此当会话需要单独的文件系统时,在每个 `query()` 调用上传递 `cwd`:25一个代理会话映射到一个子进程。运行 N 个并发会话意味着 N 个子进程,每个都有自己的进程树和记录文件。默认情况下,它们都继承您应用程序的工作目录。当会话需要单独的文件系统时,在每个会话的 `query()` 调用选项中传递不同的 `cwd`:
28 26
29<CodeGroup>27<CodeGroup>
30 ```typescript TypeScript theme={null}28 ```typescript TypeScript theme={null}
31 query({ prompt, options: { cwd: "/work/session-a" } })29 import { query } from "@anthropic-ai/claude-agent-sdk";
30
31 for await (const message of query({
32 prompt: "Summarize the files in this directory",
33 options: { cwd: "/work/session-a" },
34 })) {
35 console.log(message);
36 }
32 ```37 ```
33 38
34 ```python Python theme={null}39 ```python Python theme={null}
35 query(prompt=prompt, options=ClaudeAgentOptions(cwd="/work/session-a"))40 import asyncio
41
42 from claude_agent_sdk import ClaudeAgentOptions, query
43
44
45 async def main():
46 async for message in query(
47 prompt="Summarize the files in this directory",
48 options=ClaudeAgentOptions(cwd="/work/session-a"),
49 ):
50 print(message)
51
52
53 asyncio.run(main())
36 ```54 ```
37</CodeGroup>55</CodeGroup>
38 56
57本页面上的 TypeScript 示例使用顶级 `await`,因此将它们保存为 `.mts` 文件或在 `package.json` 中设置 `"type": "module"`。
58
39<h3 id="state-that-lives-on-local-disk">59<h3 id="state-that-lives-on-local-disk">
40 存储在本地磁盘上的状态60 存储在本地磁盘上的状态
41</h3>61</h3>
44 64
45| 状态 | 默认位置 |65| 状态 | 默认位置 |
46| ---------------- | --------------------------------------------------------------------- |66| ---------------- | --------------------------------------------------------------------- |
47| 会话记录 | `~/.claude/projects/`,或如果设置了 `CLAUDE_CONFIG_DIR`,则为其下的 `projects/` 目录 |67| 会话记录 | `~/.claude/projects/`,或如果设置了 `CLAUDE_CONFIG_DIR` 则为其下的 `projects/` 目录 |
48| `CLAUDE.md` 内存文件 | 用户层级为 `~/.claude/CLAUDE.md`,项目层级为会话的工作目录 |68| `CLAUDE.md` 内存文件 | 用户层级为 `~/.claude/CLAUDE.md`,项目层级为会话的工作目录 |
49| 工作目录工件 | 会话的工作目录 |69| 工作目录工件 | 会话的工作目录 |
50 70
51要在主机之间持久化记录,请配置 [`SessionStore` 适配器](/zh-CN/agent-sdk/session-storage)。内存文件和其他工作目录工件需要自己的存储策略,例如挂载卷或对象存储同步。71要在主机间持久化记录,请配置 [`SessionStore` 适配器](/docs/zh-CN/agent-sdk/session-storage)。内存文件和其他工作目录工件需要自己的存储策略,例如挂载卷或对象存储同步。
52 72
53有关会话、恢复和分叉在 API 级别如何工作的信息,请参阅 [Sessions](/zh-CN/agent-sdk/sessions)。73有关会话、恢复和分叉在 API 级别如何工作的信息,请参阅 [Sessions](/docs/zh-CN/agent-sdk/sessions)。
54 74
55<h2 id="choose-a-session-pattern">75<h2 id="choose-a-session-pattern">
56 选择会话模式76 选择会话模式
59这四种模式涵盖会话生命周期:容器相对于它所服务的会话的生存时间。关于容器运行的位置,[托管指南](https://github.com/anthropics/claude-cookbooks/blob/main/claude_agent_sdk/07_Hosting_the_agent.ipynb)提供了[可部署代码](https://github.com/anthropics/claude-cookbooks/tree/main/claude_agent_sdk/hosting),用于本地 Docker、Modal 和 Kubernetes。在此选择会话模式,并从指南中选择部署目标。79这四种模式涵盖会话生命周期:容器相对于它所服务的会话的生存时间。关于容器运行的位置,[托管指南](https://github.com/anthropics/claude-cookbooks/blob/main/claude_agent_sdk/07_Hosting_the_agent.ipynb)提供了[可部署代码](https://github.com/anthropics/claude-cookbooks/tree/main/claude_agent_sdk/hosting),用于本地 Docker、Modal 和 Kubernetes。在此选择会话模式,并从指南中选择部署目标。
60 80
61<h3 id="ephemeral-sessions">81<h3 id="ephemeral-sessions">
62 临时会话82 Ephemeral sessions
63</h3>83</h3>
64 84
65为每个用户任务创建一个容器,任务完成时销毁它。最适合一次性任务。用户可能仍然可以在任务完成时与 AI 交互,但一旦完成,容器就会被销毁。85为每个用户任务创建一个容器,任务完成时销毁它。最适合一次性任务。用户可能仍然可以在任务完成时与 AI 交互,但一旦完成,容器就会被销毁。
66 86
67示例工作负载包括 bug 调查和修复、发票和收据提取、文档翻译和媒体转换。87示例工作负载包括 bug 调查和修复、发票和收据提取、文档翻译和媒体转换。
68 88
69容器运行一个一次性入口点,该入口点调用 SDK 并退出。下面的示例显示了一个最小的 TypeScript 版本。将其保存为 `entrypoint.mts` 或在 `package.json` 中设置 `"type": "module"`,以便顶级 `await` 可用。89容器运行一个一次性入口点,从 `TASK_PROMPT` 环境变量读取任务,调用 SDK,然后退出。
70 90
71```typescript theme={null}91<CodeGroup>
72import { query } from "@anthropic-ai/claude-agent-sdk";92 ```typescript TypeScript theme={null}
93 import { query } from "@anthropic-ai/claude-agent-sdk";
73 94
74const prompt = process.env.TASK_PROMPT!;95 const prompt = process.env.TASK_PROMPT!;
75for await (const message of query({ prompt, options: { maxTurns: 20 } })) {96 for await (const message of query({ prompt, options: { maxTurns: 20 } })) {
76 console.log(message);97 console.log(message);
77}98 }
78```99 ```
100
101 ```python Python theme={null}
102 import asyncio
103 import os
104
105 from claude_agent_sdk import ClaudeAgentOptions, query
106
107
108 async def main():
109 async for message in query(
110 prompt=os.environ["TASK_PROMPT"],
111 options=ClaudeAgentOptions(max_turns=20),
112 ):
113 print(message)
114
115
116 asyncio.run(main())
117 ```
118</CodeGroup>
119
120脚本在每条消息到达时打印它,包括一条结果消息,当任务在轮次限制内完成时,其 `subtype` 为 `success`。如果任务改为达到 20 轮限制,结果消息的 `subtype` 为 `error_max_turns`,`query()` 调用在产生它后会抛出错误,因此如果容器需要干净地退出,请将循环包装在 try 块中。有关错误子类型,请参阅[处理结果](/docs/zh-CN/agent-sdk/agent-loop#handle-the-result)。
79 121
80<h3 id="long-running-sessions">122<h3 id="long-running-sessions">
81 长运行会话123 Long-running sessions
82</h3>124</h3>
83 125
84运行持久容器实例,通常每个容器托管多个 SDK 进程,以服务持续工作。最适合采取自主行动、提供内容或处理高容量消息流的代理。126运行持久容器实例,通常每个容器托管多个 SDK 进程,以服务持续工作。最适合采取自主行动、提供内容或处理高容量消息流的代理。
85 127
86示例工作负载包括对传入邮件进行分类和响应的电子邮件代理、通过容器端口托管每个用户可编辑站点的站点构建器,以及处理来自 Slack 等平台的连续流量的聊天机器人。128示例工作负载包括对传入邮件进行分类和响应的电子邮件代理、通过容器端口托管每个用户可编辑站点的站点构建器,以及处理来自 Slack 等平台的连续流量的聊天机器人。
87 129
88容器公开 HTTP 或 WebSocket 端点,并将每个活跃会话映射到一个长期查询及其后面的子进程。在 TypeScript 中,使用 [`streamInput()`](/zh-CN/agent-sdk/typescript#query-object) 向活跃会话添加轮次,使用 [`startup()`](/zh-CN/agent-sdk/typescript#startup) 在传入流量前预热子进程。在 Python 中,使用 [`ClaudeSDKClient`](/zh-CN/agent-sdk/python#claudesdkclient) 在多个轮次中保持会话打开。调整容器大小,使其能够在内存中容纳最大并发会话数。130容器公开 HTTP 或 WebSocket 端点,并将每个活跃会话映射到一个长期查询及其后面的子进程。在 TypeScript 中,使用 [`streamInput()`](/docs/zh-CN/agent-sdk/typescript#query-object) 向活跃会话添加轮次,使用 [`startup()`](/docs/zh-CN/agent-sdk/typescript#startup) 在传入流量前预热子进程。在 Python 中,使用 [`ClaudeSDKClient`](/docs/zh-CN/agent-sdk/python#claudesdkclient) 在轮次间保持会话打开。调整容器大小,使其能够在内存中容纳最大并发会话数。
89 131
90<h3 id="hybrid-sessions">132<h3 id="hybrid-sessions">
91 混合会话133 Hybrid sessions
92</h3>134</h3>
93 135
94临时容器在启动时从 [`SessionStore`](/zh-CN/agent-sdk/session-storage) 进行补充,并将更新持久化回去。最适合跨越许多交互但在交互之间处于空闲状态的会话。容器在空闲期间关闭,当用户返回时重新启动。136从启动时的 [`SessionStore`](/docs/zh-CN/agent-sdk/session-storage) 进行补充并将更新持久化回去的临时容器。最适合跨越许多交互但在交互之间处于空闲状态的会话。容器在空闲期间关闭,当用户返回时重新启动。
95 137
96示例工作负载包括具有间歇性检查的个人项目管理器、暂停和恢复数小时的深度研究,以及跨交互加载票证历史的客户支持代理。138示例工作负载包括具有间歇性检查的个人项目管理器、在数小时内暂停和恢复的深度研究,以及在交互间加载票证历史的客户支持代理。
97 139
98根据您期望用户返回的频率调整提供商的空闲超时。在没有配置 `SessionStore` 的情况下关闭容器会丢失其转录,因此存储对于此模式是必需的,而不是可选的。140根据您期望用户返回的频率调整您的提供商的空闲超时。在没有配置 `SessionStore` 的情况下关闭容器会丢失其转录,因此存储对于此模式是必需的,而不是可选的。
99 141
100该模式的关键在于通过 ID 恢复会话,并附加共享存储:142该模式的关键在于通过 ID 恢复会话,并附加共享存储:
101 143
116 ```158 ```
117 159
118 ```python Python theme={null}160 ```python Python theme={null}
119 from claude_agent_sdk import query, ClaudeAgentOptions161 from claude_agent_sdk import query, ClaudeAgentOptions, SessionStore
162 import asyncio
163
164 user_input: str = ...
165 session_id: str = ... # looked up from your database by user
166 session_store: SessionStore = ... # S3, Redis, Postgres, or your own adapter
120 167
168
169 async def main():
121 async for message in query(170 async for message in query(
122 prompt=user_input,171 prompt=user_input,
123 options=ClaudeAgentOptions(172 options=ClaudeAgentOptions(
124 resume=session_id, # looked up from your database by user173 resume=session_id,
125 session_store=session_store, # S3, Redis, Postgres, or your own adapter174 session_store=session_store,
126 ),175 ),
127 ):176 ):
128 ...177 ...
178
179
180 asyncio.run(main())
129 ```181 ```
130</CodeGroup>182</CodeGroup>
131 183
132有关完整的 `SessionStore` 接口和参考适配器,请参阅[会话存储](/zh-CN/agent-sdk/session-storage)。
133
134<h3 id="multi-agent-container">184<h3 id="multi-agent-container">
135 多代理容器185 Multi-agent container
136</h3>186</h3>
137 187
138在一个容器内运行多个 SDK 子进程。最适合必须紧密协作的代理,例如多代理模拟,其中代理在共享环境中相互交互。188在一个容器内运行多个 SDK 子进程。最适合必须紧密协作的代理,例如多代理模拟,其中代理在共享环境中相互交互。
139 189
140为每个代理提供自己的工作目录,以便它们不会相互覆盖文件,并隔离设置加载,以便每个代理的 `CLAUDE.md` 文件不会泄漏到其他代理。有关特定选项,请参阅[多租户隔离](#multi-tenant-isolation)。190为每个代理提供自己的工作目录,以便它们不会相互覆盖文件,并隔离设置加载,以便每个代理的 `CLAUDE.md` 文件不会泄漏到其他代理。有关具体选项,请参阅[多租户隔离](#multi-tenant-isolation)。
141 191
142<h2 id="provision-the-container">192<h2 id="provision-the-container">
143 配置容器193 配置容器
144</h2>194</h2>
145 195
146<h3 id="container-based-sandboxing">196<h3 id="container-based-sandboxing">
147 基于容器的沙箱197 基于容器的沙箱隔离
148</h3>198</h3>
149 199
150在沙箱容器内运行 SDK,以实现进程隔离、资源限制、网络控制和临时文件系统。多个提供商专门提供适合 Agent SDK 模型的沙箱容器环境。200在沙箱容器内运行 SDK,以实现进程隔离、资源限制、网络控制和临时文件系统。
151 201
152选择提供商时需要回答的问题:202选择提供商时需要回答的问题:
153 203
154* **谁运行沙箱**:沙箱即服务提供商为您运营基础设施,而自托管选项则为您提供在自己的基础设施上运行的软件。204* **谁运行沙箱**:沙箱即服务提供商为您运营基础设施,而自托管选项则提供您可以在自己的服务器上运行的软件。
155* **冷启动延迟**:从"创建沙箱"到"准备好接受第一个请求"需要多长时间。临时模式需要亚秒级启动。长期运行模式可以容忍更长的启动时间。205* **冷启动延迟**:从"创建沙箱"到"准备好接受第一个请求"需要多长时间。临时模式需要亚秒级启动。长期运行模式可以容忍更长的延迟。
156* **持久存储**:提供商是否提供持久卷或仅提供临时磁盘。混合模式需要在沙箱内或沙箱旁边的某处进行持久存储。206* **持久存储**:提供商是否提供持久卷或仅提供临时磁盘。混合模式需要在沙箱内或沙箱旁边的某处进行持久存储。
157* **定价模型**:按秒、按请求或按小时固定计费。按秒计费适合突发的临时工作负载。按小时计费适合长期运行的会话。207* **定价模式**:按秒、按请求或按小时固定计费。按秒定价适合突发的临时工作负载。按小时定价适合长期运行的会话。
158* **网络**:支持自定义出站规则、出站代理和私有 VPC 对等互联,用于受管制的环境。208* **网络**:支持自定义出站规则、出站代理和私有 VPC 对等互联,用于受管制的环境。
159 209
160要评估的提供商:210有关自托管选项(如 Docker、gVisor 和 Firecracker)以及详细的隔离配置,请参阅 [Isolation Technologies](/docs/zh-CN/agent-sdk/secure-deployment#isolation-technologies)。
161
162* [Modal Sandbox](https://modal.com/docs/guide/sandbox),包含[演示实现](https://modal.com/docs/examples/claude-slack-gif-creator)
163* [Cloudflare Sandboxes](https://github.com/cloudflare/sandbox-sdk)
164* [Daytona](https://www.daytona.io/)
165* [E2B](https://e2b.dev/)
166* [Fly Machines](https://fly.io/docs/machines/)
167* [Vercel Sandbox](https://vercel.com/docs/functions/sandbox)
168
169有关自托管选项(如 Docker、gVisor 和 Firecracker)以及详细的隔离配置,请参阅 [Isolation Technologies](/zh-CN/agent-sdk/secure-deployment#isolation-technologies)。
170 211
171<h3 id="runtime-dependencies">212<h3 id="runtime-dependencies">
172 运行时依赖213 运行时依赖项
173</h3>214</h3>
174 215
175容器只需要您的 SDK 的语言运行时:216容器需要您的 SDK 的语言运行时:
176 217
177* Python SDK 需要 Python 3.10+,或 TypeScript SDK 需要 Node.js 18+218* Python SDK 需要 Python 3.10+,或 TypeScript SDK 需要 Node.js 18+
178* 两个 SDK 包都为主机平台捆绑了本机 Claude Code 二进制文件,因此不需要为生成的 CLI 单独安装 Claude Code 或 Node.js219* TypeScript 和 Python SDK 都为大多数安装捆绑了本机 Claude Code 二进制文件,生成的 CLI 不需要单独的 Node.js 安装。有关需要单独本机 Claude Code 安装的安装,请参阅 [quickstart 的安装说明](/docs/zh-CN/agent-sdk/quickstart)。
179 220
180捆绑的二进制文件被固定到 SDK 包版本,因此更新 SDK 是更新 CLI 的方式。SDK 遵循 semver:持续采用补丁版本,并在采用次要版本之前查看 [TypeScript](https://github.com/anthropics/claude-agent-sdk-typescript/blob/main/CHANGELOG.md) 或 [Python](https://github.com/anthropics/claude-agent-sdk-python/blob/main/CHANGELOG.md) 更改日志。221捆绑的二进制文件固定到 SDK 包版本,因此更新 SDK 是更新 CLI 的方式。SDK 遵循 semver:持续采用补丁版本,并在采用次要版本之前查看 [TypeScript](https://github.com/anthropics/claude-agent-sdk-typescript/blob/main/CHANGELOG.md) 或 [Python](https://github.com/anthropics/claude-agent-sdk-python/blob/main/CHANGELOG.md) 更新日志。
181 222
182<h3 id="resources">223<h3 id="resources">
183 资源224 资源
184</h3>225</h3>
185 226
186对于新启动的实例,每个代理 1 GiB RAM、5 GiB 磁盘和 1 个 CPU 是一个合理的起点。内存使用量随着会话长度和工具活动而增长,因此应根据您实际需要的会话长度和并发性进行调整,而不是根据空闲基线。有关如何计算每个主机的代理数,请参阅[扩展和并发](#scaling-and-concurrency)。227对于新启动的实例,每个代理 1 GiB RAM、5 GiB 磁盘和 1 个 CPU 是一个合理的起点。内存使用量随会话长度和工具活动而增长,因此应根据您实际需要的会话长度和并发性进行调整,而不是根据空闲基线。有关如何计算每个主机的代理数,请参阅 [Scaling and concurrency](#scaling-and-concurrency)。
187 228
188<h3 id="network">229<h3 id="network">
189 网络230 网络
190</h3>231</h3>
191 232
192SDK 需要对 `api.anthropic.com` 的出站 HTTPS,或在 Amazon Bedrock 或 Google Cloud 的 Agent Platform 上运行时对您的提供商的区域端点的出站 HTTPS。如果您的代理使用 [MCP servers](/zh-CN/agent-sdk/mcp) 或外部工具,它们还需要对这些端点的出站访问。对于生产环境,通过强制执行域名允许列表、注入凭证和记录请求的出站代理路由出站流量。有关完整模式,请参阅[安全部署](/zh-CN/agent-sdk/secure-deployment)。233SDK 需要对 `api.anthropic.com` 的出站 HTTPS,或在 Amazon Bedrock 或 Google Cloud 的 Agent Platform 上运行时对您的提供商的区域端点的出站 HTTPS。如果您的代理使用 [MCP servers](/docs/zh-CN/agent-sdk/mcp) 或外部工具,它们还需要对这些端点的出站访问。对于生产环境,通过强制执行域允许列表、注入凭据和记录请求的出站代理路由出站流量。有关完整模式,请参阅 [Secure Deployment](/docs/zh-CN/agent-sdk/secure-deployment)。
193 234
194对于入站流量,在容器上公开 HTTP 或 WebSocket 端口。您的应用程序在该端口上处理客户端请求并在内部调用 SDK;子进程本身不在网络上侦听。235对于入站流量,在容器上公开 HTTP 或 WebSocket 端口。您的应用程序在该端口上处理客户端请求并在内部调用 SDK;子进程本身不在网络上侦听。
195 236
196<h2 id="handle-production-concerns">237<h2 id="handle-production-concerns">
197 处理生产环境问题238 处理生产环保
198</h2>239</h2>
199 240
200在部署自托管代理之前,需要完成这些决策。241在部署自托管代理之前,需要完成这些决策。
203 会话和状态持久化244 会话和状态持久化
204</h3>245</h3>
205 246
206默认本地磁盘在重启、缩减或移动到不同节点时会丢失。对于用户期望恢复的任何会话,使用 [`SessionStore` 适配器](/zh-CN/agent-sdk/session-storage)将记录副本镜像到持久存储。查看[参考实现](/zh-CN/agent-sdk/session-storage#reference-implementations)了解 S3、Redis 和 Postgres 适配器,以及用于您自己实现的一致性测试套件。247默认本地磁盘在重启、缩减或移动到不同节点时会丢失。对于用户期望恢复的任何会话,使用 [`SessionStore` 适配器](/docs/zh-CN/agent-sdk/session-storage)将记录副本镜像到持久存储。查看[参考实现](/docs/zh-CN/agent-sdk/session-storage#reference-implementations)了解 S3、Redis 和 Postgres 适配器,以及用于您自己实现的一致性测试套件。
207 248
208关于 `SessionStore` 行为需要了解三件事:249关于 `SessionStore` 行为的三个要点:
209 250
210* **仅记录**:`SessionStore` 镜像记录,不镜像 `CLAUDE.md` 内存文件或其他工作目录工件。挂载共享卷或单独同步这些文件。251* **仅限记录**:`SessionStore` 镜像记录,不镜像 `CLAUDE.md` 内存文件或其他工作目录工件。挂载共享卷或单独同步这些文件。
211* **镜像,不替换**:子进程首先写入本地磁盘,存储接收每个批次的副本。本地写入保持权威性。252* **镜像,不替换**:子进程首先写入本地磁盘,SDK 将每个批次的副本转发到存储。新会话的本地记录比运行时间更长;从存储恢复的运行在结束时删除其本地副本,因此存储保存唯一的持久副本。查看[双写架构](/docs/zh-CN/agent-sdk/session-storage#dual-write-architecture)。
212* **`mirror_error` 消息**:存储拒绝的批次最多重试三次,每次重试前有短暂的退避;超时的调用不会重试。如果批次仍然失败,SDK 会丢弃它,发出 `{ type: "system", subtype: "mirror_error" }` 消息,并继续查询。如果存储持久性很重要,请对这些消息进行告警。253* **`mirror_error` 消息**:当 SDK 无法将批次传递到存储时,它会丢弃该批次,发出 `{ type: "system", subtype: "mirror_error" }` 消息,并继续查询。如果存储持久性很重要,请对这些消息进行警报。查看[镜像写入是尽力而为](/docs/zh-CN/agent-sdk/session-storage#mirror-writes-are-best-effort)了解重试和超时行为。
213 254
214<h3 id="observability">255<h3 id="observability">
215 可观测性256 可观测性
216</h3>257</h3>
217 258
218Agent SDK 代理是长生命周期的进程,在许多 API 往返中生成工具调用。没有遥测,您无法看到哪些工具运行、花费了多长时间或会话在哪里停滞。259Agent SDK 代理是长期运行的进程,在许多 API 往返中生成工具调用。没有遥测,您无法看到哪些工具运行、它们花费了多长时间,或会话在哪里停滞。
219 260
220SDK 从环境继承 OpenTelemetry 配置。在容器或编排器级别设置 OTEL 环境变量,以便每个 `query()` 调用都将跨度、指标和日志事件导出到您的收集器。下面的示例为所有三个信号启用 OTLP 导出。`CLAUDE_CODE_ENHANCED_TELEMETRY_BETA` 仅对跟踪是必需的;如果您仅导出指标和日志,请省略它。261SDK 从环境继承 OpenTelemetry 配置。在容器或编排器级别设置 OTEL 环境变量,以便每个 `query()` 调用都将跨度、指标和日志事件导出到您的收集器。下面的示例为所有三个信号启用 OTLP 导出。`CLAUDE_CODE_ENHANCED_TELEMETRY_BETA` 仅对跟踪是必需的;如果您仅导出指标和日志,请省略它。
221 262
222```bash title=".env' theme={null}263```bash title=".env" theme={null}
223CLAUDE_CODE_ENABLE_TELEMETRY=1264CLAUDE_CODE_ENABLE_TELEMETRY=1
224CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1265CLAUDE_CODE_ENHANCED_TELEMETRY_BETA=1
225OTEL_TRACES_EXPORTER=otlp266OTEL_TRACES_EXPORTER=otlp
229OTEL_EXPORTER_OTLP_ENDPOINT=http://collector.example.com:4318270OTEL_EXPORTER_OTLP_ENDPOINT=http://collector.example.com:4318
230```271```
231 272
232默认情况下,导出中不包含提示文本和工具输入。查看[控制导出中的敏感数据](/zh-CN/agent-sdk/observability#control-sensitive-data-in-exports)了解选择加入标志,以及[可观测性](/zh-CN/agent-sdk/observability)了解完整的信号目录。273默认情况下,导出中不包含提示文本和工具输入。查看[控制导出中的敏感数据](/docs/zh-CN/agent-sdk/observability#control-sensitive-data-in-exports)了解选择加入标志,以及[可观测性](/docs/zh-CN/agent-sdk/observability)了解完整的信号目录。
233 274
234<h3 id="auth-and-secrets">275<h3 id="auth-and-secrets">
235 身份验证和密钥276 身份验证和密钥
237 278
238托管时有三个身份验证问题很重要:279托管时有三个身份验证问题很重要:
239 280
240* **Anthropic API**:子进程从其环境读取 `ANTHROPIC_API_KEY`。从您的密钥管理器提供它,或设置 `ANTHROPIC_BASE_URL` 通过在容器外注入密钥的代理路由模型调用。查看[凭证管理](/zh-CN/agent-sdk/secure-deployment#credential-management)了解代理模式,以及[SDK 概述](/zh-CN/agent-sdk/overview#get-started)了解支持的身份验证方法。281* **Anthropic API**:子进程从其环境读取 `ANTHROPIC_API_KEY`。从您的密钥管理器提供它,或设置 `ANTHROPIC_BASE_URL` 以通过在容器外注入密钥的代理路由模型调用。查看[凭证管理](/docs/zh-CN/agent-sdk/secure-deployment#credential-management)了解代理模式,以及[SDK 快速入门中的设置](/docs/zh-CN/agent-sdk/quickstart#setup)了解支持的身份验证方法。
241* **入站**:在代理容器前面的网关处放置身份验证。代理应接收预先认证的请求,不应是验证用户令牌的组件。282* **入站**:在代理容器前面的网关处放置身份验证。代理应接收预先认证的请求,不应是验证用户令牌的组件。
242* **出站工具**:将工具凭证保留在代理环境之外。通过代理路由出站调用,该代理在请求离开容器后注入 API 密钥。代理进行调用;代理添加凭证。283* **出站工具**:将工具凭证保留在代理环境之外。通过代理路由出站调用,该代理在请求离开容器后注入 API 密钥。代理进行调用;代理添加凭证。
243 284
250使用此公式调整每个主机的大小:291使用此公式调整每个主机的大小:
251 292
252```text theme={null}293```text theme={null}
253每个主机的代理数 = (主机 RAM - 开销) / (每个会话 RAM 上限)294agents per host = (host RAM - overhead) / (per-session RAM ceiling)
254```295```
255 296
256通过在您的目标长度下运行代表性会话并在您的预期工具负载下记录峰值 RSS 来测量每个会话的上限。[资源](#resources)中的 1 GiB 起点是下限,不是上限。297通过在您的目标长度下运行代表性会话并在您的预期工具负载下记录峰值 RSS 来测量每会话上限。[资源](#resources)中的 1 GiB 起点是下限,不是上限。
257 298
258水平扩展路由取决于您的模式。对于长运行会话,其中容器持有许多会话,在负载均衡器后面运行容器池,并使用 `sessionId` 上的一致性哈希将每个会话固定到一个容器。固定会话继续命中同一容器,因此同一运行的子进程,直到它被驱逐或容器重启。299水平扩展路由取决于您的模式。对于长期运行的会话(其中容器保存许多会话),在负载均衡器后面运行容器池,并使用 `sessionId` 上的一致哈希将每个会话固定到一个容器。固定会话继续命中同一容器,因此同一运行的子进程,直到它被驱逐或容器重启。
259
260来自单个会话的大量并发[子代理](/zh-CN/agent-sdk/subagents)扇出可能会触及 API 速率限制。将工作分解为较小的批次,而不是发出一个宽分派。
261 300
262<h3 id="cost">301<h3 id="cost">
263 成本302 成本
264</h3>303</h3>
265 304
266Anthropic 令牌成本通常比容器基础设施成本高一个数量级或更多。最小配置的容器运行成本大约为每小时 \$0.05,而单个长代理会话可能花费数美元的令牌。查看[成本跟踪](/zh-CN/agent-sdk/cost-tracking)了解每个会话的令牌计费。305Anthropic 令牌成本通常比容器基础设施成本高一个数量级或更多。最小配置的容器运行成本大约为每小时 \$0.05,而单个长代理会话可能花费数美元的令牌。查看[成本跟踪](/docs/zh-CN/agent-sdk/cost-tracking)了解每会话令牌计数。
267 306
268<h3 id="multi-tenant-isolation">307<h3 id="multi-tenant-isolation">
269 多租户隔离308 多租户隔离
273 312
274要在共享容器内隔离租户:313要在共享容器内隔离租户:
275 314
276* 在 TypeScript 中传递 `settingSources: []` 或在 Python 中传递 `setting_sources=[]`,以便不加载文件系统设置。315* 在 TypeScript 中传递 `settingSources: []` 或在 Python 中传递 `setting_sources=[]` 以跳过用户、项目和本地设置。
277* 在 `env` 中设置 `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1`。[自动内存](/zh-CN/memory#auto-memory)在 `~/.claude/projects/<project>/memory/` 加载到系统提示中,无论 `settingSources` 如何。查看[settingSources 不控制的内容](/zh-CN/agent-sdk/claude-code-features#what-settingsources-does-not-control)了解无条件加载的其他输入。316* 在 `env` 中设置 `CLAUDE_CODE_DISABLE_AUTO_MEMORY=1`。[自动内存](/docs/zh-CN/memory#auto-memory)在 `~/.claude/projects/<project>/memory/` 加载到系统提示中,无论 `settingSources` 如何。查看[settingSources 不控制的内容](/docs/zh-CN/agent-sdk/claude-code-features#what-settingsources-does-not-control)了解无条件加载的其他输入。
278* 将 `CLAUDE_CONFIG_DIR` 指向每个租户目录,以便租户不共享 `~/.claude.json` 全局配置。317* 将 `CLAUDE_CONFIG_DIR` 指向每个租户目录,以便租户不共享 `~/.claude.json` 全局配置。当每个配置目录服务一个工作目录,并且您不在租户之间共享 [`SessionStore`](/docs/zh-CN/agent-sdk/session-storage) 时,您也可以在 `env` 中设置 [`CLAUDE_CODE_PROJECT_DIR_NAME`](/docs/zh-CN/sessions#name-the-project-directory-yourself) 以保持其下的记录路径简短。需要 TypeScript Agent SDK v0.3.234 或更高版本,或 Python Agent SDK v0.2.140 或更高版本。
279* 使用每个租户的工作目录。在每个 `query()` 调用上显式传递 `cwd`。318* 使用每个租户工作目录。在每个 `query()` 调用上显式传递 `cwd`。
280* 在您的代理处应用每个租户的出站规则,例如不同的出站 IP、凭证或域名单,以便受损的租户无法通过另一个租户的出站策略泄露数据。319* 在您的代理处应用每个租户出站规则,例如不同的出站 IP、凭证或域名白名单,以便受损的租户无法通过另一个租户的出站策略泄露数据。
281 320
282下面的示例将四个 SDK 级别的选项应用在一起。构造 `tenantDir` 和 `configDir`,以便每个租户获得其他租户无法读取的路径。在 TypeScript 中,`env` 替换子进程环境,因此展开 `...process.env` 以保持继承的变量,如 `PATH` 和 `ANTHROPIC_API_KEY`。在 Python 中,`env` 合并在继承的环境之上。321下面的示例将设置、自动内存、配置目录和工作目录选项应用在一起。构造 `tenantDir` 和 `configDir`,以便每个租户获得其他租户无法读取的路径。在 TypeScript 中,`env` 替换子进程环境,因此展开 `...process.env` 以保持继承的变量,如 `PATH` 和 `ANTHROPIC_API_KEY`。在 Python 中,`env` 合并到继承的环境之上。
283 322
284<CodeGroup>323<CodeGroup>
285 ```typescript TypeScript theme={null}324 ```typescript TypeScript theme={null}
307 346
308 ```python Python theme={null}347 ```python Python theme={null}
309 from claude_agent_sdk import query, ClaudeAgentOptions348 from claude_agent_sdk import query, ClaudeAgentOptions
349 import asyncio
350
351 prompt: str = ...
352 tenant_dir: str = ...
353 config_dir: str = ...
354
310 355
356 async def main():
311 async for message in query(357 async for message in query(
312 prompt=prompt,358 prompt=prompt,
313 options=ClaudeAgentOptions(359 options=ClaudeAgentOptions(
320 ),366 ),
321 ):367 ):
322 ...368 ...
369
370
371 asyncio.run(main())
323 ```372 ```
324</CodeGroup>373</CodeGroup>
325 374
326有关每个租户的网络控制,请查看[安全部署](/zh-CN/agent-sdk/secure-deployment)。
327
328<h2 id="known-limitations">375<h2 id="known-limitations">
329 已知限制376 已知限制
330</h2>377</h2>
332在您的部署设计中规划这些限制。379在您的部署设计中规划这些限制。
333 380
334| 限制 | 解决方案 |381| 限制 | 解决方案 |
335| ------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |382| ------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
336| 没有顶级会话超时 | 会话不会自动超时。在 `Options` 中设置 `maxTurns` 以限制代理在停止前进行多少次工具使用往返。 |383| 没有顶级会话超时 | 会话不会自动超时。在 TypeScript 中设置 `maxTurns` 或在 Python 中设置 `max_turns` 来限制代理在停止前进行多少次工具使用往返。 |
337| 长会话中的内存增长 | 限制会话长度或定期回收子进程。请参阅 [扩展和并发](#scaling-and-concurrency)。 |384| 长会话中的内存增长 | 限制会话长度或定期回收子进程。请参阅[扩展和并发](#scaling-and-concurrency)。 |
338| 大规模并行子代理扇出可能会触发速率限制 | 将工作分解为较小的批次,而不是发出一个宽泛的调度。 |385| 大规模并行子代理扇出可能会触发速率限制 | 将工作分解为较小的批次,而不是发出一个宽范围的调度。 |
339| 没有每个子代理的挂钟截止时间 | 使用 `AgentDefinition` 中的 `maxTurns` 限制每个 [subagent](/zh-CN/agent-sdk/subagents)。仅对后台子代理,`CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS` 设置一个停滞监视程序,当 `run_in_background` 子代理停止产生输出时触发;它不是总运行时截止时间。 |386| 没有每个子代理的挂钟截止时间 | 在其 `AgentDefinition` 中使用 `maxTurns` 限制每个[子代理](/docs/zh-CN/agent-sdk/subagents)。`CLAUDE_ASYNC_AGENT_STALL_TIMEOUT_MS` 设置一个停滞监视程序,当子代理停止产生输出时触发;它不是总运行时截止时间。 |
387
388<h2 id="troubleshoot-deployment-failures">
389 排查部署失败
390</h2>
391
392当在已部署的服务中运行的代理在您的机器上工作正常但在部署后失败时,请使用本部分。下面的每一项都列出了一个失败情况并链接到相应的条目:
393
394* **服务启动时找不到 CLI**:在 Python 中,容器或服务管理器运行您的应用程序时使用的 `PATH` 与您的 shell 不同,因此在本地有效的安装对该进程不可见。在 TypeScript 中,镜像构建跳过了 SDK 的可选依赖项,或者 `pathToClaudeCodeExecutable` 指向镜像中不存在的文件。请参阅 [Claude Code not found](/docs/zh-CN/agent-sdk/troubleshooting#clinotfounderror-claude-code-not-found)。
395* **CLI 在镜像中存在但无法启动**:Claude Code 无法从与容器架构或 libc 不匹配的二进制文件启动,或者从在镜像构建中失去执行权限的文件启动。请参阅 [Failed to start Claude Code](/docs/zh-CN/agent-sdk/troubleshooting#cliconnectionerror-failed-to-start-claude-code)。
396* **Claude Code 进程在运行中途退出**:您的应用程序收到的错误取决于 SDK 语言以及 CLI 是否首先报告了错误结果。[CLI process exit](/docs/zh-CN/agent-sdk/troubleshooting#cli-process-exit) 下的条目涵盖了每条消息。
340 397
341<h2 id="next-steps">398<h2 id="next-steps">
342 后续步骤399 后续步骤
343</h2>400</h2>
344 401
345* [Hosting cookbook](https://github.com/anthropics/claude-cookbooks/blob/main/claude_agent_sdk/07_Hosting_the_agent.ipynb):包含 Docker、Modal 和 Kubernetes 的[可部署代码](https://github.com/anthropics/claude-cookbooks/tree/main/claude_agent_sdk/hosting)的笔记本演练。402* [Hosting cookbook](https://github.com/anthropics/claude-cookbooks/blob/main/claude_agent_sdk/07_Hosting_the_agent.ipynb):包含 Docker、Modal 和 Kubernetes 的[可部署代码](https://github.com/anthropics/claude-cookbooks/tree/main/claude_agent_sdk/hosting)的笔记本演练。
346* [Session storage](/zh-CN/agent-sdk/session-storage):使用 `SessionStore` 适配器在主机间持久化记录。403* [Session storage](/docs/zh-CN/agent-sdk/session-storage):使用 `SessionStore` 适配器在主机间持久化记录。
347* [Observability](/zh-CN/agent-sdk/observability):将 OTEL 跟踪、指标和日志导出到您的收集器。404* [Observability](/docs/zh-CN/agent-sdk/observability):将 OTEL 跟踪、指标和日志导出到您的收集器。
348* [Secure deployment](/zh-CN/agent-sdk/secure-deployment):网络控制、凭证管理和隔离加固。405* [Secure deployment](/docs/zh-CN/agent-sdk/secure-deployment):网络控制、凭证管理和隔离加固。
349* [Cost tracking](/zh-CN/agent-sdk/cost-tracking):按会话的令牌和成本计费。406* [Cost tracking](/docs/zh-CN/agent-sdk/cost-tracking):按会话的令牌和成本计费。