package cn.iocoder.yudao.module.ai.framework.ai.config;
|
|
import cn.hutool.core.util.StrUtil;
|
import cn.iocoder.yudao.module.ai.framework.ai.core.model.AiModelFactory;
|
import cn.iocoder.yudao.module.ai.framework.ai.core.model.AiModelFactoryImpl;
|
import io.micrometer.observation.ObservationRegistry;
|
import lombok.extern.slf4j.Slf4j;
|
import org.springframework.ai.document.MetadataMode;
|
import org.springframework.ai.embedding.BatchingStrategy;
|
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
|
import org.springframework.ai.model.tool.ToolCallingManager;
|
import org.springframework.ai.openai.OpenAiChatModel;
|
import org.springframework.ai.openai.OpenAiChatOptions;
|
import org.springframework.ai.openai.OpenAiEmbeddingModel;
|
import org.springframework.ai.openai.OpenAiEmbeddingOptions;
|
import org.springframework.ai.tokenizer.JTokkitTokenCountEstimator;
|
import org.springframework.ai.tokenizer.TokenCountEstimator;
|
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Configuration;
|
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
|
import java.time.Duration;
|
|
/**
|
* 超级管理员 AI 自动配置
|
*
|
* 使用 OpenAI 兼容接口对接通义千问 DashScope
|
* 向量库配置见 yudao.ai.vector-store 节点,不再依赖 Spring AI 的 Milvus 自动配置属性
|
*/
|
@Configuration
|
@EnableConfigurationProperties(YudaoAiProperties.class)
|
@Slf4j
|
public class AiAutoConfiguration {
|
|
private static final String DASHSCOPE_BASE_URL = "https://dashscope.aliyuncs.com/compatible-mode/v1";
|
|
@Bean
|
public AiModelFactory aiModelFactory() {
|
return new AiModelFactoryImpl();
|
}
|
|
@Bean
|
@ConditionalOnMissingBean
|
public ObservationRegistry observationRegistry() {
|
return ObservationRegistry.NOOP;
|
}
|
|
@Bean
|
@ConditionalOnMissingBean
|
public BatchingStrategy batchingStrategy() {
|
return new TokenCountBatchingStrategy();
|
}
|
|
@Bean
|
@ConditionalOnMissingBean
|
public TokenCountEstimator tokenCountEstimator() {
|
return new JTokkitTokenCountEstimator();
|
}
|
|
// ========== 通义千问 Chat(通过 OpenAI 兼容接口)==========
|
|
/**
|
* 构建通义千问 Chat 模型
|
*
|
* @param temperature 采样温度,为 null 时用 0.7(与历史行为一致)
|
* @param maxTokens 单次回复的最大 token 数,为 null 时沿用模型默认值。
|
* 不传会让长文档的输出被静默截断,表现为「JSON 尾部缺失、解析失败」
|
* @param timeout 单次调用超时。不设超时的话,模型排队时请求会一直挂到 TCP 层超时
|
*/
|
public static OpenAiChatModel buildTongYiChatModel(String apiKey, String model,
|
Double temperature, Integer maxTokens,
|
Duration timeout) {
|
return OpenAiChatModel.builder()
|
.options(OpenAiChatOptions.builder()
|
.baseUrl(DASHSCOPE_BASE_URL)
|
.apiKey(apiKey)
|
.model(StrUtil.blankToDefault(model, "qwen-plus"))
|
.temperature(temperature != null ? temperature : 0.7)
|
.maxTokens(maxTokens)
|
.timeout(timeout)
|
.build())
|
.toolCallingManager(ToolCallingManager.builder().build())
|
.build();
|
}
|
|
// ========== 通义千问 Embedding(通过 OpenAI 兼容接口)==========
|
|
public static OpenAiEmbeddingModel buildTongYiEmbeddingModel(String apiKey, String model) {
|
return OpenAiEmbeddingModel.builder()
|
.options(OpenAiEmbeddingOptions.builder()
|
.baseUrl(DASHSCOPE_BASE_URL)
|
.apiKey(apiKey)
|
.model(StrUtil.blankToDefault(model, "text-embedding-v3"))
|
.build())
|
.metadataMode(MetadataMode.EMBED)
|
.build();
|
}
|
|
}
|