Java SDK
Установка и настройка Anthropic Java SDK с использованием паттерна builder и поддержкой асинхронных операций
Anthropic Java SDK предоставляет удобный доступ к Claude API из приложений, написанных на Java. Он использует паттерн builder (строитель) для создания запросов и поддерживает как синхронные, так и асинхронные операции.
Установка
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; в разделе Выбор рабочего пространства показан вариант настройки для отдельного запроса в этом SDK.
Параметры конфигурации
| Сеттер | Системное свойство | Переменная окружения | Обязательно | Значение по умолчанию |
|---|---|---|---|---|
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 может записывать поток событий в ответе по мере их обработки и накапливать объект Message, аналогичный тому, который был бы возвращён непотоковым API.
Для синхронного ответа добавьте вызов 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();Для асинхронного ответа добавьте MessageAccumulator в вызов subscribe():
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, см. в разделе Структурированные выходные данные.
Использование инструментов
Использование инструментов с Claude («tool use») позволяет интегрировать внешние инструменты и функции непосредственно в ответы ИИ-модели. Вместо генерации простого текста модель может выдавать инструкции (с параметрами) для вызова инструмента или функции, когда это уместно. Вы определяете JSON-схемы для инструментов, а модель использует эти схемы, чтобы определить, когда и как использовать эти инструменты.
Функция использования инструментов поддерживает «строгий» (strict) режим, который гарантирует, что JSON-вывод ИИ-модели будет соответствовать JSON-схеме, предоставленной вами во входных параметрах.
SDK может автоматически вывести инструмент и его параметры из структуры произвольного Java-класса: имя класса (преобразованное в snake case) задаёт имя инструмента, а поля класса определяют параметры инструмента.
Определение инструментов с помощью аннотаций
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>), а затем вызывайте их, если это запрошено в ответе ИИ-модели. BetaToolUseBlock.input(Class<T>) можно использовать для разбора параметров инструмента в формате JSON в экземпляр вашего класса, определяющего инструмент.
После вызова инструмента используйте BetaToolResultBlockParam.Builder.contentAsJson(Object), чтобы передать результат инструмента обратно ИИ-модели:
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");
}Преобразование имён инструментов
Имена инструментов выводятся из имён классов инструментов в camel case (например, GetWeather) и преобразуются в snake case (например, 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— задаёт имя инструмента, отличное от простого имени класса, преобразованного в snake case.@JsonPropertyDescription— добавляет подробное описание к параметру инструмента.@JsonIgnore— исключаетpublic-поле или геттер из генерируемой JSON-схемы параметров инструмента.@JsonProperty— включает не-publicполе или геттер в генерируемую JSON-схему параметров инструмента.
Пакеты сообщений
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 определяет методы, возвращающие бинарные ответы для ответов API, которые не обязательно разбираются как JSON:
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 выбрасывает собственные типы непроверяемых исключений:
AnthropicServiceException— базовый класс для HTTP-ошибок.AnthropicIoException— сетевые ошибки ввода-вывода.AnthropicRetryableException— общая ошибка, указывающая на сбой, который можно повторить.AnthropicInvalidDataException— невозможность интерпретировать успешно разобранные данные (например, при обращении к свойству, которое должно быть обязательным, но API неожиданно его опустил).AnthropicException— базовый класс для всех исключений.
Соответствие кодов состояния
| Статус | Исключение |
|---|---|
| 400 | BadRequestException |
| 401 | UnauthorizedException |
| 403 | PermissionDeniedException |
| 404 | NotFoundException |
| 422 | UnprocessableEntityException |
| 429 | RateLimitException |
| 5xx | InternalServerException |
| прочие | UnexpectedStatusCodeException |
SseException выбрасывается при ошибках, возникших во время потоковой передачи SSE после успешного начального HTTP-ответа.
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());
}Идентификаторы запросов
При использовании необработанных ответов вы можете получить доступ к заголовку ответа request-id с помощью метода requestId():
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. Дополнительную информацию об отладке запросов см. в разделе Идентификатор запроса.
Повторные попытки
По умолчанию 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
)
)
)Это даёт тайм-аут до 60 минут, масштабируемый параметром maxTokens, если он не переопределён.
Для непотоковых запросов динамический тайм-аут масштабируется от минимума в 30 секунд до максимума в 10 минут в зависимости от maxTokens.
Чтобы задать собственный тайм-аут для отдельного запроса:
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 периодически отправляет ping-запросы к 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();
}Система типов
Неизменяемость и builder-ы
Каждый класс в SDK имеет связанный builder для его создания. Каждый класс неизменяем после создания. Если у класса есть связанный builder, то у него есть метод toBuilder(), который можно использовать для обратного преобразования в builder с целью создания изменённой копии.
MessageCreateParams params = MessageCreateParams.builder()
.maxTokens(1024L)
.addUserMessage("Hello, Claude")
.model(Model.CLAUDE_OPUS_5)
.build();
// Создаём изменённую копию с помощью toBuilder()
MessageCreateParams modified = params.toBuilder().maxTokens(2048L).build();Поскольку каждый класс неизменяем, изменение builder-а никогда не влияет на уже созданные экземпляры классов.
Запросы и ответы
Чтобы отправить запрос к Claude API, создайте экземпляр некоторого класса Params и передайте его соответствующему методу клиента. Когда ответ получен, он десериализуется в экземпляр Java-класса.
Например, client.messages().create(...) следует вызывать с экземпляром MessageCreateParams, и он возвращает экземпляр Message.
Недокументированные параметры
Чтобы задать недокументированные параметры, вызовите методы putAdditionalHeader, putAdditionalQueryParam или putAdditionalBodyProperty на любом классе Params:
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().
Чтобы задать документированному параметру или свойству недокументированное или ещё не поддерживаемое значение, передайте объект 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!");
// Создание значения массива JSON, эквивалентного `["Hello", "World"]`
JsonValue arrayValue = JsonValue.from(List.of("Hello", "World"));
// Создание значения объекта JSON, эквивалентного `{ "a": 1, "b": 2 }`
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)));Принудительный пропуск обязательных параметров
Обычно метод build класса Builder выбрасывает 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. Не имеет собственной логики.
Такая структура позволяет заменить HTTP-клиент SDK по умолчанию, не подтягивая ненужные зависимости.
Настроенный OkHttpClient
Чтобы использовать настроенный OkHttpClient:
- Замените зависимость
anthropic-javaнаanthropic-java-core. - Скопируйте класс
OkHttpClientизanthropic-java-client-okhttpв свой код и настройте его. - Создайте
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: используйтеBedrockMantleBackend.fromEnv()илиBedrockMantleBackend.builder()для конечной точки Bedrock с Messages API, либоBedrockBackend.fromEnv()/BedrockBackend.builder()(путьbedrock-runtime). - Claude Platform на 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 остаётся для существующих приложений, использующих API Bedrock InvokeModel.
Каждая реализация Backend передаётся клиенту с помощью .backend() на AnthropicOkHttpClient.builder(). Каждый облачный бэкенд подтягивает классы 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 зависит от Jackson для сериализации/десериализации JSON. Он совместим с версией 2.13.4 или выше, но по умолчанию зависит от версии 2.19.4.
SDK выбрасывает исключение, если обнаруживает несовместимую версию Jackson во время выполнения (например, если версия по умолчанию была переопределена в вашей конфигурации Maven или Gradle).
Если SDK выбросил исключение, но вы уверены, что версия совместима, отключите проверку версии с помощью checkJacksonVersionCompatibility на AnthropicOkHttpClient или AnthropicOkHttpClientAsync.
В более старых версиях Jackson также есть ошибки, которые могут повлиять на SDK. SDK не обходит все ошибки Jackson и ожидает, что пользователи вместо этого обновят Jackson.
Хотя SDK использует рефлексию, его всё равно можно использовать с ProGuard и R8, поскольку anthropic-java-core публикуется с конфигурационным файлом, содержащим правила keep.
ProGuard и R8 должны автоматически обнаруживать и использовать опубликованные правила, но при необходимости вы также можете вручную скопировать правила keep.
Недокументированная функциональность API
SDK типизирован для удобного использования документированного API. Однако он также поддерживает работу с недокументированными или ещё не поддерживаемыми частями API.
Недокументированные параметры запроса
Чтобы задать недокументированные параметры запроса, используйте методы putAdditionalHeader, putAdditionalQueryParam или putAdditionalBodyProperty, как описано в разделе Недокументированные параметры.
Недокументированные свойства ответа
Чтобы получить доступ к недокументированным свойствам ответа, используйте метод _additionalProperties(), как описано в разделе Свойства ответа.
Новые или ещё не выпущенные значения перечислений
Классы SDK, подобные перечислениям, такие как Model и AnthropicBeta, не являются закрытыми 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");Методы builder-а, принимающие эти типы, часто также предоставляют перегрузку со String, которая вызывает of(...) за вас:
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 обновится и начнёт возвращать новое значение перечисления.
Поскольку эти классы открыты, вы также можете создавать их с любым строковым значением через их фабричный метод of(String). См. раздел Новые или ещё не выпущенные значения перечислений, если вам нужно использовать значение, которого ещё нет в вашей версии SDK.
Использование JsonField<T> обеспечивает несколько возможностей:
- Позволяет использовать недокументированную функциональность API
- Ленивая валидация ответа API на соответствие ожидаемой форме
- Представление отсутствующих значений в отличие от явно заданных null
Добавление новых полей в data-класс не является обратно совместимым, и SDK избегает внесения критических изменений каждый раз, когда в класс добавляется поле.
Проверяемые исключения широко считаются ошибкой в языке программирования Java. Фактически, по этой причине они были исключены из Kotlin.
Проверяемые исключения:
- Многословны в обработке
- Поощряют обработку ошибок на неправильном уровне абстракции, где с ошибкой ничего нельзя сделать
- Утомительны в распространении из-за проблемы «окрашивания функций» (function coloring)
- Плохо сочетаются с лямбдами (также из-за проблемы окрашивания функций)
Семантическое версионирование
Этот пакет в целом следует соглашениям SemVer, хотя некоторые обратно несовместимые изменения могут выпускаться как минорные версии:
- Изменения во внутренних компонентах библиотеки, которые технически являются публичными, но не предназначены и не документированы для внешнего использования.
- Изменения, которые, как ожидается, на практике не затронут подавляющее большинство пользователей.
Дополнительные ресурсы
Was this page helpful?