---
title: SDK de Java
url: https://platform.claude.com/docs/es/cli-sdks-libraries/sdks/java
description: 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.

<Info>
  Para la documentación de las funcionalidades de la API con ejemplos de código, consulta la [referencia de la API](https://platform.claude.com/docs/es/api/overview). Esta página cubre las funcionalidades y la configuración del SDK específicas de Java.
</Info>

## Instalación

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

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

## Requisitos

Esta biblioteca requiere Java 8 o posterior.

<Note>
  El SDK es compatible con Java 8 y versiones posteriores. Los ejemplos de código en esta documentación están escritos como [archivos fuente compactos de JDK 25](https://openjdk.org/jeps/512), usando un punto de entrada `void main()` simple e `IO.println()` para la salida. Las llamadas a la API en sí son idénticas en todos los JDK compatibles; para compilar un ejemplo en una versión anterior, reemplaza `IO.println(...)` por `System.out.println(...)` y coloca el cuerpo dentro de `public static void main(String[] args)` en una clase.
</Note>

## Inicio rápido

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

// 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_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:

```java
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:

```java
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:

```java
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](https://platform.claude.com/docs/es/manage-claude/authentication). Si tu clave de API es una [clave personal o de cuenta de servicio](https://platform.claude.com/docs/es/manage-claude/authentication#key-types) 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](https://platform.claude.com/docs/es/manage-claude/authentication#select-a-workspace) 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.

<Tip>
  No crees más de un cliente en la misma aplicación. Cada cliente tiene un pool de conexiones y pools de hilos, que es más eficiente compartir entre solicitudes.
</Tip>

### 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:

```java
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()`:

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

AnthropicClient client = AnthropicOkHttpClient.fromEnv();

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();

CompletableFuture<Message> message = client.async().messages().create(params);
```

O crea un cliente asíncrono desde el principio:

```java
import com.anthropic.client.AnthropicClientAsync;
import com.anthropic.client.okhttp.AnthropicOkHttpClientAsync;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

AnthropicClientAsync client = AnthropicOkHttpClientAsync.fromEnv();

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();

CompletableFuture<Message> message = client.messages().create(params);
```

El cliente asíncrono admite las mismas opciones que el síncrono, excepto que la mayoría de los métodos devuelven `CompletableFuture`s.

## 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:

```java
import com.anthropic.core.http.StreamResponse;
import com.anthropic.models.messages.RawMessageStreamEvent;

try (StreamResponse<RawMessageStreamEvent> streamResponse = client.messages().createStreaming(params)) {
    streamResponse.stream().forEach(chunk -> {
        IO.println(chunk);
    });
    IO.println("No more chunks!");
}
```

### Streaming asíncrono

Para clientes asíncronos, el método devuelve `AsyncStreamResponse`:

```java
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:

```java
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`:

```java
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:

```java
import com.anthropic.core.http.StreamResponse;
import com.anthropic.helpers.MessageAccumulator;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.RawMessageStreamEvent;

MessageAccumulator messageAccumulator = MessageAccumulator.create();

try (StreamResponse<RawMessageStreamEvent> streamResponse =
         client.messages().createStreaming(createParams)) {
    streamResponse.stream()
            .peek(messageAccumulator::accumulate)
            .flatMap(event -> event.contentBlockDelta().stream())
            .flatMap(deltaEvent -> deltaEvent.delta().text().stream())
            .forEach(textDelta -> IO.print(textDelta.text()));
}

Message message = messageAccumulator.message();
```

Para una respuesta asíncrona, agrega el `MessageAccumulator` a la llamada `subscribe()`:

```java
import com.anthropic.helpers.MessageAccumulator;
import com.anthropic.models.messages.Message;

MessageAccumulator messageAccumulator = MessageAccumulator.create();

client.async().messages()
        .createStreaming(createParams)
        .subscribe(event -> messageAccumulator.accumulate(event).contentBlockDelta().stream()
                .flatMap(deltaEvent -> deltaEvent.delta().text().stream())
                .forEach(textDelta -> IO.print(textDelta.text())))
        .onCompleteFuture()
        .join();

Message message = messageAccumulator.message();
```

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](https://platform.claude.com/docs/es/build-with-claude/structured-outputs).

## Uso de herramientas

El ["tool use" (uso de herramientas) con Claude](https://platform.claude.com/docs/es/agents-and-tools/tool-use/overview) 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.

<Note>
  Declara tus clases de herramientas como clases de nivel superior o clases anidadas `static`. Este requisito proviene de la biblioteca Jackson Databind (`com.fasterxml.jackson.databind`), que el SDK usa para deserializar las entradas de herramientas en instancias de tus clases y que no puede instanciar clases internas no estáticas.
</Note>

### Definición de herramientas con anotaciones

```java
import com.fasterxml.jackson.annotation.JsonClassDescription;
import com.fasterxml.jackson.annotation.JsonPropertyDescription;

enum Unit {
  CELSIUS,
  FAHRENHEIT;

  public String toString() {
    return switch (this) {
      case CELSIUS -> "C";
      case FAHRENHEIT -> "F";
    };
  }

  public double fromKelvin(double temperatureK) {
    return switch (this) {
      case CELSIUS -> temperatureK - 273.15;
      case FAHRENHEIT -> (temperatureK - 273.15) * 1.8 + 32.0;
    };
  }
}

@JsonClassDescription("Get the weather in a given location")
static class GetWeather {

  @JsonPropertyDescription("The city and state, e.g. San Francisco, CA")
  public String location;

  @JsonPropertyDescription("The unit of temperature")
  public Unit unit;

  public Weather execute() {
    double temperatureK = switch (location) {
      case "San Francisco, CA" -> 300.0;
      case "New York, NY" -> 310.0;
      case "Dallas, TX" -> 305.0;
      default -> 295;
    };
    return new Weather(String.format("%.0f%s", unit.fromKelvin(temperatureK), unit));
  }
}

static class Weather {

  public String temperature;

  public Weather(String temperature) {
    this.temperature = temperature;
  }
}
```

### 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:

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import com.anthropic.models.beta.messages.*;
import com.anthropic.models.messages.Model;

AnthropicClient client = AnthropicOkHttpClient.fromEnv();

MessageCreateParams.Builder createParamsBuilder = MessageCreateParams.builder()
        .model(Model.CLAUDE_OPUS_5_5)
        .maxTokens(2048)
        .addTool(GetWeather.class)
        .addUserMessage("What's the temperature in New York?");

client.beta().messages().create(createParamsBuilder.build()).content().stream()
        .flatMap(contentBlock -> contentBlock.toolUse().stream())
        .forEach(toolUseBlock -> createParamsBuilder
              // Agrega un mensaje indicando 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 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 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:

```java
MessageCreateParams.Builder createParamsBuilder = MessageCreateParams.builder()
  .model(Model.CLAUDE_OPUS_5_5)
  .maxTokens(2048)
  .addTool(GetWeather.class, JsonSchemaLocalValidation.NO)
  .addUserMessage("What's the temperature in New York?");
```

### 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 getter `public` del esquema JSON generado para los parámetros de una herramienta.
* `@JsonProperty` - Incluye un campo o método getter no `public` en el esquema JSON generado para los parámetros de una herramienta.

## Lotes de mensajes

El SDK proporciona soporte para el [procesamiento por lotes](https://platform.claude.com/docs/es/build-with-claude/batch-processing) bajo el espacio de nombres `client.messages().batches()`. Consulta [Paginación](https://platform.claude.com/docs/es/cli-sdks-libraries/sdks/java#pagination) 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`:

```java
import com.anthropic.core.MultipartField;
import com.anthropic.models.files.FileMetadata;
import com.anthropic.models.files.FileUploadParams;

FileUploadParams params = FileUploadParams.builder()
  .file(
    MultipartField.<InputStream>builder()
      .value(Files.newInputStream(Paths.get("/path/to/file.pdf")))
      .contentType("application/pdf")
      .build()
  )
  .build();

FileMetadata fileMetadata = client.files().upload(params);
```

O desde un `InputStream`:

```java
import com.anthropic.core.MultipartField;
import com.anthropic.models.files.FileMetadata;
import com.anthropic.models.files.FileUploadParams;

FileUploadParams params = FileUploadParams.builder()
  .file(
    MultipartField.<InputStream>builder()
      .value(URI.create("https://example.com/path/to/file").toURL().openStream())
      .filename("document.pdf")
      .contentType("application/pdf")
      .build()
  )
  .build();

FileMetadata fileMetadata = client.files().upload(params);
```

O desde bytes en memoria:

```java
import com.anthropic.core.MultipartField;
import com.anthropic.models.files.FileMetadata;
import com.anthropic.models.files.FileUploadParams;

FileUploadParams params = FileUploadParams.builder()
  .file(
    MultipartField.<InputStream>builder()
      .value(new ByteArrayInputStream("content".getBytes()))
      .filename("document.txt")
      .contentType("text/plain")
      .build()
  )
  .build();

FileMetadata fileMetadata = client.files().upload(params);
```

### Respuestas binarias

El SDK define métodos que devuelven respuestas binarias para respuestas de la API que no necesariamente se analizan como JSON:

```java
import com.anthropic.core.http.HttpResponse;

HttpResponse response = client.files().download("file_abc123");
```

Para guardar el contenido de la respuesta en un archivo:

```java
import com.anthropic.core.http.HttpResponse;

try (HttpResponse response = client.files().download(params)) {
    Files.copy(
        response.body(),
        Paths.get(path),
        StandardCopyOption.REPLACE_EXISTING
    );
} catch (Exception e) {
    IO.println("Something went wrong!");
    throw new RuntimeException(e);
}
```

O transferir el contenido de la respuesta a cualquier `OutputStream`:

```java
import com.anthropic.core.http.HttpResponse;

try (HttpResponse response = client.files().download(params)) {
    response.body().transferTo(Files.newOutputStream(Paths.get(path)));
} catch (Exception e) {
    IO.println("Something went wrong!");
    throw new RuntimeException(e);
}
```

## 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.

```java
import com.anthropic.errors.*;

try {
    Message message = client.messages().create(params);
} catch (RateLimitException e) {
    IO.println("Rate limited, retry after: " + e.headers());
} catch (UnauthorizedException e) {
    IO.println("Invalid API key");
} catch (AnthropicServiceException e) {
    IO.println("API error: " + e.statusCode());
} catch (AnthropicIoException e) {
    IO.println("Network error: " + e.getMessage());
}
```

## IDs de solicitud

Al usar [respuestas sin procesar](https://platform.claude.com/docs/es/cli-sdks-libraries/sdks/java#raw-response-access), puedes acceder al encabezado de respuesta `request-id` usando el método `requestId()`:

```java
import com.anthropic.core.http.HttpResponseFor;
import com.anthropic.models.messages.Message;

HttpResponseFor<Message> message = client.messages().withRawResponse().create(params);

Optional<String> requestId = message.requestId();
```

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](https://platform.claude.com/docs/es/api/errors#request-id).

## 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`:

```java
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:

```java
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:

```java
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:

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .timeout(Duration.ofSeconds(30))
  .build();
```

## Solicitudes largas

<Warning>
  Considera usar [streaming](https://platform.claude.com/docs/es/cli-sdks-libraries/sdks/java#streaming) para solicitudes de larga duración.
</Warning>

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](https://platform.claude.com/docs/es/cli-sdks-libraries/sdks/java#timeouts) sin recibir una respuesta de Anthropic. El SDK hace ping 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](https://platform.claude.com/docs/es/cli-sdks-libraries/sdks/java#streaming) o [sobrescribir el tiempo de espera](https://platform.claude.com/docs/es/cli-sdks-libraries/sdks/java#timeouts) 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.

```java
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`:

```java
import com.anthropic.core.http.AsyncStreamResponse;
import com.anthropic.models.messages.batches.BatchListPageAsync;
import com.anthropic.models.messages.batches.MessageBatch;

CompletableFuture<BatchListPageAsync> pageFuture = client.async().messages().batches().list();

pageFuture.thenAccept(page -> page.autoPager().subscribe(batch -> {
    IO.println(batch);
}));

// 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:

```java
import com.anthropic.models.messages.batches.BatchListPage;
import com.anthropic.models.messages.batches.MessageBatch;

BatchListPage page = client.messages().batches().list();
while (true) {
    for (MessageBatch batch : page.items()) {
        IO.println(batch);
    }

    if (!page.hasNextPage()) {
        break;
    }

    page = page.nextPage();
}
```

## 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.

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

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

```java
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.MessageCreateParams;

MessageCreateParams params = MessageCreateParams.builder()
  .putAdditionalHeader("Secret-Header", "42")
  .putAdditionalQueryParam("secret_query_param", "42")
  .putAdditionalBodyProperty("secretProperty", JsonValue.from("42"))
  .build();
```

Se puede acceder a estos más tarde en el objeto construido usando los métodos `_additionalHeaders()`, `_additionalQueryParams()` y `_additionalBodyProperties()`.

<Warning>
  Los valores pasados a estos métodos sobrescriben los valores pasados a métodos anteriores. Por razones de seguridad, asegúrate de que estos métodos solo se usen con datos de entrada confiables.
</Warning>

Para establecer parámetros no documentados en clases anidadas de encabezados, parámetros de consulta o cuerpo:

```java
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Metadata;

MessageCreateParams params = MessageCreateParams.builder()
  .metadata(
    Metadata.builder().putAdditionalProperty("secretProperty", JsonValue.from("42")).build()
  )
  .build();
```

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:

```java
import com.anthropic.core.JsonValue;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(JsonValue.from(3.14))
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();
```

### Creación de JsonValue

La forma más directa de crear un `JsonValue` es usando su método `from(...)`:

```java
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`:

```java
import com.anthropic.core.JsonMissing;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

MessageCreateParams params = MessageCreateParams.builder()
  .addUserMessage("Hello, world")
  .model(Model.CLAUDE_OPUS_5_5)
  .maxTokens(JsonMissing.of())
  .build();
```

### Propiedades de respuesta

Para acceder a propiedades de respuesta no documentadas, llama al método `_additionalProperties()`:

```java
import com.anthropic.core.JsonValue;

Map<String, JsonValue> additionalProperties = client
  .messages()
  .create(params)
  ._additionalProperties();

JsonValue secretPropertyValue = additionalProperties.get("secretProperty");

String result = secretPropertyValue.accept(new JsonValue.Visitor<>() {
    @Override
    public String visitNull() {
        return "It's null!";
    }

    @Override
    public String visitBoolean(boolean value) {
        return "It's a boolean!";
    }

    @Override
    public String visitNumber(Number value) {
        return "It's a number!";
    }

    // 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 `_`:

```java
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()`:

```java
import com.anthropic.models.messages.Message;

Message message = client.messages().create(params).validate();
```

O configúralo por solicitud:

```java
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:

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

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;
import java.net.Proxy;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .proxy(new Proxy(Proxy.Type.HTTP, new InetSocketAddress("https://example.com", 8080)))
  .build();
```

### Configuración de HTTPS / SSL

<Note>
  La mayoría de las aplicaciones no deberían llamar a estos métodos, sino usar los valores predeterminados del sistema. Los valores predeterminados incluyen optimizaciones especiales que pueden perderse si se modifican las implementaciones.
</Note>

```java
import com.anthropic.client.AnthropicClient;
import com.anthropic.client.okhttp.AnthropicOkHttpClient;

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .sslSocketFactory(yourSSLSocketFactory)
  .trustManager(yourTrustManager)
  .hostnameVerifier(yourHostnameVerifier)
  .build();
```

### Cliente HTTP personalizado

El SDK consta de tres artefactos:

* `anthropic-java-core` - Contiene la lógica central del SDK, no depende de OkHttp. Expone `AnthropicClient`, `AnthropicClientAsync` y sus clases de implementación, todas las cuales pueden funcionar con cualquier cliente HTTP.
* `anthropic-java-client-okhttp` - Depende de OkHttp. Expone `AnthropicOkHttpClient` y `AnthropicOkHttpClientAsync`.
* `anthropic-java` - Depende de y expone las APIs tanto de `anthropic-java-core` como de `anthropic-java-client-okhttp`. No tiene lógica propia.

Esta estructura permite reemplazar el cliente HTTP predeterminado del SDK sin incorporar dependencias innecesarias.

#### OkHttpClient personalizado

<Tip>
  Prueba las [opciones de red](https://platform.claude.com/docs/es/cli-sdks-libraries/sdks/java#retries) disponibles antes de reemplazar el cliente predeterminado.
</Tip>

Para usar un `OkHttpClient` personalizado:

1. Reemplaza tu dependencia `anthropic-java` por `anthropic-java-core`.
2. Copia la clase `OkHttpClient` de `anthropic-java-client-okhttp` en tu código y personalízala.
3. Construye `AnthropicClientImpl` o `AnthropicClientAsyncImpl` usando tu cliente personalizado.

#### Cliente HTTP completamente personalizado

Para usar un cliente HTTP completamente personalizado:

1. Reemplaza tu dependencia `anthropic-java` por `anthropic-java-core`.
2. Escribe una clase que implemente la interfaz `HttpClient`.
3. Construye `AnthropicClientImpl` o `AnthropicClientAsyncImpl` usando tu nueva clase de cliente.

## Integraciones con plataformas

<Note>
  Para guías detalladas de configuración de plataformas con ejemplos de código, consulta:

  * [Amazon Bedrock](https://platform.claude.com/docs/es/build-with-claude/claude-in-amazon-bedrock)
  * [Amazon Bedrock (Opus 4.6 y anteriores)](https://platform.claude.com/docs/es/build-with-claude/claude-on-amazon-bedrock-legacy)
  * [Claude Platform en AWS](https://platform.claude.com/docs/es/build-with-claude/claude-platform-on-aws)
  * [Google Cloud](https://platform.claude.com/docs/es/build-with-claude/claude-on-vertex-ai)
  * [Microsoft Foundry](https://platform.claude.com/docs/es/build-with-claude/claude-in-microsoft-foundry)
</Note>

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`: Usa `VertexBackend.builder()` o `VertexBackend.fromEnv()`. `fromEnv()` lee `CLOUD_ML_REGION` y `ANTHROPIC_VERTEX_PROJECT_ID` y usa Application Default Credentials.
* **Bedrock:** `com.anthropic:anthropic-java-bedrock`: Usa `BedrockMantleBackend.fromEnv()` o `BedrockMantleBackend.builder()` para el endpoint de Bedrock de la Messages API, o `BedrockBackend.fromEnv()` / `BedrockBackend.builder()` (ruta `bedrock-runtime`).
* **Claude Platform en AWS:** `com.anthropic:anthropic-java-aws`: Usa `AwsBackend.fromEnv()` (lee `ANTHROPIC_AWS_WORKSPACE_ID` y la cadena predeterminada de región/credenciales de AWS) o `AwsBackend.builder()`. Disponible en beta.
* **Foundry:** `com.anthropic:anthropic-java-foundry`: Usa `FoundryBackend.fromEnv()` o `FoundryBackend.builder()`.

Usa `BedrockMantleBackend` para proyectos nuevos; `BedrockBackend` se mantiene para aplicaciones existentes que usan la API `InvokeModel` de Bedrock.

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 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:

```java
import com.anthropic.core.http.Headers;
import com.anthropic.core.http.HttpResponseFor;
import com.anthropic.models.messages.Message;
import com.anthropic.models.messages.MessageCreateParams;
import com.anthropic.models.messages.Model;

MessageCreateParams params = MessageCreateParams.builder()
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .model(Model.CLAUDE_OPUS_5_5)
  .build();

HttpResponseFor<Message> message = client.messages().withRawResponse().create(params);

int statusCode = message.statusCode();

Headers headers = message.headers();
```

Aún puedes deserializar la respuesta en una instancia de una clase Java si es necesario:

```java
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`:

```bash
export ANTHROPIC_LOG=info
```

O en `debug` para un logging más detallado:

```bash
export ANTHROPIC_LOG=debug
```

<Accordion title="Compatibilidad con Jackson">
  El 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`.

  <Warning>
    No hay garantía de que el SDK funcione correctamente cuando la verificación de versión de Jackson está deshabilitada.
  </Warning>

  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.
</Accordion>

<Accordion title="Configuración de ProGuard/R8">
  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.
</Accordion>

### 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](https://platform.claude.com/docs/es/cli-sdks-libraries/sdks/java#undocumented-parameters).

#### 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](https://platform.claude.com/docs/es/cli-sdks-libraries/sdks/java#response-properties).

#### 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:

```java
import com.anthropic.models.beta.AnthropicBeta;
import com.anthropic.models.messages.Model;

Model model = Model.of("some-new-model");
AnthropicBeta beta = AnthropicBeta.of("some-new-beta-2026-01-01");
```

Los métodos builder que aceptan estos tipos a menudo también proporcionan una sobrecarga de `String` que llama a `of(...)` por ti:

```java
import com.anthropic.models.messages.MessageCreateParams;

MessageCreateParams params = MessageCreateParams.builder()
  .model("some-new-model") // same as .model(Model.of("some-new-model"))
  .maxTokens(1024L)
  .addUserMessage("Hello, Claude")
  .build();
```

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 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](https://platform.claude.com/docs/es/build-with-claude/overview).

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](https://platform.claude.com/docs/es/api/beta-headers) apropiado con `.addBeta()` al construir los parámetros del mensaje.

Por ejemplo, para habilitar la [edición de contexto](https://platform.claude.com/docs/es/build-with-claude/context-editing):

```java
import com.anthropic.models.beta.AnthropicBeta;
import com.anthropic.models.beta.messages.BetaMessage;
import com.anthropic.models.beta.messages.MessageCreateParams;
// ...
void main() {
    AnthropicClient client = AnthropicOkHttpClient.fromEnv();

    BetaMessage message = client.beta().messages().create(
        MessageCreateParams.builder()
            .model(Model.CLAUDE_OPUS_5_5)
            .maxTokens(1024L)
            .addBeta(AnthropicBeta.CONTEXT_MANAGEMENT_2025_06_27)
            .addUserMessage("Hello, Claude")
            .build());
}
```

## Preguntas frecuentes

<AccordionGroup>
  <Accordion title="¿Por qué el SDK no usa clases enum simples?">
    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](https://platform.claude.com/docs/es/cli-sdks-libraries/sdks/java#new-or-unreleased-enum-values) si necesitas usar un valor que aún no está en tu versión del SDK.
  </Accordion>

  <Accordion title="¿Por qué los campos se representan usando JsonField<T> en lugar de simplemente T?">
    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
  </Accordion>

  <Accordion title="¿Por qué el SDK no usa clases de datos?">
    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.
  </Accordion>

  <Accordion title="¿Por qué el SDK no usa excepciones verificadas (checked)?">
    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)
  </Accordion>
</AccordionGroup>

## Versionado semántico

Este paquete generalmente sigue las convenciones de [SemVer](https://semver.org/spec/v2.0.0.html), aunque ciertos cambios incompatibles hacia atrás pueden publicarse como versiones menores:

1. Cambios en los componentes internos de la biblioteca que técnicamente son públicos pero no están destinados ni documentados para uso externo.
2. Cambios que no se espera que afecten a la gran mayoría de los usuarios en la práctica.

## Recursos adicionales

* [Repositorio de GitHub](https://github.com/anthropics/anthropic-sdk-java)
* [Javadocs](https://javadoc.io/doc/com.anthropic/anthropic-java)
* [Referencia de la API](https://platform.claude.com/docs/es/api/overview)
* [Streaming de mensajes](https://platform.claude.com/docs/es/build-with-claude/streaming)
* [Uso de herramientas con Claude](https://platform.claude.com/docs/es/agents-and-tools/tool-use/overview)
