SDK de Java
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 Claude API 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:2.58.0")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;
// Se configura usando las propiedades del sistema `anthropic.apiKey`, `anthropic.authToken` y `anthropic.baseUrl`
// O se 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)
.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()
// Se configura mediante 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, consulta Autenticación. Si tu clave de API es una clave personal o de cuenta de servicio con acceso a múltiples espacios 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 | Requerido | 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.
Modificación de la configuración
Para usar temporalmente una configuración de cliente modificada mientras reutilizas los mismos pools de conexiones e 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)
.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)
.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 flujos de "chunks" (fragmentos) de respuesta, donde cada fragmento puede procesarse individualmente tan pronto como 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 de pool de hilos en caché dedicado 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 flujo 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 la acumulación de un objeto BetaMessage. Se usa de la misma manera que el MessageAccumulator.
Salidas estructuradas
Para la documentación completa de salidas estructuradas, incluidos ejemplos en Java, consulta Salidas estructuradas.
Uso de herramientas
El "tool use" (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 sea apropiado. Tú defines esquemas JSON para las herramientas, y el modelo usa los esquemas para determinar cuándo y cómo usar estas herramientas.
La funcionalidad 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 una herramienta y sus parámetros automáticamente 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.
Definición de 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;
}
}Llamada 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 pasar el resultado de la herramienta de vuelta 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)
.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.
.addAssistantMessageOfBetaContentBlockParams(
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.
.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");
}Conversión de nombres de herramientas
Los nombres de las herramientas se derivan de los nombres en camel case de las clases de herramientas (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 o bien el carácter anterior está en minúscula, o bien 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 sobrescribirse 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)
.maxTokens(2048)
.addTool(GetWeather.class, JsonSchemaLocalValidation.NO)
.addUserMessage("What's the temperature in New York?");Anotación de 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 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 proporciona 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 transferir 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 (unchecked) 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 que es obligatoria, pero que la API omitió inesperadamente).AnthropicException- Clase base para todas las excepciones.
Mapeo 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 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 backoff 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 reintente 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 el 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 sobrescriba.
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 descartar 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 hace ping periódicamente a la API para mantener la conexión activa 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 sobrescribir el tiempo de espera a nivel de cliente o de solicitud deshabilita el error.
Paginación
El SDK proporciona 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 de páginas individuales 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 hacer una copia modificada.
MessageCreateParams params = MessageCreateParams.builder()
.maxTokens(1024L)
.addUserMessage("Hello, Claude")
.model(Model.CLAUDE_OPUS_5)
.build();
// Crea una copia modificada usando toBuilder()
MessageCreateParams modified = params.toBuilder().maxTokens(2048L).build();Dado que 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 Claude API, construye una instancia de alguna clase Params y pásala al método del 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 tarde 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 tarde 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 admitido, 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)
.build();Creación de JsonValue
La forma más directa de crear un JsonValue es usando 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)));Omisión forzada de 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)
.maxTokens(JsonMissing.of())
.build();Propiedades de 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 está ausente en la respuesta JSON
} else if (stopReason.isNull()) {
// La propiedad se estableció como null literal
} else {
// Verifica 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 central del SDK, 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 y expone las APIs tanto deanthropic-java-corecomo deanthropic-java-client-okhttp. 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 con plataformas
El SDK de Java admite las siguientes plataformas a través de dependencias separadas que proporcionan implementaciones de Backend específicas de cada plataforma:
- Agent Platform:
com.anthropic:anthropic-java-vertex: UsaVertexBackend.fromEnv()oVertexBackend.builder(). - 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 aplicaciones existentes que usan la API InvokeModel de Bedrock.
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 de nube como dependencias transitivas.
Uso avanzado
Acceso a respuestas sin procesar
Para acceder a los encabezados HTTP, los códigos de estado y el cuerpo de la respuesta sin procesar, antepón 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)
.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 de logs
El SDK usa el interceptor de logging estándar de OkHttp.
Habilita el logging estableciendo la variable de entorno ANTHROPIC_LOG en info:
export ANTHROPIC_LOG=infoO en debug para un logging 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 de Jackson incompatible en tiempo de ejecución (por ejemplo, si la versión predeterminada fue sobrescrita 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 verificación de versión usando checkJacksonVersionCompatibility en AnthropicOkHttpClient o AnthropicOkHttpClientAsync.
También hay errores en versiones antiguas de Jackson que pueden afectar al SDK. El SDK no implementa soluciones alternativas para todos los errores de Jackson y espera que los usuarios actualicen Jackson en esos casos.
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.
Funcionalidad no documentada de la API
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 admitidas.
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 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 builder que aceptan estos tipos a menudo también proporcionan una sobrecarga de 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 de String y of(...) son principalmente para establecer el campo en un valor no documentado o aún no admitido mientras esperas una versión del SDK que lo incluya.
Funcionalidades beta
Las funcionalidades beta están disponibles antes del lanzamiento general para obtener retroalimentación temprana y probar nuevas funcionalidades. Puedes verificar la disponibilidad de todas las capacidades y herramientas de Claude en la descripción general de construir con Claude.
Puedes acceder a la mayoría de las funcionalidades beta de la API a través del método beta() del cliente. Para habilitar una funcionalidad beta en particular, agrega el encabezado beta apropiado 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)
.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.
Dado que estas clases son abiertas, también puedes construirlas con cualquier valor de cadena a través de 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 funcionalidades:
- Permitir el uso de funcionalidad no documentada de la API
- Validar de forma diferida la respuesta de la API contra la forma esperada
- Representar valores ausentes frente a valores explícitamente null
Agregar nuevos campos a una clase de datos no es compatible hacia atrás, 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 equivocado, donde no se puede hacer nada respecto al error
- Son tediosas de propagar debido al problema de coloración de funciones
- No funcionan bien con lambdas (también debido al problema de coloración de funciones)
Versionado semántico
Este paquete generalmente sigue las convenciones de SemVer, aunque ciertos cambios incompatibles hacia atrás pueden publicarse como versiones menores:
- Cambios en los componentes internos de la biblioteca que técnicamente son públicos pero no están destinados ni documentados para uso externo.
- Cambios que no se espera que afecten a la gran mayoría de los usuarios en la práctica.
Recursos adicionales
Was this page helpful?