Claude Platform Docs

SDK Java

Installez et configurez le SDK Java Anthropic avec les patrons builder et la prise en charge asynchrone

Le SDK Java Anthropic offre un accès pratique à l'API Claude depuis des applications écrites en Java. Il utilise le « builder pattern » (patron de conception builder) pour créer les requêtes et prend en charge les opérations synchrones et asynchrones.

Installation

implementation("com.anthropic:anthropic-java:2.58.0")

Prérequis

Cette bibliothèque nécessite Java 8 ou une version ultérieure.

Démarrage rapide

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;

// Configure à l'aide des propriétés système `anthropic.apiKey`, `anthropic.authToken` et `anthropic.baseUrl`
// Ou configure à l'aide des variables d'environnement `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN` et `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);

Configuration du client

Configuration de la clé API

Configurez le client à l'aide de propriétés système ou de variables d'environnement :

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

// Configure à l'aide des propriétés système `anthropic.apiKey`, `anthropic.authToken` et `anthropic.baseUrl`
// Ou configure à l'aide des variables d'environnement `ANTHROPIC_API_KEY`, `ANTHROPIC_AUTH_TOKEN` et `ANTHROPIC_BASE_URL`
AnthropicClient client = AnthropicOkHttpClient.fromEnv();

Ou configurez-le manuellement :

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

AnthropicClient client = AnthropicOkHttpClient.builder()
  .apiKey("my-anthropic-api-key")
  .build();

Ou utilisez une combinaison des deux approches :

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

AnthropicClient client = AnthropicOkHttpClient.builder()
  // Configuration via les propriétés système ou les variables d'environnement
  .fromEnv()
  .apiKey("my-anthropic-api-key")
  .build();

Pour les options d'authentification, y compris Workload Identity Federation, consultez Authentification. Si votre clé API est une clé personnelle ou de compte de service ayant accès à plusieurs espaces de travail, définissez l'identifiant de l'espace de travail dans l'en-tête de requête anthropic-workspace-id ; Sélectionner un espace de travail présente l'option par requête pour ce SDK.

Options de configuration

SetterPropriété systèmeVariable d'environnementObligatoireValeur par défaut
apiKeyanthropic.apiKeyANTHROPIC_API_KEYfalse-
authTokenanthropic.authTokenANTHROPIC_AUTH_TOKENfalse-
baseUrlanthropic.baseUrlANTHROPIC_BASE_URLtrue"https://api.anthropic.com"

Les propriétés système ont priorité sur les variables d'environnement.

Modification de la configuration

Pour utiliser temporairement une configuration de client modifiée tout en réutilisant les mêmes pools de connexions et de threads, appelez withOptions() sur n'importe quel client ou service :

import com.anthropic.client.AnthropicClient;

AnthropicClient clientWithOptions = client.withOptions(optionsBuilder -> {
  optionsBuilder.baseUrl("https://example.com");
  optionsBuilder.maxRetries(42);
});

La méthode withOptions() n'affecte pas le client ou le service d'origine.

Utilisation asynchrone

Le client par défaut est synchrone. Pour passer à une exécution asynchrone, appelez la méthode 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);

Ou créez un client asynchrone dès le départ :

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);

Le client asynchrone prend en charge les mêmes options que le client synchrone, sauf que la plupart des méthodes renvoient des CompletableFuture.

Streaming

Le SDK définit des méthodes qui renvoient des flux de « chunks » (fragments) de réponse, où chaque fragment peut être traité individuellement dès son arrivée au lieu d'attendre la réponse complète.

Streaming synchrone

Ces méthodes de streaming renvoient StreamResponse pour les clients synchrones :

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 asynchrone

Pour les clients asynchrones, la méthode renvoie AsyncStreamResponse :

import com.anthropic.core.http.AsyncStreamResponse;
import com.anthropic.models.messages.RawMessageStreamEvent;

client.async().messages().createStreaming(params).subscribe(chunk -> {
    IO.println(chunk);
});

// Si vous devez gérer les erreurs ou la fin du flux
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!");
        }
    }
});

// Ou utilisez des 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!");
        }
    });

Le streaming asynchrone utilise un Executor dédié par client, basé sur un pool de threads mis en cache, pour diffuser le flux sans bloquer le thread courant. Pour utiliser un autre Executor :

Executor executor = Executors.newFixedThreadPool(4);
client.async().messages().createStreaming(params).subscribe(
    chunk -> IO.println(chunk), executor
);

Ou configurez le client globalement à l'aide de la méthode streamHandlerExecutor :

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

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .streamHandlerExecutor(Executors.newFixedThreadPool(4))
  .build();

Streaming avec accumulateur de messages

Un MessageAccumulator peut enregistrer le flux d'événements de la réponse au fur et à mesure de leur traitement et accumuler un objet Message similaire à celui qui aurait été renvoyé par l'API sans streaming.

Pour une réponse synchrone, ajoutez un appel Stream.peek() au pipeline du flux pour accumuler chaque événement :

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

Pour une réponse asynchrone, ajoutez le MessageAccumulator à l'appel 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();

Un BetaMessageAccumulator est également disponible pour l'accumulation d'un objet BetaMessage. Il s'utilise de la même manière que le MessageAccumulator.

Sorties structurées

Pour la documentation complète sur les sorties structurées, y compris des exemples Java, consultez Sorties structurées.

Utilisation d'outils

L'utilisation d'outils avec Claude (« tool use ») vous permet d'intégrer des outils et fonctions externes directement dans les réponses du modèle d'IA. Au lieu de produire du texte brut, le modèle peut générer des instructions (avec des paramètres) pour appeler un outil ou une fonction lorsque cela est approprié. Vous définissez des schémas JSON pour les outils, et le modèle utilise ces schémas pour déterminer quand et comment utiliser ces outils.

La fonctionnalité d'utilisation d'outils prend en charge un mode « strict » qui garantit que la sortie JSON du modèle d'IA sera conforme au schéma JSON que vous fournissez dans les paramètres d'entrée.

Le SDK peut dériver automatiquement un outil et ses paramètres à partir de la structure d'une classe Java arbitraire : le nom de la classe (converti en snake case) fournit le nom de l'outil, et les champs de la classe définissent les paramètres de l'outil.

Définition d'outils avec des annotations

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;
  }
}

Appel des outils

Une fois vos classes d'outils définies, ajoutez-les aux paramètres du message à l'aide de MessageCreateParams.Builder.addTool(Class<T>), puis appelez-les si la réponse du modèle d'IA le demande. BetaToolUseBlock.input(Class<T>) peut être utilisé pour analyser les paramètres d'un outil au format JSON en une instance de votre classe définissant l'outil.

Après avoir appelé l'outil, utilisez BetaToolResultBlockParam.Builder.contentAsJson(Object) pour renvoyer le résultat de l'outil au modèle d'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
              // Ajouter un message indiquant que l'utilisation d'outils a été demandée.
              .addAssistantMessageOfBetaContentBlockParams(
                      List.of(BetaContentBlockParam.ofToolUse(BetaToolUseBlockParam.builder()
                              .name(toolUseBlock.name())
                              .id(toolUseBlock.id())
                              .input(toolUseBlock._input())
                              .build())))
              // Ajouter un message avec le résultat de l'utilisation d'outils demandée.
              .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");
}

Conversion des noms d'outils

Les noms d'outils sont dérivés des noms de classes d'outils en camel case (par exemple, GetWeather) et convertis en snake case (par exemple, get_weather). Les limites de mots commencent là où le caractère courant n'est pas le premier caractère, est en majuscule, et où soit le caractère précédent est en minuscule, soit le caractère suivant est en minuscule. Par exemple, MyJSONParser devient my_json_parser et ParseJSON devient parse_json. Cette conversion peut être remplacée à l'aide de l'annotation @JsonTypeName.

Validation locale du schéma JSON des outils

Vous pouvez effectuer une validation locale pour vérifier que le schéma JSON dérivé de votre classe d'outil respecte les restrictions d'Anthropic. La validation locale est activée par défaut, mais elle peut être désactivée :

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?");

Annotation des classes d'outils

Vous pouvez utiliser des annotations pour ajouter des informations supplémentaires sur les outils aux schémas JSON :

  • @JsonClassDescription - Ajoute une description à une classe d'outil détaillant quand et comment utiliser cet outil.
  • @JsonTypeName - Définit le nom de l'outil sur autre chose que le nom simple de la classe converti en snake case.
  • @JsonPropertyDescription - Ajoute une description détaillée à un paramètre d'outil.
  • @JsonIgnore - Exclut un champ ou une méthode getter public du schéma JSON généré pour les paramètres d'un outil.
  • @JsonProperty - Inclut un champ ou une méthode getter non public dans le schéma JSON généré pour les paramètres d'un outil.

Lots de messages

Le SDK prend en charge le traitement par lots sous l'espace de noms client.messages().batches(). Consultez Pagination pour savoir comment lister et paginer les lots.

Téléversement de fichiers

Le SDK définit des méthodes qui acceptent des fichiers via la classe 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);

Ou à partir d'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);

Ou à partir d'octets en mémoire :

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);

Réponses binaires

Le SDK définit des méthodes qui renvoient des réponses binaires pour les réponses de l'API qui ne sont pas nécessairement analysées en JSON :

import com.anthropic.core.http.HttpResponse;

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

Pour enregistrer le contenu de la réponse dans un fichier :

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);
}

Ou transférer le contenu de la réponse vers n'importe quel 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);
}

Gestion des erreurs

Le SDK lève des types d'exceptions non vérifiées personnalisés :

  • AnthropicServiceException - Classe de base pour les erreurs HTTP.
  • AnthropicIoException - Erreurs réseau d'E/S.
  • AnthropicRetryableException - Erreur générique indiquant un échec qui pourrait être réessayé.
  • AnthropicInvalidDataException - Échec de l'interprétation de données analysées avec succès (par exemple, lors de l'accès à une propriété censée être obligatoire, mais que l'API a omise de manière inattendue).
  • AnthropicException - Classe de base pour toutes les exceptions.

Correspondance des codes de statut

StatutException
400BadRequestException
401UnauthorizedException
403PermissionDeniedException
404NotFoundException
422UnprocessableEntityException
429RateLimitException
5xxInternalServerException
autresUnexpectedStatusCodeException

SseException est levée pour les erreurs rencontrées pendant le streaming SSE après une réponse HTTP initiale réussie.

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());
}

Identifiants de requête

Lorsque vous utilisez les réponses brutes, vous pouvez accéder à l'en-tête de réponse request-id à l'aide de la méthode 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();

Cela peut servir à consigner rapidement les requêtes en échec et à les signaler à Anthropic. Pour plus d'informations sur le débogage des requêtes, consultez Identifiant de requête.

Nouvelles tentatives

Le SDK effectue automatiquement 2 nouvelles tentatives par défaut, avec un court backoff exponentiel entre les requêtes.

Seuls les types d'erreurs suivants font l'objet de nouvelles tentatives :

  • Erreurs de connexion (par exemple, en raison d'un problème de connectivité réseau)
  • 408 Request Timeout
  • 409 Conflict
  • 429 Rate Limit
  • 5xx Internal

L'API peut également indiquer explicitement au SDK de réessayer ou non une requête.

Pour définir un nombre personnalisé de nouvelles tentatives, configurez le client à l'aide de la méthode maxRetries :

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

AnthropicClient client = AnthropicOkHttpClient.builder().fromEnv().maxRetries(4).build();

Délais d'expiration

Les requêtes expirent après 10 minutes par défaut.

Cependant, pour les méthodes qui acceptent maxTokens, si vous spécifiez une grande valeur de maxTokens et utilisez le streaming, le délai d'expiration par défaut sera calculé dynamiquement selon cette formule :

Duration.ofSeconds(
    Math.min(
        60 * 60, // 1 hour max
        Math.max(
            10 * 60, // 10 minute minimum
            60 * 60 * maxTokens / 128_000
        )
    )
)

Cela donne un délai d'expiration pouvant aller jusqu'à 60 minutes, proportionnel au paramètre maxTokens, sauf s'il est remplacé.

Pour les requêtes sans streaming, le délai d'expiration dynamique varie d'un minimum de 30 secondes à un maximum de 10 minutes en fonction de maxTokens.

Pour définir un délai d'expiration personnalisé par requête :

import com.anthropic.models.messages.Message;

Message message = client
  .messages()
  .create(params, RequestOptions.builder().timeout(Duration.ofSeconds(30)).build());

Ou configurez la valeur par défaut pour tous les appels de méthode au niveau du client :

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

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

Requêtes longues

Évitez de définir une grande valeur de maxTokens sans utiliser le streaming. Certains réseaux peuvent interrompre les connexions inactives après un certain temps, ce qui peut faire échouer la requête ou provoquer un délai d'expiration sans recevoir de réponse d'Anthropic. Le SDK envoie périodiquement des pings à l'API pour maintenir la connexion active et réduire l'impact de ces réseaux.

Le SDK lève une erreur si une requête sans streaming est censée prendre plus de 10 minutes. L'utilisation d'une méthode de streaming ou le remplacement du délai d'expiration au niveau du client ou de la requête désactive cette erreur.

Pagination

Le SDK offre des moyens pratiques d'accéder aux résultats paginés, soit une page à la fois, soit élément par élément sur l'ensemble des pages.

Pagination automatique

Pour parcourir tous les résultats sur l'ensemble des pages, utilisez la méthode autoPager(), qui récupère automatiquement des pages supplémentaires selon les besoins.

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

BatchListPage page = client.messages().batches().list();

// Traiter comme un Iterable
for (MessageBatch batch : page.autoPager()) {
    IO.println(batch);
}

// Traiter comme un Stream
page.autoPager()
    .stream()
    .limit(50)
    .forEach(batch -> IO.println(batch));

Lorsque vous utilisez le client asynchrone, la méthode renvoie 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 vous devez gérer les erreurs ou la fin du flux
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!");
        }
    }
}));

// Ou utilisez des 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!");
        }
    }));

Pagination manuelle

Pour accéder aux éléments d'une page individuelle et demander manuellement la page suivante :

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();
}

Système de types

Immuabilité et builders

Chaque classe du SDK possède un builder associé pour la construire. Chaque classe est immuable une fois construite. Si la classe possède un builder associé, elle dispose alors d'une méthode toBuilder(), qui peut être utilisée pour la reconvertir en builder afin d'en créer une copie modifiée.

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

// Créer une copie modifiée à l'aide de toBuilder()
MessageCreateParams modified = params.toBuilder().maxTokens(2048L).build();

Comme chaque classe est immuable, la modification d'un builder n'affecte jamais les instances de classe déjà construites.

Requêtes et réponses

Pour envoyer une requête à l'API Claude, construisez une instance d'une classe Params et transmettez-la à la méthode client correspondante. Lorsque la réponse est reçue, elle est désérialisée en une instance d'une classe Java.

Par exemple, client.messages().create(...) doit être appelée avec une instance de MessageCreateParams, et elle renvoie une instance de Message.

Paramètres non documentés

Pour définir des paramètres non documentés, appelez les méthodes putAdditionalHeader, putAdditionalQueryParam ou putAdditionalBodyProperty sur n'importe quelle classe 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();

Ceux-ci sont ensuite accessibles sur l'objet construit à l'aide des méthodes _additionalHeaders(), _additionalQueryParams() et _additionalBodyProperties().

Pour définir des paramètres non documentés sur des classes imbriquées d'en-têtes, de paramètres de requête ou de corps :

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

Ces propriétés sont ensuite accessibles sur l'objet imbriqué construit à l'aide de la méthode _additionalProperties().

Pour définir un paramètre ou une propriété documenté(e) sur une valeur non documentée ou pas encore prise en charge, transmettez un objet JsonValue à son 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();

Création de JsonValue

La façon la plus simple de créer un JsonValue est d'utiliser sa méthode from(...) :

import com.anthropic.core.JsonValue;

// Créer des valeurs JSON primitives
JsonValue nullValue = JsonValue.from(null);

JsonValue booleanValue = JsonValue.from(true);

JsonValue numberValue = JsonValue.from(42);

JsonValue stringValue = JsonValue.from("Hello World!");

// Créer une valeur de tableau JSON équivalente à `["Hello", "World"]`
JsonValue arrayValue = JsonValue.from(List.of("Hello", "World"));

// Créer une valeur d'objet JSON équivalente à `{ "a": 1, "b": 2 }`
JsonValue objectValue = JsonValue.from(Map.of("a", 1, "b", 2));

// Créer un JSON imbriqué arbitrairement, équivalent à :
// { "a": [1, 2], "b": [3, 4] }
JsonValue complexValue = JsonValue.from(Map.of("a", List.of(1, 2), "b", List.of(3, 4)));

Omission forcée de paramètres obligatoires

Normalement, la méthode build d'une classe Builder lève une IllegalStateException si un paramètre ou une propriété obligatoire n'est pas défini(e). Pour omettre de force un paramètre ou une propriété obligatoire, transmettez 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();

Propriétés de réponse

Pour accéder aux propriétés de réponse non documentées, appelez la méthode _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!";
    }

    // Les autres méthodes incluent `visitMissing`, `visitString`, `visitArray` et `visitObject`
    // L'implémentation par défaut de chaque méthode non implémentée délègue à `visitDefault`,
    // qui lève une exception par défaut, mais peut aussi être redéfinie
});

Pour accéder à la valeur JSON brute d'une propriété, appelez sa méthode préfixée par _ :

import com.anthropic.core.JsonField;
import com.anthropic.models.messages.StopReason;

JsonField<StopReason> stopReason = client.messages().create(params)._stopReason();

if (stopReason.isMissing()) {
  // La propriété est absente de la réponse JSON
} else if (stopReason.isNull()) {
  // La propriété a été définie sur la valeur littérale null
} else {
  // Vérifier si la valeur a été fournie sous forme de chaîne
  // Les autres méthodes incluent `asNumber()`, `asBoolean()`, etc.
  Optional<String> jsonString = stopReason.asString();

  // Tenter de désérialiser vers un type personnalisé
  MyClass myObject = stopReason.asUnknown().orElseThrow().convert(MyClass.class);
}

Validation des réponses

Par défaut, le SDK ne lève pas d'exception lorsque l'API renvoie une réponse qui ne correspond pas au type attendu. Il lève une AnthropicInvalidDataException uniquement si vous accédez directement à la propriété.

Pour vérifier d'emblée que la réponse est entièrement bien typée, appelez validate() :

import com.anthropic.models.messages.Message;

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

Ou configurez par requête :

import com.anthropic.models.messages.Message;

Message message = client
  .messages()
  .create(params, RequestOptions.builder().responseValidation(true).build());

Ou configurez la valeur par défaut pour tous les appels de méthode au niveau du client :

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

AnthropicClient client = AnthropicOkHttpClient.builder()
  .fromEnv()
  .responseValidation(true)
  .build();

Personnalisation du client HTTP

Configuration du 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();

Configuration 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();

Client HTTP personnalisé

Le SDK se compose de trois artefacts :

  • anthropic-java-core - Contient la logique centrale du SDK, ne dépend pas d'OkHttp. Expose AnthropicClient, AnthropicClientAsync et leurs classes d'implémentation, qui peuvent toutes fonctionner avec n'importe quel client HTTP.
  • anthropic-java-client-okhttp - Dépend d'OkHttp. Expose AnthropicOkHttpClient et AnthropicOkHttpClientAsync.
  • anthropic-java - Dépend de anthropic-java-core et anthropic-java-client-okhttp et expose leurs API. Ne possède pas de logique propre.

Cette structure permet de remplacer le client HTTP par défaut du SDK sans importer de dépendances inutiles.

OkHttpClient personnalisé

Pour utiliser un OkHttpClient personnalisé :

  1. Remplacez votre dépendance anthropic-java par anthropic-java-core.
  2. Copiez la classe OkHttpClient de anthropic-java-client-okhttp dans votre code et personnalisez-la.
  3. Construisez AnthropicClientImpl ou AnthropicClientAsyncImpl à l'aide de votre client personnalisé.

Client HTTP entièrement personnalisé

Pour utiliser un client HTTP entièrement personnalisé :

  1. Remplacez votre dépendance anthropic-java par anthropic-java-core.
  2. Écrivez une classe qui implémente l'interface HttpClient.
  3. Construisez AnthropicClientImpl ou AnthropicClientAsyncImpl à l'aide de votre nouvelle classe client.

Intégrations de plateformes

Le SDK Java prend en charge les plateformes suivantes via des dépendances distinctes qui fournissent des implémentations de Backend spécifiques à chaque plateforme :

  • Agent Platform : com.anthropic:anthropic-java-vertex : utilisez VertexBackend.fromEnv() ou VertexBackend.builder().
  • Bedrock : com.anthropic:anthropic-java-bedrock : utilisez BedrockMantleBackend.fromEnv() ou BedrockMantleBackend.builder() pour le point de terminaison Bedrock de l'API Messages, ou BedrockBackend.fromEnv() / BedrockBackend.builder() (chemin bedrock-runtime).
  • Claude Platform sur AWS : com.anthropic:anthropic-java-aws : utilisez AwsBackend.fromEnv() (lit ANTHROPIC_AWS_WORKSPACE_ID ainsi que la région par défaut et la chaîne d'informations d'identification AWS) ou AwsBackend.builder(). Disponible en bêta.
  • Foundry : com.anthropic:anthropic-java-foundry : utilisez FoundryBackend.fromEnv() ou FoundryBackend.builder().

Utilisez BedrockMantleBackend pour les nouveaux projets ; BedrockBackend reste disponible pour les applications existantes utilisant l'API InvokeModel de Bedrock.

Chaque implémentation de Backend est transmise au client avec .backend() sur AnthropicOkHttpClient.builder(). Chaque backend cloud importe les classes du SDK de sa plateforme cloud respective en tant que dépendances transitives.

Utilisation avancée

Accès aux réponses brutes

Pour accéder aux en-têtes HTTP, aux codes de statut et au corps brut de la réponse, préfixez tout appel de méthode HTTP avec withRawResponse() :

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

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

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

int statusCode = message.statusCode();

Headers headers = message.headers();

Vous pouvez toujours désérialiser la réponse en une instance d'une classe Java si nécessaire :

import com.anthropic.models.messages.Message;

Message parsedMessage = message.parse();

Journalisation

Le SDK utilise l'intercepteur de journalisation standard d'OkHttp.

Activez la journalisation en définissant la variable d'environnement ANTHROPIC_LOG sur info :

export ANTHROPIC_LOG=info

Ou sur debug pour une journalisation plus détaillée :

export ANTHROPIC_LOG=debug

Fonctionnalités non documentées de l'API

Le SDK est typé pour une utilisation pratique de l'API documentée. Cependant, il permet également de travailler avec des parties de l'API non documentées ou pas encore prises en charge.

Paramètres de requête non documentés

Pour définir des paramètres de requête non documentés, utilisez les méthodes putAdditionalHeader, putAdditionalQueryParam ou putAdditionalBodyProperty comme décrit dans Paramètres non documentés.

Propriétés de réponse non documentées

Pour accéder aux propriétés de réponse non documentées, utilisez la méthode _additionalProperties() comme décrit dans Propriétés de réponse.

Valeurs d'énumération nouvelles ou non publiées

Les classes de type énumération du SDK, telles que Model et AnthropicBeta, ne sont pas des types enum Java fermés. Chacune fournit une méthode de fabrique of(String) qui accepte n'importe quelle chaîne, ce qui vous permet d'utiliser des valeurs qui n'ont pas encore été ajoutées au SDK, comme un modèle ou un en-tête bêta publié après votre version du 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");

Les méthodes de builder qui acceptent ces types fournissent souvent aussi une surcharge String qui appelle of(...) pour vous :

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

Privilégiez les constantes bien typées (par exemple, Model.CLAUDE_OPUS_5) afin de bénéficier de l'autocomplétion et des avertissements de dépréciation. Les surcharges String et of(...) servent principalement à définir le champ sur une valeur non documentée ou pas encore prise en charge en attendant une version du SDK qui l'inclut.

Fonctionnalités bêta

Les fonctionnalités bêta sont disponibles avant leur publication générale afin de recueillir des retours précoces et de tester de nouvelles fonctionnalités. Vous pouvez vérifier la disponibilité de toutes les capacités et de tous les outils de Claude dans la vue d'ensemble Créer avec Claude.

Vous pouvez accéder à la plupart des fonctionnalités bêta de l'API via la méthode beta() du client. Pour activer une fonctionnalité bêta particulière, ajoutez l'en-tête bêta approprié avec .addBeta() lors de la construction des paramètres du message.

Par exemple, pour activer l'édition de contexte :

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());
}

Foire aux questions

Gestion sémantique de version

Ce package suit généralement les conventions SemVer, bien que certains changements non rétrocompatibles puissent être publiés en tant que versions mineures :

  1. Les modifications des éléments internes de la bibliothèque qui sont techniquement publics, mais qui ne sont ni destinés ni documentés pour un usage externe.
  2. Les modifications qui ne devraient pas affecter la grande majorité des utilisateurs en pratique.

Ressources supplémentaires

Was this page helpful?