---
title: Java SDK
url: https://platform.claude.com/docs/ko/cli-sdks-libraries/sdks/java
description: 빌더 패턴과 비동기 지원을 갖춘 Anthropic Java SDK를 설치하고 구성합니다
---

Anthropic Java SDK는 Java로 작성된 애플리케이션에서 Claude API에 편리하게 접근할 수 있도록 해 줍니다. 요청 생성에 빌더 패턴을 사용하며 동기 및 비동기 작업을 모두 지원합니다.

<Info>
  코드 예제가 포함된 API 기능 문서는 [API 레퍼런스](https://platform.claude.com/docs/ko/api/overview)를 참조하세요. 이 페이지에서는 Java 전용 SDK 기능과 구성을 다룹니다.
</Info>

## 설치

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

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

## 요구 사항

이 라이브러리는 Java 8 이상이 필요합니다.

<Note>
  SDK는 Java 8 이상을 지원합니다. 이 문서의 코드 예제는 [JDK 25 compact source files](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/ko/manage-claude/authentication)을 참조하세요. API 키가 워크스페이스로 범위가 지정되지 않은 [개인 또는 서비스 계정 키](https://platform.claude.com/docs/ko/manage-claude/authentication#key-types)인 경우 `anthropic-workspace-id` 요청 헤더에 워크스페이스 ID를 설정하세요. [워크스페이스 선택](https://platform.claude.com/docs/ko/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"(청크) 스트림을 반환하는 메서드를 정의하며, 각 청크는 전체 응답을 기다리지 않고 도착하는 즉시 개별적으로 처리할 수 있습니다.

### 동기 스트리밍

이러한 스트리밍 메서드는 동기 클라이언트에서 `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`는 응답의 이벤트 스트림이 처리될 때 이를 기록하고, 비스트리밍 API가 반환했을 것과 유사한 `Message` 객체를 누적할 수 있습니다.

동기 응답의 경우, 스트림 파이프라인에 `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();
```

비동기 응답의 경우, `subscribe()` 호출에 `MessageAccumulator`를 추가합니다:

```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();
```

`BetaMessage` 객체를 누적하기 위한 `BetaMessageAccumulator`도 제공됩니다. 사용 방법은 `MessageAccumulator`와 동일합니다.

## 구조화된 출력

Java 예제를 포함한 구조화된 출력에 대한 전체 문서는 [구조화된 출력](https://platform.claude.com/docs/ko/build-with-claude/structured-outputs)을 참조하세요.

## 도구 사용

[Claude를 사용한 도구 사용](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/overview)을 통해 외부 도구와 함수를 AI 모델의 응답에 직접 통합할 수 있습니다. 모델은 일반 텍스트를 생성하는 대신, 적절한 경우 도구나 함수를 호출하기 위한 지시(매개변수 포함)를 출력할 수 있습니다. 도구에 대한 JSON 스키마를 정의하면, 모델은 이 스키마를 사용하여 도구를 언제 어떻게 사용할지 결정합니다.

도구 사용 기능은 AI 모델의 JSON 출력이 입력 매개변수에 제공한 JSON 스키마를 준수하도록 보장하는 "strict" 모드를 지원합니다.

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
              // 도구 사용이 요청되었음을 나타내는 메시지를 추가합니다.
              .addAssistantMessageOfContentBlockParams(
                      List.of(BetaContentBlockParam.ofToolUse(BetaToolUseBlockParam.builder()
                              .name(toolUseBlock.name())
                              .id(toolUseBlock.id())
                              .input(toolUseBlock._input())
                              .build())))
              // 요청된 도구 사용의 결과가 담긴 메시지를 추가합니다.
              .addUserMessageOfContentBlockParams(
                      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 스키마 검증

도구 클래스에서 도출된 JSON 스키마가 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 스키마에 도구에 대한 추가 정보를 넣을 수 있습니다:

* `@JsonClassDescription` - 도구 클래스에 해당 도구를 언제 어떻게 사용하는지 설명하는 설명을 추가합니다.
* `@JsonTypeName` - 도구 이름을 snake case로 변환된 클래스의 단순 이름이 아닌 다른 이름으로 설정합니다.
* `@JsonPropertyDescription` - 도구 매개변수에 자세한 설명을 추가합니다.
* `@JsonIgnore` - 도구 매개변수에 대해 생성되는 JSON 스키마에서 `public` 필드나 getter 메서드를 제외합니다.
* `@JsonProperty` - 도구 매개변수에 대해 생성되는 JSON 스키마에 `public`이 아닌 필드나 getter 메서드를 포함합니다.

## 메시지 배치

SDK는 `client.messages().batches()` 네임스페이스에서 [배치 처리](https://platform.claude.com/docs/ko/build-with-claude/batch-processing)를 지원합니다. 배치를 나열하고 페이지를 넘기는 방법은 [페이지네이션](https://platform.claude.com/docs/ko/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);
```

### 바이너리 응답

SDK는 반드시 JSON으로 파싱되지 않는 API 응답에 대해 바이너리 응답을 반환하는 메서드를 정의합니다:

```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는 사용자 정의 unchecked 예외 타입을 발생시킵니다:

* `AnthropicServiceException` - HTTP 오류의 기본 클래스입니다.
* `AnthropicIoException` - I/O 네트워킹 오류입니다.
* `AnthropicRetryableException` - 재시도할 수 있는 실패를 나타내는 일반 오류입니다.
* `AnthropicInvalidDataException` - 성공적으로 파싱된 데이터를 해석하지 못한 경우입니다(예: 필수여야 하는 속성에 접근했는데 API가 예기치 않게 이를 생략한 경우).
* `AnthropicException` - 모든 예외의 기본 클래스입니다.

### 상태 코드 매핑

| 상태  | 예외                              |
| --- | ------------------------------- |
| 400 | `BadRequestException`           |
| 401 | `UnauthorizedException`         |
| 403 | `PermissionDeniedException`     |
| 404 | `NotFoundException`             |
| 422 | `UnprocessableEntityException`  |
| 429 | `RateLimitException`            |
| 5xx | `InternalServerException`       |
| 기타  | `UnexpectedStatusCodeException` |

`SseException`은 초기 HTTP 응답이 성공한 후 SSE 스트리밍 중에 발생한 오류에 대해 발생합니다.

```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/ko/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/ko/api/errors#request-id)를 참조하세요.

## 재시도

SDK는 기본적으로 요청 사이에 짧은 지수 백오프를 두고 자동으로 2회 재시도합니다.

다음 오류 유형만 재시도됩니다:

* 연결 오류(예: 네트워크 연결 문제로 인한 경우)
* 408 Request Timeout
* 409 Conflict
* 429 Rate Limit
* 5xx Internal

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

재정의하지 않는 한, 이로 인해 `maxTokens` 매개변수에 따라 조정되는 최대 60분의 타임아웃이 적용됩니다.

비스트리밍 요청의 경우, 동적 타임아웃은 `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/ko/cli-sdks-libraries/sdks/java#streaming) 사용을 고려하세요.
</Warning>

스트리밍을 사용하지 않고 큰 `maxTokens` 값을 설정하지 마세요. 일부 네트워크는 일정 시간이 지나면 유휴 연결을 끊을 수 있으며, 이로 인해 Anthropic으로부터 응답을 받지 못한 채 요청이 실패하거나 [타임아웃](https://platform.claude.com/docs/ko/cli-sdks-libraries/sdks/java#timeouts)될 수 있습니다. SDK는 연결을 유지하고 이러한 네트워크의 영향을 줄이기 위해 주기적으로 API에 ping을 보냅니다.

비스트리밍 요청이 10분 이상 걸릴 것으로 예상되면 SDK는 오류를 발생시킵니다. [스트리밍 메서드](https://platform.claude.com/docs/ko/cli-sdks-libraries/sdks/java#streaming)를 사용하거나 클라이언트 또는 요청 수준에서 [타임아웃을 재정의](https://platform.claude.com/docs/ko/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()` 메서드를 사용하여 접근할 수 있습니다.

문서화된 매개변수나 속성을 문서화되지 않았거나 아직 지원되지 않는 값으로 설정하려면 해당 setter에 `JsonValue` 객체를 전달하세요:

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

### 응답 검증

기본적으로 SDK는 API가 예상 타입과 일치하지 않는 응답을 반환해도 예외를 발생시키지 않습니다. 해당 속성에 직접 접근하는 경우에만 `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 클라이언트 사용자 지정

### 프록시 구성

```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는 세 가지 아티팩트로 구성됩니다:

* `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/ko/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/ko/build-with-claude/claude-in-amazon-bedrock)
  * [Amazon Bedrock (Opus 4.6 이하)](https://platform.claude.com/docs/ko/build-with-claude/claude-on-amazon-bedrock-legacy)
  * [Claude Platform on AWS](https://platform.claude.com/docs/ko/build-with-claude/claude-platform-on-aws)
  * [Claude Models on Google Cloud (Google managed)](https://platform.claude.com/docs/ko/build-with-claude/claude-models-on-google-cloud/google-managed)
  * [Microsoft Foundry](https://platform.claude.com/docs/ko/build-with-claude/claude-in-microsoft-foundry)

  [Claude Models on Google Cloud (Anthropic managed)](https://platform.claude.com/docs/ko/build-with-claude/claude-models-on-google-cloud/anthropic-managed)도 참조하세요.
</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()`를 사용하고, `bedrock-runtime` 경로에는 `BedrockBackend.fromEnv()` / `BedrockBackend.builder()`를 사용합니다.
* **Claude Platform on AWS:** `com.anthropic:anthropic-java-aws`: `AwsBackend.fromEnv()`(`ANTHROPIC_AWS_WORKSPACE_ID`와 AWS 기본 리전/자격 증명 체인을 읽음) 또는 `AwsBackend.builder()`를 사용합니다. 베타로 제공됩니다.
* **Foundry:** `com.anthropic:anthropic-java-foundry`: `FoundryBackend.fromEnv()` 또는 `FoundryBackend.builder()`를 사용합니다.

새 프로젝트에는 `BedrockMantleBackend`를 사용하세요. `BedrockBackend`는 Bedrock `InvokeModel` API를 사용하는 기존 애플리케이션을 위해 유지됩니다.

Java SDK는 `com.anthropic:anthropic-java-google-cloud` 종속성의 `GoogleCloudBackend`를 통해 Claude Models on Google Cloud (Anthropic managed)도 지원합니다. 이 백엔드는 베타 버전입니다. `GoogleCloudBackend.builder()` 또는 `GoogleCloudBackend.fromEnv()`로 생성하세요. `fromEnv()`는 `ANTHROPIC_GOOGLE_CLOUD_WORKSPACE_ID`, `ANTHROPIC_GOOGLE_CLOUD_PROJECT` 및 Google Application Default Credentials를 읽습니다. [프로젝트, 위치 및 워크스페이스 확인](https://platform.claude.com/docs/ko/build-with-claude/claude-models-on-google-cloud/anthropic-managed#project-location-and-workspace-resolution)을 참조하세요.

플랫폼 아티팩트는 `AnthropicOkHttpClient`를 제공하는 기본 `com.anthropic:anthropic-java` 의존성에 대한 애드온이므로 둘 다 설치하세요. 각 `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는 JSON 직렬화/역직렬화를 위해 Jackson에 의존합니다. 버전 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는 리플렉션을 사용하지만, `anthropic-java-core`가 keep 규칙이 포함된 구성 파일과 함께 게시되므로 ProGuard 및 R8과 함께 사용할 수 있습니다.

  ProGuard와 R8은 게시된 규칙을 자동으로 감지하여 사용하지만, 필요한 경우 keep 규칙을 수동으로 복사할 수도 있습니다.
</Accordion>

### OpenTelemetry 추적

애플리케이션이 OpenTelemetry 트레이서 프로바이더를 등록하면 SDK는 전송하는 각 요청에 대해 스팬을 내보냅니다. 스팬을 관측성 플랫폼으로 전송하려면 [Claude SDK에서 OpenTelemetry 설정하기](https://platform.claude.com/docs/ko/manage-claude/opentelemetry/sdk)를 참조하세요.

### 문서화되지 않은 API 기능

SDK는 문서화된 API를 편리하게 사용할 수 있도록 타입이 지정되어 있습니다. 그러나 문서화되지 않았거나 아직 지원되지 않는 API 부분을 사용하는 것도 지원합니다.

#### 문서화되지 않은 요청 매개변수

문서화되지 않은 요청 매개변수를 설정하려면 [문서화되지 않은 매개변수](https://platform.claude.com/docs/ko/cli-sdks-libraries/sdks/java#undocumented-parameters)에 설명된 대로 `putAdditionalHeader`, `putAdditionalQueryParam` 또는 `putAdditionalBodyProperty` 메서드를 사용하세요.

#### 문서화되지 않은 응답 속성

문서화되지 않은 응답 속성에 접근하려면 [응답 속성](https://platform.claude.com/docs/ko/cli-sdks-libraries/sdks/java#response-properties)에 설명된 대로 `_additionalProperties()` 메서드를 사용하세요.

#### 새로운 또는 출시되지 않은 enum 값

`Model`, `AnthropicBeta`와 같은 SDK의 enum 유사 클래스는 닫힌 Java `enum` 타입이 아닙니다. 각 클래스는 임의의 문자열을 받는 `of(String)` 팩토리 메서드를 제공하므로, SDK 버전 이후에 출시된 모델이나 베타 헤더처럼 아직 SDK에 추가되지 않은 값을 사용할 수 있습니다:

```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 릴리스를 기다리는 동안 필드를 문서화되지 않았거나 아직 지원되지 않는 값으로 설정하기 위한 것입니다.

## 베타 기능

베타 기능은 초기 피드백을 받고 새로운 기능을 테스트하기 위해 정식 출시 전에 제공됩니다. Claude의 모든 기능과 도구의 가용성은 [기능 개요](https://platform.claude.com/docs/ko/build-with-claude/overview)에서 확인할 수 있습니다.

대부분의 베타 API 기능은 클라이언트의 `beta()` 메서드를 통해 접근할 수 있습니다. 특정 베타 기능을 활성화하려면 메시지 매개변수를 빌드할 때 `.addBeta()`로 적절한 [베타 헤더](https://platform.claude.com/docs/ko/api/beta-headers)를 추가하세요.

예를 들어 [컨텍스트 편집](https://platform.claude.com/docs/ko/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가 새로운 enum 값으로 응답하도록 업데이트될 경우 런타임 예외가 발생할 수 있습니다.

    이러한 클래스는 열려 있으므로 `of(String)` 팩토리 메서드를 통해 임의의 문자열 값으로 생성할 수도 있습니다. SDK 버전에 아직 없는 값을 사용해야 하는 경우 [새로운 또는 출시되지 않은 enum 값](https://platform.claude.com/docs/ko/cli-sdks-libraries/sdks/java#new-or-unreleased-enum-values)을 참조하세요.
  </Accordion>

  <Accordion title="필드가 단순한 T 대신 JsonField<T>로 표현되는 이유는 무엇인가요?">
    `JsonField<T>`를 사용하면 몇 가지 기능이 가능해집니다:

    * 문서화되지 않은 API 기능 사용 허용
    * 예상 형태에 대한 API 응답의 지연 검증
    * 값이 없는 경우와 명시적으로 null인 경우의 구분
  </Accordion>

  <Accordion title="SDK가 data 클래스를 사용하지 않는 이유는 무엇인가요?">
    data 클래스에 새 필드를 추가하는 것은 하위 호환되지 않으며, SDK는 클래스에 필드가 추가될 때마다 호환성을 깨는 변경이 발생하는 것을 피합니다.
  </Accordion>

  <Accordion title="SDK가 checked 예외를 사용하지 않는 이유는 무엇인가요?">
    Checked 예외는 Java 프로그래밍 언어의 실수로 널리 여겨집니다. 실제로 이러한 이유로 Kotlin에서는 제외되었습니다.

    Checked 예외는:

    * 처리하기가 장황합니다
    * 오류에 대해 아무것도 할 수 없는 잘못된 추상화 수준에서 오류 처리를 유도합니다
    * 함수 색칠 문제로 인해 전파하기가 번거롭습니다
    * 람다와 잘 어울리지 않습니다(이 역시 함수 색칠 문제 때문입니다)
  </Accordion>
</AccordionGroup>

## 시맨틱 버전 관리

이 SDK의 각 메이저 버전은 기본적으로 `anthropic-version` 헤더에 하나의 API 버전을 보내며, 새로운 API 버전마다 새로운 메이저 버전이 함께 출시됩니다. `2026-10-21`을 보내는 첫 번째 메이저 버전은 3.0.0입니다. [API 버전 2026-10-21로 마이그레이션](https://platform.claude.com/docs/ko/api/migration-2026-10-21#upgrade)을 참조하세요.

이 패키지는 일반적으로 [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/ko/api/overview)
* [메시지 스트리밍](https://platform.claude.com/docs/ko/build-with-claude/streaming)
* [Claude를 사용한 도구 사용](https://platform.claude.com/docs/ko/agents-and-tools/tool-use/overview)
