Skip to content

Commit eeccd04

Browse files
author
wmz7year
committed
Re-implementing Amazon Bedrock Chat model with Amazon Bedrock Converse API.
1 parent e4ee01a commit eeccd04

File tree

58 files changed

+1713
-1225
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

58 files changed

+1713
-1225
lines changed
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
/*
2+
* Copyright 2023 - 2024 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.ai.bedrock;
17+
18+
import java.util.HashMap;
19+
20+
import org.springframework.ai.chat.metadata.ChatResponseMetadata;
21+
import org.springframework.ai.chat.metadata.EmptyUsage;
22+
import org.springframework.ai.chat.metadata.Usage;
23+
24+
import software.amazon.awssdk.services.bedrockruntime.model.ConverseMetrics;
25+
import software.amazon.awssdk.services.bedrockruntime.model.ConverseResponse;
26+
import software.amazon.awssdk.services.bedrockruntime.model.ConverseStreamMetadataEvent;
27+
import software.amazon.awssdk.services.bedrockruntime.model.ConverseStreamMetrics;
28+
29+
/**
30+
* {@link ChatResponseMetadata} implementation for {@literal Amazon Bedrock}.
31+
*
32+
* @author Wei Jiang
33+
* @since 1.0.0
34+
*/
35+
public class BedrockChatResponseMetadata extends HashMap<String, Object> implements ChatResponseMetadata {
36+
37+
protected static final String AI_METADATA_STRING = "{ @type: %1$s, id: %2$s, usage: %3$s, latency: %4$sms}";
38+
39+
private final String id;
40+
41+
private final Usage usage;
42+
43+
private final Long latencyMs;
44+
45+
public static BedrockChatResponseMetadata from(ConverseResponse response) {
46+
String requestId = response.responseMetadata().requestId();
47+
48+
BedrockUsage usage = BedrockUsage.from(response.usage());
49+
50+
ConverseMetrics metrics = response.metrics();
51+
52+
return new BedrockChatResponseMetadata(requestId, usage, metrics.latencyMs());
53+
}
54+
55+
public static BedrockChatResponseMetadata from(ConverseStreamMetadataEvent converseStreamMetadataEvent) {
56+
BedrockUsage usage = BedrockUsage.from(converseStreamMetadataEvent.usage());
57+
58+
ConverseStreamMetrics metrics = converseStreamMetadataEvent.metrics();
59+
60+
return new BedrockChatResponseMetadata(null, usage, metrics.latencyMs());
61+
}
62+
63+
protected BedrockChatResponseMetadata(String id, BedrockUsage usage, Long latencyMs) {
64+
this.id = id;
65+
this.usage = usage;
66+
this.latencyMs = latencyMs;
67+
}
68+
69+
public String getId() {
70+
return this.id;
71+
}
72+
73+
public Long getLatencyMs() {
74+
return latencyMs;
75+
}
76+
77+
@Override
78+
public Usage getUsage() {
79+
Usage usage = this.usage;
80+
return usage != null ? usage : new EmptyUsage();
81+
}
82+
83+
@Override
84+
public String toString() {
85+
return AI_METADATA_STRING.formatted(getClass().getName(), getId(), getUsage(), getLatencyMs());
86+
}
87+
88+
}

models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/BedrockUsage.java

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -19,42 +19,49 @@
1919
import org.springframework.ai.chat.metadata.Usage;
2020
import org.springframework.util.Assert;
2121

22+
import software.amazon.awssdk.services.bedrockruntime.model.TokenUsage;
23+
2224
/**
2325
* {@link Usage} implementation for Bedrock API.
2426
*
2527
* @author Christian Tzolov
28+
* @author Wei Jiang
2629
* @since 0.8.0
2730
*/
2831
public class BedrockUsage implements Usage {
2932

3033
public static BedrockUsage from(AmazonBedrockInvocationMetrics usage) {
31-
return new BedrockUsage(usage);
34+
return new BedrockUsage(usage.inputTokenCount().longValue(), usage.outputTokenCount().longValue());
3235
}
3336

34-
private final AmazonBedrockInvocationMetrics usage;
37+
public static BedrockUsage from(TokenUsage usage) {
38+
Assert.notNull(usage, "'TokenUsage' must not be null.");
3539

36-
protected BedrockUsage(AmazonBedrockInvocationMetrics usage) {
37-
Assert.notNull(usage, "OpenAI Usage must not be null");
38-
this.usage = usage;
40+
return new BedrockUsage(usage.inputTokens().longValue(), usage.outputTokens().longValue());
3941
}
4042

41-
protected AmazonBedrockInvocationMetrics getUsage() {
42-
return this.usage;
43+
private final Long inputTokens;
44+
45+
private final Long outputTokens;
46+
47+
protected BedrockUsage(Long inputTokens, Long outputTokens) {
48+
this.inputTokens = inputTokens;
49+
this.outputTokens = outputTokens;
4350
}
4451

4552
@Override
4653
public Long getPromptTokens() {
47-
return getUsage().inputTokenCount().longValue();
54+
return inputTokens;
4855
}
4956

5057
@Override
5158
public Long getGenerationTokens() {
52-
return getUsage().outputTokenCount().longValue();
59+
return outputTokens;
5360
}
5461

5562
@Override
5663
public String toString() {
57-
return getUsage().toString();
64+
return "BedrockUsage [inputTokens=" + inputTokens + ", outputTokens=" + outputTokens + "]";
5865
}
5966

6067
}

models/spring-ai-bedrock/src/main/java/org/springframework/ai/bedrock/anthropic/AnthropicChatOptions.java

Lines changed: 12 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@
2525
import com.fasterxml.jackson.annotation.JsonProperty;
2626

2727
/**
28+
* Java {@link ChatOptions} for the Bedrock Anthropic chat generative model chat options.
29+
* https://docs.aws.amazon.com/bedrock/latest/userguide/model-parameters-anthropic-claude-text-completion.html
30+
*
2831
* @author Christian Tzolov
32+
* @author Wei Jiang
2933
*/
3034
@JsonInclude(Include.NON_NULL)
3135
public class AnthropicChatOptions implements ChatOptions {
@@ -44,7 +48,7 @@ public class AnthropicChatOptions implements ChatOptions {
4448
* reaching this maximum. This parameter only specifies the absolute maximum number of tokens to generate. We
4549
* recommend a limit of 4,000 tokens for optimal performance.
4650
*/
47-
private @JsonProperty("max_tokens_to_sample") Integer maxTokensToSample;
51+
private @JsonProperty("max_tokens") Integer maxTokens;
4852

4953
/**
5054
* Specify the number of token choices the generative uses to generate the next token.
@@ -62,11 +66,6 @@ public class AnthropicChatOptions implements ChatOptions {
6266
* generating further tokens. The returned text doesn't contain the stop sequence.
6367
*/
6468
private @JsonProperty("stop_sequences") List<String> stopSequences;
65-
66-
/**
67-
* The version of the generative to use. The default value is bedrock-2023-05-31.
68-
*/
69-
private @JsonProperty("anthropic_version") String anthropicVersion;
7069
// @formatter:on
7170

7271
public static Builder builder() {
@@ -82,8 +81,8 @@ public Builder withTemperature(Float temperature) {
8281
return this;
8382
}
8483

85-
public Builder withMaxTokensToSample(Integer maxTokensToSample) {
86-
this.options.setMaxTokensToSample(maxTokensToSample);
84+
public Builder withMaxTokens(Integer maxTokens) {
85+
this.options.setMaxTokens(maxTokens);
8786
return this;
8887
}
8988

@@ -102,11 +101,6 @@ public Builder withStopSequences(List<String> stopSequences) {
102101
return this;
103102
}
104103

105-
public Builder withAnthropicVersion(String anthropicVersion) {
106-
this.options.setAnthropicVersion(anthropicVersion);
107-
return this;
108-
}
109-
110104
public AnthropicChatOptions build() {
111105
return this.options;
112106
}
@@ -122,12 +116,12 @@ public void setTemperature(Float temperature) {
122116
this.temperature = temperature;
123117
}
124118

125-
public Integer getMaxTokensToSample() {
126-
return this.maxTokensToSample;
119+
public Integer getMaxTokens() {
120+
return maxTokens;
127121
}
128122

129-
public void setMaxTokensToSample(Integer maxTokensToSample) {
130-
this.maxTokensToSample = maxTokensToSample;
123+
public void setMaxTokens(Integer maxTokens) {
124+
this.maxTokens = maxTokens;
131125
}
132126

133127
@Override
@@ -156,21 +150,12 @@ public void setStopSequences(List<String> stopSequences) {
156150
this.stopSequences = stopSequences;
157151
}
158152

159-
public String getAnthropicVersion() {
160-
return this.anthropicVersion;
161-
}
162-
163-
public void setAnthropicVersion(String anthropicVersion) {
164-
this.anthropicVersion = anthropicVersion;
165-
}
166-
167153
public static AnthropicChatOptions fromOptions(AnthropicChatOptions fromOptions) {
168154
return builder().withTemperature(fromOptions.getTemperature())
169-
.withMaxTokensToSample(fromOptions.getMaxTokensToSample())
155+
.withMaxTokens(fromOptions.getMaxTokens())
170156
.withTopK(fromOptions.getTopK())
171157
.withTopP(fromOptions.getTopP())
172158
.withStopSequences(fromOptions.getStopSequences())
173-
.withAnthropicVersion(fromOptions.getAnthropicVersion())
174159
.build();
175160
}
176161

0 commit comments

Comments
 (0)