自托管沙箱
在您自己的自托管沙箱环境中运行智能体会话。
默认情况下,托管智能体在 Anthropic 托管的云容器内执行工具和代码。自托管沙箱将编排保留在 Anthropic 侧,但将工具执行转移到您控制的基础设施中,因此智能体的代码、文件系统和网络出口永远不会离开您的环境。
自托管沙箱尚未在 Claude Platform on AWS 上可用。
与云环境的区别
| 云环境 | 自托管沙箱 | |
|---|---|---|
| 工具运行位置 | Anthropic 托管的容器 | 您的基础设施 |
| 网络访问 | Anthropic 的出口控制 | 您的网络策略 |
| 文件和 GitHub 仓库挂载 | Anthropic 管理 | 您管理 |
| 生命周期 | Anthropic 管理 | 您管理 |
当智能体需要操作不能离开您网络边界的数据、访问不可公开路由的内部服务,或在您组织自己的合规性和审计控制下运行时,自托管是一个很好的选择。
有关零数据保留和 HIPAA BAA 资格,请参阅 API 和数据保留。
何时与 MCP 隧道结合使用
自托管控制智能体代码在哪里执行。MCP 隧道控制Anthropic 如何访问您网络中的 MCP 服务器。它们是独立的:在 Anthropic 云容器中运行的会话仍然可以通过隧道访问私有 MCP 服务器,自托管会话可以使用隧道或公共 MCP 服务器。当您希望执行和工具访问都保持在您的边界内时,请同时使用两者。
环境工作者
以下指南描述了如何使用任何通用沙箱平台构建工作者。还有针对 Cloudflare、Daytona、Modal 和 Vercel 的平台特定指南。
环境工作者是您在自己基础设施上运行的进程,它接收来自 Anthropic 的工具执行请求并在本地运行。self_hosted 环境是一个工作队列,将 Anthropic 的编排连接到您的工作者:当会话被分配到环境时,Anthropic 将其作为工作项入队。您的工作者从该队列中获取项,为每个会话生成执行上下文,下载智能体技能,在本地运行工具调用,并将结果发回。
工作通过轮询环境的队列来获取:由持续轮询的常驻工作者,或在 session.status_run_started 时唤醒并开始轮询的 webhook 触发处理器。
CLI 和 SDK 都包含预构建的工作者来编排您的会话。ant CLI 仅支持常驻模式;SDK 支持常驻和 webhook 触发架构。
CLI 和 SDK 都是可配置的(参见参考),但如果您需要更多控制,可以直接使用环境工作端点并实现自己的工作者。
SDK 辅助程序需要 /bin/bash 在该确切路径。TypeScript SDK 还需要 unzip、tar 和 Node.js 22 或更高版本。这些依赖项在固定路径解析,不尊重 PATH 覆盖。
沙箱文件系统
/workspace:工具执行和技能下载的默认工作目录。技能下载到/workspace/skills/<name>/。如果您将--workdir从默认值更改,请更新智能体的系统提示,让 Claude 知道在哪里找到它们。/mnt/session/outputs:智能体将最终输出文件写入此路径。在容器中运行时,在此处挂载主机目录以检索它们。
创建自托管环境
在控制台:Workspace > Environments > New > Self-hosted
或通过 API:
curl -sS --fail-with-body https://api.anthropic.com/v1/environments \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "anthropic-beta: managed-agents-2026-04-01" \ -H "content-type: application/json" \ -d '{ "name": "self-hosted", "config": {"type": "self_hosted"} }'ant beta:environments create \ --name self-hosted \ --config '{"type": "self_hosted"}'client = anthropic.Anthropic() environment = client.beta.environments.create( name="self-hosted", config={"type": "self_hosted"} ) print(environment.id)const client = new Anthropic(); const environment = await client.beta.environments.create({ name: "self-hosted", config: { type: "self_hosted" } }); console.log(environment.id);using Anthropic.Models.Beta.Environments; var client = new AnthropicClient(); var environment = await client.Beta.Environments.Create( new EnvironmentCreateParams { Name = "self-hosted", Config = new BetaSelfHostedConfigParams(), } ); Console.WriteLine(environment.ID);package main import ( "context" "fmt" "github.com/anthropics/anthropic-sdk-go" ) func main() { client := anthropic.NewClient() environment, err := client.Beta.Environments.New(context.Background(), anthropic.BetaEnvironmentNewParams{ Name: "self-hosted", Config: anthropic.BetaEnvironmentNewParamsConfigUnion{ OfSelfHosted: &anthropic.BetaSelfHostedConfigParams{}, }, }) if err != nil { panic(err) } fmt.Println(environment.ID) }import com.anthropic.models.beta.environments.BetaSelfHostedConfigParams; import com.anthropic.models.beta.environments.EnvironmentCreateParams; var client = AnthropicOkHttpClient.fromEnv(); var environment = client.beta().environments().create( EnvironmentCreateParams.builder() .name("self-hosted") .config(BetaSelfHostedConfigParams.builder().build()) .build() ); IO.println(environment.id());$client = new Anthropic\Client(); $environment = $client->beta->environments->create( name: 'self-hosted', config: ['type' => 'self_hosted'], ); echo $environment->id, PHP_EOL;client = Anthropic::Client.new environment = client.beta.environments.create( name: "self-hosted", config: {type: :self_hosted} ) puts environment.id设置环境密钥
在控制台中,打开环境并单击生成环境密钥。然后在工作者主机上导出环境 ID 和密钥:
export ANTHROPIC_ENVIRONMENT_KEY="sk-ant-oat01-..." export ANTHROPIC_ENVIRONMENT_ID="env_..."安装 ant CLI
在工作者将运行的计算机上运行此命令。
VERSION=1.9.1 OS=$(uname -s | tr '[:upper:]' '[:lower:]') ARCH=$(uname -m | sed -e 's/x86_64/amd64/' -e 's/aarch64/arm64/') curl -fsSL "https://github.com/anthropics/anthropic-cli/releases/download/v${VERSION}/ant_${VERSION}_${OS}_${ARCH}.tar.gz" \ | sudo tar -xz -C /usr/local/bin ant运行工作者
进程内
ant beta:worker poll获取分配给环境的会话,下载技能,在工作目录中执行工具调用,并将结果发回。Note技能可以包含智能体可能直接运行的可执行文件。CLI 会自动将下载的技能文件在沙箱中标记为可执行。如果您手动实现技能下载,您有责任设置可执行权限。
ant beta:worker poll \ --workdir "/workspace"工作者在 SIGTERM 或 SIGINT 时干净退出,在停止前排空进行中的工具调用。
每个会话一个容器
为了更强的隔离:每个会话的新文件系统、资源限制或网络控制。在各自的容器中运行每个会话。首先构建一个安装了
ant并以ant beta:worker run作为入口点的镜像。当容器启动时,它从环境变量读取会话详细信息,处理该会话,然后退出:FROM your-base-image ARG ANT_VERSION=1.9.1 ARG TARGETARCH RUN ARCH=$([ "$TARGETARCH" = "arm64" ] && echo arm64 || echo amd64) && \ curl -fsSL "https://github.com/anthropics/anthropic-cli/releases/download/v${ANT_VERSION}/ant_${VERSION}_linux_${ARCH}.tar.gz" \ | tar -xz -C /usr/local/bin ant WORKDIR /workspace VOLUME /mnt/session/outputs ENTRYPOINT ["ant", "beta:worker", "run"]然后编写一个生成脚本,将会话详细信息转发到新容器中,并启动指向它的轮询器:
#!/bin/bash # spawn.sh: 每个会话调用一次 mkdir -p "/host/outputs/$ANTHROPIC_SESSION_ID" exec docker run --rm \ -e ANTHROPIC_SESSION_ID -e ANTHROPIC_ENVIRONMENT_KEY \ -e ANTHROPIC_WORK_ID -e ANTHROPIC_ENVIRONMENT_ID -e ANTHROPIC_BASE_URL \ -v "/host/outputs/$ANTHROPIC_SESSION_ID":/mnt/session/outputs \ your-imageant beta:worker poll \ --on-work ./spawn.sh
创建自托管环境
在控制台:Workspace > Environments > New > Self-hosted
或通过 API:
curl -sS --fail-with-body https://api.anthropic.com/v1/environments \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "anthropic-beta: managed-agents-2026-04-01" \ -H "content-type: application/json" \ -d '{ "name": "self-hosted", "config": {"type": "self_hosted"} }'ant beta:environments create \ --name self-hosted \ --config '{"type": "self_hosted"}'client = anthropic.Anthropic() environment = client.beta.environments.create( name="self-hosted", config={"type": "self_hosted"} ) print(environment.id)const client = new Anthropic(); const environment = await client.beta.environments.create({ name: "self-hosted", config: { type: "self_hosted" } }); console.log(environment.id);using Anthropic.Models.Beta.Environments; var client = new AnthropicClient(); var environment = await client.Beta.Environments.Create( new EnvironmentCreateParams { Name = "self-hosted", Config = new BetaSelfHostedConfigParams(), } ); Console.WriteLine(environment.ID);package main import ( "context" "fmt" "github.com/anthropics/anthropic-sdk-go" ) func main() { client := anthropic.NewClient() environment, err := client.Beta.Environments.New(context.Background(), anthropic.BetaEnvironmentNewParams{ Name: "self-hosted", Config: anthropic.BetaEnvironmentNewParamsConfigUnion{ OfSelfHosted: &anthropic.BetaSelfHostedConfigParams{}, }, }) if err != nil { panic(err) } fmt.Println(environment.ID) }import com.anthropic.models.beta.environments.BetaSelfHostedConfigParams; import com.anthropic.models.beta.environments.EnvironmentCreateParams; var client = AnthropicOkHttpClient.fromEnv(); var environment = client.beta().environments().create( EnvironmentCreateParams.builder() .name("self-hosted") .config(BetaSelfHostedConfigParams.builder().build()) .build() ); IO.println(environment.id());$client = new Anthropic\Client(); $environment = $client->beta->environments->create( name: 'self-hosted', config: ['type' => 'self_hosted'], ); echo $environment->id, PHP_EOL;client = Anthropic::Client.new environment = client.beta.environments.create( name: "self-hosted", config: {type: :self_hosted} ) puts environment.id设置环境密钥
在控制台中,打开环境并单击生成环境密钥。然后在工作者主机上导出环境 ID 和密钥:
export ANTHROPIC_ENVIRONMENT_KEY="sk-ant-oat01-..." export ANTHROPIC_ENVIRONMENT_ID="env_..."运行工作者
EnvironmentWorker获取分配给环境的会话,下载技能,在工作目录中执行工具调用,并将结果发回。使用您在步骤 2 中生成的环境密钥进行身份验证。Note技能可以包含智能体可能直接运行的可执行文件。SDK 会自动将下载的技能文件在沙箱中标记为可执行。如果您手动实现技能下载,您有责任设置可执行权限。
import asyncio import os from anthropic import AsyncAnthropic from anthropic.lib.environments import EnvironmentWorker async def main() -> None: environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"] environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"] async with AsyncAnthropic(auth_token=environment_key) as client: await EnvironmentWorker( client, environment_id=environment_id, environment_key=environment_key, workdir="/workspace", ).run() asyncio.run(main())import Anthropic from "@anthropic-ai/sdk"; import { EnvironmentWorker } from "@anthropic-ai/sdk/helpers/beta/environments"; const environmentKey = process.env.ANTHROPIC_ENVIRONMENT_KEY!; const environmentId = process.env.ANTHROPIC_ENVIRONMENT_ID!; const client = new Anthropic({ authToken: environmentKey }); const ctrl = new AbortController(); process.once("SIGTERM", () => ctrl.abort()); await new EnvironmentWorker({ client, environmentId, environmentKey, workdir: "/workspace", signal: ctrl.signal }).run();// EnvironmentWorker 目前在 C# SDK 中不可用。请参阅上面的常驻(ant CLI)选项卡。package main import ( "context" "log" "os" "os/signal" "syscall" "github.com/anthropics/anthropic-sdk-go" "github.com/anthropics/anthropic-sdk-go/lib/environments" "github.com/anthropics/anthropic-sdk-go/option" ) func main() { environmentKey := os.Getenv("ANTHROPIC_ENVIRONMENT_KEY") environmentID := os.Getenv("ANTHROPIC_ENVIRONMENT_ID") ctx, stop := signal.NotifyContext(context.Background(), os.Interrupt, syscall.SIGTERM) defer stop() client := anthropic.NewClient(option.WithAuthToken(environmentKey)) worker := environments.NewEnvironmentWorker(client, environments.EnvironmentWorkerOptions{ EnvironmentID: environmentID, EnvironmentKey: environmentKey, Workdir: "/workspace", }) if err := worker.Run(ctx); err != nil { log.Fatalf("worker: %v", err) } }// EnvironmentWorker 目前在 Java SDK 中不可用。请参阅上面的常驻(ant CLI)选项卡。// EnvironmentWorker 目前在 PHP SDK 中不可用。请参阅上面的常驻(ant CLI)选项卡。# EnvironmentWorker 目前在 Ruby SDK 中不可用。请参阅上面的常驻(ant CLI)选项卡。
订阅会话 webhook
在控制台中,定义一个侦听
session.status_run_started事件的 webhook 端点。有关更多详细信息,请参阅 webhook 文档。创建自托管环境
在控制台:Workspace > Environments > New > Self-hosted
或通过 API:
curl -sS --fail-with-body https://api.anthropic.com/v1/environments \ -H "x-api-key: $ANTHROPIC_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "anthropic-beta: managed-agents-2026-04-01" \ -H "content-type: application/json" \ -d '{ "name": "self-hosted", "config": {"type": "self_hosted"} }'ant beta:environments create \ --name self-hosted \ --config '{"type": "self_hosted"}'client = anthropic.Anthropic() environment = client.beta.environments.create( name="self-hosted", config={"type": "self_hosted"} ) print(environment.id)const client = new Anthropic(); const environment = await client.beta.environments.create({ name: "self-hosted", config: { type: "self_hosted" } }); console.log(environment.id);using Anthropic.Models.Beta.Environments; var client = new AnthropicClient(); var environment = await client.Beta.Environments.Create( new EnvironmentCreateParams { Name = "self-hosted", Config = new BetaSelfHostedConfigParams(), } ); Console.WriteLine(environment.ID);package main import ( "context" "fmt" "github.com/anthropics/anthropic-sdk-go" ) func main() { client := anthropic.NewClient() environment, err := client.Beta.Environments.New(context.Background(), anthropic.BetaEnvironmentNewParams{ Name: "self-hosted", Config: anthropic.BetaEnvironmentNewParamsConfigUnion{ OfSelfHosted: &anthropic.BetaSelfHostedConfigParams{}, }, }) if err != nil { panic(err) } fmt.Println(environment.ID) }import com.anthropic.models.beta.environments.BetaSelfHostedConfigParams; import com.anthropic.models.beta.environments.EnvironmentCreateParams; var client = AnthropicOkHttpClient.fromEnv(); var environment = client.beta().environments().create( EnvironmentCreateParams.builder() .name("self-hosted") .config(BetaSelfHostedConfigParams.builder().build()) .build() ); IO.println(environment.id());$client = new Anthropic\Client(); $environment = $client->beta->environments->create( name: 'self-hosted', config: ['type' => 'self_hosted'], ); echo $environment->id, PHP_EOL;client = Anthropic::Client.new environment = client.beta.environments.create( name: "self-hosted", config: {type: :self_hosted} ) puts environment.id设置凭据
在控制台中,打开环境并单击生成环境密钥。在您的处理器主机上导出所有三个:
export ANTHROPIC_ENVIRONMENT_KEY="sk-ant-oat01-..." export ANTHROPIC_ENVIRONMENT_ID="env_..." export ANTHROPIC_WEBHOOK_SIGNING_KEY="whsec_..."实现 webhook 处理器
EnvironmentWorker获取会话,下载技能,在工作目录中执行工具调用,发回结果,然后退出。在session.status_run_started触发时调用它。Note技能可以包含智能体可能直接运行的可执行文件。SDK 会自动将下载的技能文件在沙箱中标记为可执行。如果您手动实现技能下载,您有责任设置可执行权限。
import os import anthropic environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"] environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"] client = anthropic.AsyncAnthropic( auth_token=environment_key, ) async def handle(raw: bytes, headers: dict[str, str]) -> dict: event = client.beta.webhooks.unwrap(raw.decode(), headers=headers) if event.data.type != "session.status_run_started": return {"status": "ignored"} async for work in client.beta.environments.work.poller( environment_id=environment_id, environment_key=environment_key, block_ms=None, reclaim_older_than_ms=2000, drain=True, auto_stop=False, ): await client.beta.environments.work.worker(workdir="/workspace").handle_item( work_id=work.id, environment_id=environment_id, session_id=work.data.id, environment_key=environment_key, ) return {"status": "ok"}import Anthropic from "@anthropic-ai/sdk"; const environmentKey = process.env.ANTHROPIC_ENVIRONMENT_KEY!; const environmentId = process.env.ANTHROPIC_ENVIRONMENT_ID!; const client = new Anthropic({ authToken: environmentKey }); export async function handle(req: Request): Promise<Response> { const body = await req.text(); let event; try { event = client.beta.webhooks.unwrap(body, { headers: Object.fromEntries(req.headers) }); } catch { return new Response("signature verification failed", { status: 401 }); } if (event.data.type !== "session.status_run_started") { return Response.json({ status: "ignored" }); } for await (const work of client.beta.environments.work.poller({ environmentId, environmentKey, blockMs: null, reclaimOlderThanMs: 2000, drain: true, autoStop: false })) { await client.beta.environments.work.worker({ workdir: "/workspace" }).handleItem({ workId: work.id, environmentId, sessionId: work.data.id, environmentKey }); } return Response.json({ status: "ok" }); }// EnvironmentWorker 目前在 C# SDK 中不可用。 // 要直接处理工作项,请参阅介绍中链接的环境工作端点。package main import ( "context" "encoding/json" "io" "log/slog" "net/http" "os" "github.com/anthropics/anthropic-sdk-go" "github.com/anthropics/anthropic-sdk-go/lib/environments" "github.com/anthropics/anthropic-sdk-go/option" ) var ( environmentKey = os.Getenv("ANTHROPIC_ENVIRONMENT_KEY") environmentID = os.Getenv("ANTHROPIC_ENVIRONMENT_ID") client = anthropic.NewClient( option.WithAuthToken(environmentKey), option.WithWebhookKey(os.Getenv("ANTHROPIC_WEBHOOK_SIGNING_KEY")), ) worker = environments.NewEnvironmentWorker(client, environments.EnvironmentWorkerOptions{ Workdir: "/workspace", }) ) func handle(w http.ResponseWriter, r *http.Request) { body, err := io.ReadAll(r.Body) if err != nil { http.Error(w, "bad request", http.StatusBadRequest) return } event, err := client.Beta.Webhooks.Unwrap(body, r.Header) if err != nil { http.Error(w, "signature verification failed", http.StatusUnauthorized) return } if event.Data.Type != "session.status_run_started" { json.NewEncoder(w).Encode(map[string]string{"status": "ignored"}) return } // Go SDK 不提供 RunOne 便利方法:使用 WorkPoller 获取项, // 然后使用 HandleItem 运行它。 // 从 r.Context() 分离:会话可能比 webhook 交付超时更长。 ctx := context.Background() poller := environments.NewWorkPoller(ctx, client, environments.WorkPollerOptions{ EnvironmentID: environmentID, EnvironmentKey: environmentKey, Drain: true, }) defer poller.Close() if poller.Next() { item := poller.Current() if err := worker.HandleItem(ctx, environments.HandleItemOptions{ WorkID: item.ID, EnvironmentID: item.EnvironmentID, SessionID: item.Data.ID, EnvironmentKey: environmentKey, }); err != nil { slog.Error("handle work item", "work_id", item.ID, "err", err) http.Error(w, "internal error", http.StatusInternalServerError) return } } if err := poller.Err(); err != nil { slog.Error("poll work queue", "err", err) http.Error(w, "internal error", http.StatusInternalServerError) return } json.NewEncoder(w).Encode(map[string]string{"status": "ok"}) } func main() { http.HandleFunc("POST /webhook", handle) if err := http.ListenAndServe(":8080", nil); err != nil { slog.Error("http server", "err", err) os.Exit(1) } }// EnvironmentWorker 目前在 Java SDK 中不可用。 // 要直接处理工作项,请参阅介绍中链接的环境工作端点。// EnvironmentWorker 目前在 PHP SDK 中不可用。 // 要直接处理工作项,请参阅介绍中链接的环境工作端点。# EnvironmentWorker 目前在 Ruby SDK 中不可用。 # 要直接处理工作项,请参阅介绍中链接的环境工作端点。
启动会话
工作者运行后,创建目标为环境的会话。Anthropic 将其入队,您的工作者获取并执行它。
文件和 GitHub 资源挂载在您的容器镜像中处理,而不是由 Anthropic 处理。要加载具有会话特定文件的沙箱,您可以在创建会话时传递会话元数据。您的编排层可以读取该元数据,并在工作者开始执行之前挂载相关文件。
curl -sS --fail-with-body https://api.anthropic.com/v1/sessions \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "content-type: application/json" \
-d @- <<EOF
{
"agent": "$AGENT_ID",
"environment_id": "$ENVIRONMENT_ID",
"metadata": {"input_file": "s3://my-bucket/data.csv"}
}
EOF
ant beta:sessions create \
--agent "$AGENT_ID" \
--environment-id "$ENVIRONMENT_ID" \
--metadata '{"input_file": "s3://my-bucket/data.csv"}'
session = client.beta.sessions.create(
agent=agent.id,
environment_id=environment.id,
metadata={"input_file": "s3://my-bucket/data.csv"},
)
const session = await client.beta.sessions.create({
agent: agent.id,
environment_id: environment.id,
metadata: { input_file: "s3://my-bucket/data.csv" }
});
var session = await client.Beta.Sessions.Create(new()
{
Agent = agent.ID,
EnvironmentID = environment.ID,
Metadata = new Dictionary<string, string> { ["input_file"] = "s3://my-bucket/data.csv" },
});
session, err := client.Beta.Sessions.New(ctx, anthropic.BetaSessionNewParams{
Agent: anthropic.BetaSessionNewParamsAgentUnion{OfString: anthropic.String(agent.ID)},
EnvironmentID: environment.ID,
Metadata: map[string]string{
"input_file": "s3://my-bucket/data.csv",
},
})
if err != nil {
panic(err)
}
var session = client.beta().sessions().create(SessionCreateParams.builder()
.agent(agent.id())
.environmentId(environment.id())
.metadata(SessionCreateParams.Metadata.builder()
.putAdditionalProperty("input_file", JsonValue.from("s3://my-bucket/data.csv"))
.build())
.build());
$session = $client->beta->sessions->create(
agent: $agent->id,
environmentID: $environment->id,
metadata: ['input_file' => 's3://my-bucket/data.csv'],
);
session = client.beta.sessions.create(
agent: agent.id,
environment_id: environment.id,
metadata: {input_file: "s3://my-bucket/data.csv"}
)
记忆尚不支持自托管沙箱。
参考
| 标志 | 描述 |
|---|---|
--environment-id | 轮询工作的环境。也从 ANTHROPIC_ENVIRONMENT_ID 读取。 |
--environment-key | 使用此环境对工作者进行身份验证。也从 ANTHROPIC_ENVIRONMENT_KEY 读取。 |
--workdir | 下载技能和工具读写文件的目录。默认为 /workspace。 |
--on-work | 为每个获取的工作项调用的脚本,而不是在进程内运行工具。接收会话详细信息作为环境变量。 |
--unrestricted-paths | 允许工具调用访问 --workdir 之外的路径。 |
--max-idle | 在 end_turn 空闲后等待多长时间再关闭。默认为 60s。 |
--log-format | 日志输出格式。使用 json 进行结构化日志摄取。默认为 text。 |
SDK 在不同级别提供三个辅助程序:
EnvironmentWorker:开箱即用的工作者。端到端处理轮询、设置和执行。.run():无限期运行,随会话到达而获取。在 SIGTERM 时干净退出。.handle_item():获取一个待处理会话,处理它,然后退出。
work.poller():代表您轮询工作队列并向您提供每个获取的会话。当您想决定每个会话发生什么时使用此选项,例如启动容器而不是在进程内运行工具。drain:队列为空时是否停止轮询,而不是等待新工作。block_ms:在返回之前等待工作到达的时间(毫秒)。必须在 1 到 999 之间。设置为None进行非阻塞检查。reclaim_older_than_ms:重新获取已租给停止响应的工作者的工作项。auto_stop:迭代器退出后是否在工作项上发布停止信号。
tool_runner():为单个会话运行工具调用。当您已获取工作并且只需要执行层时使用。
EnvironmentWorker 覆盖大多数用例。当您想启动自己的每会话进程时,直接使用工作轮询器,例如为每个获取的会话启动容器:
# 轮询端点需要环境密钥(Bearer 身份验证),而不是您的
# API 密钥。使用下面的 SDK 选项之一。
# 轮询端点需要环境密钥(Bearer 身份验证),而不是您的
# API 密钥。使用下面的 SDK 选项之一。
import asyncio
import os
from anthropic import AsyncAnthropic
from anthropic.types.beta.environments import BetaSelfHostedWork
async def launch_container(work: BetaSelfHostedWork) -> None:
# 替换为您自己的每会话沙箱启动器。将
# ANTHROPIC_ENVIRONMENT_KEY 传入启动的容器,永远不要
# 传入您的 API 密钥。
print(f"claimed session {work.data.id}")
async def main() -> None:
environment_key = os.environ["ANTHROPIC_ENVIRONMENT_KEY"]
environment_id = os.environ["ANTHROPIC_ENVIRONMENT_ID"]
async with AsyncAnthropic(auth_token=environment_key) as client:
async for work in client.beta.environments.work.poller(
environment_id=environment_id,
environment_key=environment_key,
auto_stop=False, # 启动的容器拥有停止调用
):
await launch_container(work)
asyncio.run(main())
import Anthropic from "@anthropic-ai/sdk";
import { WorkPoller } from "@anthropic-ai/sdk/helpers/beta/environments";
import type { BetaSelfHostedWork } from "@anthropic-ai/sdk/resources/beta/environments";
const environmentKey = process.env.ANTHROPIC_ENVIRONMENT_KEY!;
const environmentId = process.env.ANTHROPIC_ENVIRONMENT_ID!;
const client = new Anthropic({ authToken: environmentKey });
async function launchContainer(work: BetaSelfHostedWork): Promise<void> {
// 替换为您自己的每会话沙箱启动器。将
// ANTHROPIC_ENVIRONMENT_KEY 传入启动的容器,永远不要
// 传入您的 API 密钥。
console.log(`claimed session ${work.data.id}`);
}
const poller = new WorkPoller({
client,
environmentId,
environmentKey,
autoStop: false // 启动的容器拥有停止调用
});
for await (const work of poller) {
await launchContainer(work);
}
// 工作轮询目前在 C# SDK 中不可用。
package main
import (
"context"
"fmt"
"log"
"os"
"github.com/anthropics/anthropic-sdk-go"
"github.com/anthropics/anthropic-sdk-go/lib/environments"
"github.com/anthropics/anthropic-sdk-go/option"
)
func launchContainer(work *anthropic.BetaSelfHostedWork) {
// 替换为您自己的每会话沙箱启动器。Go 轮询器
// 在此函数返回时调用 work.Stop(它没有自动停止
// 选择退出),因此在此处阻塞直到会话完成,而不是
// 像 Python 和 TypeScript 选项卡那样分离。
fmt.Printf("claimed session %s\n", work.Data.ID)
}
func main() {
environmentID := os.Getenv("ANTHROPIC_ENVIRONMENT_ID")
environmentKey := os.Getenv("ANTHROPIC_ENVIRONMENT_KEY")
client := anthropic.NewClient(option.WithAuthToken(environmentKey))
ctx := context.Background()
poller := environments.NewWorkPoller(ctx, client, environments.WorkPollerOptions{
EnvironmentID: environmentID,
EnvironmentKey: environmentKey,
})
defer poller.Close()
for work, err := range poller.All() {
if err != nil {
log.Fatal(err)
}
launchContainer(work)
}
}
// 工作轮询目前在 Java SDK 中不可用。
// 工作轮询目前在 PHP SDK 中不可用。
# 工作轮询目前在 Ruby SDK 中不可用。
AgentToolContext 是工具调用的执行上下文,定义工作目录、路径策略,并在作为上下文管理器进入时可选地下载会话的技能。beta_agent_toolset_20260401(env) 接收 AgentToolContext 并返回标准工具实现(bash、read、write、edit、glob、grep)。
使用 EnvironmentWorker: 两者都自动管理。传递 tools 工厂来自定义工具列表:
EnvironmentWorker(client, ..., tools=lambda env: [beta_bash_tool(env), my_custom_tool])
使用 work.poller() / tool_runner(): 在运行工具之前自己设置 AgentToolContext 和 beta_agent_toolset_20260401(env):
from anthropic.lib.tools.agent_toolset import (
AgentToolContext,
beta_agent_toolset_20260401,
)
async with AgentToolContext(
workdir="/workspace", client=client, session_id=work.data.id
) as env:
# 技能下载到 /workspace/skills/<name>/
tools = beta_agent_toolset_20260401(env)
import {
setupSkills,
betaAgentToolset20260401
} from "@anthropic-ai/sdk/tools/agent-toolset/node";
const ctx = { workdir: "/workspace", client, sessionId: work.data.id };
await setupSkills(ctx);
const tools = betaAgentToolset20260401(ctx);
// AgentToolContext 目前在 C# SDK 中不可用。
env := &agenttoolset.AgentToolContext{Workdir: "/workspace"}
if err := env.SetupSkills(ctx, client, work.Data.ID); err != nil {
panic(err)
}
// 技能下载到 /workspace/skills/<name>/
tools := agenttoolset.BetaAgentToolset20260401(env)
// AgentToolContext 目前在 Java SDK 中不可用。
// AgentToolContext 目前在 PHP SDK 中不可用。
# AgentToolContext 目前在 Ruby SDK 中不可用。
监控和运维
这些调用从您的监控或运维工具运行,使用您的 Claude API 密钥进行身份验证,以观察和管理工作者集群。获取和保活循环在工作者辅助程序内部处理,因此您不需要直接调用这些端点。
这些端点使用您的组织 API 密钥进行身份验证,而不是环境密钥。从工作者主机外部调用它们。在工作者主机上设置 ANTHROPIC_API_KEY 会将组织范围的凭据暴露给智能体工具调用。
读取队列深度
work.stats 返回环境的队列状态:
depth是等待获取的项数。根据此值扩展您的工作者集群或对积压工作进行警报。pending是工作者已获取并当前正在处理的项数。oldest_queued_at是队列中最旧项的时间戳,如果队列为空则为null。workers_polling是在过去 30 秒内轮询的工作者数量。将此用于存活性警报。
curl -sS "https://api.anthropic.com/v1/environments/$ANTHROPIC_ENVIRONMENT_ID/work/stats" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "anthropic-version: 2023-06-01"
ant beta:environments:work stats --environment-id "$ANTHROPIC_ENVIRONMENT_ID"
import os
import anthropic
client = anthropic.Anthropic()
stats = client.beta.environments.work.stats(os.environ["ANTHROPIC_ENVIRONMENT_ID"])
print(f"depth={stats.depth} pending={stats.pending}")
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const stats = await client.beta.environments.work.stats(process.env.ANTHROPIC_ENVIRONMENT_ID!);
console.log(`depth=${stats.depth} pending=${stats.pending}`);
using Anthropic;
var client = new AnthropicClient();
var environmentId = Environment.GetEnvironmentVariable("ANTHROPIC_ENVIRONMENT_ID")!;
var stats = await client.Beta.Environments.Work.Stats(environmentId);
Console.WriteLine({{CONTENT}}quot;depth={stats.Depth} pending={stats.Pending}");
package main
import (
"context"
"fmt"
"os"
"github.com/anthropics/anthropic-sdk-go"
)
func main() {
client := anthropic.NewClient()
environmentID := os.Getenv("ANTHROPIC_ENVIRONMENT_ID")
stats, err := client.Beta.Environments.Work.Stats(
context.Background(),
environmentID,
anthropic.BetaEnvironmentWorkStatsParams{},
)
if err != nil {
panic(err)
}
fmt.Printf("depth=%d pending=%d\n", stats.Depth, stats.Pending)
}
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.beta.environments.work.BetaSelfHostedWorkQueueStats;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
BetaSelfHostedWorkQueueStats stats = client.beta()
.environments()
.work()
.stats(System.getenv("ANTHROPIC_ENVIRONMENT_ID"));
IO.println("depth=" + stats.depth() + " pending=" + stats.pending());
}
<?php
use Anthropic\Client;
$client = new Client();
$stats = $client->beta->environments->work->stats(getenv('ANTHROPIC_ENVIRONMENT_ID'));
printf("depth=%d pending=%d\n", $stats->depth, $stats->pending);
require "anthropic"
client = Anthropic::Client.new
stats = client.beta.environments.work.stats(ENV.fetch("ANTHROPIC_ENVIRONMENT_ID"))
puts "depth=#{stats.depth} pending=#{stats.pending}"
{
"type": "work_queue_stats",
"depth": 0,
"pending": 0,
"oldest_queued_at": null,
"workers_polling": 0
}
优雅停止会话
使用 work.stop 请求处理特定会话的工作者干净地关闭它。工作者完成任何进行中的工具调用,发布最终状态,并释放会话。在请求体中传递 force: true 以立即中断,而不是等待当前工具调用完成。
因为这些调用从您的运维工具而不是工作者主机运行,ANTHROPIC_WORK_ID 不会自动设置。在运行以下示例之前,将其设置为目标工作项的 ID。
curl -sS "https://api.anthropic.com/v1/environments/$ANTHROPIC_ENVIRONMENT_ID/work/$ANTHROPIC_WORK_ID/stop" \
-H "x-api-key: $ANTHROPIC_API_KEY" \
-H "anthropic-beta: managed-agents-2026-04-01" \
-H "anthropic-version: 2023-06-01" \
-H "content-type: application/json" \
-d '{}'
ant beta:environments:work stop \
--environment-id "$ANTHROPIC_ENVIRONMENT_ID" \
--work-id "$ANTHROPIC_WORK_ID"
import os
import anthropic
client = anthropic.Anthropic()
work = client.beta.environments.work.stop(
os.environ["ANTHROPIC_WORK_ID"],
environment_id=os.environ["ANTHROPIC_ENVIRONMENT_ID"],
)
print(work.state)
import Anthropic from "@anthropic-ai/sdk";
const client = new Anthropic();
const work = await client.beta.environments.work.stop(process.env.ANTHROPIC_WORK_ID!, {
environment_id: process.env.ANTHROPIC_ENVIRONMENT_ID!
});
console.log(work.state);
using Anthropic;
var client = new AnthropicClient();
var work = await client.Beta.Environments.Work.Stop(
Environment.GetEnvironmentVariable("ANTHROPIC_WORK_ID")!,
new()
{
EnvironmentID = Environment.GetEnvironmentVariable("ANTHROPIC_ENVIRONMENT_ID")!
}
);
Console.WriteLine(work.State);
package main
import (
"context"
"fmt"
"os"
"github.com/anthropics/anthropic-sdk-go"
)
func main() {
client := anthropic.NewClient()
work, err := client.Beta.Environments.Work.Stop(
context.Background(),
os.Getenv("ANTHROPIC_WORK_ID"),
anthropic.BetaEnvironmentWorkStopParams{
EnvironmentID: os.Getenv("ANTHROPIC_ENVIRONMENT_ID"),
},
)
if err != nil {
panic(err)
}
fmt.Println(work.State)
}
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.beta.environments.work.BetaSelfHostedWork;
import com.anthropic.models.beta.environments.work.BetaSelfHostedWorkStopRequest;
import com.anthropic.models.beta.environments.work.WorkStopParams;
void main() {
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
BetaSelfHostedWork work = client.beta().environments().work().stop(
WorkStopParams.builder()
.environmentId(System.getenv("ANTHROPIC_ENVIRONMENT_ID"))
.workId(System.getenv("ANTHROPIC_WORK_ID"))
.betaSelfHostedWorkStopRequest(BetaSelfHostedWorkStopRequest.builder().build())
.build()
);
IO.println(work.state());
}
<?php
use Anthropic\Client;
$client = new Client();
$work = $client->beta->environments->work->stop(
getenv('ANTHROPIC_WORK_ID'),
environmentID: getenv('ANTHROPIC_ENVIRONMENT_ID'),
);
echo $work->state . "\n";
require "anthropic"
client = Anthropic::Client.new
work = client.beta.environments.work.stop(
ENV.fetch("ANTHROPIC_WORK_ID"),
environment_id: ENV.fetch("ANTHROPIC_ENVIRONMENT_ID")
)
puts work.state