---
title: 監控自行託管的 worker 並進行疑難排解
url: https://platform.claude.com/docs/zh-TW/managed-agents/self-hosted-sandboxes-operations
description: 讀取佇列深度、在不遺失工作的情況下停止工作階段與 worker，並修正常見的自行託管沙箱故障。
featureMetadata:
  topic:
    title: Managed Agents
    url: https://platform.claude.com/docs/en/managed-agents/overview
  status: beta
  betaHeader: managed-agents-2026-04-01
---

本頁面上的監控呼叫是從您的監控或維運工具執行，並使用您的 Claude API 金鑰進行驗證。worker 輔助工具會處理認領與保持連線的迴圈，因此您不需要直接呼叫這些端點。

<Warning>
  這些端點接受您的組織 API 金鑰或環境金鑰。請從 worker 主機外部使用您的組織 API 金鑰呼叫它們。在 worker 主機上設定 `ANTHROPIC_API_KEY` 會將組織範圍的憑證暴露給代理的工具呼叫。
</Warning>

## 讀取佇列深度

`GET /v1/environments/{environment_id}/work/stats` (python, typescript, ruby: `client.beta.environments.work.stats()`; go, csharp: `client.Beta.Environments.Work.Stats()`; java: `client.beta().environments().work().stats()`; php: `$client->beta->environments->work->stats()`; cli: `ant beta:environments:work stats`) 會傳回環境的佇列狀態：

| 欄位                                                                             | 意義                                                                                                                        | 用途                                 |
| ------------------------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------------- | ---------------------------------- |
| `depth` (csharp, go: `Depth`)                                                  | 等待被認領的項目。                                                                                                                 | 擴展您的 worker 叢集，或針對積壓發出警示。          |
| `pending` (csharp, go: `Pending`)                                              | 已被 worker 認領但尚未確認的項目。worker 輔助工具會在處理每個項目之前先確認它，因此在正常運作下此值會維持在接近零。                                                         | 偵測在認領與確認之間停滯的 worker：針對持續非零的值發出警示。 |
| `oldest_queued_at` (java, php: `oldestQueuedAt`; csharp, go: `OldestQueuedAt`) | 仍在佇列中最舊項目的時間戳記，該項目可能正在等待被認領，或已被認領但尚未確認。沒有此類項目時為 `null` (python: `None`; ruby: `nil`; java: `Optional.empty()`; go: `""`)。 | 查看最舊的項目已等待多久。                      |
| `workers_polling` (java, php: `workersPolling`; csharp, go: `WorkersPolling`)  | 在過去 30 秒內進行過輪詢的 worker。                                                                                                   | 針對存活狀態發出警示。                        |

<CodeGroup>
  ```bash cURL
  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"
  ```

  ```bash CLI
  ant beta:environments:work stats --environment-id "$ANTHROPIC_ENVIRONMENT_ID"
  ```

  ```python Python
  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}")
  ```

  ```typescript TypeScript
  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}`);
  ```

  ```csharp C#
  using Anthropic;

  var client = new AnthropicClient();

  var environmentId = Environment.GetEnvironmentVariable("ANTHROPIC_ENVIRONMENT_ID")!;

  var stats = await client.Beta.Environments.Work.Stats(environmentId);

  Console.WriteLine($"depth={stats.Depth} pending={stats.Pending}");
  ```

  ```go Go
  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)
  }
  ```

  ```java Java
  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 PHP
  <?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);
  ```

  ```ruby Ruby
  require "anthropic"

  client = Anthropic::Client.new

  stats = client.beta.environments.work.stats(ENV.fetch("ANTHROPIC_ENVIRONMENT_ID"))

  puts "depth=#{stats.depth} pending=#{stats.pending}"
  ```
</CodeGroup>

```text wrap
{
  "type": "work_queue_stats",
  "depth": 0,
  "pending": 0,
  "oldest_queued_at": null,
  "workers_polling": 0
}
```

## 正常停止工作階段

使用 `POST /v1/environments/{environment_id}/work/{work_id}/stop` (python, typescript, ruby: `client.beta.environments.work.stop()`; go, csharp: `client.Beta.Environments.Work.Stop()`; java: `client.beta().environments().work().stop()`; php: `$client->beta->environments->work->stop()`; cli: `ant beta:environments:work stop`) 要求處理特定工作階段的 worker 將其關閉。

預設情況下，工作項目會轉為 `stopping`。worker 會在下一次租約心跳時察覺，取消該工作階段進行中的工具呼叫，並確認關閉。接著工作項目會變為 `stopped`。

傳入 `force: true` (python: `force=True`; cli: `--force`) 可立即將工作項目標記為 `stopped`，而不等待 worker 的確認。

由於這些呼叫是從您的維運工具而非 worker 主機執行，因此不會自動設定 `ANTHROPIC_WORK_ID`。在執行以下範例之前，請將其設定為目標工作項目的 ID。若要找出工作項目的 ID，請透過 [Environments Work 端點](https://platform.claude.com/docs/zh-TW/api/beta/environments/work)列出環境的工作項目。

<CodeGroup>
  ```bash cURL
  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 '{}'
  ```

  ```bash CLI
  ant beta:environments:work stop \
    --environment-id "$ANTHROPIC_ENVIRONMENT_ID" \
    --work-id "$ANTHROPIC_WORK_ID"
  ```

  ```python Python
  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)
  ```

  ```typescript TypeScript
  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);
  ```

  ```csharp C#
  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);
  ```

  ```go Go
  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)
  }
  ```

  ```java Java
  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 PHP
  <?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";
  ```

  ```ruby Ruby
  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
  ```
</CodeGroup>

## 正常停止 worker

在工作階段執行期間被取消的 worker，會在結束前停止其進行中的工作。如果工作階段附加了[記憶體儲存區](https://platform.claude.com/docs/zh-TW/managed-agents/self-hosted-sandboxes-memory)，worker 會略過最後的同步，但仍會上傳已變更的檔案並移除儲存區目錄。

被強制終止的程序不會執行任何清理作業。若要乾淨地停止 worker：

1. **確保 SIGTERM 和 SIGINT 會取消 worker。** 做法取決於 worker：

   | Worker                      | 該怎麼做                                                                  |
   | --------------------------- | --------------------------------------------------------------------- |
   | `ant` CLI                   | 無需任何動作。CLI 會自行處理這兩個訊號：它會取消任何進行中的工具呼叫、發布其錯誤結果，並釋放工作項目。                 |
   | 作為獨立程序的 SDK worker          | `EnvironmentWorker` 不會安裝任何訊號處理常式。請從訊號處理常式中取消 worker，如同獨立 worker 範例所示。 |
   | 位於 webhook 伺服器內的 SDK worker | 請從伺服器本身的關閉掛鉤中取消 worker，如同 webhook 範例所示。worker 不得接管伺服器的訊號。             |

2. **使用 SIGTERM 停止 worker，並在任何強制終止之前預留至少 30 秒。** 最後的上傳可能需要這麼久。Docker 預設會在停止訊號發出 10 秒後傳送 SIGKILL。請在 `docker run` 上使用 `--stop-timeout`，或透過您的協調器的終止寬限期來提高此限制。

如果 worker 在執行清理作業之前就被終止，任何尚未同步的記憶編輯都會遺失。在長期運作的主機上，還需在下一個附加該儲存區的工作階段之前，移除 `/mnt/memory/` 下殘留的儲存區目錄。僅服務一個工作階段後即被捨棄的沙箱則不需要清理。

## 疑難排解

### worker 無法連線

如果 `workers_polling` (java, php: `workersPolling`; csharp, go: `WorkersPolling`) 一直維持在 0，表示 worker 無法連到佇列。請確認 worker 主機上已設定 `ANTHROPIC_ENVIRONMENT_KEY` 和 `ANTHROPIC_ENVIRONMENT_ID`。

### 工作階段一直處於佇列中

沒有 worker 在認領工作。佇列中的工作階段會持續等待，而不會失敗。請在[讀取佇列深度](https://platform.claude.com/docs/zh-TW/managed-agents/self-hosted-sandboxes-operations#read-queue-depth)中檢查 `workers_polling` (java, php: `workersPolling`; csharp, go: `WorkersPolling`) 和 `depth` (csharp, go: `Depth`)。

### 記憶體儲存區無法掛載

worker 會將掛載與背景同步失敗記錄到日誌中，而不是回報給工作階段。只有唯讀拒絕會以工具錯誤的形式傳達給代理（請參閱[唯讀儲存區與衝突](https://platform.claude.com/docs/zh-TW/managed-agents/self-hosted-sandboxes-memory#read-only-stores-and-conflicts)）。

如果 worker 在認領工作階段時無法掛載記憶體儲存區，它會使該工作項目失敗。工作階段不會發出錯誤事件，並維持閒置狀態。

| 症狀                                                                                                            | 原因                                                                                             | 修正方式                                                                                                                                                                       |
| ------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| worker 日誌包含 `the work item carried no sessions token`（在 Go 中為 `ErrSessionMemoryNoToken` 錯誤），且工作項目失敗。          | 工作項目的每個工作階段 `secret` (csharp, go: `Secret`) 未送達 worker。可能是您的程式碼沒有轉送它，或是您的組織尚未啟用自行託管沙箱上的記憶體儲存區。 | [轉送工作項目的密鑰](https://platform.claude.com/docs/zh-TW/managed-agents/self-hosted-sandboxes-workers#forward-the-work-items-secret)。如果 worker 在同一個程序中輪詢並執行工作階段，卻仍記錄此訊息，請聯絡支援團隊。 |
| worker 日誌包含 `something already exists at the memory store's path`。                                            | 先前工作階段殘留的目錄，通常是其 worker 在執行清理作業之前就被終止的工作階段。                                                    | 移除日誌行中指出的殘留目錄。其中尚未同步的編輯將會遺失。                                                                                                                                               |
| worker 日誌包含 `cannot create the memory store's folder` 和 `the worker host must make this mount path writable`。 | 執行 worker 的使用者無法在 `/mnt/memory` 下建立目錄。                                                         | 建立 `/mnt/memory` 並將其 `chown` 給該使用者。請參閱[準備主機](https://platform.claude.com/docs/zh-TW/managed-agents/self-hosted-sandboxes-memory#prepare-the-host)。                         |
| 在 worker 認領工作階段後不久，工作階段處於 `idle` 狀態，停止原因為 `requires_action`，且沒有錯誤事件。                                          | worker 因上述其中一個原因無法掛載記憶體儲存區，而使工作項目失敗。                                                           | 在主機上修正原因，然後傳送 [`user.interrupt`](https://platform.claude.com/docs/zh-TW/managed-agents/events-and-streaming#interrupt-the-agent) 事件。工作階段的工作會重新排入佇列，下一個認領它的 worker 會重試掛載。   |

### 自訂工具呼叫一直沒有回傳

如果工作階段處於暫停狀態且停止原因為 `requires_action`，表示沒有任何 worker 或用戶端提供該工具。請參閱[提供自訂工具](https://platform.claude.com/docs/zh-TW/managed-agents/self-hosted-sandboxes-custom-tools#serve-a-custom-tool)。

### 包裝的 MCP 工具呼叫停滯

如果 MCP 用戶端沒有設定逾時，對[包裝的 MCP 伺服器](https://platform.claude.com/docs/zh-TW/managed-agents/self-hosted-sandboxes-custom-tools#wrap-an-mcp-server-as-custom-tools)的停滯呼叫只有在後備機制觸發時才會變成錯誤工具結果：

| SDK        | 後備機制                   | 觸發時間  |
| ---------- | ---------------------- | ----- |
| Python     | worker 本身的工具呼叫限制       | 約兩分半鐘 |
| TypeScript | MCP SDK 的預設請求逾時        | 約一分鐘  |
| Go         | worker 會取消超過其預設限制的工具呼叫 | 120 秒 |
