Skip to content

Commit 1d99486

Browse files
committed
[fel] add apiKey logical of rerank model.
1 parent efd61f0 commit 1d99486

10 files changed

Lines changed: 195 additions & 136 deletions

File tree

framework/fel/java/fel-community/model-openai/src/main/java/modelengine/fel/community/model/openai/OpenAiModel.java

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,25 +19,33 @@
1919
import modelengine.fel.community.model.openai.entity.embed.OpenAiEmbeddingResponse;
2020
import modelengine.fel.community.model.openai.entity.image.OpenAiImageRequest;
2121
import modelengine.fel.community.model.openai.entity.image.OpenAiImageResponse;
22+
import modelengine.fel.community.model.openai.entity.rerank.OpenAiRerankRequest;
23+
import modelengine.fel.community.model.openai.entity.rerank.OpenAiRerankResponse;
2224
import modelengine.fel.community.model.openai.enums.ModelProcessingState;
2325
import modelengine.fel.community.model.openai.util.HttpUtils;
2426
import modelengine.fel.core.chat.ChatMessage;
2527
import modelengine.fel.core.chat.ChatModel;
2628
import modelengine.fel.core.chat.ChatOption;
2729
import modelengine.fel.core.chat.Prompt;
2830
import modelengine.fel.core.chat.support.AiMessage;
31+
import modelengine.fel.core.document.MeasurableDocument;
2932
import modelengine.fel.core.embed.EmbedModel;
3033
import modelengine.fel.core.embed.EmbedOption;
3134
import modelengine.fel.core.embed.Embedding;
3235
import modelengine.fel.core.image.ImageModel;
3336
import modelengine.fel.core.image.ImageOption;
3437
import modelengine.fel.core.model.http.SecureConfig;
38+
import modelengine.fel.core.rerank.RerankApi;
39+
import modelengine.fel.core.rerank.RerankModel;
40+
import modelengine.fel.core.rerank.RerankOption;
3541
import modelengine.fit.http.client.HttpClassicClient;
3642
import modelengine.fit.http.client.HttpClassicClientFactory;
3743
import modelengine.fit.http.client.HttpClassicClientRequest;
3844
import modelengine.fit.http.client.HttpClassicClientResponse;
45+
import modelengine.fit.http.entity.Entity;
3946
import modelengine.fit.http.entity.ObjectEntity;
4047
import modelengine.fit.http.protocol.HttpRequestMethod;
48+
import modelengine.fit.http.protocol.HttpResponseStatus;
4149
import modelengine.fit.security.Decryptor;
4250
import modelengine.fitframework.annotation.Component;
4351
import modelengine.fitframework.annotation.Fit;
@@ -69,7 +77,7 @@
6977
* @since 2024-08-07
7078
*/
7179
@Component
72-
public class OpenAiModel implements EmbedModel, ChatModel, ImageModel {
80+
public class OpenAiModel implements EmbedModel, ChatModel, ImageModel, RerankModel {
7381
private static final Logger log = Logger.get(OpenAiModel.class);
7482
private static final Map<String, Boolean> HTTPS_CONFIG_KEY_MAPS = MapBuilder.<String, Boolean>get()
7583
.put("client.http.secure.ignore-trust", Boolean.FALSE)
@@ -168,6 +176,43 @@ public List<Media> generate(String prompt, ImageOption option) {
168176
}
169177
}
170178

179+
@Override
180+
public List<MeasurableDocument> generate(List<MeasurableDocument> documents, RerankOption rerankOption) {
181+
notEmpty(documents, "The documents cannot be empty.");
182+
notNull(rerankOption, "The rerank option cannot be null.");
183+
List<String> docs = documents.stream().map(MeasurableDocument::text).collect(Collectors.toList());
184+
OpenAiRerankRequest fields = new OpenAiRerankRequest(rerankOption, docs);
185+
186+
HttpClassicClientRequest request = this.httpClient.get()
187+
.createRequest(HttpRequestMethod.POST,
188+
UrlUtils.combine(rerankOption.baseUri(), RerankApi.RERANK_ENDPOINT));
189+
HttpUtils.setBearerAuth(request, StringUtils.blankIf(rerankOption.apiKey(), this.defaultApiKey));
190+
request.entity(Entity.createObject(request, fields));
191+
OpenAiRerankResponse rerankResponse = this.rerankExchange(request);
192+
193+
return rerankResponse.results()
194+
.stream()
195+
.map(result -> new MeasurableDocument(documents.get(result.index()), result.relevanceScore()))
196+
.sorted((document1, document2) -> (int) (document2.score() - document1.score()))
197+
.collect(Collectors.toList());
198+
}
199+
200+
private OpenAiRerankResponse rerankExchange(HttpClassicClientRequest request) {
201+
try (HttpClassicClientResponse<Object> response = request.exchange(OpenAiRerankResponse.class)) {
202+
if (response.statusCode() != HttpResponseStatus.OK.statusCode()) {
203+
log.error("Failed to get rerank model response. [code={}, reason={}]",
204+
response.statusCode(),
205+
response.reasonPhrase());
206+
throw new FitException("Failed to get rerank model response.");
207+
}
208+
return ObjectUtils.cast(response.objectEntity()
209+
.map(ObjectEntity::object)
210+
.orElseThrow(() -> new FitException("The response body is abnormal.")));
211+
} catch (IOException e) {
212+
throw new IllegalStateException("Failed to request rerank model.", e);
213+
}
214+
}
215+
171216
private Choir<ChatMessage> createChatStream(HttpClassicClientRequest request) {
172217
AtomicReference<ModelProcessingState> modelProcessingState =
173218
new AtomicReference<>(ModelProcessingState.INITIAL);

framework/fel/java/fel-core/src/main/java/modelengine/fel/core/document/support/RerankRequest.java renamed to framework/fel/java/fel-community/model-openai/src/main/java/modelengine/fel/community/model/openai/entity/rerank/OpenAiRerankRequest.java

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,36 @@
44
* Licensed under the MIT License. See License.txt in the project root for license information.
55
*--------------------------------------------------------------------------------------------*/
66

7-
package modelengine.fel.core.document.support;
7+
package modelengine.fel.community.model.openai.entity.rerank;
88

9+
import modelengine.fel.core.rerank.RerankOption;
910
import modelengine.fitframework.annotation.Property;
1011
import modelengine.fitframework.inspection.Validation;
1112
import modelengine.fitframework.serialization.annotation.SerializeStrategy;
1213

1314
import java.util.List;
1415

1516
/**
16-
* 表示 Rerank API 格式的请求
17+
* 表示 OpenAi API 格式的 重排请求
1718
*
18-
* @since 2024-09-27
19+
* @author 陈镕希
20+
* @since 2025-07-28
1921
*/
2022
@SerializeStrategy(include = SerializeStrategy.Include.NON_NULL)
21-
public class RerankRequest {
23+
public class OpenAiRerankRequest {
2224
private final String model;
2325
private final String query;
2426
private final List<String> documents;
2527
@Property(name = "top_n")
2628
private final Integer topN;
2729

2830
/**
29-
* 创建 {@link RerankRequest} 的实体。
31+
* 创建 {@link OpenAiRerankRequest} 的实体。
3032
*
3133
* @param documents 表示要重新排序的文档对象。
3234
* @param rerankOption 表示 rerank 模型参数。
3335
*/
34-
public RerankRequest(RerankOption rerankOption, List<String> documents) {
36+
public OpenAiRerankRequest(RerankOption rerankOption, List<String> documents) {
3537
Validation.notNull(rerankOption, "The rerankOption cannot be null.");
3638
this.model = rerankOption.model();
3739
this.query = rerankOption.query();

framework/fel/java/fel-core/src/main/java/modelengine/fel/core/document/support/RerankResponse.java renamed to framework/fel/java/fel-community/model-openai/src/main/java/modelengine/fel/community/model/openai/entity/rerank/OpenAiRerankResponse.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
* Licensed under the MIT License. See License.txt in the project root for license information.
55
*--------------------------------------------------------------------------------------------*/
66

7-
package modelengine.fel.core.document.support;
7+
package modelengine.fel.community.model.openai.entity.rerank;
88

99
import modelengine.fitframework.annotation.Property;
1010
import modelengine.fitframework.util.CollectionUtils;
@@ -13,25 +13,26 @@
1313
import java.util.List;
1414

1515
/**
16-
* 表示 Rerank API 格式的请求
16+
* 表示 OpenAi API 格式的 重排响应
1717
*
18-
* @since 2024-09-27
18+
* @author 陈镕希
19+
* @since 2025-07-28
1920
*/
20-
public class RerankResponse {
21-
private List<RerankOrder> results;
21+
public class OpenAiRerankResponse {
22+
private List<OpenAiRerankResponse.RerankOrder> results;
2223

2324
/**
2425
* 获取重新排序后的文档列表。
2526
*
26-
* @return 表示重新排序后的文档列表的 {@link List}{@code <}{@link RerankOrder}{@code >}。
27+
* @return 表示重新排序后的文档列表的 {@link List}{@code <}{@link OpenAiRerankResponse.RerankOrder}{@code >}。
2728
*/
28-
public List<RerankOrder> results() {
29+
public List<OpenAiRerankResponse.RerankOrder> results() {
2930
return CollectionUtils.isEmpty(this.results)
3031
? Collections.emptyList()
3132
: Collections.unmodifiableList(this.results);
3233
}
3334

34-
static class RerankOrder {
35+
public static class RerankOrder {
3536
private int index;
3637
@Property(name = "relevance_score")
3738
private double relevanceScore;

framework/fel/java/fel-core/src/main/java/modelengine/fel/core/document/support/RerankDocumentProcessor.java

Lines changed: 8 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,9 @@
88

99
import modelengine.fel.core.document.DocumentPostProcessor;
1010
import modelengine.fel.core.document.MeasurableDocument;
11+
import modelengine.fel.core.rerank.RerankApi;
12+
import modelengine.fel.core.rerank.RerankModel;
13+
import modelengine.fel.core.rerank.RerankOption;
1114
import modelengine.fit.http.client.HttpClassicClient;
1215
import modelengine.fit.http.client.HttpClassicClientFactory;
1316
import modelengine.fit.http.client.HttpClassicClientRequest;
@@ -35,22 +38,18 @@
3538
* @since 2024-09-14
3639
*/
3740
public class RerankDocumentProcessor implements DocumentPostProcessor {
38-
private static final Logger log = Logger.get(RerankDocumentProcessor.class);
39-
40-
private final LazyLoader<HttpClassicClient> httpClient;
4141
private final RerankOption rerankOption;
42+
private final RerankModel rerankModel;
4243

4344
/**
4445
* 创建 {@link RerankDocumentProcessor} 的实体。
4546
*
46-
* @param httpClientFactory 表示 {@link HttpClassicClientFactory} 的实例。
4747
* @param rerankOption 表示 rerank 模型参数的 {@link RerankOption}
48+
* @param rerankModel 表示 rerank 模型接口的 {@link RerankModel}
4849
*/
49-
public RerankDocumentProcessor(HttpClassicClientFactory httpClientFactory, RerankOption rerankOption) {
50-
Validation.notNull(httpClientFactory, "The httpClientFactory cannot be null.");
51-
this.httpClient =
52-
new LazyLoader<>(() -> httpClientFactory.create(HttpClassicClientFactory.Config.builder().build()));
50+
public RerankDocumentProcessor(RerankOption rerankOption, RerankModel rerankModel) {
5351
this.rerankOption = Validation.notNull(rerankOption, "The rerankOption cannot be null.");
52+
this.rerankModel = Validation.notNull(rerankModel, "The rerankModel cannot be null.");
5453
}
5554

5655
/**
@@ -63,35 +62,6 @@ public List<MeasurableDocument> process(List<MeasurableDocument> documents) {
6362
if (CollectionUtils.isEmpty(documents)) {
6463
return Collections.emptyList();
6564
}
66-
List<String> docs = documents.stream().map(MeasurableDocument::text).collect(Collectors.toList());
67-
RerankRequest fields = new RerankRequest(this.rerankOption, docs);
68-
69-
HttpClassicClientRequest request = this.httpClient.get()
70-
.createRequest(HttpRequestMethod.POST,
71-
UrlUtils.combine(this.rerankOption.baseUri(), RerankApi.RERANK_ENDPOINT));
72-
request.entity(Entity.createObject(request, fields));
73-
RerankResponse rerankResponse = this.rerankExchange(request);
74-
75-
return rerankResponse.results()
76-
.stream()
77-
.map(result -> new MeasurableDocument(documents.get(result.index()), result.relevanceScore()))
78-
.sorted((document1, document2) -> (int) (document2.score() - document1.score()))
79-
.collect(Collectors.toList());
80-
}
81-
82-
private RerankResponse rerankExchange(HttpClassicClientRequest request) {
83-
try (HttpClassicClientResponse<Object> response = request.exchange(RerankResponse.class)) {
84-
if (response.statusCode() != HttpResponseStatus.OK.statusCode()) {
85-
log.error("Failed to get rerank model response. [code={}, reason={}]",
86-
response.statusCode(),
87-
response.reasonPhrase());
88-
throw new FitException("Failed to get rerank model response.");
89-
}
90-
return ObjectUtils.cast(response.objectEntity()
91-
.map(ObjectEntity::object)
92-
.orElseThrow(() -> new FitException("The response body is abnormal.")));
93-
} catch (IOException e) {
94-
throw new IllegalStateException("Failed to request rerank model.", e);
95-
}
65+
return rerankModel.generate(documents, rerankOption);
9666
}
9767
}
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
3+
* This file is a part of the ModelEngine Project.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*--------------------------------------------------------------------------------------------*/
6+
7+
package modelengine.fel.core.rerank;
8+
9+
/**
10+
* 提供 Rerank 客户端接口:发送 Rerank API 格式的请求并接收响应。
11+
*
12+
* @since 2024-09-27
13+
*/
14+
public interface RerankApi {
15+
/**
16+
* Rerank 模型请求的端点。
17+
*/
18+
String RERANK_ENDPOINT = "/rerank";
19+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) 2025 Huawei Technologies Co., Ltd. All rights reserved.
3+
* This file is a part of the ModelEngine Project.
4+
* Licensed under the MIT License. See License.txt in the project root for license information.
5+
*--------------------------------------------------------------------------------------------*/
6+
7+
package modelengine.fel.core.rerank;
8+
9+
import modelengine.fel.core.document.MeasurableDocument;
10+
11+
import java.util.List;
12+
13+
/**
14+
* 表示重排模型服务。
15+
*
16+
* @author 陈镕希
17+
* @since 2025-07-26
18+
*/
19+
public interface RerankModel {
20+
/**
21+
* 对检索结果进行重排序。
22+
*
23+
* @param documents 表示输入文档的 {@link List}{@code <}{@link MeasurableDocument}{@code >}。
24+
* @param rerankOption 表示重排模型参数的 {@link RerankOption}。
25+
* @return 表示处理后文档的 {@link List}{@code <}{@link MeasurableDocument}{@code >}。
26+
*/
27+
List<MeasurableDocument> generate(List<MeasurableDocument> documents, RerankOption rerankOption);
28+
}

framework/fel/java/fel-core/src/main/java/modelengine/fel/core/document/support/RerankOption.java renamed to framework/fel/java/fel-core/src/main/java/modelengine/fel/core/rerank/RerankOption.java

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@
44
* Licensed under the MIT License. See License.txt in the project root for license information.
55
*--------------------------------------------------------------------------------------------*/
66

7-
package modelengine.fel.core.document.support;
7+
package modelengine.fel.core.rerank;
88

9+
import modelengine.fel.core.model.http.SecureConfig;
910
import modelengine.fitframework.pattern.builder.BuilderFactory;
1011

1112
/**
@@ -35,13 +36,27 @@ public interface RerankOption {
3536
*/
3637
String baseUri();
3738

39+
/**
40+
* 获取模型接口秘钥。
41+
*
42+
* @return 表示模型接口秘钥的 {@link String}。
43+
*/
44+
String apiKey();
45+
3846
/**
3947
* 获取返回的最相关的文档数量。
4048
*
4149
* @return 表示返回的最相关的文档数量的 {@link Integer}。
4250
*/
4351
Integer topN();
4452

53+
/**
54+
* 获取调用重排模型服务的安全配置。
55+
*
56+
* @return 表示调用重排模型服务安全配置的 {@link SecureConfig}。
57+
*/
58+
SecureConfig secureConfig();
59+
4560
/**
4661
* {@link RerankOption} 的构建器。
4762
*/
@@ -70,6 +85,14 @@ interface Builder {
7085
*/
7186
Builder baseUri(String baseUri);
7287

88+
/**
89+
* 设置模型接口秘钥。
90+
*
91+
* @param apiKey 表示模型接口秘钥的 {@link String}。
92+
* @return 表示当前构建器的 {@link RerankOption.Builder}。
93+
*/
94+
Builder apiKey(String apiKey);
95+
7396
/**
7497
* 设置返回的最相关的文档数量。
7598
*
@@ -78,6 +101,14 @@ interface Builder {
78101
*/
79102
Builder topN(Integer topN);
80103

104+
/**
105+
* 设置调用重排模型服务的安全配置。
106+
*
107+
* @param secureConfig 表示调用重排模型服务安全配置的 {@link SecureConfig}。
108+
* @return 表示当前构建器的 {@link Builder}。
109+
*/
110+
Builder secureConfig(SecureConfig secureConfig);
111+
81112
/**
82113
* 构建对象。
83114
*

0 commit comments

Comments
 (0)