@@ -63,8 +66,15 @@ public @interface AIChat {
String userPrompt() default "";
/**
- * 是否开启 stream,默认 false
+ * 是否开启 stream,默认 true
*/
- boolean streaming() default false;
+ boolean streaming() default true;
+
+ /**
+ * 传输类型,默认 SSE
+ *
+ * 请在此查看传输类型 -> {@link TransportType}
+ */
+ TransportType transportType() default TransportType.SSE;
}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIClassify.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIClassify.java
index 06e4888e5..afd07627c 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIClassify.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIClassify.java
@@ -1,5 +1,8 @@
package com.yomahub.liteflow.ai.annotation;
+import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatOptions;
+import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatRequest;
+
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@@ -16,6 +19,41 @@ import java.lang.annotation.Target;
@Target(ElementType.TYPE)
public @interface AIClassify {
+ /**
+ * 从上下文中获取的请求参数的上下文路径表达式。
+ *
+ * 如果你不希望在注解中进行静态的模型配置,或者你希望使用特定厂商实现的 ChatRequest(其中可能存在一些独有的参数),
+ * 请使用这个属性,并在上下文中提供对应的 {@link ChatRequest} 值。
+ * 如果不提供,框架将统一使用 {@link ChatRequest} 发起请求。
+ *
+ * {@link ChatRequest} 可以是对应提供商的具体实现类。
+ *
+ * 如果你使用了这个属性可以不进行 {@link AIChat#systemPrompt()} 和 {@link AIChat#userPrompt()} 和 {@link AIChat#streaming()} 的配置,
+ * 因为这些配置会从 {@link ChatRequest} 中获取。如果进行了配置,优先使用 {@link ChatRequest} 中的配置。
+ *
+ * 以及,你会发现 {@link ChatRequest#getOptions()} 的 {@link ChatOptions} 和 {@link AIComponent} 中的配置有重合。
+ * 同样的,即使你进行了 {@link AIComponent} 的配置,会优先使用 {@link ChatRequest} 的配置。
+ *
+ * 请注意:如果相关的配置为空或默认值,则会使用 {@link AIComponent} 和 {@link AIChat} 中的配置!!!
+ *
+ * 该方法用于从一个必须提供 {@code get} 方法的上下文中检索数据。
+ *
+ * 表达式支持以下两种形式:
+ *
+ * -
+ * 直接属性检索:
+ * 例如,从上下文中获取 OpenAI 的 ChatRequest,他的名字为 {@code openAIChatRequest},
+ * 表达式应为:{@code "openAIChatRequest"}。
+ *
+ * -
+ * 嵌套属性检索 (例如 Map):
+ * 例如,从上下文的一个名为 {@code requestMap} 的 Map 对象中,获取键为 {@code openAI} 的 ChatRequest 对象,
+ * 表达式应为:{@code "requestMap.openAI"}。
+ *
+ *
+ */
+ String getChatRequest() default "";
+
/**
* 系统提示词
*/
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIComponent.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIComponent.java
index 1170886cb..d5ac4a6f9 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIComponent.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIComponent.java
@@ -7,6 +7,7 @@ import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
+import java.time.Duration;
/**
* AI 组件注解,提供配置和标识功能
@@ -134,12 +135,90 @@ public @interface AIComponent {
* 是否并行 ToolCall
*/
TriState parallelToolCalls() default TriState.UNSET;
+ /**
+ * 是否自动进行 ToolCall
+ */
+ TriState autoToolCallEnabled() default TriState.UNSET;
// --- 网络和日志参数 ---
/**
- * 超时时间
+ * 连接超时时间
+ *
+ * 该值最终会被解析为一个 {@link Duration} 对象。为了提供灵活性,
+ * 支持以下两种字符串格式:
+ *
+ *
+ * - 标准 ISO-8601 格式:
+ * 这是由 {@link Duration#parse(CharSequence)} 支持的标准格式。
+ *
示例:
+ *
+ * - {@code "PT30S"} 代表 30 秒。
+ * - {@code "PT10M"} 代表 10 分钟。
+ * - {@code "PT2H"} 代表 2 小时。
+ * - {@code "P1D"} 代表 1 天。
+ *
+ *
+ * - 自定义简化格式:
+ * 为了方便配置,也支持由数字和单位后缀组成的简化格式 (单位不区分大小写)。
+ *
支持的单位:
+ *
+ * - {@code s} - 秒
+ * - {@code m} - 分钟
+ * - {@code h} - 小时
+ *
+ * 示例:
+ *
+ * - {@code "60s"} 代表 60 秒。
+ * - {@code "5m"} 代表 5 分钟。
+ *
+ *
+ *
+ *
+ * 默认值行为:
+ * 如果该值保持默认的空字符串 ({@code ""}),处理该注解的系统将会应用一个预设的、
+ * 全局的默认超时时间(60s)。
+ * @see Duration
*/
- String timeout() default "";
+ String connectTimeout() default "";
+ /**
+ * 读取超时时间
+ *
+ * 该值最终会被解析为一个 {@link Duration} 对象。为了提供灵活性,
+ * 支持以下两种字符串格式:
+ *
+ *
+ * - 标准 ISO-8601 格式:
+ * 这是由 {@link Duration#parse(CharSequence)} 支持的标准格式。
+ *
示例:
+ *
+ * - {@code "PT30S"} 代表 30 秒。
+ * - {@code "PT10M"} 代表 10 分钟。
+ * - {@code "PT2H"} 代表 2 小时。
+ * - {@code "P1D"} 代表 1 天。
+ *
+ *
+ * - 自定义简化格式:
+ * 为了方便配置,也支持由数字和单位后缀组成的简化格式 (单位不区分大小写)。
+ *
支持的单位:
+ *
+ * - {@code s} - 秒
+ * - {@code m} - 分钟
+ * - {@code h} - 小时
+ *
+ * 示例:
+ *
+ * - {@code "60s"} 代表 60 秒。
+ * - {@code "5m"} 代表 5 分钟。
+ *
+ *
+ *
+ *
+ * 默认值行为:
+ * 如果该值保持默认的空字符串 ({@code ""}),处理该注解的系统将会应用一个预设的、
+ * 全局的默认超时时间(60s)。
+ * @see Duration
+ */
+ String readTimeout() default "";
/**
* 最大重试次数
*/
@@ -158,5 +237,9 @@ public @interface AIComponent {
* 自定义请求头
*/
KeyValue[] customHeaders() default {};
+ /**
+ * 是否开启思考模式
+ */
+ TriState enableThinking() default TriState.UNSET;
}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIOutput.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIOutput.java
index 8b1cbe8cb..060f1d534 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIOutput.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/annotation/AIOutput.java
@@ -1,6 +1,6 @@
package com.yomahub.liteflow.ai.annotation;
-import com.yomahub.liteflow.ai.domain.enums.ResponseType;
+import com.yomahub.liteflow.ai.engine.model.output.ResponseType;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
@@ -95,7 +95,7 @@ public @interface AIOutput {
/**
* 如需启用,请设置 {@link AIOutput#responseType()} 为 {@link ResponseType#JSON}
*
- * 表示输出的 JSON Schema 定义。如果需要添加描述信息,请使用 LangChain4j 的相关注解
+ * 表示输出的 JSON Schema 定义。如果需要添加描述信息,请使用{@link com.yomahub.liteflow.ai.engine.model.output.structure.Description}
*/
Class> entityClass() default String.class;
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/context/StreamHandler.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/context/StreamHandler.java
index 52e1234a7..66ecdd838 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/context/StreamHandler.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/context/StreamHandler.java
@@ -2,6 +2,7 @@ package com.yomahub.liteflow.ai.context;
import com.yomahub.liteflow.ai.engine.interact.pipeline.InteractContext;
import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatResponse;
+import com.yomahub.liteflow.ai.engine.model.output.TokenUsage;
/**
* 流式输出处理器
@@ -11,6 +12,29 @@ import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatResponse;
*/
public interface StreamHandler {
+
+ /**
+ * 请求开始时的回调方法
+ *
+ * @param context 聊天上下文,包含处理过程中的状态和信息
+ */
+ void onStart(InteractContext context);
+
+ /**
+ * 请求关闭时的回调方法
+ *
+ * @param context 聊天上下文,包含处理过程中的状态和信息
+ */
+ void onClose(InteractContext context);
+
+ /**
+ * 处理过程中发生错误的回调方法。
+ *
+ * @param context 聊天上下文,包含处理过程中的状态和信息
+ * @param t
+ */
+ void onError(InteractContext context, Throwable t);
+
/**
* 处理文本消息的回调方法。需要启用流式调用
*
@@ -42,8 +66,7 @@ public interface StreamHandler {
* @param content Token 统计信息内容
* @param context 聊天上下文,包含处理过程中的状态和信息
*/
- // TODO args
- Object onUsage(Object content, InteractContext context);
+ TokenUsage onUsage(Object content, InteractContext context);
/**
* 处理基础信息/搜索结果的回调方法。需要启用流式调用
@@ -61,20 +84,8 @@ public interface StreamHandler {
* @param context 聊天上下文,包含处理过程中的状态和信息
* @return 处理后的结果
*/
- // TODO args
ChatResponse onCompletion(ChatResponse response, InteractContext context);
- /**
- * 处理过程中发生错误的回调方法。
- *
- * @param response 处理后的聊天响应结果,可能包含错误信息
- * @param context 聊天上下文,包含处理过程中的状态和信息
- * @param e
- * @return 处理后的结果
- */
- // TODO args
- ChatResponse onError(ChatResponse response, InteractContext context, Exception e);
-
/**
* 最终结果处理的回调方法。无论是否发生错误均会调用此方法。
*
@@ -82,6 +93,5 @@ public interface StreamHandler {
* @param context 聊天上下文,包含处理过程中的状态和信息
* @return 处理后的结果
*/
- // TODO args
ChatResponse onFinal(ChatResponse response, InteractContext context);
}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/ModelConfig.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/ModelConfig.java
deleted file mode 100644
index b6839c98b..000000000
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/ModelConfig.java
+++ /dev/null
@@ -1,224 +0,0 @@
-package com.yomahub.liteflow.ai.domain;
-
-import com.yomahub.liteflow.ai.annotation.AIComponent;
-import com.yomahub.liteflow.ai.util.KeyValue;
-import com.yomahub.liteflow.ai.util.TriState;
-
-import java.util.Arrays;
-import java.util.List;
-import java.util.Objects;
-
-/**
- * 模型配置
- *
- * @author 苍镜月
- * @since TODO
- */
-
-public final class ModelConfig {
-
- private final String provider;
- private final String apiUrl;
- private final String endPoint;
- private final String model;
- private final String apiKey;
- private final String version;
- private final String timeout;
- private final int maxRetries;
- private final double temperature;
- private final double topP;
- private final int topK;
- private final int maxTokens;
- private final List stop;
- private final int seed;
- private final double repeatPenalty;
- private final double presencePenalty;
- private final double frequencyPenalty;
- private final TriState parallelToolCalls;
- private final TriState logRequests;
- private final TriState logResponses;
- private final List customHeaders;
-
- public ModelConfig(String provider, String apiUrl, String endPoint, String model, String apiKey,
- String version, String timeout, int maxRetries, double temperature, double topP,
- int topK, int maxTokens, List stop, int seed, double repeatPenalty,
- double presencePenalty, double frequencyPenalty,
- TriState parallelToolCalls, TriState logRequests,
- TriState logResponses, List customHeaders) {
- this.provider = provider;
- this.apiUrl = apiUrl;
- this.endPoint = endPoint;
- this.model = model;
- this.apiKey = apiKey;
- this.version = version;
- this.timeout = timeout;
- this.maxRetries = maxRetries;
- this.temperature = temperature;
- this.topP = topP;
- this.topK = topK;
- this.maxTokens = maxTokens;
- this.stop = stop;
- this.seed = seed;
- this.repeatPenalty = repeatPenalty;
- this.presencePenalty = presencePenalty;
- this.frequencyPenalty = frequencyPenalty;
- this.parallelToolCalls = parallelToolCalls;
- this.logRequests = logRequests;
- this.logResponses = logResponses;
- this.customHeaders = customHeaders;
- }
-
- public static ModelConfig fromAnnotation(AIComponent anno) {
- return new ModelConfig(
- anno.provider(), anno.apiUrl(), anno.endPoint(), anno.model(), anno.apiKey(), anno.version(),
- anno.timeout(), anno.maxRetries(), anno.temperature(), anno.topP(), anno.topK(),
- anno.maxTokens(), Arrays.asList(anno.stop()), anno.seed(), anno.repeatPenalty(),
- anno.presencePenalty(), anno.frequencyPenalty(), anno.parallelToolCalls(), anno.logRequests(),
- anno.logResponses(), Arrays.asList(anno.customHeaders())
- );
- }
-
- public String getProvider() {
- return provider;
- }
-
- public String getApiUrl() {
- return apiUrl;
- }
-
- public String getEndPoint() {
- return endPoint;
- }
-
- public String getModel() {
- return model;
- }
-
- public String getApiKey() {
- return apiKey;
- }
-
- public String getVersion() {
- return version;
- }
-
- public String getTimeout() {
- return timeout;
- }
-
- public int getMaxRetries() {
- return maxRetries;
- }
-
- public double getTemperature() {
- return temperature;
- }
-
- public double getTopP() {
- return topP;
- }
-
- public int getTopK() {
- return topK;
- }
-
- public int getMaxTokens() {
- return maxTokens;
- }
-
- public List getStop() {
- return stop;
- }
-
- public int getSeed() {
- return seed;
- }
-
- public double getRepeatPenalty() {
- return repeatPenalty;
- }
-
- public double getPresencePenalty() {
- return presencePenalty;
- }
-
- public double getFrequencyPenalty() {
- return frequencyPenalty;
- }
-
- public TriState getParallelToolCalls() {
- return parallelToolCalls;
- }
-
- public TriState getLogRequests() {
- return logRequests;
- }
-
- public TriState getLogResponses() {
- return logResponses;
- }
-
- public List getCustomHeaders() {
- return customHeaders;
- }
-
- @Override
- public boolean equals(Object o) {
- if (this == o) return true;
- if (o == null || getClass() != o.getClass()) return false;
- ModelConfig that = (ModelConfig) o;
- return maxRetries == that.maxRetries &&
- Double.compare(that.temperature, temperature) == 0 &&
- Double.compare(that.topP, topP) == 0 &&
- topK == that.topK &&
- maxTokens == that.maxTokens &&
- seed == that.seed &&
- Double.compare(that.repeatPenalty, repeatPenalty) == 0 &&
- Double.compare(that.presencePenalty, presencePenalty) == 0 &&
- Double.compare(that.frequencyPenalty, frequencyPenalty) == 0 &&
- Objects.equals(provider, that.provider) &&
- Objects.equals(apiUrl, that.apiUrl) &&
- Objects.equals(endPoint, that.endPoint) &&
- Objects.equals(model, that.model) &&
- Objects.equals(apiKey, that.apiKey) &&
- Objects.equals(version, that.version) &&
- Objects.equals(timeout, that.timeout) &&
- Objects.equals(stop, that.stop) &&
- parallelToolCalls == that.parallelToolCalls &&
- logRequests == that.logRequests &&
- logResponses == that.logResponses &&
- Objects.equals(customHeaders, that.customHeaders);
- }
-
- @Override
- public int hashCode() {
- return Objects.hash(provider, apiUrl, endPoint, model, apiKey, version, timeout, maxRetries, temperature, topP, topK, maxTokens, stop, seed, repeatPenalty, presencePenalty, frequencyPenalty, parallelToolCalls, logRequests, logResponses, customHeaders);
- }
-
- @Override
- public String toString() {
- return "ModelConfig{" +
- "provider='" + provider + '\'' +
- ", apiUrl='" + apiUrl + '\'' +
- ", endPoint='" + endPoint + '\'' +
- ", model='" + model + '\'' +
- ", apiKey='" + apiKey + '\'' +
- ", version='" + version + '\'' +
- ", timeout='" + timeout + '\'' +
- ", maxRetries=" + maxRetries +
- ", temperature=" + temperature +
- ", topP=" + topP +
- ", topK=" + topK +
- ", maxTokens=" + maxTokens +
- ", stop=" + stop +
- ", seed=" + seed +
- ", repeatPenalty=" + repeatPenalty +
- ", presencePenalty=" + presencePenalty +
- ", frequencyPenalty=" + frequencyPenalty +
- ", parallelToolCalls=" + parallelToolCalls +
- ", logRequests=" + logRequests +
- ", logResponses=" + logResponses +
- ", customHeaders=" + customHeaders +
- '}';
- }
-}
\ No newline at end of file
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/dto/ModelConfigAggregator.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/dto/ModelConfigAggregator.java
new file mode 100644
index 000000000..4e6eb2018
--- /dev/null
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/dto/ModelConfigAggregator.java
@@ -0,0 +1,251 @@
+package com.yomahub.liteflow.ai.domain.dto;
+
+import com.yomahub.liteflow.ai.annotation.AIComponent;
+import com.yomahub.liteflow.ai.util.DurationUtil;
+import com.yomahub.liteflow.ai.util.KeyValue;
+import com.yomahub.liteflow.ai.util.TriState;
+
+import java.time.Duration;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * 模型配置聚合(与 {@link AIComponent} 相互映射)
+ *
+ * @author 苍镜月
+ * @since TODO
+ */
+
+public final class ModelConfigAggregator {
+
+ private final String provider;
+ // --- 连接、鉴权参数 ---
+ private final String apiUrl;
+ private final String endPoint;
+ private final String model;
+ private final String apiKey;
+ private final String version;
+ // --- 核心参数 ---
+ private final double temperature;
+ private final double topP;
+ private final int topK;
+ private final int maxTokens;
+ private final List stop;
+ private final int seed;
+ // --- 惩罚参数 ---
+ private final double repeatPenalty;
+ private final double presencePenalty;
+ private final double frequencyPenalty;
+ // --- Tool Calling ----
+ private final TriState parallelToolCalls;
+ private final TriState autoToolCallEnabled;
+ // --- 网络和日志参数 ---
+ private final Duration connectTimeout;
+ private final Duration readTimeout;
+ private final int maxRetries;
+ private final TriState logRequests;
+ private final TriState logResponses;
+ // --- 其他参数 ---
+ private final List customHeaders;
+ private final TriState enableThinking;
+
+ /**
+ * 从 {@link AIComponent} 注解中解析模型配置
+ *
+ * @param aiComponent AIComponent 注解实例
+ * @return ModelConfigAggregator 实例
+ */
+ public static ModelConfigAggregator parseFromAnnotation(AIComponent aiComponent) {
+ return new ModelConfigAggregator(
+ aiComponent.provider(),
+ aiComponent.apiUrl(),
+ aiComponent.endPoint(),
+ aiComponent.model(),
+ aiComponent.apiKey(),
+ aiComponent.version(),
+ aiComponent.temperature(),
+ aiComponent.topP(),
+ aiComponent.topK(),
+ aiComponent.maxTokens(),
+ Objects.nonNull(aiComponent.stop()) ? Arrays.asList(aiComponent.stop()) : Collections.emptyList(),
+ aiComponent.seed(),
+ aiComponent.repeatPenalty(),
+ aiComponent.presencePenalty(),
+ aiComponent.frequencyPenalty(),
+ aiComponent.parallelToolCalls(),
+ aiComponent.autoToolCallEnabled(),
+ DurationUtil.toDuration(aiComponent.connectTimeout(), Duration.ofSeconds(60)),
+ DurationUtil.toDuration(aiComponent.readTimeout(), Duration.ofSeconds(60)),
+ aiComponent.maxRetries() <= 0 ? 3 : aiComponent.maxRetries(),
+ aiComponent.logRequests(),
+ aiComponent.logResponses(),
+ Objects.nonNull(aiComponent.customHeaders()) ? Arrays.asList(aiComponent.customHeaders()) : Collections.emptyList(),
+ aiComponent.enableThinking()
+ );
+ }
+
+ private ModelConfigAggregator(String provider, String apiUrl, String endPoint,
+ String model, String apiKey, String version,
+ double temperature, double topP, int topK,
+ int maxTokens, List stop, int seed,
+ double repeatPenalty, double presencePenalty,
+ double frequencyPenalty, TriState parallelToolCalls,
+ TriState autoToolCallEnabled, Duration connectTimeout,
+ Duration readTimeout, int maxRetries, TriState logRequests,
+ TriState logResponses, List customHeaders, TriState enableThinking) {
+ this.provider = provider;
+ this.apiUrl = apiUrl;
+ this.endPoint = endPoint;
+ this.model = model;
+ this.apiKey = apiKey;
+ this.version = version;
+ this.temperature = temperature;
+ this.topP = topP;
+ this.topK = topK;
+ this.maxTokens = maxTokens;
+ this.stop = stop;
+ this.seed = seed;
+ this.repeatPenalty = repeatPenalty;
+ this.presencePenalty = presencePenalty;
+ this.frequencyPenalty = frequencyPenalty;
+ this.parallelToolCalls = parallelToolCalls;
+ this.autoToolCallEnabled = autoToolCallEnabled;
+ this.connectTimeout = connectTimeout;
+ this.readTimeout = readTimeout;
+ this.maxRetries = maxRetries;
+ this.logRequests = logRequests;
+ this.logResponses = logResponses;
+ this.customHeaders = customHeaders;
+ this.enableThinking = enableThinking;
+ }
+
+ /**
+ * 获取默认的模型配置聚合实例
+ */
+ public static ModelConfigAggregator getDefault() {
+ return new ModelConfigAggregator(
+ "",
+ "",
+ "",
+ "",
+ "",
+ "",
+ -1.0,
+ -1.0,
+ -1,
+ -1,
+ Collections.emptyList(),
+ -1,
+ -1.0,
+ -1.0,
+ -1.0,
+ TriState.UNSET,
+ TriState.UNSET,
+ Duration.ofSeconds(60),
+ Duration.ofSeconds(60),
+ -1,
+ TriState.UNSET,
+ TriState.UNSET,
+ Collections.emptyList(),
+ TriState.UNSET
+ );
+ }
+
+ public String getProvider() {
+ return provider;
+ }
+
+ public String getApiUrl() {
+ return apiUrl;
+ }
+
+ public String getEndPoint() {
+ return endPoint;
+ }
+
+ public String getModel() {
+ return model;
+ }
+
+ public String getApiKey() {
+ return apiKey;
+ }
+
+ public String getVersion() {
+ return version;
+ }
+
+ public double getTemperature() {
+ return temperature;
+ }
+
+ public double getTopP() {
+ return topP;
+ }
+
+ public int getTopK() {
+ return topK;
+ }
+
+ public int getMaxTokens() {
+ return maxTokens;
+ }
+
+ public List getStop() {
+ return stop;
+ }
+
+ public int getSeed() {
+ return seed;
+ }
+
+ public double getRepeatPenalty() {
+ return repeatPenalty;
+ }
+
+ public double getPresencePenalty() {
+ return presencePenalty;
+ }
+
+ public double getFrequencyPenalty() {
+ return frequencyPenalty;
+ }
+
+ public TriState getParallelToolCalls() {
+ return parallelToolCalls;
+ }
+
+ public TriState getAutoToolCallEnabled() {
+ return autoToolCallEnabled;
+ }
+
+ public Duration getConnectTimeout() {
+ return connectTimeout;
+ }
+
+ public Duration getReadTimeout() {
+ return readTimeout;
+ }
+
+ public int getMaxRetries() {
+ return maxRetries;
+ }
+
+ public TriState getLogRequests() {
+ return logRequests;
+ }
+
+ public TriState getLogResponses() {
+ return logResponses;
+ }
+
+ public List getCustomHeaders() {
+ return customHeaders;
+ }
+
+ public TriState getEnableThinking() {
+ return enableThinking;
+ }
+}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/dto/ParsedAnnotationConfig.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/dto/ParsedAnnotationConfig.java
new file mode 100644
index 000000000..a289f9d90
--- /dev/null
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/dto/ParsedAnnotationConfig.java
@@ -0,0 +1,50 @@
+package com.yomahub.liteflow.ai.domain.dto;
+
+import com.yomahub.liteflow.ai.engine.model.output.ResponseType;
+
+/**
+ * 解析后的注解配置类
+ *
+ * @author 苍镜月
+ * @since TODO
+ */
+
+public class ParsedAnnotationConfig {
+
+ private String systemPrompt;
+ private String userPrompt;
+ private ResponseType responseType = ResponseType.TEXT;
+ private Class> entityClass = String.class;
+
+ public String getSystemPrompt() {
+ return systemPrompt;
+ }
+
+ public String getUserPrompt() {
+ return userPrompt;
+ }
+
+ public ResponseType getResponseType() {
+ return responseType;
+ }
+
+ public Class> getEntityClass() {
+ return entityClass;
+ }
+
+ public void setSystemPrompt(String systemPrompt) {
+ this.systemPrompt = systemPrompt;
+ }
+
+ public void setUserPrompt(String userPrompt) {
+ this.userPrompt = userPrompt;
+ }
+
+ public void setResponseType(ResponseType responseType) {
+ this.responseType = responseType;
+ }
+
+ public void setEntityClass(Class> entityClass) {
+ this.entityClass = entityClass;
+ }
+}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/AbstractAnnotationProcessor.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/AbstractAnnotationProcessor.java
index 2adb3cd3a..73b91326d 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/AbstractAnnotationProcessor.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/AbstractAnnotationProcessor.java
@@ -1,10 +1,16 @@
package com.yomahub.liteflow.ai.parse;
import cn.hutool.core.util.StrUtil;
+import com.yomahub.liteflow.ai.annotation.AIComponent;
import com.yomahub.liteflow.ai.annotation.AIInput;
import com.yomahub.liteflow.ai.annotation.AIOutput;
+import com.yomahub.liteflow.ai.domain.dto.ModelConfigAggregator;
+import com.yomahub.liteflow.ai.domain.dto.ParsedAnnotationConfig;
import com.yomahub.liteflow.ai.domain.enums.AITypeEnum;
-import com.yomahub.liteflow.ai.domain.enums.ResponseType;
+import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatRequest;
+import com.yomahub.liteflow.ai.engine.model.output.ResponseType;
+import com.yomahub.liteflow.ai.parse.assemble.ChatRequestAssembler;
+import com.yomahub.liteflow.ai.parse.assemble.RequestAssembler;
import com.yomahub.liteflow.ai.parse.context.ContextAccessor;
import com.yomahub.liteflow.ai.parse.context.ProcessorContext;
import com.yomahub.liteflow.ai.parse.prompt.PromptTemplateParser;
@@ -31,6 +37,8 @@ public abstract class AbstractAnnotationProcessor CHAT_REQUEST_ASSEMBLER = new ChatRequestAssembler();
+
@Override
public void afterPropertiesSet() throws Exception {
AnnotationParser.register(getAIType().getCode(), this);
@@ -43,6 +51,23 @@ public abstract class AbstractAnnotationProcessor context) {
+ T wrapBean = context.getWrapBean();
+ // 获取模型配置聚合器
+ AIComponent aiComponent = wrapBean.getAiComponent();
+ if (Objects.isNull(aiComponent)) {
+ LOG.warn("AIComponent annotation is null, using default model configuration.");
+ wrapBean.setConfig(ModelConfigAggregator.getDefault());
+ return;
+ }
+ wrapBean.setConfig(ModelConfigAggregator.parseFromAnnotation(aiComponent));
+ }
+
/**
* 解析提示词
*
@@ -85,15 +110,16 @@ public abstract class AbstractAnnotationProcessor context) {
+ // 解析模型配置
+ parseModelConfig(context);
+
ChatProxyWrapBean wrapBean = context.getWrapBean();
+ ParsedAnnotationConfig annotationConfig = context.getParsedAnnotationConfig();
// 设置基本属性
SetUtil.setIfPresent(wrapBean::setStreaming, annotation.streaming());
// 处理系统提示词
- parsePrompt(annotation.systemPrompt(), context, wrapBean::setSystemPrompt);
+ parsePrompt(annotation.systemPrompt(), context, annotationConfig::setSystemPrompt);
// 处理用户提示词
- parsePrompt(annotation.userPrompt(), context, wrapBean::setUserPrompt);
+ parsePrompt(annotation.userPrompt(), context, annotationConfig::setUserPrompt);
// 处理结构化输出参数绑定
parseOutput(context);
- // TODO 组装 Request
+ // 从上下文获取动态 ChatRequest
+ ChatRequest contextChatRequest = ContextAccessor.searchContextByExpression(annotation.getChatRequest(), context);
+
+ // 组装 ChatRequest
+ CHAT_REQUEST_ASSEMBLER.assemble(contextChatRequest, context);
}
@Override
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/anno/ClassifyAnnotationProcessor.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/anno/ClassifyAnnotationProcessor.java
index 136c8ee9a..62d33a064 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/anno/ClassifyAnnotationProcessor.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/anno/ClassifyAnnotationProcessor.java
@@ -1,8 +1,11 @@
package com.yomahub.liteflow.ai.parse.anno;
import com.yomahub.liteflow.ai.annotation.AIClassify;
+import com.yomahub.liteflow.ai.domain.dto.ParsedAnnotationConfig;
import com.yomahub.liteflow.ai.domain.enums.AITypeEnum;
+import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatRequest;
import com.yomahub.liteflow.ai.parse.AbstractAnnotationProcessor;
+import com.yomahub.liteflow.ai.parse.context.ContextAccessor;
import com.yomahub.liteflow.ai.parse.context.ProcessorContext;
import com.yomahub.liteflow.ai.proxy.wrap.ClassifyProxyWrapBean;
import com.yomahub.liteflow.ai.util.SetUtil;
@@ -21,20 +24,30 @@ public class ClassifyAnnotationProcessor extends AbstractAnnotationProcessor context) {
+ // 解析模型配置
+ parseModelConfig(context);
+
ClassifyProxyWrapBean wrapBean = context.getWrapBean();
+ ParsedAnnotationConfig annotationConfig = context.getParsedAnnotationConfig();
SetUtil.setIfPresent(wrapBean::setCategories, Arrays.stream(annotation.categories()).collect(Collectors.toList()));
SetUtil.setIfPresent(wrapBean::setMultiLabel, annotation.multiLabel());
// 处理系统提示词
- parsePrompt(annotation.systemPrompt(), context, wrapBean::setSystemPrompt);
+ parsePrompt(annotation.systemPrompt(), context, annotationConfig::setSystemPrompt);
// 处理用户提示词
- parsePrompt(annotation.userPrompt(), context, wrapBean::setUserPrompt);
+ parsePrompt(annotation.userPrompt(), context, annotationConfig::setUserPrompt);
// 处理结构化输出参数绑定
parseOutput(context);
+
+ // 从上下文获取动态 ChatRequest
+ ChatRequest contextChatRequest = ContextAccessor.searchContextByExpression(annotation.getChatRequest(), context);
+
+ // 组装 ChatRequest
+ CHAT_REQUEST_ASSEMBLER.assemble(contextChatRequest, context);
}
@Override
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/assemble/AbstractRequestAssembler.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/assemble/AbstractRequestAssembler.java
new file mode 100644
index 000000000..793f4139d
--- /dev/null
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/assemble/AbstractRequestAssembler.java
@@ -0,0 +1,74 @@
+package com.yomahub.liteflow.ai.parse.assemble;
+
+import com.yomahub.liteflow.ai.context.ChatContext;
+import com.yomahub.liteflow.ai.domain.dto.ModelConfigAggregator;
+import com.yomahub.liteflow.ai.domain.dto.ParsedAnnotationConfig;
+import com.yomahub.liteflow.ai.engine.model.ModelRequest;
+import com.yomahub.liteflow.ai.parse.context.ProcessorContext;
+import com.yomahub.liteflow.ai.util.SetUtil;
+import com.yomahub.liteflow.log.LFLog;
+import com.yomahub.liteflow.log.LFLoggerManager;
+
+import java.util.function.Supplier;
+
+/**
+ * 抽象请求组装器
+ *
+ * @author 苍镜月
+ * @since TODO
+ */
+
+public abstract class AbstractRequestAssembler implements RequestAssembler {
+
+ protected final LFLog LOG = LFLoggerManager.getLogger(this.getClass());
+
+ /**
+ * 组装请求对象(最终请求对象存储于 {@link ProcessorContext} 中的 {@link ModelRequest} 属性中)
+ *
+ * @param contextRequest 上下文中的请求示例(可以为 null)
+ * @param context 处理器上下文
+ */
+ public final void assemble(R contextRequest, ProcessorContext> context) {
+ ParsedAnnotationConfig annotationConfig = context.getParsedAnnotationConfig();
+ ModelConfigAggregator config = context.getWrapBean().getConfig();
+
+ // 组装请求
+ R req = doAssemble(contextRequest, annotationConfig, config, context.getChatContext());
+ // 设置到处理器上下文
+ context.setModelRequest(req);
+ }
+
+ /**
+ * 实际的请求组装逻辑
+ *
+ * @param contextRequest 上下文中的请求示例(可以为 null)
+ * @param annotationConfig 注解解析配置
+ * @param config 模型配置聚合
+ * @param context chat上下文
+ * @return 最终请求对象
+ */
+ protected abstract R doAssemble(
+ R contextRequest,
+ ParsedAnnotationConfig annotationConfig,
+ ModelConfigAggregator config,
+ ChatContext context
+ );
+
+ /**
+ * 合并多个 Supplier 的值,返回第一个非空的值
+ *
+ * @param suppliers 多个 Supplier
+ * @param 值的类型
+ * @return 第一个非空的值,如果都为空则返回 null
+ */
+ @SafeVarargs
+ protected static T merge(Supplier... suppliers) {
+ for (Supplier supplier : suppliers) {
+ T value = supplier.get();
+ if (SetUtil.isPresent(value)) {
+ return value;
+ }
+ }
+ return null;
+ }
+}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/assemble/ChatRequestAssembler.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/assemble/ChatRequestAssembler.java
new file mode 100644
index 000000000..2c2dfcc8d
--- /dev/null
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/assemble/ChatRequestAssembler.java
@@ -0,0 +1,73 @@
+package com.yomahub.liteflow.ai.parse.assemble;
+
+import com.yomahub.liteflow.ai.context.ChatContext;
+import com.yomahub.liteflow.ai.context.StreamHandler;
+import com.yomahub.liteflow.ai.domain.dto.ModelConfigAggregator;
+import com.yomahub.liteflow.ai.domain.dto.ParsedAnnotationConfig;
+import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatOptions;
+import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatRequest;
+import com.yomahub.liteflow.ai.engine.model.chat.message.Message;
+import com.yomahub.liteflow.ai.engine.model.chat.message.SystemMessage;
+import com.yomahub.liteflow.ai.engine.model.chat.message.UserMessage;
+import com.yomahub.liteflow.ai.util.SetUtil;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Objects;
+import java.util.Optional;
+
+/**
+ * ChatRequest 组装器
+ *
+ * @author 苍镜月
+ * @since TODO
+ */
+
+public class ChatRequestAssembler extends AbstractRequestAssembler {
+
+ @Override
+ protected ChatRequest doAssemble(ChatRequest contextRequest, ParsedAnnotationConfig annotationConfig, ModelConfigAggregator config, ChatContext context) {
+ ChatOptions contextOptions = Optional.ofNullable(contextRequest)
+ .map(ChatRequest::getOptions)
+ .orElse(ChatOptions.builder().build());
+
+ ChatRequest.Builder> builder = ChatRequest.builder();
+
+ // 1. 连接 StreamHandler 回调
+ StreamHandler streamHandler = context.getStreamHandler();
+ if (Objects.nonNull(streamHandler)) {
+ LOG.info("Connecting StreamHandler to ChatRequest");
+ builder.onStart(streamHandler::onStart)
+ .onClose(streamHandler::onClose)
+ .onError(streamHandler::onError)
+ .onText(streamHandler::onText)
+ .onThinking(streamHandler::onThinking)
+ .onToolsCalling(streamHandler::onToolsCalling)
+ .onUsage(streamHandler::onUsage)
+ .onGrounding(streamHandler::onGrounding)
+ .onCompletion(streamHandler::onCompletion)
+ .onFinal(streamHandler::onFinal);
+ }
+
+ // 2. 合并 ChatOptions
+ ChatOptions.Builder> optionsBuilder = ChatOptions.builder();
+ optionsBuilder.temperature(merge(contextOptions::getTemperature, config::getTemperature));
+ optionsBuilder.topP(merge(contextOptions::getTopP, config::getTopP));
+ optionsBuilder.topK(merge(contextOptions::getTopK, config::getTopK));
+ optionsBuilder.maxTokens(merge(contextOptions::getMaxTokens, config::getMaxTokens));
+ optionsBuilder.seed(merge(contextOptions::getSeed, config::getSeed));
+ optionsBuilder.enableThinking(merge(contextOptions::getEnableThinking, () -> config.getEnableThinking().toBool()));
+ builder.options(optionsBuilder.build());
+
+ // 3. 合并 Message
+ List messages = new ArrayList<>();
+ SetUtil.setIfPresent(t -> messages.add(new SystemMessage(t)), annotationConfig.getSystemPrompt());
+ SetUtil.setIfPresent(t -> messages.add(new UserMessage(t)), annotationConfig.getUserPrompt());
+
+ builder.messages(
+ merge(() -> Objects.nonNull(contextRequest) ? contextRequest.getMessages() : null, () -> messages)
+ );
+
+ return builder.build();
+ }
+}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/assemble/RequestAssembler.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/assemble/RequestAssembler.java
new file mode 100644
index 000000000..4c641dfe3
--- /dev/null
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/assemble/RequestAssembler.java
@@ -0,0 +1,22 @@
+package com.yomahub.liteflow.ai.parse.assemble;
+
+import com.yomahub.liteflow.ai.engine.model.ModelRequest;
+import com.yomahub.liteflow.ai.parse.context.ProcessorContext;
+
+/**
+ * 请求组装器接口
+ *
+ * @author 苍镜月
+ * @since TODO
+ */
+
+public interface RequestAssembler {
+
+ /**
+ * 组装请求对象(最终请求对象存储于 {@link ProcessorContext} 中的 {@link ModelRequest} 属性中)
+ *
+ * @param contextRequest 上下文中的请求示例(可以为 null)
+ * @param context 处理器上下文
+ */
+ void assemble(R contextRequest, ProcessorContext> context);
+}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/context/ContextAccessor.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/context/ContextAccessor.java
index 1f6a68f78..3bc971cd4 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/context/ContextAccessor.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/context/ContextAccessor.java
@@ -30,7 +30,7 @@ public class ContextAccessor {
* @param context 处理器上下文
* @return 查找到的值
*/
- public static String searchContextByExpression(String expression, ProcessorContext> context) {
+ public static T searchContextByExpression(String expression, ProcessorContext> context) {
if (StrUtil.isBlank(expression)) {
return null;
}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/context/ProcessorContext.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/context/ProcessorContext.java
index 4f8340820..bc02a8311 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/context/ProcessorContext.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/parse/context/ProcessorContext.java
@@ -3,6 +3,8 @@ package com.yomahub.liteflow.ai.parse.context;
import com.yomahub.liteflow.ai.annotation.AIInput;
import com.yomahub.liteflow.ai.annotation.AIOutput;
import com.yomahub.liteflow.ai.context.ChatContext;
+import com.yomahub.liteflow.ai.domain.dto.ParsedAnnotationConfig;
+import com.yomahub.liteflow.ai.engine.model.ModelRequest;
import com.yomahub.liteflow.ai.parse.prompt.loader.DefaultPromptResourceLoader;
import com.yomahub.liteflow.ai.parse.prompt.loader.PromptResourceLoader;
import com.yomahub.liteflow.ai.proxy.wrap.AIProxyWrapBean;
@@ -18,14 +20,18 @@ import com.yomahub.liteflow.core.NodeComponent;
public class ProcessorContext> {
private final T wrapBean;
+ private final ParsedAnnotationConfig parsedAnnotationConfig;
private final ChatContext chatContext;
private final NodeComponent nodeComponent;
private final AIInput aiInputAnno;
private final AIOutput aiOutputAnno;
private final PromptResourceLoader resourceLoader;
+ private ModelRequest modelRequest;
+
public ProcessorContext(T wrapBean, ChatContext chatContext, NodeComponent nodeComponent) {
this.wrapBean = wrapBean;
+ parsedAnnotationConfig = new ParsedAnnotationConfig();
this.chatContext = chatContext;
this.nodeComponent = nodeComponent;
this.aiInputAnno = wrapBean.getInterfaceClass().getAnnotation(AIInput.class);
@@ -56,4 +62,16 @@ public class ProcessorContext> {
public PromptResourceLoader getResourceLoader() {
return resourceLoader;
}
+
+ public ParsedAnnotationConfig getParsedAnnotationConfig() {
+ return parsedAnnotationConfig;
+ }
+
+ public ModelRequest getModelRequest() {
+ return modelRequest;
+ }
+
+ public void setModelRequest(ModelRequest modelRequest) {
+ this.modelRequest = modelRequest;
+ }
}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/AbstractAIInvocationHandler.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/AbstractAIInvocationHandler.java
index e6de9acf4..a8571847e 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/AbstractAIInvocationHandler.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/AbstractAIInvocationHandler.java
@@ -1,7 +1,7 @@
package com.yomahub.liteflow.ai.proxy.invocation;
import com.yomahub.liteflow.ai.context.ChatContext;
-import com.yomahub.liteflow.ai.domain.ModelConfig;
+import com.yomahub.liteflow.ai.domain.dto.ModelConfigAggregator;
import com.yomahub.liteflow.ai.exception.LiteFlowAIException;
import com.yomahub.liteflow.ai.parse.AnnotationParser;
import com.yomahub.liteflow.ai.parse.context.ProcessorContext;
@@ -77,19 +77,15 @@ public abstract class AbstractAIInvocationHandler>
* @param processorContext 处理器上下文
*/
protected void checkValidation(ProcessorContext processorContext) {
- // 校验Prompt
- if (SetUtil.isNotPresent(wrapBean.getUserPrompt()) && SetUtil.isNotPresent(wrapBean.getSystemPrompt())) {
- throw new LiteFlowAIException("User prompt and system prompt cannot both be empty");
- }
// 校验必需参数
- ModelConfig modelConfig = wrapBean.getConfig();
- if (SetUtil.isNotPresent(modelConfig.getProvider())) {
+ ModelConfigAggregator modelConfigAggregator = wrapBean.getConfig();
+ if (SetUtil.isNotPresent(modelConfigAggregator.getProvider())) {
throw new LiteFlowAIException("Provider cannot be empty for AI node: " + wrapBean.getNodeId());
}
- if (SetUtil.isNotPresent(modelConfig.getApiUrl())) {
+ if (SetUtil.isNotPresent(modelConfigAggregator.getApiUrl())) {
throw new LiteFlowAIException("API URL cannot be empty for AI node: " + wrapBean.getNodeId());
}
- if (SetUtil.isNotPresent(modelConfig.getModel())) {
+ if (SetUtil.isNotPresent(modelConfigAggregator.getModel())) {
throw new LiteFlowAIException("Model cannot be empty for AI node: " + wrapBean.getNodeId());
}
}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/ChatAIInvocationHandler.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/ChatAIInvocationHandler.java
index abb25180a..c9343ea40 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/ChatAIInvocationHandler.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/ChatAIInvocationHandler.java
@@ -5,7 +5,6 @@ import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatRequest;
import com.yomahub.liteflow.ai.model.ModelFactory;
import com.yomahub.liteflow.ai.parse.context.ProcessorContext;
import com.yomahub.liteflow.ai.proxy.wrap.ChatProxyWrapBean;
-import com.yomahub.liteflow.core.NodeComponent;
/**
* 聊天组件的调用处理器
@@ -28,50 +27,14 @@ public class ChatAIInvocationHandler extends AbstractAIInvocationHandler processorContext, Object[] args) {
- NodeComponent nodeComponent = processorContext.getNodeComponent();
+ ChatModel chatModel = ModelFactory.getChatModel(wrapBean);
+ ChatRequest chatRequest = processorContext.getModelRequest().toChatRequest();
+
if (wrapBean.isStreaming()) {
- return processStreaming(nodeComponent);
+ chatModel.stream(chatRequest);
+ return null;
} else {
- return processBlocking(nodeComponent);
+ return chatModel.chat(chatRequest);
}
}
-
- private Void processStreaming(NodeComponent nodeComponent) {
- ChatModel chatModel = ModelFactory.getChatModel(wrapBean);
-// StreamingChatModel streamingChatModel = ModelFactory.getStreamingChatModel(wrapBean);
-// // 创建AI服务实例
-// Object aiService = AiServiceFactory.createAiService(wrapBean.getEntityClass(), streamingChatModel);
-//
-// try {
-// TokenStream tokenStream = AiServiceFactory.chatStream(aiService, wrapBean.getUserPrompt(), wrapBean.getSystemPrompt());
-// // 处理流式响应
-// ChatContext chatContext = nodeComponent.getContextBean(ChatContext.class);
-// // 如果存在流处理器,则将TokenStream传递给它
-// if (Objects.nonNull(chatContext)) {
-// Optional.of(chatContext.getStreamHandler())
-// .ifPresent(streamHandler -> streamHandler.acceptTokenStream(tokenStream));
-// }
-// } catch (Throwable e) {
-// throw new LiteFlowAIException("Error during streaming chat processing", e);
-// }
- return null;
- }
-
- private Object processBlocking(NodeComponent nodeComponent) {
- ChatModel chatModel = ModelFactory.getChatModel(wrapBean);
- chatModel.chat(ChatRequest.builder().build());
-// ChatModel chatModel = ModelFactory.getChatModel(wrapBean);
-//
-// // 创建AI服务实例
-// Object aiService = AiServiceFactory.createAiService(wrapBean.getEntityClass(), chatModel);
-//
-// try {
-// Object result = AiServiceFactory.chat(aiService, wrapBean.getUserPrompt(), wrapBean.getSystemPrompt());
-// LOG.info("Chat response: {}", result);
-// return result;
-// } catch (Throwable e) {
-// throw new LiteFlowAIException("Error during blocking chat processing", e);
-// }
- return null;
- }
}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/ClassifyAIInvocationHandler.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/ClassifyAIInvocationHandler.java
index 8616af66b..95a5dee4f 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/ClassifyAIInvocationHandler.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/invocation/ClassifyAIInvocationHandler.java
@@ -1,6 +1,8 @@
package com.yomahub.liteflow.ai.proxy.invocation;
+import com.yomahub.liteflow.ai.engine.model.chat.ChatModel;
import com.yomahub.liteflow.ai.exception.LiteFlowAIException;
+import com.yomahub.liteflow.ai.model.ModelFactory;
import com.yomahub.liteflow.ai.parse.context.ProcessorContext;
import com.yomahub.liteflow.ai.proxy.wrap.ClassifyProxyWrapBean;
import com.yomahub.liteflow.ai.util.SetUtil;
@@ -37,9 +39,7 @@ public class ClassifyAIInvocationHandler extends AbstractAIInvocationHandler processorContext, Object[] args) {
-
-// ChatModel chatModel = ModelFactory.getChatModel(wrapBean);
-
- return null;
+ ChatModel chatModel = ModelFactory.getChatModel(processorContext.getWrapBean());
+ return chatModel.chat(processorContext.getModelRequest().toChatRequest());
}
}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/AIProxyWrapBean.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/AIProxyWrapBean.java
index 702cad74d..acb44599c 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/AIProxyWrapBean.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/AIProxyWrapBean.java
@@ -1,8 +1,7 @@
package com.yomahub.liteflow.ai.proxy.wrap;
import com.yomahub.liteflow.ai.annotation.AIComponent;
-import com.yomahub.liteflow.ai.domain.ModelConfig;
-import com.yomahub.liteflow.ai.domain.enums.ResponseType;
+import com.yomahub.liteflow.ai.domain.dto.ModelConfigAggregator;
import java.lang.annotation.Annotation;
@@ -15,31 +14,24 @@ import java.lang.annotation.Annotation;
public abstract class AIProxyWrapBean {
- protected T annotation;
+ // AI组件注解
+ protected final T annotation;
+ // AI 组件配置注解
+ protected final AIComponent aiComponent;
+ // LiteFlow Node ID
+ protected final String nodeId;
+ // LiteFlow Node 名称
+ protected final String nodeName;
+ // 代理接口名称
+ protected final Class> interfaceClass;
+ // Bean 名称
+ protected final String beanName;
+ // 模型配置聚合
+ protected ModelConfigAggregator config;
- protected ModelConfig config;
-
- protected String nodeId;
-
- protected String nodeName;
-
- protected Class> interfaceClass;
-
- protected String beanName;
-
- protected String systemPrompt;
-
- protected String userPrompt;
-
- protected ResponseType responseType = ResponseType.TEXT;
-
- protected Class> entityClass = String.class;
-
- public AIProxyWrapBean() {
- }
-
- public AIProxyWrapBean(AIComponent aiComponent, Class> interfaceClass, String beanName) {
- this.config = ModelConfig.fromAnnotation(aiComponent);
+ public AIProxyWrapBean(AIComponent aiComponent, T annotation, Class> interfaceClass, String beanName) {
+ this.aiComponent = aiComponent;
+ this.annotation = annotation;
this.nodeId = aiComponent.nodeId();
this.nodeName = aiComponent.nodeName();
this.interfaceClass = interfaceClass;
@@ -58,7 +50,11 @@ public abstract class AIProxyWrapBean {
return nodeName;
}
- public ModelConfig getConfig() {
+ public AIComponent getAiComponent() {
+ return aiComponent;
+ }
+
+ public ModelConfigAggregator getConfig() {
return config;
}
@@ -70,55 +66,7 @@ public abstract class AIProxyWrapBean {
return beanName;
}
- public String getSystemPrompt() {
- return systemPrompt;
- }
-
- public String getUserPrompt() {
- return userPrompt;
- }
-
- public ResponseType getResponseType() {
- return responseType;
- }
-
- public Class> getEntityClass() {
- return entityClass;
- }
-
- public void setNodeId(String nodeId) {
- this.nodeId = nodeId;
- }
-
- public void setNodeName(String nodeName) {
- this.nodeName = nodeName;
- }
-
- public void setConfig(ModelConfig config) {
+ public void setConfig(ModelConfigAggregator config) {
this.config = config;
}
-
- public void setInterfaceClass(Class> interfaceClass) {
- this.interfaceClass = interfaceClass;
- }
-
- public void setBeanName(String beanName) {
- this.beanName = beanName;
- }
-
- public void setSystemPrompt(String systemPrompt) {
- this.systemPrompt = systemPrompt;
- }
-
- public void setUserPrompt(String userPrompt) {
- this.userPrompt = userPrompt;
- }
-
- public void setResponseType(ResponseType responseType) {
- this.responseType = responseType;
- }
-
- public void setEntityClass(Class> entityClass) {
- this.entityClass = entityClass;
- }
}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/ChatProxyWrapBean.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/ChatProxyWrapBean.java
index 2356b6f23..d658b76e0 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/ChatProxyWrapBean.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/ChatProxyWrapBean.java
@@ -14,14 +14,8 @@ public class ChatProxyWrapBean extends AIProxyWrapBean {
private boolean streaming;
- public ChatProxyWrapBean() {
- super();
- }
-
- public ChatProxyWrapBean(AIComponent aiComponent, AIChat annotation,
- Class> interfaceClass, String beanName) {
- super(aiComponent, interfaceClass, beanName);
- this.annotation = annotation;
+ public ChatProxyWrapBean(AIComponent aiComponent, AIChat annotation, Class> interfaceClass, String beanName) {
+ super(aiComponent, annotation, interfaceClass, beanName);
}
public boolean isStreaming() {
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/ClassifyProxyWrapBean.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/ClassifyProxyWrapBean.java
index 0188b0383..5d90a91ba 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/ClassifyProxyWrapBean.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/ClassifyProxyWrapBean.java
@@ -18,14 +18,8 @@ public class ClassifyProxyWrapBean extends AIProxyWrapBean {
private boolean multiLabel;
- public ClassifyProxyWrapBean() {
- super();
- }
-
- public ClassifyProxyWrapBean(AIComponent aiComponent, AIClassify annotation,
- Class> interfaceClass, String beanName) {
- super(aiComponent, interfaceClass, beanName);
- this.annotation = annotation;
+ public ClassifyProxyWrapBean(AIComponent aiComponent, AIClassify annotation, Class> interfaceClass, String beanName) {
+ super(aiComponent, annotation, interfaceClass, beanName);
}
public List getCategories() {
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/RetrievalProxyWrapBean.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/RetrievalProxyWrapBean.java
index 307b98522..2d6d16b21 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/RetrievalProxyWrapBean.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/proxy/wrap/RetrievalProxyWrapBean.java
@@ -12,13 +12,7 @@ import com.yomahub.liteflow.ai.annotation.AIRetrieval;
public class RetrievalProxyWrapBean extends AIProxyWrapBean {
- public RetrievalProxyWrapBean() {
- super();
- }
-
- public RetrievalProxyWrapBean(AIComponent aiComponent, AIRetrieval annotation,
- Class> interfaceClass, String beanName) {
- super(aiComponent, interfaceClass, beanName);
- this.annotation = annotation;
+ public RetrievalProxyWrapBean(AIComponent aiComponent, AIRetrieval annotation, Class> interfaceClass, String beanName) {
+ super(aiComponent, annotation, interfaceClass, beanName);
}
}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/util/DurationUtil.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/util/DurationUtil.java
new file mode 100644
index 000000000..88c21c462
--- /dev/null
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/util/DurationUtil.java
@@ -0,0 +1,108 @@
+package com.yomahub.liteflow.ai.util;
+
+import cn.hutool.core.util.StrUtil;
+
+import java.time.Duration;
+import java.time.format.DateTimeParseException;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+
+/**
+ * 将时间字符串转换为 {@link java.time.Duration} 工具类
+ *
+ * @author 苍镜月
+ * @since TODO
+ */
+
+public class DurationUtil {
+ /**
+ * 用于解析简化时间格式 (e.g., "10s", "5m", "1h") 的正则表达式.
+ * 它捕获一个或多个数字作为第一组,以及单位 's', 'm', 或 'h' 作为第二组.
+ */
+ private static final Pattern SIMPLE_FORMAT_PATTERN = Pattern.compile("(\\d+)([smh])", Pattern.CASE_INSENSITIVE);
+
+ /**
+ * 私有构造函数
+ */
+ private DurationUtil() {
+ }
+
+ /**
+ * 将一个字符串解析为 {@link Duration} 对象。
+ *
+ * 该方法提供了两种格式的解析支持:
+ *
+ * - 标准 ISO 8601 持续时间格式: 这是 Java 内置支持的标准格式,以 {@code "PT"} 开头。
+ * 这是首选的解析方式。
+ * - 自定义简化格式: 为了方便用户配置,支持一种更简洁的格式,由数字和单位后缀组成。
+ * 支持的单位包括:
+ *
+ * - {@code s} - 秒
+ * - {@code m} - 分钟
+ * - {@code h} - 小时
+ *
+ * 单位不区分大小写 (例如, {@code "10S"} 和 {@code "10s"} 效果相同)。
+ *
+ *
+ *
+ * 解析逻辑:
+ * 方法会首先尝试使用标准的 ISO 8601 格式进行解析。如果解析失败,它会回退 (fallback) 到自定义的
+ * 简化格式进行尝试。如果两种格式都无法解析,或者输入字符串为 {@code null} 或空,
+ * 将返回指定的默认 {@code Duration} 对象。
+ *
+ * @param durationStr 要解析的持续时间字符串。
+ * ISO 8601 格式示例:
+ *
+ * - {@code "PT20S"} - 20 秒
+ * - {@code "PT15M"} - 15 分钟
+ * - {@code "PT10H"} - 10 小时
+ * - {@code "P2D"} - 2 天
+ *
+ * 自定义简化格式示例:
+ *
+ * - {@code "30s"} - 30 秒
+ * - {@code "5m"} - 5 分钟
+ * - {@code "1h"} - 1 小时
+ *
+ * @param defaultDuration 当输入字符串无法被解析、为 {@code null} 或为空时,返回的默认 {@code Duration} 对象。
+ * 此参数不能为 {@code null}。
+ * @return 解析后的 {@link Duration} 对象,或在无法解析时返回 {@code defaultDuration}。
+ * @throws NullPointerException 如果 {@code defaultDuration} 为 {@code null}。
+ * @see java.time.Duration#parse(CharSequence)
+ */
+ public static Duration toDuration(String durationStr, Duration defaultDuration) {
+ if (StrUtil.isBlank(durationStr)) {
+ return defaultDuration;
+ }
+
+ // 1. 尝试使用标准的 ISO 8601 格式进行解析
+ try {
+ return Duration.parse(durationStr);
+ } catch (DateTimeParseException ignore) {
+ }
+
+ // 2. 尝试使用自定义的简化格式进行解析
+ Matcher matcher = SIMPLE_FORMAT_PATTERN.matcher(durationStr.trim());
+
+ if (matcher.matches()) {
+ try {
+ long value = Long.parseLong(matcher.group(1));
+ String unit = matcher.group(2).toLowerCase();
+
+ switch (unit) {
+ case "s":
+ return Duration.ofSeconds(value);
+ case "m":
+ return Duration.ofMinutes(value);
+ case "h":
+ return Duration.ofHours(value);
+ default:
+ break;
+ }
+ } catch (Exception ignore) {
+ }
+ }
+ // 3. 如果两种格式都无法解析,返回默认的 Duration
+ return defaultDuration;
+ }
+}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/util/TriState.java b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/util/TriState.java
index 30c3d8f99..65aa289c2 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/util/TriState.java
+++ b/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/util/TriState.java
@@ -11,4 +11,17 @@ public enum TriState {
TRUE,
FALSE,
UNSET,
+ ;
+
+ public Boolean toBool() {
+ switch (this) {
+ case TRUE:
+ return true;
+ case FALSE:
+ return false;
+ case UNSET:
+ default:
+ return null;
+ }
+ }
}
diff --git a/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/interact/transport/impl/HttpTransport.java b/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/interact/transport/impl/HttpTransport.java
index b084693b6..202d3a6b1 100644
--- a/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/interact/transport/impl/HttpTransport.java
+++ b/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/interact/transport/impl/HttpTransport.java
@@ -32,7 +32,6 @@ public class HttpTransport implements Transport {
.builder()
.connectTimeout(config.getTimeout())
.readTimeout(config.getTimeout())
- .writeTimeout(config.getTimeout())
.build()) {
// 构建请求体
String requestBody = buildRequestBody(config, request);
diff --git a/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/ModelRequest.java b/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/ModelRequest.java
index 8016c6a6e..3b389a4a1 100644
--- a/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/ModelRequest.java
+++ b/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/ModelRequest.java
@@ -1,5 +1,6 @@
package com.yomahub.liteflow.ai.engine.model;
+import com.yomahub.liteflow.ai.engine.model.chat.entity.ChatRequest;
import com.yomahub.liteflow.ai.engine.util.request.RequestBodyConvertible;
/**
@@ -11,4 +12,7 @@ import com.yomahub.liteflow.ai.engine.util.request.RequestBodyConvertible;
public interface ModelRequest extends RequestBodyConvertible {
+ default ChatRequest toChatRequest() {
+ return (ChatRequest) this;
+ }
}
diff --git a/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/chat/entity/ChatOptions.java b/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/chat/entity/ChatOptions.java
index 79f24c2ae..5488fb23e 100644
--- a/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/chat/entity/ChatOptions.java
+++ b/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/chat/entity/ChatOptions.java
@@ -13,23 +13,23 @@ import com.yomahub.liteflow.ai.engine.util.request.RequestBody;
public class ChatOptions implements ModelOptions {
public static final ChatOptions DEFAULT = ChatOptions.builder()
- .temperature(0.8f)
- .topP(0.9f)
- .topK(50f)
+ .temperature(0.8)
+ .topP(0.9)
+ .topK(50)
.maxTokens(512)
.seed(null)
.enableThinking(false)
.build();
- protected Float temperature;
+ protected Double temperature;
- protected Float topP;
+ protected Double topP;
- protected Float topK;
+ protected Integer topK;
protected Integer maxTokens;
- protected String seed;
+ protected Integer seed;
protected Boolean enableThinking;
@@ -49,11 +49,11 @@ public class ChatOptions implements ModelOptions {
}
public ChatOptions(
- Float temperature,
- Float topP,
- Float topK,
+ Double temperature,
+ Double topP,
+ Integer topK,
Integer maxTokens,
- String seed,
+ Integer seed,
Boolean enableThinking
) {
this.temperature = temperature;
@@ -83,15 +83,15 @@ public class ChatOptions implements ModelOptions {
.putIfNotEmpty(THINK_KEY, enableThinking);
}
- public Float getTemperature() {
+ public Double getTemperature() {
return temperature;
}
- public Float getTopP() {
+ public Double getTopP() {
return topP;
}
- public Float getTopK() {
+ public Integer getTopK() {
return topK;
}
@@ -99,7 +99,7 @@ public class ChatOptions implements ModelOptions {
return maxTokens;
}
- public String getSeed() {
+ public Integer getSeed() {
return seed;
}
@@ -107,15 +107,15 @@ public class ChatOptions implements ModelOptions {
return enableThinking;
}
- public void setTemperature(Float temperature) {
+ public void setTemperature(Double temperature) {
this.temperature = temperature;
}
- public void setTopP(Float topP) {
+ public void setTopP(Double topP) {
this.topP = topP;
}
- public void setTopK(Float topK) {
+ public void setTopK(Integer topK) {
this.topK = topK;
}
@@ -123,7 +123,7 @@ public class ChatOptions implements ModelOptions {
this.maxTokens = maxTokens;
}
- public void setSeed(String seed) {
+ public void setSeed(Integer seed) {
this.seed = seed;
}
@@ -136,28 +136,28 @@ public class ChatOptions implements ModelOptions {
}
public static abstract class Builder> {
- protected Float temperature;
- protected Float topP;
- protected Float topK;
+ protected Double temperature;
+ protected Double topP;
+ protected Integer topK;
protected Integer maxTokens;
- protected String seed;
+ protected Integer seed;
protected Boolean enableThinking;
protected abstract B self();
public abstract ChatOptions build();
- public B temperature(Float temperature) {
+ public B temperature(Double temperature) {
this.temperature = temperature;
return self();
}
- public B topP(Float topP) {
+ public B topP(Double topP) {
this.topP = topP;
return self();
}
- public B topK(Float topK) {
+ public B topK(Integer topK) {
this.topK = topK;
return self();
}
@@ -167,7 +167,7 @@ public class ChatOptions implements ModelOptions {
return self();
}
- public B seed(String seed) {
+ public B seed(Integer seed) {
this.seed = seed;
return self();
}
diff --git a/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/chat/message/UserMessage.java b/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/chat/message/UserMessage.java
index 369ac8bdd..b526721b9 100644
--- a/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/chat/message/UserMessage.java
+++ b/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/chat/message/UserMessage.java
@@ -19,7 +19,4 @@ public class UserMessage extends AbstractMessage {
public UserMessage(String textContent) {
this(textContent, new HashMap<>());
}
-
- // TODO 添加 Resource 支持
-
}
diff --git a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/enums/ResponseType.java b/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/output/ResponseType.java
similarity index 79%
rename from liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/enums/ResponseType.java
rename to liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/output/ResponseType.java
index e813df379..3d97bd495 100644
--- a/liteflow-ai/liteflow-ai-core/src/main/java/com/yomahub/liteflow/ai/domain/enums/ResponseType.java
+++ b/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/model/output/ResponseType.java
@@ -1,4 +1,4 @@
-package com.yomahub.liteflow.ai.domain.enums;
+package com.yomahub.liteflow.ai.engine.model.output;
/**
* AI响应类型枚举
diff --git a/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/util/HttpUtil.java b/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/util/HttpUtil.java
index 256ad81bd..a1fce19fc 100644
--- a/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/util/HttpUtil.java
+++ b/liteflow-ai/liteflow-ai-engine/src/main/java/com/yomahub/liteflow/ai/engine/util/HttpUtil.java
@@ -37,7 +37,6 @@ public final class HttpUtil implements AutoCloseable {
this.syncClient = new OkHttpClient.Builder()
.connectTimeout(builder.connectTimeout)
.readTimeout(builder.readTimeout)
- .writeTimeout(builder.writeTimeout)
.build();
}
@@ -305,9 +304,8 @@ public final class HttpUtil implements AutoCloseable {
* 用于创建 {@link HttpUtil} 的构建器。
*/
public static class Builder {
- private Duration connectTimeout = Duration.ofSeconds(30);
+ private Duration connectTimeout = Duration.ofSeconds(60);
private Duration readTimeout = Duration.ofSeconds(60);
- private Duration writeTimeout = Duration.ofSeconds(30);
public Builder connectTimeout(Duration duration) {
this.connectTimeout = Objects.requireNonNull(duration, "connectTimeout 不能为空");
@@ -319,11 +317,6 @@ public final class HttpUtil implements AutoCloseable {
return this;
}
- public Builder writeTimeout(Duration duration) {
- this.writeTimeout = Objects.requireNonNull(duration, "writeTimeout 不能为空");
- return this;
- }
-
public HttpUtil build() {
return new HttpUtil(this);
}
diff --git a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/AICmp.java b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/AICmp.java
index 20fb4e412..c809922c8 100644
--- a/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/AICmp.java
+++ b/liteflow-testcase-el/liteflow-testcase-el-ai/src/test/java/com/yomahub/liteflow/test/ai/core/proxy/cmp/AICmp.java
@@ -1,7 +1,7 @@
package com.yomahub.liteflow.test.ai.core.proxy.cmp;
import com.yomahub.liteflow.ai.annotation.*;
-import com.yomahub.liteflow.ai.domain.enums.ResponseType;
+import com.yomahub.liteflow.ai.engine.model.output.ResponseType;
/**
* TODO