Java SDK
빌더 패턴과 비동기 지원을 갖춘 Anthropic Java SDK를 설치하고 구성합니다
Anthropic Java SDK는 Java로 작성된 애플리케이션에서 Claude API에 편리하게 접근할 수 있도록 해줍니다. 요청 생성에 "builder pattern"(빌더 패턴)을 사용하며 동기 및 비동기 작업을 모두 지원합니다.
설치
implementation("com.anthropic:anthropic-java:2.58.0")요구 사항
이 라이브러리는 Java 8 이상이 필요합니다.
빠른 시작
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)
.build();
Message message = client.messages().create(params);클라이언트 구성
API 키 설정
시스템 속성 또는 환경 변수를 사용하여 클라이언트를 구성합니다:
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();또는 수동으로 구성합니다:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
AnthropicClient client = AnthropicOkHttpClient.builder()
.apiKey("my-anthropic-api-key")
.build();또는 두 가지 방식을 조합하여 사용합니다:
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을 포함한 인증 옵션에 대해서는 인증을 참조하세요. API 키가 여러 워크스페이스에 액세스할 수 있는 개인 또는 서비스 계정 키인 경우, anthropic-workspace-id 요청 헤더에 워크스페이스 ID를 설정하세요. 워크스페이스 선택에서 이 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" |
시스템 속성이 환경 변수보다 우선합니다.
구성 수정
동일한 연결 및 스레드 풀을 재사용하면서 수정된 클라이언트 구성을 일시적으로 사용하려면, 임의의 클라이언트 또는 서비스에서 withOptions()를 호출하세요:
import com.anthropic.client.AnthropicClient;
AnthropicClient clientWithOptions = client.withOptions(optionsBuilder -> {
optionsBuilder.baseUrl("https://example.com");
optionsBuilder.maxRetries(42);
});withOptions() 메서드는 원래 클라이언트나 서비스에 영향을 주지 않습니다.
비동기 사용
기본 클라이언트는 동기식입니다. 비동기 실행으로 전환하려면 async() 메서드를 호출하세요:
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)
.build();
CompletableFuture<Message> message = client.async().messages().create(params);또는 처음부터 비동기 클라이언트를 생성합니다:
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)
.build();
CompletableFuture<Message> message = client.messages().create(params);비동기 클라이언트는 동기 클라이언트와 동일한 옵션을 지원하지만, 대부분의 메서드가 CompletableFuture를 반환한다는 점이 다릅니다.
스트리밍
SDK는 응답 "청크" 스트림을 반환하는 메서드를 정의합니다. 각 청크는 전체 응답을 기다리지 않고 도착하는 즉시 개별적으로 처리할 수 있습니다.
동기 스트리밍
이러한 "streaming"(스트리밍) 메서드는 동기 클라이언트의 경우 StreamResponse를 반환합니다:
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를 반환합니다:
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를 사용하려면:
Executor executor = Executors.newFixedThreadPool(4);
client.async().messages().createStreaming(params).subscribe(
chunk -> IO.println(chunk), executor
);또는 streamHandlerExecutor 메서드를 사용하여 클라이언트를 전역적으로 구성합니다:
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() 호출을 추가하세요:
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를 추가하세요:
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 예제를 포함한 전체 구조화된 출력 문서는 구조화된 출력을 참조하세요.
도구 사용
Claude와 함께하는 도구 사용을 통해 외부 도구와 함수를 AI 모델의 응답에 직접 통합할 수 있습니다. 모델은 일반 텍스트를 생성하는 대신, 적절한 경우 도구나 함수를 호출하기 위한 지시(매개변수 포함)를 출력할 수 있습니다. 도구에 대한 JSON 스키마를 정의하면, 모델은 이 스키마를 사용하여 언제 어떻게 이러한 도구를 사용할지 결정합니다.
"tool use"(도구 사용) 기능은 AI 모델의 JSON 출력이 입력 매개변수에 제공한 JSON 스키마를 준수하도록 보장하는 "strict" 모드를 지원합니다.
SDK는 임의의 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 모델에 다시 전달하세요:
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)
.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
// 도구 사용이 요청되었음을 나타내는 메시지를 추가합니다.
.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");
}도구 이름 변환
도구 이름은 카멜 케이스 도구 클래스 이름(예: GetWeather)에서 도출되어 스네이크 케이스(예: get_weather)로 변환됩니다. 단어 경계는 현재 문자가 첫 번째 문자가 아니고, 대문자이며, 앞 문자가 소문자이거나 뒤 문자가 소문자인 위치에서 시작됩니다. 예를 들어, MyJSONParser는 my_json_parser가 되고 ParseJSON은 parse_json이 됩니다. 이 변환은 @JsonTypeName 어노테이션을 사용하여 재정의할 수 있습니다.
로컬 도구 JSON 스키마 검증
도구 클래스에서 도출된 JSON 스키마가 Anthropic의 제한 사항을 준수하는지 확인하기 위해 로컬 검증을 수행할 수 있습니다. 로컬 검증은 기본적으로 활성화되어 있지만 비활성화할 수 있습니다:
MessageCreateParams.Builder createParamsBuilder = MessageCreateParams.builder()
.model(Model.CLAUDE_OPUS_5)
.maxTokens(2048)
.addTool(GetWeather.class, JsonSchemaLocalValidation.NO)
.addUserMessage("What's the temperature in New York?");도구 클래스에 어노테이션 추가하기
어노테이션을 사용하여 JSON 스키마에 도구에 대한 추가 정보를 더할 수 있습니다:
@JsonClassDescription- 도구 클래스에 해당 도구를 언제 어떻게 사용하는지 상세히 설명하는 설명을 추가합니다.@JsonTypeName- 도구 이름을 스네이크 케이스로 변환된 클래스의 단순 이름이 아닌 다른 이름으로 설정합니다.@JsonPropertyDescription- 도구 매개변수에 상세한 설명을 추가합니다.@JsonIgnore- 도구 매개변수에 대해 생성된 JSON 스키마에서public필드 또는 getter 메서드를 제외합니다.@JsonProperty- 도구 매개변수에 대해 생성된 JSON 스키마에public이 아닌 필드 또는 getter 메서드를 포함합니다.
메시지 배치
SDK는 client.messages().batches() 네임스페이스에서 배치 처리를 지원합니다. 배치를 나열하고 페이지네이션하는 방법은 페이지네이션을 참조하세요.
파일 업로드
SDK는 MultipartField 클래스를 통해 파일을 받는 메서드를 정의합니다:
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에서:
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);또는 메모리 내 바이트에서:
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 응답에 대해 바이너리 응답을 반환하는 메서드를 정의합니다:
import com.anthropic.core.http.HttpResponse;
HttpResponse response = client.files().download("file_abc123");응답 내용을 파일에 저장하려면:
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으로 전송하려면:
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 스트리밍 중에 발생한 오류에 대해 던져집니다.
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
원시 응답을 사용할 때, requestId() 메서드를 사용하여 request-id 응답 헤더에 접근할 수 있습니다:
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를 참조하세요.
재시도
SDK는 기본적으로 요청 사이에 짧은 지수 백오프를 두고 자동으로 2회 재시도합니다.
다음 오류 타입만 재시도됩니다:
- 연결 오류(예: 네트워크 연결 문제로 인한)
- 408 Request Timeout
- 409 Conflict
- 429 Rate Limit
- 5xx Internal
API가 SDK에 요청을 재시도하거나 재시도하지 않도록 명시적으로 지시할 수도 있습니다.
사용자 정의 재시도 횟수를 설정하려면 maxRetries 메서드를 사용하여 클라이언트를 구성하세요:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
AnthropicClient client = AnthropicOkHttpClient.builder().fromEnv().maxRetries(4).build();타임아웃
요청은 기본적으로 10분 후에 타임아웃됩니다.
그러나 maxTokens를 받는 메서드의 경우, 큰 maxTokens 값을 지정하고 스트리밍 중이라면 기본 타임아웃은 다음 공식을 사용하여 동적으로 계산됩니다:
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분까지 조정됩니다.
요청별로 사용자 정의 타임아웃을 설정하려면:
import com.anthropic.models.messages.Message;
Message message = client
.messages()
.create(params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build());또는 클라이언트 수준에서 모든 메서드 호출에 대한 기본값을 구성하려면:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
AnthropicClient client = AnthropicOkHttpClient.builder()
.fromEnv()
.timeout(Duration.ofSeconds(30))
.build();긴 요청
스트리밍을 사용하지 않고 큰 maxTokens 값을 설정하는 것을 피하세요. 일부 네트워크는 일정 시간이 지나면 유휴 연결을 끊을 수 있으며, 이로 인해 Anthropic으로부터 응답을 받지 못한 채 요청이 실패하거나 타임아웃될 수 있습니다. SDK는 연결을 유지하고 이러한 네트워크의 영향을 줄이기 위해 주기적으로 API에 핑을 보냅니다.
SDK는 비스트리밍 요청이 10분 이상 걸릴 것으로 예상되면 오류를 던집니다. 스트리밍 메서드를 사용하거나 클라이언트 또는 요청 수준에서 타임아웃을 재정의하면 이 오류가 비활성화됩니다.
페이지네이션
SDK는 페이지네이션된 결과에 한 번에 한 페이지씩 또는 모든 페이지에 걸쳐 항목별로 접근할 수 있는 편리한 방법을 제공합니다.
자동 페이지네이션
모든 페이지에 걸쳐 모든 결과를 반복하려면, 필요에 따라 자동으로 더 많은 페이지를 가져오는 autoPager() 메서드를 사용하세요.
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를 반환합니다:
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!");
}
}));수동 페이지네이션
개별 페이지 항목에 접근하고 다음 페이지를 수동으로 요청하려면:
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() 메서드가 있으며, 이를 사용하여 수정된 복사본을 만들기 위해 다시 빌더로 변환할 수 있습니다.
MessageCreateParams params = MessageCreateParams.builder()
.maxTokens(1024L)
.addUserMessage("Hello, Claude")
.model(Model.CLAUDE_OPUS_5)
.build();
// toBuilder()를 사용하여 수정된 복사본 생성
MessageCreateParams modified = params.toBuilder().maxTokens(2048L).build();각 클래스는 불변이므로, 빌더 수정은 이미 빌드된 클래스 인스턴스에 절대 영향을 주지 않습니다.
요청과 응답
Claude API에 요청을 보내려면, 어떤 Params 클래스의 인스턴스를 빌드하여 해당 클라이언트 메서드에 전달하세요. 응답이 수신되면 Java 클래스의 인스턴스로 역직렬화됩니다.
예를 들어, client.messages().create(...)는 MessageCreateParams의 인스턴스로 호출해야 하며, Message의 인스턴스를 반환합니다.
문서화되지 않은 매개변수
문서화되지 않은 매개변수를 설정하려면, 임의의 Params 클래스에서 putAdditionalHeader, putAdditionalQueryParam 또는 putAdditionalBodyProperty 메서드를 호출하세요:
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() 메서드를 사용하여 접근할 수 있습니다.
중첩된 헤더, 쿼리 매개변수 또는 본문 클래스에 문서화되지 않은 매개변수를 설정하려면:
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 객체를 전달하세요:
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)
.build();JsonValue 생성
JsonValue를 생성하는 가장 간단한 방법은 from(...) 메서드를 사용하는 것입니다:
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을 전달하세요:
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)
.maxTokens(JsonMissing.of())
.build();응답 속성
문서화되지 않은 응답 속성에 접근하려면 _additionalProperties() 메서드를 호출하세요:
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 값에 접근하려면 _ 접두사가 붙은 메서드를 호출하세요:
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()를 호출하세요:
import com.anthropic.models.messages.Message;
Message message = client.messages().create(params).validate();또는 요청별로 구성하려면:
import com.anthropic.models.messages.Message;
Message message = client
.messages()
.create(params, RequestOptions.builder().responseValidation(true).build());또는 클라이언트 수준에서 모든 메서드 호출에 대한 기본값을 구성하려면:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
AnthropicClient client = AnthropicOkHttpClient.builder()
.fromEnv()
.responseValidation(true)
.build();HTTP 클라이언트 사용자 정의
프록시 구성
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 구성
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
사용자 정의된 OkHttpClient를 사용하려면:
anthropic-java의존성을anthropic-java-core로 교체합니다.anthropic-java-client-okhttp의OkHttpClient클래스를 코드에 복사하고 사용자 정의합니다.- 사용자 정의된 클라이언트를 사용하여
AnthropicClientImpl또는AnthropicClientAsyncImpl을 생성합니다.
완전한 사용자 정의 HTTP 클라이언트
완전한 사용자 정의 HTTP 클라이언트를 사용하려면:
anthropic-java의존성을anthropic-java-core로 교체합니다.HttpClient인터페이스를 구현하는 클래스를 작성합니다.- 새 클라이언트 클래스를 사용하여
AnthropicClientImpl또는AnthropicClientAsyncImpl을 생성합니다.
플랫폼 통합
Java SDK는 플랫폼별 Backend 구현을 제공하는 별도의 의존성을 통해 다음 플랫폼을 지원합니다:
- Agent Platform:
com.anthropic:anthropic-java-vertex:VertexBackend.fromEnv()또는VertexBackend.builder()를 사용하세요. - 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()를 사용하세요. 베타로 제공됩니다. - Foundry:
com.anthropic:anthropic-java-foundry:FoundryBackend.fromEnv()또는FoundryBackend.builder()를 사용하세요.
새 프로젝트에는 BedrockMantleBackend를 사용하세요. BedrockBackend는 Bedrock InvokeModel API를 사용하는 기존 애플리케이션을 위해 유지됩니다.
각 Backend 구현은 AnthropicOkHttpClient.builder()에서 .backend()를 통해 클라이언트에 전달됩니다. 각 클라우드 백엔드는 해당 클라우드 플랫폼 SDK 클래스를 전이적 의존성으로 끌어옵니다.
고급 사용법
원시 응답 접근
HTTP 헤더, 상태 코드 및 원시 응답 본문에 접근하려면, 임의의 HTTP 메서드 호출 앞에 withRawResponse()를 붙이세요:
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)
.build();
HttpResponseFor<Message> message = client.messages().withRawResponse().create(params);
int statusCode = message.statusCode();
Headers headers = message.headers();필요한 경우 여전히 응답을 Java 클래스의 인스턴스로 역직렬화할 수 있습니다:
import com.anthropic.models.messages.Message;
Message parsedMessage = message.parse();로깅
SDK는 표준 OkHttp 로깅 인터셉터를 사용합니다.
ANTHROPIC_LOG 환경 변수를 info로 설정하여 로깅을 활성화하세요:
export ANTHROPIC_LOG=info또는 더 상세한 로깅을 위해 debug로 설정하세요:
export ANTHROPIC_LOG=debugSDK는 JSON 직렬화/역직렬화를 위해 Jackson에 의존합니다. 버전 2.13.4 이상과 호환되지만, 기본적으로 버전 2.19.4에 의존합니다.
SDK는 런타임에 호환되지 않는 Jackson 버전을 감지하면(예: Maven 또는 Gradle 구성에서 기본 버전이 재정의된 경우) 예외를 던집니다.
SDK가 예외를 던졌지만 버전이 호환된다고 확신한다면, AnthropicOkHttpClient 또는 AnthropicOkHttpClientAsync에서 checkJacksonVersionCompatibility를 사용하여 버전 검사를 비활성화하세요.
또한 이전 Jackson 버전에는 SDK에 영향을 줄 수 있는 버그가 있습니다. SDK는 모든 Jackson 버그를 우회하지 않으며, 대신 사용자가 해당 버그에 대해 Jackson을 업그레이드할 것을 기대합니다.
SDK는 리플렉션을 사용하지만, anthropic-java-core가 keep 규칙을 포함한 구성 파일과 함께 게시되므로 ProGuard 및 R8과 함께 사용할 수 있습니다.
ProGuard와 R8은 게시된 규칙을 자동으로 감지하고 사용해야 하지만, 필요한 경우 keep 규칙을 수동으로 복사할 수도 있습니다.
문서화되지 않은 API 기능
SDK는 문서화된 API를 편리하게 사용할 수 있도록 타입이 지정되어 있습니다. 그러나 문서화되지 않았거나 아직 지원되지 않는 API 부분과의 작업도 지원합니다.
문서화되지 않은 요청 매개변수
문서화되지 않은 요청 매개변수를 설정하려면, 문서화되지 않은 매개변수에 설명된 대로 putAdditionalHeader, putAdditionalQueryParam 또는 putAdditionalBodyProperty 메서드를 사용하세요.
문서화되지 않은 응답 속성
문서화되지 않은 응답 속성에 접근하려면, 응답 속성에 설명된 대로 _additionalProperties() 메서드를 사용하세요.
새로운 또는 미출시 enum 값
Model 및 AnthropicBeta와 같은 SDK의 enum 유사 클래스는 닫힌 Java enum 타입이 아닙니다. 각각은 임의의 문자열을 받는 of(String) 팩토리 메서드를 제공하므로, SDK 버전 이후에 출시된 모델이나 베타 헤더와 같이 아직 SDK에 추가되지 않은 값을 사용할 수 있습니다:
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 오버로드도 제공합니다:
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의 모든 기능과 도구의 가용성은 Claude로 빌드하기 개요에서 확인할 수 있습니다.
대부분의 베타 API 기능은 클라이언트의 beta() 메서드를 통해 접근할 수 있습니다. 특정 베타 기능을 활성화하려면, 메시지 매개변수를 빌드할 때 .addBeta()로 적절한 베타 헤더를 추가하세요.
예를 들어, 컨텍스트 편집을 활성화하려면:
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)
.maxTokens(1024L)
.addBeta(AnthropicBeta.CONTEXT_MANAGEMENT_2025_06_27)
.addUserMessage("Hello, Claude")
.build());
}자주 묻는 질문
Java enum 클래스는 간단하게 상위 호환되지 않습니다. SDK에서 이를 사용하면 API가 새로운 enum 값으로 응답하도록 업데이트될 경우 런타임 예외가 발생할 수 있습니다.
이러한 클래스는 열려 있으므로, of(String) 팩토리 메서드를 통해 임의의 문자열 값으로 생성할 수도 있습니다. 아직 SDK 버전에 없는 값을 사용해야 한다면 새로운 또는 미출시 enum 값을 참조하세요.
JsonField<T>를 사용하면 몇 가지 기능이 가능해집니다:
- 문서화되지 않은 API 기능 사용 허용
- 예상 형태에 대해 API 응답을 지연 검증
- 부재 값과 명시적 null 값의 구분 표현
데이터 클래스에 새 필드를 추가하는 것은 하위 호환되지 않으며, SDK는 클래스에 필드가 추가될 때마다 호환성을 깨는 변경을 도입하는 것을 피합니다.
검사 예외는 Java 프로그래밍 언어의 실수로 널리 여겨집니다. 실제로 이러한 이유로 Kotlin에서는 생략되었습니다.
검사 예외는:
- 처리하기 장황합니다
- 오류에 대해 아무것도 할 수 없는 잘못된 추상화 수준에서 오류 처리를 조장합니다
- 함수 색칠(function coloring) 문제로 인해 전파하기 번거롭습니다
- 람다와 잘 어울리지 않습니다(역시 함수 색칠 문제 때문)
시맨틱 버저닝
이 패키지는 일반적으로 SemVer 규칙을 따르지만, 특정 하위 호환되지 않는 변경 사항이 마이너 버전으로 릴리스될 수 있습니다:
- 기술적으로는 public이지만 외부 사용을 위해 의도되거나 문서화되지 않은 라이브러리 내부에 대한 변경.
- 실제로 대다수의 사용자에게 영향을 미치지 않을 것으로 예상되는 변경.
추가 리소스
Was this page helpful?