---
title: Java SDK
url: https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/sdks/java
description: 安裝並設定 Anthropic Java SDK，支援建構器模式與非同步操作
---

Anthropic Java SDK 讓以 Java 撰寫的應用程式能夠便利地存取 Claude API。它使用「builder pattern」（建構器模式）來建立請求，並同時支援同步與非同步操作。

<Info>
  如需附有程式碼範例的 API 功能文件，請參閱 [API 參考文件](https://platform.claude.com/docs/zh-TW/api/overview)。本頁涵蓋 Java 專屬的 SDK 功能與設定。
</Info>

## 安裝

<Tabs>
  <Tab title="Gradle">
    ```kotlin
    implementation("com.anthropic:anthropic-java:2.73.0")
    ```
  </Tab>

  <Tab title="Maven">
    ```xml
    <dependency>
        <groupId>com.anthropic</groupId>
        <artifactId>anthropic-java</artifactId>
        <version>2.73.0</version>
    </dependency>
    ```
  </Tab>
</Tabs>

## 需求

此函式庫需要 Java 8 或更新版本。

<Note>
  此 SDK 支援 Java 8 及更新版本。本文件中的程式碼範例是以 [JDK 25 精簡原始檔](https://openjdk.org/jeps/512)的形式撰寫，使用裸露的 `void main()` 進入點以及 `IO.println()` 進行輸出。API 呼叫本身在每個受支援的 JDK 上都完全相同；若要在較早版本上編譯範例，請將 `IO.println(...)` 替換為 `System.out.println(...)`，並將主體放入某個類別內的 `public static void main(String[] args)` 之中。
</Note>

## 快速開始

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

// 使用 `anthropic.apiKey`、`anthropic.authToken` 和 `anthropic.baseUrl` 系統屬性進行設定
// 或使用 `ANTHROPIC_API_KEY`、`ANTHROPIC_AUTH_TOKEN` 和 `ANTHROPIC_BASE_URL` 環境變數進行設定
AnthropicClient client = AnthropicOkHttpClient.fromEnv();

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();

Message message = client.messages().create(params);
```

## 用戶端設定

### API 金鑰設定

使用系統屬性或環境變數來設定用戶端：

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

// 使用 `anthropic.apiKey`、`anthropic.authToken` 與 `anthropic.baseUrl` 系統屬性進行設定
// 或使用 `ANTHROPIC_API_KEY`、`ANTHROPIC_AUTH_TOKEN` 與 `ANTHROPIC_BASE_URL` 環境變數進行設定
AnthropicClient client = AnthropicOkHttpClient.fromEnv();
```

或手動設定：

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .apiKey("my-anthropic-api-key")
  .build();
```

或結合使用兩種方式：

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  // 使用系統屬性或環境變數進行設定
  .fromEnv()
  .apiKey("my-anthropic-api-key")
  .build();
```

如需了解包括 Workload Identity Federation（工作負載身分聯合）在內的驗證選項，請參閱[驗證](https://platform.claude.com/docs/zh-TW/manage-claude/authentication)。如果您的 API 金鑰是可存取多個工作區的[個人或服務帳戶金鑰](https://platform.claude.com/docs/zh-TW/manage-claude/authentication#key-types)，請在 `anthropic-workspace-id` 請求標頭中設定工作區 ID；[選擇工作區](https://platform.claude.com/docs/zh-TW/manage-claude/authentication#select-a-workspace)說明了此 SDK 的逐請求選項。

### 設定選項

| Setter 方法   | 系統屬性                  | 環境變數                   | 必填    | 預設值                           |
| ----------- | --------------------- | ---------------------- | ----- | ----------------------------- |
| `apiKey`    | `anthropic.apiKey`    | `ANTHROPIC_API_KEY`    | false | -                             |
| `authToken` | `anthropic.authToken` | `ANTHROPIC_AUTH_TOKEN` | false | -                             |
| `baseUrl`   | `anthropic.baseUrl`   | `ANTHROPIC_BASE_URL`   | true  | `"https://api.anthropic.com"` |

系統屬性的優先順序高於環境變數。

<Tip>
  請勿在同一個應用程式中建立超過一個用戶端。每個用戶端都有連線池與執行緒池，在請求之間共用會更有效率。
</Tip>

### 修改設定

若要在重複使用相同連線池與執行緒池的同時，暫時使用修改過的用戶端設定，請在任何用戶端或服務上呼叫 `withOptions()`：

```java
import com.anthropic.client.AnthropicClient;

AnthropicClient clientWithOptions = client.withOptions(optionsBuilder -> {
  optionsBuilder.baseUrl("https://example.com");
  optionsBuilder.maxRetries(42);
});
```

`withOptions()` 方法不會影響原本的用戶端或服務。

## 非同步用法

預設的用戶端是同步的。若要切換為非同步執行，請呼叫 `async()` 方法：

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

AnthropicClient client = AnthropicOkHttpClient.fromEnv();

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();

CompletableFuture<Message> message = client.async().messages().create(params);
```

或從一開始就建立非同步用戶端：

```java
import com.anthropic.client.AnthropicClientAsync;
import com.anthropic.client.okhttp.AnthropicOkHttpClientAsync;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

AnthropicClientAsync client = AnthropicOkHttpClientAsync.fromEnv();

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();

CompletableFuture<Message> message = client.messages().create(params);
```

非同步用戶端支援與同步用戶端相同的選項，差別在於大多數方法會回傳 `CompletableFuture`。

## 串流

SDK 定義了會回傳回應「chunk」（區塊）串流的方法，每個區塊一抵達即可個別處理，而不必等待完整回應。

### 同步串流

對於同步用戶端，這些「streaming」（串流）方法會回傳 `StreamResponse`：

```java
import com.anthropic.core.http.StreamResponse;
import com.anthropic.models.messages.RawMessageStreamEvent;

try (StreamResponse<RawMessageStreamEvent> streamResponse = client.messages().createStreaming(params)) {
    streamResponse.stream().forEach(chunk -> {
        IO.println(chunk);
    });
    IO.println("No more chunks!");
}
```

### 非同步串流

對於非同步用戶端，該方法會回傳 `AsyncStreamResponse`：

```java
import com.anthropic.core.http.AsyncStreamResponse;
import com.anthropic.models.messages.RawMessageStreamEvent;

client.async().messages().createStreaming(params).subscribe(chunk -> {
    IO.println(chunk);
});

// 如果您需要處理串流的錯誤或完成事件
client.async().messages().createStreaming(params).subscribe(new AsyncStreamResponse.Handler<>() {
    @Override
    public void onNext(RawMessageStreamEvent chunk) {
        IO.println(chunk);
    }

    @Override
    public void onComplete(Optional<Throwable> error) {
        if (error.isPresent()) {
            IO.println("Something went wrong!");
            throw new RuntimeException(error.get());
        } else {
            IO.println("No more chunks!");
        }
    }
});

// 或使用 futures
client.async().messages().createStreaming(params)
    .subscribe(chunk -> {
        IO.println(chunk);
    })
    .onCompleteFuture()
    .whenComplete((unused, error) -> {
        if (error != null) {
            IO.println("Something went wrong!");
            throw new RuntimeException(error);
        } else {
            IO.println("No more chunks!");
        }
    });
```

非同步串流使用每個用戶端專屬的快取執行緒池 `Executor` 來進行串流，而不會阻塞目前的執行緒。若要使用不同的 `Executor`：

```java
Executor executor = Executors.newFixedThreadPool(4);
client.async().messages().createStreaming(params).subscribe(
    chunk -> IO.println(chunk), executor
);
```

或使用 `streamHandlerExecutor` 方法在用戶端層級進行全域設定：

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .streamHandlerExecutor(Executors.newFixedThreadPool(4))
  .build();
```

### 搭配訊息累加器進行串流

`MessageAccumulator` 可以在處理回應中的事件串流時加以記錄，並累加出一個 `Message` 物件，類似於非串流 API 所會回傳的結果。

對於同步回應，請在串流管線中加入 `Stream.peek()` 呼叫以累加每個事件：

```java
import com.anthropic.core.http.StreamResponse;
import com.anthropic.helpers.MessageAccumulator;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.RawMessageStreamEvent;

MessageAccumulator messageAccumulator = MessageAccumulator.create();

try (StreamResponse<RawMessageStreamEvent> streamResponse =
         client.messages().createStreaming(createParams)) {
    streamResponse.stream()
            .peek(messageAccumulator::accumulate)
            .flatMap(event -> event.contentBlockDelta().stream())
            .flatMap(deltaEvent -> deltaEvent.delta().text().stream())
            .forEach(textDelta -> IO.print(textDelta.text()));
}

Message message = messageAccumulator.message();
```

對於非同步回應，請將 `MessageAccumulator` 加入 `subscribe()` 呼叫中：

```java
import com.anthropic.helpers.MessageAccumulator;
import com.anthropic.models.messages.Message;

MessageAccumulator messageAccumulator = MessageAccumulator.create();

client.async().messages()
        .createStreaming(createParams)
        .subscribe(event -> messageAccumulator.accumulate(event).contentBlockDelta().stream()
                .flatMap(deltaEvent -> deltaEvent.delta().text().stream())
                .forEach(textDelta -> IO.print(textDelta.text())))
        .onCompleteFuture()
        .join();

Message message = messageAccumulator.message();
```

另外也提供 `BetaMessageAccumulator` 用於累加 `BetaMessage` 物件。其使用方式與 `MessageAccumulator` 相同。

## 結構化輸出

如需包含 Java 範例的完整結構化輸出文件，請參閱[結構化輸出](https://platform.claude.com/docs/zh-TW/build-with-claude/structured-outputs)。

## 工具使用

[搭配 Claude 的工具使用](https://platform.claude.com/docs/zh-TW/agents-and-tools/tool-use/overview)（tool use）讓您能將外部工具與函式直接整合到 AI 模型的回應中。模型不再只是產生純文字，而是能在適當時機輸出呼叫工具或函式的指令（附帶參數）。您為工具定義 JSON schema，模型則使用這些 schema 來判斷何時以及如何使用這些工具。

工具使用功能支援「strict」（嚴格）模式，可保證 AI 模型的 JSON 輸出符合您在輸入參數中提供的 JSON schema。

SDK 可以從任意 Java 類別的結構自動推導出工具及其參數：類別名稱（轉換為 snake case）提供工具名稱，而類別的欄位則定義工具的參數。

<Note>
  請將您的工具類別宣告為頂層類別或 `static` 巢狀類別。此要求來自 Jackson Databind 函式庫（`com.fasterxml.jackson.databind`），SDK 使用它將工具輸入反序列化為您的類別實例，而它無法實例化非靜態的內部類別。
</Note>

### 使用註解定義工具

```java
import com.fasterxml.jackson.annotation.JsonClassDescription;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;

enum Unit {
  CELSIUS,
  FAHRENHEIT;

  public String toString() {
    return switch (this) {
      case CELSIUS -> "C";
      case FAHRENHEIT -> "F";
    };
  }

  public double fromKelvin(double temperatureK) {
    return switch (this) {
      case CELSIUS -> temperatureK - 273.15;
      case FAHRENHEIT -> (temperatureK - 273.15) * 1.8 + 32.0;
    };
  }
}

@JsonClassDescription("Get the weather in a given location")
static class GetWeather {

  @JsonPropertyDescription("The city and state, e.g. San Francisco, CA")
  public String location;

  @JsonPropertyDescription("The unit of temperature")
  public Unit unit;

  public Weather execute() {
    double temperatureK = switch (location) {
      case "San Francisco, CA" -> 300.0;
      case "New York, NY" -> 310.0;
      case "Dallas, TX" -> 305.0;
      default -> 295;
    };
    return new Weather(String.format("%.0f%s", unit.fromKelvin(temperatureK), unit));
  }
}

static class Weather {

  public String temperature;

  public Weather(String temperature) {
    this.temperature = temperature;
  }
}
```

### 呼叫工具

定義好工具類別後，使用 `MessageCreateParams.Builder.addTool(Class<T>)` 將它們加入訊息參數中，然後在 AI 模型的回應要求時呼叫它們。`BetaToolUseBlock.input(Class<T>)` 可用於將 JSON 形式的工具參數解析為您定義工具之類別的實例。

呼叫工具後，使用 `BetaToolResultBlockParam.Builder.contentAsJson(Object)` 將工具的結果傳回給 AI 模型：

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.beta.messages.*;
import com.anthropic.models.messages.Model;

AnthropicClient client = AnthropicOkHttpClient.fromEnv();

MessageCreateParams.Builder createParamsBuilder = MessageCreateParams.builder()
        .model(Model.CLAUDE_OPUS_5_5)
        .maxTokens(2048)
        .addTool(GetWeather.class)
        .addUserMessage("What's the temperature in New York?");

client.beta().messages().create(createParamsBuilder.build()).content().stream()
        .flatMap(contentBlock -> contentBlock.toolUse().stream())
        .forEach(toolUseBlock -> createParamsBuilder
              // 新增一則訊息，表示已請求 tool use（工具使用）。
              .addAssistantMessageOfBetaContentBlockParams(
                      List.of(BetaContentBlockParam.ofToolUse(BetaToolUseBlockParam.builder()
                              .name(toolUseBlock.name())
                              .id(toolUseBlock.id())
                              .input(toolUseBlock._input())
                              .build())))
              // 新增一則訊息，內含所請求之工具使用的結果。
              .addUserMessageOfBetaContentBlockParams(
                      List.of(BetaContentBlockParam.ofToolResult(BetaToolResultBlockParam.builder()
                              .toolUseId(toolUseBlock.id())
                              .contentAsJson(callTool(toolUseBlock))
                              .build()))));

client.beta().messages().create(createParamsBuilder.build()).content().stream()
        .flatMap(contentBlock -> contentBlock.text().stream())
        .forEach(textBlock -> IO.println(textBlock.text()));

private static Object callTool(BetaToolUseBlock toolUseBlock) {
  if (!"get_weather".equals(toolUseBlock.name())) {
    throw new IllegalArgumentException("Unknown tool: " + toolUseBlock.name());
  }

  GetWeather tool = toolUseBlock.input(GetWeather.class);
  return tool != null ? tool.execute() : new Weather("unknown");
}
```

### 工具名稱轉換

工具名稱由 camel case 的工具類別名稱（例如 `GetWeather`）推導而來，並轉換為 snake case（例如 `get_weather`）。當目前字元不是第一個字元、為大寫，且前一個字元為小寫或下一個字元為小寫時，即為單字邊界的開始。例如，`MyJSONParser` 會變成 `my_json_parser`，而 `ParseJSON` 會變成 `parse_json`。此轉換可以使用 `@JsonTypeName` 註解覆寫。

### 本機工具 JSON schema 驗證

您可以執行本機驗證，以檢查從工具類別推導出的 JSON schema 是否符合 Anthropic 的限制。本機驗證預設為啟用，但可以停用：

```java
MessageCreateParams.Builder createParamsBuilder = MessageCreateParams.builder()
  .model(Model.CLAUDE_OPUS_5_5)
  .maxTokens(2048)
  .addTool(GetWeather.class, JsonSchemaLocalValidation.NO)
  .addUserMessage("What's the temperature in New York?");
```

### 為工具類別加上註解

您可以使用註解在 JSON schema 中加入更多關於工具的資訊：

* `@JsonClassDescription` - 為工具類別加入描述，詳細說明何時以及如何使用該工具。
* `@JsonTypeName` - 將工具名稱設定為類別簡單名稱轉換為 snake case 以外的其他名稱。
* `@JsonPropertyDescription` - 為工具參數加入詳細描述。
* `@JsonIgnore` - 將 `public` 欄位或 getter 方法從為工具參數產生的 JSON schema 中排除。
* `@JsonProperty` - 將非 `public` 的欄位或 getter 方法納入為工具參數產生的 JSON schema 中。

## 訊息批次

SDK 在 `client.messages().batches()` 命名空間下提供對[批次處理](https://platform.claude.com/docs/zh-TW/build-with-claude/batch-processing)的支援。關於如何列出批次並進行分頁，請參閱[分頁](https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/sdks/java#pagination)。

## 檔案上傳

SDK 定義了透過 `MultipartField` 類別接受檔案的方法：

```java
import com.anthropic.core.MultipartField;
import com.anthropic.models.files.FileMetadata;
import com.anthropic.models.files.FileUploadParams;

FileUploadParams params = FileUploadParams.builder()
  .file(
    MultipartField.<InputStream>builder()
      .value(Files.newInputStream(Paths.get("/path/to/file.pdf")))
      .contentType("application/pdf")
      .build()
  )
  .build();

FileMetadata fileMetadata = client.files().upload(params);
```

或從 `InputStream`：

```java
import com.anthropic.core.MultipartField;
import com.anthropic.models.files.FileMetadata;
import com.anthropic.models.files.FileUploadParams;

FileUploadParams params = FileUploadParams.builder()
  .file(
    MultipartField.<InputStream>builder()
      .value(URI.create("https://example.com/path/to/file").toURL().openStream())
      .filename("document.pdf")
      .contentType("application/pdf")
      .build()
  )
  .build();

FileMetadata fileMetadata = client.files().upload(params);
```

或從記憶體中的位元組：

```java
import com.anthropic.core.MultipartField;
import com.anthropic.models.files.FileMetadata;
import com.anthropic.models.files.FileUploadParams;

FileUploadParams params = FileUploadParams.builder()
  .file(
    MultipartField.<InputStream>builder()
      .value(new ByteArrayInputStream("content".getBytes()))
      .filename("document.txt")
      .contentType("text/plain")
      .build()
  )
  .build();

FileMetadata fileMetadata = client.files().upload(params);
```

### 二進位回應

對於不一定會被解析為 JSON 的 API 回應，SDK 定義了回傳二進位回應的方法：

```java
import com.anthropic.core.http.HttpResponse;

HttpResponse response = client.files().download("file_abc123");
```

若要將回應內容儲存至檔案：

```java
import com.anthropic.core.http.HttpResponse;

try (HttpResponse response = client.files().download(params)) {
    Files.copy(
        response.body(),
        Paths.get(path),
        StandardCopyOption.REPLACE_EXISTING
    );
} catch (Exception e) {
    IO.println("Something went wrong!");
    throw new RuntimeException(e);
}
```

或將回應內容傳輸至任何 `OutputStream`：

```java
import com.anthropic.core.http.HttpResponse;

try (HttpResponse response = client.files().download(params)) {
    response.body().transferTo(Files.newOutputStream(Paths.get(path)));
} catch (Exception e) {
    IO.println("Something went wrong!");
    throw new RuntimeException(e);
}
```

## 錯誤處理

SDK 會拋出自訂的非受檢例外類型：

* `AnthropicServiceException` - HTTP 錯誤的基底類別。
* `AnthropicIoException` - I/O 網路錯誤。
* `AnthropicRetryableException` - 表示可重試之失敗的通用錯誤。
* `AnthropicInvalidDataException` - 無法解讀已成功解析的資料（例如，存取一個應為必填的屬性，但 API 意外地省略了它）。
* `AnthropicException` - 所有例外的基底類別。

### 狀態碼對應

| 狀態碼 | 例外                              |
| --- | ------------------------------- |
| 400 | `BadRequestException`           |
| 401 | `UnauthorizedException`         |
| 403 | `PermissionDeniedException`     |
| 404 | `NotFoundException`             |
| 422 | `UnprocessableEntityException`  |
| 429 | `RateLimitException`            |
| 5xx | `InternalServerException`       |
| 其他  | `UnexpectedStatusCodeException` |

在初始 HTTP 回應成功之後，若於 SSE 串流期間遇到錯誤，則會拋出 `SseException`。

```java
import com.anthropic.errors.*;

try {
    Message message = client.messages().create(params);
} catch (RateLimitException e) {
    IO.println("Rate limited, retry after: " + e.headers());
} catch (UnauthorizedException e) {
    IO.println("Invalid API key");
} catch (AnthropicServiceException e) {
    IO.println("API error: " + e.statusCode());
} catch (AnthropicIoException e) {
    IO.println("Network error: " + e.getMessage());
}
```

## 請求 ID

使用[原始回應](https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/sdks/java#raw-response-access)時，您可以透過 `requestId()` 方法存取 `request-id` 回應標頭：

```java
import com.anthropic.core.http.HttpResponseFor;
import com.anthropic.models.messages.Message;

HttpResponseFor<Message> message = client.messages().withRawResponse().create(params);

Optional<String> requestId = message.requestId();
```

這可用於快速記錄失敗的請求並回報給 Anthropic。如需更多關於偵錯請求的資訊，請參閱[請求 ID](https://platform.claude.com/docs/zh-TW/api/errors#request-id)。

## 重試

SDK 預設會自動重試 2 次，請求之間採用短暫的指數退避。

只有下列錯誤類型會被重試：

* 連線錯誤（例如，因網路連線問題所致）
* 408 Request Timeout
* 409 Conflict
* 429 Rate Limit
* 5xx 內部錯誤

API 也可能明確指示 SDK 重試或不重試某個請求。

若要設定自訂的重試次數，請使用 `maxRetries` 方法設定用戶端：

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder().fromEnv().maxRetries(4).build();
```

## 逾時

請求預設在 10 分鐘後逾時。

然而，對於接受 `maxTokens` 的方法，如果您指定了較大的 `maxTokens` 值且正在使用串流，則預設逾時將使用以下公式動態計算：

```java
Duration.ofSeconds(
    Math.min(
        60 * 60, // 1 hour max
        Math.max(
            10 * 60, // 10 minute minimum
            60 * 60 * maxTokens / 128_000
        )
    )
)
```

除非被覆寫，否則這會產生最長 60 分鐘的逾時，並依 `maxTokens` 參數縮放。

對於非串流請求，動態逾時會根據 `maxTokens`，從最短 30 秒調整至最長 10 分鐘。

若要為每個請求設定自訂逾時：

```java
import com.anthropic.models.messages.Message;

Message message = client
  .messages()
  .create(params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build());
```

或在用戶端層級為所有方法呼叫設定預設值：

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .timeout(Duration.ofSeconds(30))
  .build();
```

## 長時間請求

<Warning>
  對於執行時間較長的請求，請考慮使用[串流](https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/sdks/java#streaming)。
</Warning>

請避免在未使用串流的情況下設定較大的 `maxTokens` 值。某些網路可能會在一段時間後中斷閒置連線，這可能導致請求失敗或[逾時](https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/sdks/java#timeouts)而未收到來自 Anthropic 的回應。SDK 會定期 ping API 以保持連線存活，並降低這類網路的影響。

如果預期非串流請求會花費超過 10 分鐘，SDK 會拋出錯誤。使用[串流方法](https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/sdks/java#streaming)或在用戶端或請求層級[覆寫逾時](https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/sdks/java#timeouts)即可停用此錯誤。

## 分頁

SDK 提供便利的方式來存取分頁結果，可以一次一頁，也可以跨所有頁面逐項存取。

### 自動分頁

若要迭代所有頁面中的所有結果，請使用 `autoPager()` 方法，它會視需要自動擷取更多頁面。

```java
import com.anthropic.models.messages.batches.BatchListPage;
import com.anthropic.models.messages.batches.MessageBatch;

BatchListPage page = client.messages().batches().list();

// 以 Iterable 方式處理
for (MessageBatch batch : page.autoPager()) {
    IO.println(batch);
}

// 以 Stream 方式處理
page.autoPager()
    .stream()
    .limit(50)
    .forEach(batch -> IO.println(batch));
```

使用非同步用戶端時，該方法會回傳 `AsyncStreamResponse`：

```java
import com.anthropic.core.http.AsyncStreamResponse;
import com.anthropic.models.messages.batches.BatchListPageAsync;
import com.anthropic.models.messages.batches.MessageBatch;

CompletableFuture<BatchListPageAsync> pageFuture = client.async().messages().batches().list();

pageFuture.thenAccept(page -> page.autoPager().subscribe(batch -> {
    IO.println(batch);
}));

// 如果您需要處理串流的錯誤或完成事件
pageFuture.thenAccept(page -> page.autoPager().subscribe(new AsyncStreamResponse.Handler<>() {
    @Override
    public void onNext(MessageBatch batch) {
        IO.println(batch);
    }

    @Override
    public void onComplete(Optional<Throwable> error) {
        if (error.isPresent()) {
            IO.println("Something went wrong!");
            throw new RuntimeException(error.get());
        } else {
            IO.println("No more!");
        }
    }
}));

// 或使用 futures
pageFuture.thenAccept(page -> page.autoPager()
    .subscribe(batch -> {
        IO.println(batch);
    })
    .onCompleteFuture()
    .whenComplete((unused, error) -> {
        if (error != null) {
            IO.println("Something went wrong!");
            throw new RuntimeException(error);
        } else {
            IO.println("No more!");
        }
    }));
```

### 手動分頁

若要存取個別頁面的項目並手動請求下一頁：

```java
import com.anthropic.models.messages.batches.BatchListPage;
import com.anthropic.models.messages.batches.MessageBatch;

BatchListPage page = client.messages().batches().list();
while (true) {
    for (MessageBatch batch : page.items()) {
        IO.println(batch);
    }

    if (!page.hasNextPage()) {
        break;
    }

    page = page.nextPage();
}
```

## 型別系統

### 不可變性與建構器

SDK 中的每個類別都有一個相關聯的建構器用於建構它。每個類別一旦建構完成即為不可變。如果類別有相關聯的建構器，則它會有一個 `toBuilder()` 方法，可用於將其轉換回建構器以製作修改過的副本。

```java
MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();

// 使用 toBuilder() 建立修改後的副本
MessageCreateParams modified = params.toBuilder().maxTokens(2048L).build();
```

由於每個類別都是不可變的，修改建構器絕不會影響已建構的類別實例。

### 請求與回應

若要向 Claude API 傳送請求，請建構某個 `Params` 類別的實例，並將其傳遞給對應的用戶端方法。收到回應後，它會被反序列化為某個 Java 類別的實例。

例如，`client.messages().create(...)` 應以 `MessageCreateParams` 的實例呼叫，並回傳 `Message` 的實例。

### 未記載的參數

若要設定未記載的參數，請在任何 `Params` 類別上呼叫 `putAdditionalHeader`、`putAdditionalQueryParam` 或 `putAdditionalBodyProperty` 方法：

```java
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.MessageCreateParams;

MessageCreateParams params = MessageCreateParams.builder()
  .putAdditionalHeader("Secret-Header", "42")
  .putAdditionalQueryParam("secret_query_param", "42")
  .putAdditionalBodyProperty("secretProperty", JsonValue.from("42"))
  .build();
```

之後可以在已建構的物件上使用 `_additionalHeaders()`、`_additionalQueryParams()` 和 `_additionalBodyProperties()` 方法存取這些值。

<Warning>
  傳遞給這些方法的值會覆寫傳遞給先前方法的值。基於安全考量，請確保這些方法僅用於受信任的輸入資料。
</Warning>

若要在巢狀的標頭、查詢參數或主體類別上設定未記載的參數：

```java
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Metadata;

MessageCreateParams params = MessageCreateParams.builder()
  .metadata(
    Metadata.builder().putAdditionalProperty("secretProperty", JsonValue.from("42")).build()
  )
  .build();
```

之後可以在巢狀的已建構物件上使用 `_additionalProperties()` 方法存取這些屬性。

若要將已記載的參數或屬性設定為未記載或尚未支援的值，請將 `JsonValue` 物件傳遞給其 setter：

```java
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(JsonValue.from(3.14))
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();
```

### 建立 JsonValue

建立 `JsonValue` 最直接的方式是使用其 `from(...)` 方法：

```java
import com.anthropic.core.JsonValue;

// 建立基本型別的 JSON 值
JsonValue nullValue = JsonValue.from(null);

JsonValue booleanValue = JsonValue.from(true);

JsonValue numberValue = JsonValue.from(42);

JsonValue stringValue = JsonValue.from("Hello World!");

// 建立等同於 `["Hello", "World"]` 的 JSON 陣列值
JsonValue arrayValue = JsonValue.from(List.of("Hello", "World"));

// 建立等同於 `{ "a": 1, "b": 2 }` 的 JSON 物件值
JsonValue objectValue = JsonValue.from(Map.of("a", 1, "b", 2));

// 建立任意巢狀的 JSON，等同於：
// { "a": [1, 2], "b": [3, 4] }
JsonValue complexValue = JsonValue.from(Map.of("a", List.of(1, 2), "b", List.of(3, 4)));
```

### 強制省略必填參數

通常，如果有任何必填參數或屬性未設定，`Builder` 類別的 `build` 方法會拋出 `IllegalStateException`。若要強制省略必填參數或屬性，請傳遞 `JsonMissing`：

```java
import com.anthropic.core.JsonMissing;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

MessageCreateParams params = MessageCreateParams.builder()
  .addUserMessage("Hello, world")
  .model(Model.CLAUDE_OPUS_5_5)
  .maxTokens(JsonMissing.of())
  .build();
```

### 回應屬性

若要存取未記載的回應屬性，請呼叫 `_additionalProperties()` 方法：

```java
import com.anthropic.core.JsonValue;

Map<String, JsonValue> additionalProperties = client
  .messages()
  .create(params)
  ._additionalProperties();

JsonValue secretPropertyValue = additionalProperties.get("secretProperty");

String result = secretPropertyValue.accept(new JsonValue.Visitor<>() {
    @Override
    public String visitNull() {
        return "It's null!";
    }

    @Override
    public String visitBoolean(boolean value) {
        return "It's a boolean!";
    }

    @Override
    public String visitNumber(Number value) {
        return "It's a number!";
    }

    // 其他方法包括 `visitMissing`、`visitString`、`visitArray` 和 `visitObject`
    // 每個未實作方法的預設實作會委派給 `visitDefault`，
    // 其預設會拋出例外，但也可以被覆寫
});
```

若要存取屬性的原始 JSON 值，請呼叫其以 `_` 為前綴的方法：

```java
import com.anthropic.core.JsonField;
import com.anthropic.models.messages.StopReason;

JsonField<StopReason> stopReason = client.messages().create(params)._stopReason();

if (stopReason.isMissing()) {
  // JSON 回應中不存在此屬性
} else if (stopReason.isNull()) {
  // 此屬性被設為字面值 null
} else {
  // 檢查值是否以字串形式提供
  // 其他方法包括 `asNumber()`、`asBoolean()` 等
  Optional<String> jsonString = stopReason.asString();

  // 嘗試反序列化為自訂型別
  MyClass myObject = stopReason.asUnknown().orElseThrow().convert(MyClass.class);
}
```

### 回應驗證

預設情況下，當 API 回傳與預期型別不符的回應時，SDK 不會拋出例外。只有在您直接存取該屬性時，它才會拋出 `AnthropicInvalidDataException`。

若要預先檢查回應是否完全型別正確，請呼叫 `validate()`：

```java
import com.anthropic.models.messages.Message;

Message message = client.messages().create(params).validate();
```

或針對每個請求進行設定：

```java
import com.anthropic.models.messages.Message;

Message message = client
  .messages()
  .create(params, RequestOptions.builder().responseValidation(true).build());
```

或在用戶端層級為所有方法呼叫設定預設值：

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .responseValidation(true)
  .build();
```

## HTTP 用戶端自訂

### Proxy 設定

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import java.net.Proxy;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("https://example.com", 8080)))
  .build();
```

### HTTPS / SSL 設定

<Note>
  大多數應用程式不應呼叫這些方法，而應使用系統預設值。預設值包含特殊的最佳化，若修改實作可能會失去這些最佳化。
</Note>

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .sslSocketFactory(yourSSLSocketFactory)
  .trustManager(yourTrustManager)
  .hostnameVerifier(yourHostnameVerifier)
  .build();
```

### 自訂 HTTP 用戶端

SDK 由三個 artifact 組成：

* `anthropic-java-core` - 包含核心 SDK 邏輯，不依賴 OkHttp。公開 `AnthropicClient`、`AnthropicClientAsync` 及其實作類別，這些全都可以搭配任何 HTTP 用戶端運作。
* `anthropic-java-client-okhttp` - 依賴 OkHttp。公開 `AnthropicOkHttpClient` 與 `AnthropicOkHttpClientAsync`。
* `anthropic-java` - 依賴並公開 `anthropic-java-core` 與 `anthropic-java-client-okhttp` 兩者的 API。本身沒有自己的邏輯。

此結構允許在不引入不必要相依性的情況下替換 SDK 的預設 HTTP 用戶端。

#### 自訂的 OkHttpClient

<Tip>
  在替換預設用戶端之前，請先嘗試可用的[網路選項](https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/sdks/java#retries)。
</Tip>

若要使用自訂的 `OkHttpClient`：

1. 將您的 `anthropic-java` 相依性替換為 `anthropic-java-core`。
2. 將 `anthropic-java-client-okhttp` 的 `OkHttpClient` 類別複製到您的程式碼中並加以自訂。
3. 使用您自訂的用戶端建構 `AnthropicClientImpl` 或 `AnthropicClientAsyncImpl`。

#### 完全自訂的 HTTP 用戶端

若要使用完全自訂的 HTTP 用戶端：

1. 將您的 `anthropic-java` 相依性替換為 `anthropic-java-core`。
2. 撰寫一個實作 `HttpClient` 介面的類別。
3. 使用您的新用戶端類別建構 `AnthropicClientImpl` 或 `AnthropicClientAsyncImpl`。

## 平台整合

<Note>
  如需附有程式碼範例的詳細平台設定指南，請參閱：

  * [Amazon Bedrock](https://platform.claude.com/docs/zh-TW/build-with-claude/claude-in-amazon-bedrock)
  * [Amazon Bedrock（Opus 4.6 及更早版本）](https://platform.claude.com/docs/zh-TW/build-with-claude/claude-on-amazon-bedrock-legacy)
  * [Claude Platform on AWS](https://platform.claude.com/docs/zh-TW/build-with-claude/claude-platform-on-aws)
  * [Google Cloud](https://platform.claude.com/docs/zh-TW/build-with-claude/claude-on-vertex-ai)
  * [Microsoft Foundry](https://platform.claude.com/docs/zh-TW/build-with-claude/claude-in-microsoft-foundry)
</Note>

Java SDK 透過提供平台專屬 `Backend` 實作的獨立相依性來支援下列平台：

* **Agent Platform：** `com.anthropic:anthropic-java-vertex`：使用 `VertexBackend.builder()` 或 `VertexBackend.fromEnv()`。`fromEnv()` 會讀取 `CLOUD_ML_REGION` 和 `ANTHROPIC_VERTEX_PROJECT_ID`，並使用 Application Default Credentials。
* **Bedrock：** `com.anthropic:anthropic-java-bedrock`：針對 Messages-API Bedrock 端點使用 `BedrockMantleBackend.fromEnv()` 或 `BedrockMantleBackend.builder()`，或使用 `BedrockBackend.fromEnv()` / `BedrockBackend.builder()`（`bedrock-runtime` 路徑）。
* **Claude Platform on AWS：** `com.anthropic:anthropic-java-aws`：使用 `AwsBackend.fromEnv()`（讀取 `ANTHROPIC_AWS_WORKSPACE_ID` 以及 AWS 預設區域／憑證鏈）或 `AwsBackend.builder()`。目前為 beta 版。
* **Foundry：** `com.anthropic:anthropic-java-foundry`：使用 `FoundryBackend.fromEnv()` 或 `FoundryBackend.builder()`。

新專案請使用 `BedrockMantleBackend`；`BedrockBackend` 則保留給使用 Bedrock `InvokeModel` API 的既有應用程式。

平台 artifact 是基礎 `com.anthropic:anthropic-java` 相依性的附加元件，該相依性提供 `AnthropicOkHttpClient`，因此請同時安裝兩者。每個 `Backend` 實作都透過 `AnthropicOkHttpClient.builder()` 上的 `.backend()` 傳遞給用戶端。每個雲端後端都會將其各自的雲端平台 SDK 類別作為遞移相依性引入。

## 進階用法

### 原始回應存取

若要存取 HTTP 標頭、狀態碼與原始回應主體，請在任何 HTTP 方法呼叫前加上 `withRawResponse()`：

```java
import com.anthropic.core.http.Headers;
import com.anthropic.core.http.HttpResponseFor;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();

HttpResponseFor<Message> message = client.messages().withRawResponse().create(params);

int statusCode = message.statusCode();

Headers headers = message.headers();
```

如有需要，您仍可將回應反序列化為 Java 類別的實例：

```java
import com.anthropic.models.messages.Message;

Message parsedMessage = message.parse();
```

### 日誌記錄

SDK 使用標準的 OkHttp 日誌攔截器。

將 `ANTHROPIC_LOG` 環境變數設定為 `info` 以啟用日誌記錄：

```bash
export ANTHROPIC_LOG=info
```

或設定為 `debug` 以取得更詳細的日誌：

```bash
export ANTHROPIC_LOG=debug
```

<Accordion title="Jackson 相容性">
  SDK 依賴 Jackson 進行 JSON 序列化／反序列化。它與 2.13.4 或更高版本相容，但預設依賴 2.19.4 版本。

  如果 SDK 在執行階段偵測到不相容的 Jackson 版本（例如，預設版本在您的 Maven 或 Gradle 設定中被覆寫），它會拋出例外。

  如果 SDK 拋出了例外，但您確定版本是相容的，則可在 `AnthropicOkHttpClient` 或 `AnthropicOkHttpClientAsync` 上使用 `checkJacksonVersionCompatibility` 停用版本檢查。

  <Warning>
    停用 Jackson 版本檢查時，無法保證 SDK 能正確運作。
  </Warning>

  較舊的 Jackson 版本中也存在可能影響 SDK 的錯誤。SDK 不會繞過所有 Jackson 錯誤，而是期望使用者針對這些問題升級 Jackson。
</Accordion>

<Accordion title="ProGuard/R8 設定">
  雖然 SDK 使用反射，但它仍可搭配 ProGuard 與 R8 使用，因為 `anthropic-java-core` 發布時附帶了包含 keep 規則的設定檔。

  ProGuard 與 R8 應會自動偵測並使用已發布的規則，但如有必要，您也可以手動複製這些 keep 規則。
</Accordion>

### 未記載的 API 功能

SDK 的型別設計是為了便利地使用已記載的 API。然而，它也支援使用 API 中未記載或尚未支援的部分。

#### 未記載的請求參數

若要設定未記載的請求參數，請依照[未記載的參數](https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/sdks/java#undocumented-parameters)中所述，使用 `putAdditionalHeader`、`putAdditionalQueryParam` 或 `putAdditionalBodyProperty` 方法。

#### 未記載的回應屬性

若要存取未記載的回應屬性，請依照[回應屬性](https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/sdks/java#response-properties)中所述，使用 `_additionalProperties()` 方法。

#### 新的或尚未發布的列舉值

SDK 中類似列舉的類別，例如 `Model` 與 `AnthropicBeta`，並非封閉的 Java `enum` 型別。每一個都提供接受任意字串的 `of(String)` 工廠方法，因此您可以使用尚未加入 SDK 的值，例如在您的 SDK 版本之後才發布的模型或 beta 標頭：

```java
import com.anthropic.models.beta.AnthropicBeta;
import com.anthropic.models.messages.Model;

Model model = Model.of("some-new-model");
AnthropicBeta beta = AnthropicBeta.of("some-new-beta-2026-01-01");
```

接受這些型別的建構器方法通常也提供會替您呼叫 `of(...)` 的 `String` 多載：

```java
import com.anthropic.models.messages.MessageCreateParams;

MessageCreateParams params = MessageCreateParams.builder()
  .model("some-new-model") // same as .model(Model.of("some-new-model"))
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .build();
```

請優先使用型別明確的常數（例如 `Model.CLAUDE_OPUS_5`），以便獲得自動完成與棄用警告。`String` 多載與 `of(...)` 主要用於在等待包含該值的 SDK 版本發布期間，將欄位設定為未記載或尚未支援的值。

## Beta 功能

Beta 功能會在正式發布前提供，以取得早期回饋並測試新功能。您可以在[功能總覽](https://platform.claude.com/docs/zh-TW/build-with-claude/overview)中查看 Claude 所有功能與工具的可用性。

您可以透過用戶端上的 `beta()` 方法存取大多數 beta API 功能。若要啟用特定的 beta 功能，請在建構訊息參數時使用 `.addBeta()` 加入適當的 [beta 標頭](https://platform.claude.com/docs/zh-TW/api/beta-headers)。

例如，若要啟用[上下文編輯](https://platform.claude.com/docs/zh-TW/build-with-claude/context-editing)：

```java
import com.anthropic.models.beta.AnthropicBeta;
import com.anthropic.models.beta.messages.BetaMessage;
import com.anthropic.models.beta.messages.MessageCreateParams;
// ...
void main() {
    AnthropicClient client = AnthropicOkHttpClient.fromEnv();

    BetaMessage message = client.beta().messages().create(
        MessageCreateParams.builder()
            .model(Model.CLAUDE_OPUS_5_5)
            .maxTokens(1024L)
            .addBeta(AnthropicBeta.CONTEXT_MANAGEMENT_2025_06_27)
            .addUserMessage("Hello, Claude")
            .build());
}
```

## 常見問題

<AccordionGroup>
  <Accordion title="為什麼 SDK 不使用一般的 enum 類別？">
    Java `enum` 類別並非天生就具備向前相容性。在 SDK 中使用它們，可能會在 API 更新為回應新的列舉值時導致執行階段例外。

    由於這些類別是開放的，您也可以透過其 `of(String)` 工廠方法以任意字串值建構它們。如果您需要使用尚未包含在您 SDK 版本中的值，請參閱[新的或尚未發布的列舉值](https://platform.claude.com/docs/zh-TW/cli-sdks-libraries/sdks/java#new-or-unreleased-enum-values)。
  </Accordion>

  <Accordion title="為什麼欄位使用 JsonField<T> 表示，而不是直接使用 T？">
    使用 `JsonField<T>` 可實現幾項功能：

    * 允許使用未記載的 API 功能
    * 延遲驗證 API 回應是否符合預期的結構
    * 區分不存在的值與明確為 null 的值
  </Accordion>

  <Accordion title="為什麼 SDK 不使用資料類別？">
    在資料類別中新增欄位並不具備向後相容性，而 SDK 希望避免每次在類別中新增欄位時都引入破壞性變更。
  </Accordion>

  <Accordion title="為什麼 SDK 不使用受檢例外？">
    受檢例外被廣泛認為是 Java 程式語言中的一個錯誤。事實上，Kotlin 正是因為這個原因而省略了它們。

    受檢例外：

    * 處理起來很冗長
    * 鼓勵在錯誤的抽象層級處理錯誤，而在該層級對錯誤無能為力
    * 由於函式著色問題，傳播起來很繁瑣
    * 與 lambda 搭配不佳（同樣是因為函式著色問題）
  </Accordion>
</AccordionGroup>

## 語意化版本

此套件大致遵循 [SemVer](https://semver.org/spec/v2.0.0.html) 慣例，但某些向後不相容的變更可能會以次要版本發布：

1. 對函式庫內部的變更，這些內部在技術上是公開的，但並非預期或記載供外部使用。
2. 預期在實務上不會影響絕大多數使用者的變更。

## 其他資源

* [GitHub 儲存庫](https://github.com/anthropics/anthropic-sdk-java)
* [Javadocs](https://javadoc.io/doc/com.anthropic/anthropic-java)
* [API 參考文件](https://platform.claude.com/docs/zh-TW/api/overview)
* [串流訊息](https://platform.claude.com/docs/zh-TW/build-with-claude/streaming)
* [搭配 Claude 的工具使用](https://platform.claude.com/docs/zh-TW/agents-and-tools/tool-use/overview)
