Java SDK
Instala y configura el SDK de Java de Anthropic con patrones builder y soporte asíncrono
El SDK de Java de Anthropic proporciona acceso conveniente a la API de Claude desde aplicaciones escritas en Java. Utiliza el patrón builder para crear solicitudes y admite operaciones tanto síncronas como asíncronas.
Instalación
implementation("com.anthropic:anthropic-java:3.3.0")<dependency>
<groupId>com.anthropic</groupId>
<artifactId>anthropic-java</artifactId>
<version>3.3.0</version>
</dependency>Requisitos
Esta biblioteca requiere Java 8 o posterior.
Inicio rápido
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;
// Configura usando las propiedades del sistema `anthropic.apiKey`, `anthropic.authToken` y `anthropic.baseUrl`
// O configura usando las variables de entorno `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN` y `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);Configuración del cliente
Configuración de la clave de API
Configura el cliente usando propiedades del sistema o variables de entorno:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
// Configura usando las propiedades del sistema `anthropic.apiKey`, `anthropic.authToken` y `anthropic.baseUrl`
// O configura usando las variables de entorno `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN` y `ANTHROPIC_BASE_URL`
AnthropicClient client = AnthropicOkHttpClient.fromEnv();O configúralo manualmente:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
AnthropicClient client = AnthropicOkHttpClient.builder()
.apiKey("my-anthropic-api-key")
.build();O usa una combinación de ambos enfoques:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
AnthropicClient client = AnthropicOkHttpClient.builder()
// Configura usando propiedades del sistema o variables de entorno
.fromEnv()
.apiKey("my-anthropic-api-key")
.build();Para conocer las opciones de autenticación, incluida "Workload Identity Federation" (federación de identidades de carga de trabajo), consulta Autenticación. Si tu "API key" (clave de API) es una clave personal o de cuenta de servicio que no está limitada a un espacio de trabajo, establece el ID del espacio de trabajo en el encabezado de solicitud anthropic-workspace-id; Seleccionar un espacio de trabajo muestra la opción por solicitud para este SDK.
Opciones de configuración
| Setter | Propiedad del sistema | Variable de entorno | Obligatorio | Valor predeterminado |
|---|---|---|---|---|
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" |
Las propiedades del sistema tienen prioridad sobre las variables de entorno.
Modificar la configuración
Para usar temporalmente una configuración de cliente modificada mientras reutilizas los mismos pools de conexiones y de hilos, llama a withOptions() en cualquier cliente o servicio:
import com.anthropic.client.AnthropicClient;
AnthropicClient clientWithOptions = client.withOptions(optionsBuilder -> {
optionsBuilder.baseUrl("https://example.com");
optionsBuilder.maxRetries(42);
});El método withOptions() no afecta al cliente o servicio original.
Uso asíncrono
El cliente predeterminado es síncrono. Para cambiar a ejecución asíncrona, llama al método 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_5)
.build();
CompletableFuture<Message> message = client.async().messages().create(params);O crea un cliente asíncrono desde el principio:
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);El cliente asíncrono admite las mismas opciones que el síncrono, excepto que la mayoría de los métodos devuelven CompletableFutures.
Streaming
El SDK define métodos que devuelven streams de "chunks" (fragmentos) de respuesta, donde cada fragmento puede procesarse individualmente en cuanto llega, en lugar de esperar la respuesta completa.
Streaming síncrono
Estos métodos de streaming devuelven StreamResponse para clientes síncronos:
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!");
}Streaming asíncrono
Para clientes asíncronos, el método devuelve AsyncStreamResponse:
import com.anthropic.core.http.AsyncStreamResponse;
import com.anthropic.models.messages.RawMessageStreamEvent;
client.async().messages().createStreaming(params).subscribe(chunk -> {
IO.println(chunk);
});
// Si necesitas manejar errores o la finalización del stream
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!");
}
}
});
// O usa 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!");
}
});El streaming asíncrono usa un Executor dedicado de pool de hilos en caché por cliente para hacer streaming sin bloquear el hilo actual. Para usar un Executor diferente:
Executor executor = Executors.newFixedThreadPool(4);
client.async().messages().createStreaming(params).subscribe(
chunk -> IO.println(chunk), executor
);O configura el cliente globalmente usando el método streamHandlerExecutor:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
AnthropicClient client = AnthropicOkHttpClient.builder()
.fromEnv()
.streamHandlerExecutor(Executors.newFixedThreadPool(4))
.build();Streaming con acumulador de mensajes
Un MessageAccumulator puede registrar el stream de eventos de la respuesta a medida que se procesan y acumular un objeto Message similar al que habría devuelto la API sin streaming.
Para una respuesta síncrona, agrega una llamada a Stream.peek() al pipeline del stream para acumular cada evento:
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();Para una respuesta asíncrona, agrega el MessageAccumulator a la llamada 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();También está disponible un BetaMessageAccumulator para acumular un objeto BetaMessage. Se usa de la misma manera que el MessageAccumulator.
Salidas estructuradas
Para consultar la documentación completa de salidas estructuradas, incluidos ejemplos en Java, consulta Salidas estructuradas.
Uso de herramientas
El uso de herramientas con Claude te permite integrar herramientas y funciones externas directamente en las respuestas del modelo de IA. En lugar de producir texto plano, el modelo puede generar instrucciones (con parámetros) para llamar a una herramienta o función cuando corresponda. Tú defines esquemas JSON para las herramientas, y el modelo usa los esquemas para determinar cuándo y cómo usar estas herramientas.
La función de uso de herramientas admite un modo "strict" (estricto) que garantiza que la salida JSON del modelo de IA se ajustará al esquema JSON que proporciones en los parámetros de entrada.
El SDK puede derivar automáticamente una herramienta y sus parámetros a partir de la estructura de una clase Java arbitraria: el nombre de la clase (convertido a snake case) proporciona el nombre de la herramienta, y los campos de la clase definen los parámetros de la herramienta.
Definir herramientas con anotaciones
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;
}
}Llamar a herramientas
Cuando tus clases de herramientas estén definidas, agrégalas a los parámetros del mensaje usando MessageCreateParams.Builder.addTool(Class<T>) y luego llámalas si así se solicita en la respuesta del modelo de IA. BetaToolUseBlock.input(Class<T>) puede usarse para analizar los parámetros de una herramienta en formato JSON y convertirlos en una instancia de tu clase que define la herramienta.
Después de llamar a la herramienta, usa BetaToolResultBlockParam.Builder.contentAsJson(Object) para devolver el resultado de la herramienta al modelo de IA:
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
// Agrega un mensaje que indique que se solicitó el uso de herramientas.
.addAssistantMessageOfContentBlockParams(
List.of(BetaContentBlockParam.ofToolUse(BetaToolUseBlockParam.builder()
.name(toolUseBlock.name())
.id(toolUseBlock.id())
.input(toolUseBlock._input())
.build())))
// Agrega un mensaje con el resultado del uso de herramientas solicitado.
.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");
}Conversión de nombres de herramientas
Los nombres de las herramientas se derivan de los nombres de las clases de herramientas en camel case (por ejemplo, GetWeather) y se convierten a snake case (por ejemplo, get_weather). Los límites de palabra comienzan donde el carácter actual no es el primer carácter, está en mayúscula, y el carácter anterior está en minúscula o el carácter siguiente está en minúscula. Por ejemplo, MyJSONParser se convierte en my_json_parser y ParseJSON se convierte en parse_json. Esta conversión puede anularse usando la anotación @JsonTypeName.
Validación local del esquema JSON de herramientas
Puedes realizar una validación local para comprobar que el esquema JSON derivado de tu clase de herramienta respeta las restricciones de Anthropic. La validación local está habilitada de forma predeterminada, pero puede deshabilitarse:
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?");Anotar clases de herramientas
Puedes usar anotaciones para agregar más información sobre las herramientas a los esquemas JSON:
@JsonClassDescription- Agrega una descripción a una clase de herramienta que detalla cuándo y cómo usar esa herramienta.@JsonTypeName- Establece el nombre de la herramienta en algo distinto del nombre simple de la clase convertido a snake case.@JsonPropertyDescription- Agrega una descripción detallada a un parámetro de la herramienta.@JsonIgnore- Excluye un campo o método getterpublicdel esquema JSON generado para los parámetros de una herramienta.@JsonProperty- Incluye un campo o método getter nopublicen el esquema JSON generado para los parámetros de una herramienta.
Lotes de mensajes
El SDK ofrece soporte para el procesamiento por lotes bajo el espacio de nombres client.messages().batches(). Consulta Paginación para saber cómo listar y paginar los lotes.
Carga de archivos
El SDK define métodos que aceptan archivos a través de la clase 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);O desde un 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);O desde bytes en memoria:
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);Respuestas binarias
El SDK define métodos que devuelven respuestas binarias para respuestas de la API que no necesariamente se analizan como JSON:
import com.anthropic.core.http.HttpResponse;
HttpResponse response = client.files().download("file_abc123");Para guardar el contenido de la respuesta en un archivo:
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);
}O transfiere el contenido de la respuesta a cualquier 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);
}Manejo de errores
El SDK lanza tipos de excepciones no verificadas personalizadas:
AnthropicServiceException- Clase base para errores HTTP.AnthropicIoException- Errores de red de E/S.AnthropicRetryableException- Error genérico que indica un fallo que podría reintentarse.AnthropicInvalidDataException- Fallo al interpretar datos analizados correctamente (por ejemplo, al acceder a una propiedad que se supone obligatoria, pero que la API omitió inesperadamente).AnthropicException- Clase base para todas las excepciones.
Asignación de códigos de estado
| Estado | Excepción |
|---|---|
| 400 | BadRequestException |
| 401 | UnauthorizedException |
| 403 | PermissionDeniedException |
| 404 | NotFoundException |
| 422 | UnprocessableEntityException |
| 429 | RateLimitException |
| 5xx | InternalServerException |
| otros | UnexpectedStatusCodeException |
SseException se lanza para errores encontrados durante el streaming SSE después de una respuesta HTTP inicial exitosa.
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());
}IDs de solicitud
Al usar respuestas sin procesar, puedes acceder al encabezado de respuesta request-id usando el método 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();Esto puede usarse para registrar rápidamente las solicitudes fallidas y reportarlas a Anthropic. Para obtener más información sobre la depuración de solicitudes, consulta ID de solicitud.
Reintentos
El SDK reintenta automáticamente 2 veces de forma predeterminada, con un breve retroceso exponencial entre solicitudes.
Solo se reintentan los siguientes tipos de error:
- Errores de conexión (por ejemplo, debido a un problema de conectividad de red)
- 408 Request Timeout
- 409 Conflict
- 429 Rate Limit
- 5xx Internal
La API también puede indicar explícitamente al SDK que reintente o no una solicitud.
Para establecer un número personalizado de reintentos, configura el cliente usando el método maxRetries:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
AnthropicClient client = AnthropicOkHttpClient.builder().fromEnv().maxRetries(4).build();Tiempos de espera
Las solicitudes agotan su tiempo de espera después de 10 minutos de forma predeterminada.
Sin embargo, para los métodos que aceptan maxTokens, si especificas un valor grande de maxTokens y estás usando streaming, el tiempo de espera predeterminado se calculará dinámicamente usando esta fórmula:
Duration.ofSeconds(
Math.min(
60 * 60, // 1 hour max
Math.max(
10 * 60, // 10 minute minimum
60 * 60 * maxTokens / 128_000
)
)
)Esto da como resultado un tiempo de espera de hasta 60 minutos, escalado según el parámetro maxTokens, a menos que se anule.
Para solicitudes sin streaming, el tiempo de espera dinámico escala desde un mínimo de 30 segundos hasta un máximo de 10 minutos según maxTokens.
Para establecer un tiempo de espera personalizado por solicitud:
import com.anthropic.models.messages.Message;
Message message = client
.messages()
.create(params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build());O configura el valor predeterminado para todas las llamadas a métodos a nivel de cliente:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
AnthropicClient client = AnthropicOkHttpClient.builder()
.fromEnv()
.timeout(Duration.ofSeconds(30))
.build();Solicitudes largas
Evita establecer un valor grande de maxTokens sin usar streaming. Algunas redes pueden cerrar las conexiones inactivas después de cierto período de tiempo, lo que puede hacer que la solicitud falle o agote el tiempo de espera sin recibir una respuesta de Anthropic. El SDK envía pings periódicamente a la API para mantener viva la conexión y reducir el impacto de estas redes.
El SDK lanza un error si se espera que una solicitud sin streaming tarde más de 10 minutos. Usar un método de streaming o anular el tiempo de espera a nivel de cliente o de solicitud deshabilita el error.
Paginación
El SDK ofrece formas convenientes de acceder a resultados paginados, ya sea una página a la vez o elemento por elemento a través de todas las páginas.
Paginación automática
Para iterar por todos los resultados de todas las páginas, usa el método autoPager(), que obtiene automáticamente más páginas según sea necesario.
import com.anthropic.models.messages.batches.BatchListPage;
import com.anthropic.models.messages.batches.MessageBatch;
BatchListPage page = client.messages().batches().list();
// Procesar como un Iterable
for (MessageBatch batch : page.autoPager()) {
IO.println(batch);
}
// Procesar como un Stream
page.autoPager()
.stream()
.limit(50)
.forEach(batch -> IO.println(batch));Al usar el cliente asíncrono, el método devuelve un 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);
}));
// Si necesitas manejar errores o la finalización del stream
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!");
}
}
}));
// O usa 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!");
}
}));Paginación manual
Para acceder a los elementos individuales de una página y solicitar manualmente la página siguiente:
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();
}Sistema de tipos
Inmutabilidad y builders
Cada clase del SDK tiene un builder asociado para construirla. Cada clase es inmutable una vez construida. Si la clase tiene un builder asociado, entonces tiene un método toBuilder(), que puede usarse para convertirla de nuevo en un builder y crear una copia modificada.
MessageCreateParams params = MessageCreateParams.builder()
.maxTokens(1024L)
.addUserMessage("Hello, Claude")
.model(Model.CLAUDE_OPUS_5_5)
.build();
// Crea una copia modificada usando toBuilder()
MessageCreateParams modified = params.toBuilder().maxTokens(2048L).build();Como cada clase es inmutable, la modificación del builder nunca afecta a las instancias de clase ya construidas.
Solicitudes y respuestas
Para enviar una solicitud a la API de Claude, construye una instancia de alguna clase Params y pásala al método de cliente correspondiente. Cuando se recibe la respuesta, se deserializa en una instancia de una clase Java.
Por ejemplo, client.messages().create(...) debe llamarse con una instancia de MessageCreateParams, y devuelve una instancia de Message.
Parámetros no documentados
Para establecer parámetros no documentados, llama a los métodos putAdditionalHeader, putAdditionalQueryParam o putAdditionalBodyProperty en cualquier clase 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();Se puede acceder a estos más adelante en el objeto construido usando los métodos _additionalHeaders(), _additionalQueryParams() y _additionalBodyProperties().
Para establecer parámetros no documentados en clases anidadas de encabezados, parámetros de consulta o cuerpo:
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();Se puede acceder a estas propiedades más adelante en el objeto anidado construido usando el método _additionalProperties().
Para establecer un parámetro o propiedad documentado en un valor no documentado o aún no compatible, pasa un objeto JsonValue a su setter:
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();Creación de JsonValue
La forma más sencilla de crear un JsonValue es usar su método from(...):
import com.anthropic.core.JsonValue;
// Crea valores JSON primitivos
JsonValue nullValue = JsonValue.from(null);
JsonValue booleanValue = JsonValue.from(true);
JsonValue numberValue = JsonValue.from(42);
JsonValue stringValue = JsonValue.from("Hello World!");
// Crea un valor de arreglo JSON equivalente a `["Hello", "World"]`
JsonValue arrayValue = JsonValue.from(List.of("Hello", "World"));
// Crea un valor de objeto JSON equivalente a `{ "a": 1, "b": 2 }`
JsonValue objectValue = JsonValue.from(Map.of("a", 1, "b", 2));
// Crea un JSON anidado arbitrariamente equivalente a:
// { "a": [1, 2], "b": [3, 4] }
JsonValue complexValue = JsonValue.from(Map.of("a", List.of(1, 2), "b", List.of(3, 4)));Omitir forzosamente parámetros obligatorios
Normalmente, el método build de una clase Builder lanzará IllegalStateException si algún parámetro o propiedad obligatorio no está establecido. Para omitir forzosamente un parámetro o propiedad obligatorio, pasa 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_5)
.maxTokens(JsonMissing.of())
.build();Propiedades de la respuesta
Para acceder a propiedades de respuesta no documentadas, llama al método _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!";
}
// Otros métodos incluyen `visitMissing`, `visitString`, `visitArray` y `visitObject`
// La implementación predeterminada de cada método no implementado delega en `visitDefault`,
// que lanza una excepción por defecto, pero también se puede sobrescribir
});Para acceder al valor JSON sin procesar de una propiedad, llama a su método con prefijo _:
import com.anthropic.core.JsonField;
import com.anthropic.models.messages.StopReason;
JsonField<StopReason> stopReason = client.messages().create(params)._stopReason();
if (stopReason.isMissing()) {
// La propiedad no está presente en la respuesta JSON
} else if (stopReason.isNull()) {
// La propiedad se estableció en null literal
} else {
// Comprueba si el valor se proporcionó como cadena
// Otros métodos incluyen `asNumber()`, `asBoolean()`, etc.
Optional<String> jsonString = stopReason.asString();
// Intenta deserializar en un tipo personalizado
MyClass myObject = stopReason.asUnknown().orElseThrow().convert(MyClass.class);
}Validación de respuestas
De forma predeterminada, el SDK no lanza una excepción cuando la API devuelve una respuesta que no coincide con el tipo esperado. Lanza AnthropicInvalidDataException solo si accedes directamente a la propiedad.
Para comprobar de antemano que la respuesta está completamente bien tipada, llama a validate():
import com.anthropic.models.messages.Message;
Message message = client.messages().create(params).validate();O configúralo por solicitud:
import com.anthropic.models.messages.Message;
Message message = client
.messages()
.create(params, RequestOptions.builder().responseValidation(true).build());O configura el valor predeterminado para todas las llamadas a métodos a nivel de cliente:
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
AnthropicClient client = AnthropicOkHttpClient.builder()
.fromEnv()
.responseValidation(true)
.build();Personalización del cliente HTTP
Configuración de proxy
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();Configuración de 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();Cliente HTTP personalizado
El SDK consta de tres artefactos:
anthropic-java-core- Contiene la lógica principal del SDK y no depende de OkHttp. ExponeAnthropicClient,AnthropicClientAsyncy sus clases de implementación, todas las cuales pueden funcionar con cualquier cliente HTTP.anthropic-java-client-okhttp- Depende de OkHttp. ExponeAnthropicOkHttpClientyAnthropicOkHttpClientAsync.anthropic-java- Depende de las API deanthropic-java-coreyanthropic-java-client-okhttpy las expone. No tiene lógica propia.
Esta estructura permite reemplazar el cliente HTTP predeterminado del SDK sin incorporar dependencias innecesarias.
OkHttpClient personalizado
Para usar un OkHttpClient personalizado:
- Reemplaza tu dependencia
anthropic-javaporanthropic-java-core. - Copia la clase
OkHttpClientdeanthropic-java-client-okhttpen tu código y personalízala. - Construye
AnthropicClientImploAnthropicClientAsyncImplusando tu cliente personalizado.
Cliente HTTP completamente personalizado
Para usar un cliente HTTP completamente personalizado:
- Reemplaza tu dependencia
anthropic-javaporanthropic-java-core. - Escribe una clase que implemente la interfaz
HttpClient. - Construye
AnthropicClientImploAnthropicClientAsyncImplusando tu nueva clase de cliente.
Integraciones de plataforma
El SDK de Java es compatible con las siguientes plataformas mediante dependencias separadas que proporcionan implementaciones de Backend específicas de cada plataforma:
- Agent Platform:
com.anthropic:anthropic-java-vertex: UsaVertexBackend.builder()oVertexBackend.fromEnv().fromEnv()leeCLOUD_ML_REGIONyANTHROPIC_VERTEX_PROJECT_IDy usa Application Default Credentials. - Bedrock:
com.anthropic:anthropic-java-bedrock: UsaBedrockMantleBackend.fromEnv()oBedrockMantleBackend.builder()para el endpoint de Bedrock de la Messages API, oBedrockBackend.fromEnv()/BedrockBackend.builder()(rutabedrock-runtime). - Claude Platform en AWS:
com.anthropic:anthropic-java-aws: UsaAwsBackend.fromEnv()(leeANTHROPIC_AWS_WORKSPACE_IDy la cadena predeterminada de región/credenciales de AWS) oAwsBackend.builder(). Disponible en beta. - Foundry:
com.anthropic:anthropic-java-foundry: UsaFoundryBackend.fromEnv()oFoundryBackend.builder().
Usa BedrockMantleBackend para proyectos nuevos; BedrockBackend se mantiene para las aplicaciones existentes que usan la API InvokeModel de Bedrock.
El SDK de Java también es compatible con Claude Models on Google Cloud (Anthropic managed) a través de GoogleCloudBackend, de la dependencia com.anthropic:anthropic-java-google-cloud. Este backend está en beta. Créalo con GoogleCloudBackend.builder() o GoogleCloudBackend.fromEnv(). fromEnv() lee ANTHROPIC_GOOGLE_CLOUD_WORKSPACE_ID, ANTHROPIC_GOOGLE_CLOUD_PROJECT y las credenciales predeterminadas de aplicación (Application Default Credentials) de Google. Consulta Resolución del proyecto, la ubicación y el workspace.
Los artefactos de plataforma son complementos de la dependencia base com.anthropic:anthropic-java, que proporciona AnthropicOkHttpClient, así que instala ambos. Cada implementación de Backend se pasa al cliente con .backend() en AnthropicOkHttpClient.builder(). Cada backend de nube incorpora las clases del SDK de su respectiva plataforma en la nube como dependencias transitivas.
Uso avanzado
Acceso a la respuesta sin procesar
Para acceder a los encabezados HTTP, los códigos de estado y el cuerpo de la respuesta sin procesar, antepone withRawResponse() a cualquier llamada a un método HTTP:
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();Aún puedes deserializar la respuesta en una instancia de una clase Java si es necesario:
import com.anthropic.models.messages.Message;
Message parsedMessage = message.parse();Registro
El SDK usa el interceptor de registro estándar de OkHttp.
Habilita el registro estableciendo la variable de entorno ANTHROPIC_LOG en info:
export ANTHROPIC_LOG=infoO en debug para un registro más detallado:
export ANTHROPIC_LOG=debugEl SDK depende de Jackson para la serialización/deserialización de JSON. Es compatible con la versión 2.13.4 o superior, pero depende de la versión 2.19.4 de forma predeterminada.
El SDK lanza una excepción si detecta una versión incompatible de Jackson en tiempo de ejecución (por ejemplo, si la versión predeterminada se anuló en tu configuración de Maven o Gradle).
Si el SDK lanzó una excepción, pero estás seguro de que la versión es compatible, deshabilita la comprobación de versión usando checkJacksonVersionCompatibility en AnthropicOkHttpClient o AnthropicOkHttpClientAsync.
También existen errores en versiones anteriores de Jackson que pueden afectar al SDK. El SDK no soluciona todos los errores de Jackson y espera que los usuarios actualicen Jackson para resolverlos.
Aunque el SDK usa reflexión, sigue siendo utilizable con ProGuard y R8 porque anthropic-java-core se publica con un archivo de configuración que contiene reglas keep.
ProGuard y R8 deberían detectar y usar automáticamente las reglas publicadas, pero también puedes copiar manualmente las reglas keep si es necesario.
Trazado de OpenTelemetry
Cuando tu aplicación registra un tracer provider de OpenTelemetry, el SDK emite un span por cada solicitud que envía. Para enviar los spans a tu plataforma de observabilidad, consulta Configura OpenTelemetry con el Claude SDK.
Funcionalidad de la API no documentada
El SDK está tipado para un uso conveniente de la API documentada. Sin embargo, también admite trabajar con partes de la API no documentadas o aún no compatibles.
Parámetros de solicitud no documentados
Para establecer parámetros de solicitud no documentados, usa los métodos putAdditionalHeader, putAdditionalQueryParam o putAdditionalBodyProperty como se describe en Parámetros no documentados.
Propiedades de respuesta no documentadas
Para acceder a propiedades de respuesta no documentadas, usa el método _additionalProperties() como se describe en Propiedades de la respuesta.
Valores de enum nuevos o no publicados
Las clases tipo enum del SDK, como Model y AnthropicBeta, no son tipos enum cerrados de Java. Cada una proporciona un método de fábrica of(String) que acepta cualquier cadena, por lo que puedes usar valores que aún no se han agregado al SDK, como un modelo o un encabezado beta publicado después de tu versión del 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");Los métodos del builder que aceptan estos tipos a menudo también proporcionan una sobrecarga String que llama a of(...) por ti:
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();Prefiere las constantes bien tipadas (por ejemplo, Model.CLAUDE_OPUS_5) para obtener autocompletado y advertencias de obsolescencia. Las sobrecargas String y of(...) sirven principalmente para establecer el campo en un valor no documentado o aún no compatible mientras esperas una versión del SDK que lo incluya.
Funciones beta
Las funciones beta están disponibles antes del lanzamiento general para obtener comentarios tempranos y probar nuevas funcionalidades. Puedes consultar la disponibilidad de todas las capacidades y herramientas de Claude en la descripción general de funciones.
Puedes acceder a la mayoría de las funciones beta de la API a través del método beta() del cliente. Para habilitar una función beta en particular, agrega el encabezado beta correspondiente con .addBeta() al construir los parámetros del mensaje.
Por ejemplo, para habilitar la edición de contexto:
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());
}Preguntas frecuentes
Las clases enum de Java no son trivialmente compatibles hacia adelante. Usarlas en el SDK podría causar excepciones en tiempo de ejecución si la API se actualiza para responder con un nuevo valor de enum.
Como estas clases son abiertas, también puedes construirlas con cualquier valor de cadena mediante su método de fábrica of(String). Consulta Valores de enum nuevos o no publicados si necesitas usar un valor que aún no está en tu versión del SDK.
Usar JsonField<T> habilita algunas funciones:
- Permitir el uso de funcionalidad de la API no documentada
- Validar de forma diferida la respuesta de la API contra la forma esperada
- Representar valores ausentes frente a valores explícitamente nulos
Agregar nuevos campos a una clase de datos no es compatible con versiones anteriores, y el SDK evita introducir un cambio incompatible cada vez que se agrega un campo a una clase.
Las excepciones verificadas se consideran ampliamente un error en el lenguaje de programación Java. De hecho, se omitieron de Kotlin por esta razón.
Las excepciones verificadas:
- Son verbosas de manejar
- Fomentan el manejo de errores en el nivel de abstracción incorrecto, donde no se puede hacer nada con el error
- Son tediosas de propagar debido al problema de coloreado de funciones
- No funcionan bien con lambdas (también debido al problema de coloreado de funciones)
Versionado semántico
Cada versión principal de este SDK envía una versión de la API en el encabezado anthropic-version de forma predeterminada, y con cada nueva versión de la API llega una nueva versión principal. La primera versión principal que envía 2026-10-21 es la 3.0.0; consulta Migrar a la versión de la API 2026-10-21.
Este paquete generalmente sigue las convenciones de SemVer, aunque ciertos cambios incompatibles con versiones anteriores pueden publicarse como versiones menores:
- Cambios en los componentes internos de la biblioteca que técnicamente son públicos, pero que no están destinados ni documentados para uso externo.
- Cambios que no se espera que afecten en la práctica a la gran mayoría de los usuarios.
Recursos adicionales
Was this page helpful?