aws-sdk-java-v2-bedrock について
AWS SDK for Java 2.xでAmazon Bedrockの基盤モデルを利用するJava開発者向けのスキルガイドです。モデル別ペイロード、ストリーミングとエラー回復、埋め込み生成、Spring Boot連携を扱います。
主な機能
- 01複数のBedrockモデルの呼び出し
- 02モデル別ペイロードの構築と解析
- 03ストリーミングとエラー回復
- 04RAG向け埋め込みの生成
- 05Spring Boot連携の設定
- 06指数バックオフによるスロットリング再試行
活用シーン
- 01Javaアプリでのテキストや画像生成
- 02RAGパイプライン向け埋め込み作成
- 03Spring BootマイクロサービスへのBedrock導入
インストール
コマンドをコピーしてターミナルで実行します。
$
npx skills add https:/ / github.com/ giuseppe-trisciuoglio/ developer-kit --skill aws-sdk-java-v2-bedrockインストール後、Claude Code で/aws-sdk-java-v2-bedrockを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
references/advanced-model-patterns.mdadvanced-topics.mdaws-bedrock-api-reference.mdaws-bedrock-user-guide.mdaws-sdk-examples.mdaws-sdk-java-bedrock-api.mdbedrock-code-examples.mdbedrock-models-supported.mdbedrock-runtime-code-examples.mdmodel-reference.mdmodels-lookup.mdtesting-strategies.md詳細
AWS SDK for Java 2.x - Amazon Bedrock
概要
AWS SDK for Java 2.x を通じて基盤モデルを呼び出します。クライアントを設定し、モデル固有の JSON ペイロードを構築し、エラーリカバリーに対応したストリーミングレスポンスを処理し、RAG 用の埋め込みを作成し、Spring Boot アプリケーションに生成 AI を統合し、信頼性を高めるための指数バックオフを実装します。
使用する場面
- Claude、Llama、Titan、Stable Diffusion を呼び出してテキストや画像を生成する
BedrockClientおよびBedrockRuntimeClientのインスタンスを設定する- モデル固有のペイロード(Claude、Titan、Llama の形式)を構築して解析する
- 非同期ハンドラーとエラーリカバリーを使用して、AI のレスポンスをリアルタイムでストリーミングする
- 検索拡張生成用の埋め込みを作成する
- 生成 AI を Spring Boot マイクロサービスに統合する
- 指数バックオフによる再試行ロジックでスロットリングに対処する
クイックスタート
依存関係
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bedrock</artifactId>
</dependency>
<dependency>
<groupId>software.amazon.awssdk</groupId>
<artifactId>bedrockruntime</artifactId>
</dependency>
<dependency>
<groupId>org.json</groupId>
<artifactId>json</artifactId>
<version>20231013</version>
</dependency>
クライアントの設定
import software.amazon.awssdk.regions.Region;
import software.amazon.awssdk.services.bedrock.BedrockClient;
import software.amazon.awssdk.services.bedrockruntime.BedrockRuntimeClient;
// Model management client
BedrockClient bedrockClient = BedrockClient.builder()
.region(Region.US_EAST_1)
.build();
// Model invocation client
BedrockRuntimeClient bedrockRuntimeClient = BedrockRuntimeClient.builder()
.region(Region.US_EAST_1)
.build();
手順
Bedrock を本番環境で使用できるよう、次の手順に従って統合します。
- AWS 認証情報を設定する - Bedrock の権限を持つ IAM ロールを設定します(アクセスキーは避けてください)
- モデルへのアクセスを有効にする - AWS コンソールで特定の基盤モデルへのアクセスをリクエストします
- クライアントを初期化する - 再利用可能な
BedrockClientおよびBedrockRuntimeClientのインスタンスを作成します - モデルの利用可能性を検証する - 本番環境で使用する前に、簡単な呼び出しでテストします
- ペイロードを構築する - 適切な形式でモデル固有の JSON ペイロードを作成します
- レスポンスを処理する - レスポンスの構造を解析し、コンテンツを抽出します
- ストリーミングを実装する - レスポンスストリームハンドラーを使用して、リアルタイムに生成します
- エラー処理を追加する - 指数バックオフによる再試行ロジックを実装します
検証チェックポイント:本番環境で使用する前に、モデルへのアクセスとレスポンスの解析を確認するため、必ず簡単なプロンプト(例:「Hello」)でテストしてください。
例
Claude によるテキスト生成
public String generateWithClaude(BedrockRuntimeClient client, String prompt) {
JSONObject payload = new JSONObject()
.put("anthropic_version", "bedrock-2023-05-31")
.put("max_tokens", 1000)
.put("messages", new JSONObject[]{
new JSONObject().put("role", "user").put("content", prompt)
});
InvokeModelResponse response = client.invokeModel(InvokeModelRequest.builder()
.modelId("anthropic.claude-sonnet-4-5-20250929-v1:0")
.body(SdkBytes.fromUtf8String(payload.toString()))
.build());
JSONObject responseBody = new JSONObject(response.body().asUtf8String());
return responseBody.getJSONArray("content")
.getJSONObject(0)
.getString("text");
}
モデルの検出
import software.amazon.awssdk.services.bedrock.model.*;
public List<FoundationModelSummary> listFoundationModels(BedrockClient bedrockClient) {
return bedrockClient.listFoundationModels().modelSummaries();
}
複数モデルの呼び出し
public String invokeModel(BedrockRuntimeClient client, String modelId, String prompt) {
JSONObject payload = createPayload(modelId, prompt);
InvokeModelResponse response = client.invokeModel(request -> request
.modelId(modelId)
.body(SdkBytes.fromUtf8String(payload.toString())));
return extractTextFromResponse(modelId, response.body().asUtf8String());
}
private JSONObject createPayload(String modelId, String prompt) {
if (modelId.startsWith("anthropic.claude")) {
return new JSONObject()
.put("anthropic_version", "bedrock-2023-05-31")
.put("max_tokens", 1000)
.put("messages", new JSONObject[]{
new JSONObject().put("role", "user").put("content", prompt)
});
} else if (modelId.startsWith("amazon.titan")) {
return new JSONObject()
.put("inputText", prompt)
.put("textGenerationConfig", new JSONObject()
.put("maxTokenCount", 512)
.put("temperature", 0.7));
} else if (modelId.startsWith("meta.llama")) {
return new JSONObject()
.put("prompt", "[INST] " + prompt + " [/INST]")
.put("max_gen_len", 512)
.put("temperature", 0.7);
}
throw new IllegalArgumentException("Unsupported model: " + modelId);
}
エラー処理を伴うストリーミングレスポンス
public String streamResponseWithRetry(BedrockRuntimeClient client, String modelId, String prompt, int maxRetries) {
int attempt = 0;
while (attempt < maxRetries) {
try {
JSONObject payload = createPayload(modelId, prompt);
StringBuilder fullResponse = new StringBuilder();
InvokeModelWithResponseStreamRequest request = InvokeModelWithResponseStreamRequest.builder()
.modelId(modelId)
.body(SdkBytes.fromUtf8String(payload.toString()))
.build();
client.invokeModelWithResponseStream(request,
InvokeModelWithResponseStreamResponseHandler.builder()
.onEventStream(stream -> stream.forEach(event -> {
if (event instanceof PayloadPart) {
String chunk = ((PayloadPart) event).bytes().asUtf8String();
fullResponse.append(chunk);
}
}))
.onError(e -> System.err.println("Stream error: " + e.getMessage()))
.build());
return fullResponse.toString();
} catch (Exception e) {
attempt++;
if (attempt >= maxRetries) {
throw new RuntimeException("Stream failed after " + maxRetries + " attempts", e);
}
try {
Thread.sleep((long) Math.pow(2, attempt) * 1000); // Exponential backoff
} catch (InterruptedException ie) {
Thread.currentThread().interrupt();
throw new RuntimeException("Interrupted during retry", ie);
}
}
}
throw new RuntimeException("Unexpected error in streaming");
}
スロットリングに対する指数バックオフ
import software.amazon.awssdk.awscore.exception.AwsServiceException;
public <T> T invokeWithRetry(Supplier<T> invocation, int maxRetries) {
int attempt = 0;
while (attempt < maxRetries) {
try {
return invocation.get();
} catch (AwsServiceException e) {
if (e.statusCode() == 429 || e.statusCode() >= 500) {
attempt++;
if (attempt >= maxRetries) throw e;
long delayMs = Math.min(1000 * (1L << attempt) + (long) (Math.random() * 1000), 30000);
Thread.sleep(delayMs);
} else {
throw e;
}
}
}
throw new IllegalStateException("Should not reach here");
}
テキスト埋め込み
public double[] createEmbeddings(BedrockRuntimeClient client, String text) {
String modelId = "amazon.titan-embed-text-v1";
JSONObject payload = new JSONObject().put("inputText", text);
InvokeModelResponse response = client.invokeModel(request -> request
.modelId(modelId)
.body(SdkBytes.fromUtf8String(payload.toString())));
JSONObject responseBody = new JSONObject(response.body().asUtf8String());
JSONArray embeddingArray = responseBody.getJSONArray("embedding");
double[] embeddings = new double[embeddingArray.length()];
for (int i = 0; i < embeddingArray.length(); i++) {
embeddings[i] = embeddingArray.getDouble(i);
}
return embeddings;
}
Spring Boot との統合
@Configuration
public class BedrockConfiguration {
@Bean
public BedrockClient bedrockClient() {
return BedrockClient.builder()
.region(Region.US_EAST_1)
.build();
}
@Bean
public BedrockRuntimeClient bedrockRuntimeClient() {
return BedrockRuntimeClient.builder()
.region(Region.US_EAST_1)
.build();
}
}
@Service
public class BedrockAIService {
private final BedrockRuntimeClient bedrockRuntimeClient;
private final ObjectMapper mapper;
@Value("${bedrock.default-model-id:anthropic.claude-sonnet-4-5-20250929-v1:0}")
private String defaultModelId;
public BedrockAIService(BedrockRuntimeClient bedrockRuntimeClient, ObjectMapper mapper) {
this.bedrockRuntimeClient = bedrockRuntimeClient;
this.mapper = mapper;
}
public String generateText(String prompt) {
Map<String, Object> payload = Map.of(
"anthropic_version", "bedrock-2023-05-31",
"max_tokens", 1000,
"messages", List.of(Map.of("role", "user", "content", prompt))
);
InvokeModelResponse response = bedrockRuntimeClient.invokeModel(
InvokeModelRequest.builder()
.modelId(defaultModelId)
.body(SdkBytes.fromUtf8String(mapper.writeValueAsString(payload)))
.build());
return extractText(response.body().asUtf8String());
}
}
包括的な使用パターンについては、examples directory を参照してください。
ベストプラクティス
モデルの選択
- Claude 4.5 Sonnet:複雑な推論、分析、創造的なタスク向け
- Claude 4.5 Haiku:リアルタイムアプリケーション向けの高速かつ低コストなモデル
- Llama 3.1:一般的なタスク向けのオープンソースの代替モデル
- Titan:AWS ネイティブで、簡単なテキスト生成に適した低コストのモデル
パフォーマンス
- クライアントインスタンスを再利用する(リクエストごとに新しいクライアントを作成しない)
- I/O 操作には非同期クライアントを使用する
- 長いレスポンスにはストリーミングを実装する
- 基盤モデルの一覧をキャッシュする
セキュリティ
- 機密性の高いプロンプトデータをログに記録しない
- 認証には IAM ロールを使用する
- プロンプトインジェクションを防ぐため、ユーザー入力をサニタイズする
- パブリックアプリケーションにはレート制限を実装する
制約と警告
- コスト管理:Bedrock API の呼び出しにはトークンごとの料金が発生します。使用状況のモニタリングと予算アラートを設定してください。
- モデルへのアクセス:基盤モデルは AWS コンソールで有効にする必要があります。リージョンで利用可能か確認してください。
- レート制限:スロットリングに対して指数バックオフを実装し、モデルごとの制限を確認してください。
- ペイロードサイズ:最大ペイロードサイズはモデルによって異なります。大きなドキュメントにはチャンク分割を使用してください。
- ストリーミングの複雑さ:部分的なコンテンツとエラーリカバリーを慎重に処理してください。
- データプライバシー:プロンプトやレスポンスは AWS によってログに記録される場合があります。データポリシーを確認してください。
- 認証情報:認証情報をコードに埋め込まないでください。EC2/Lambda では IAM ロールを使用してください。
よく使われるモデル ID
- Claude Sonnet 4.5:
anthropic.claude-sonnet-4-5-20250929-v1:0 - Claude Haiku 4.5:
anthropic.claude-haiku-4-5-20251001-v1:0 - Llama 3.1 70B:
meta.llama3-1-70b-instruct-v1:0 - Titan Embeddings:
amazon.titan-embed-text-v1
完全な一覧については、Model Reference を参照してください。
参考資料
- 高度なトピック - マルチモデルのパターン、高度なエラー処理
- モデルリファレンス - 詳細な仕様、ペイロード形式
- テスト戦略 - 単体テスト、LocalStack との統合
- AWS Bedrock ユーザーガイド
- AWS SDK の例
- サポート対象モデル
関連スキル
aws-sdk-java-v2-core- AWS SDK の基本的なパターンlangchain4j-ai-services-patterns- LangChain4j との統合spring-boot-dependency-injection- Spring DI のパターン
コメント
Markdown 対応