【功能新增】AI:新增 function call 示例,完成所有模型的测试 = = 累
This commit is contained in:
parent
25a0fe908a
commit
ffe4afaaaf
|
@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
|
||||||
import cn.iocoder.yudao.framework.ai.core.util.AiUtils;
|
import cn.iocoder.yudao.framework.ai.core.util.AiUtils;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
import cn.iocoder.yudao.framework.common.pojo.CommonResult;
|
||||||
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
import cn.iocoder.yudao.framework.common.pojo.PageResult;
|
||||||
|
import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
|
||||||
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
|
||||||
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
|
||||||
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO;
|
import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO;
|
||||||
|
@ -238,7 +239,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
|
||||||
// 2. 构建 ChatOptions 对象
|
// 2. 构建 ChatOptions 对象
|
||||||
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform());
|
AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform());
|
||||||
ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(),
|
ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(),
|
||||||
conversation.getTemperature(), conversation.getMaxTokens());
|
conversation.getTemperature(), conversation.getMaxTokens(),
|
||||||
|
SetUtils.asSet("directory_list", "weather_query"));
|
||||||
return new Prompt(chatMessages, chatOptions);
|
return new Prompt(chatMessages, chatOptions);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,95 +0,0 @@
|
||||||
package cn.iocoder.yudao.module.ai.service.tool;
|
|
||||||
|
|
||||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
|
||||||
import cn.hutool.core.io.FileUtil;
|
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
|
||||||
import lombok.AllArgsConstructor;
|
|
||||||
import lombok.Data;
|
|
||||||
import lombok.NoArgsConstructor;
|
|
||||||
import org.springframework.ai.tool.annotation.Tool;
|
|
||||||
import org.springframework.ai.tool.annotation.ToolParam;
|
|
||||||
import org.springframework.stereotype.Component;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_PATTERN;
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 目录内容列表工具:列出指定目录的内容
|
|
||||||
*
|
|
||||||
* @author 芋道源码
|
|
||||||
*/
|
|
||||||
@Component
|
|
||||||
public class ListDirTool {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 列出指定目录的内容
|
|
||||||
*
|
|
||||||
* @param relativePath 要列出内容的目录路径,相对于工作区根目录
|
|
||||||
* @return 目录内容列表
|
|
||||||
*/
|
|
||||||
@Tool(name = "listDir", description = "列出指定目录的内容")
|
|
||||||
public Response listDir(@ToolParam(description = "要列出内容的目录路径,相对于工作区根目录") String relativePath) {
|
|
||||||
// 校验目录存在
|
|
||||||
String path = StrUtil.blankToDefault(relativePath, ".");
|
|
||||||
Path dirPath = Paths.get(path);
|
|
||||||
if (!FileUtil.exist(dirPath.toString()) || !FileUtil.isDirectory(dirPath.toString())) {
|
|
||||||
return new Response(Collections.emptyList());
|
|
||||||
}
|
|
||||||
// 列出目录内容
|
|
||||||
File[] files = dirPath.toFile().listFiles();
|
|
||||||
if (ArrayUtil.isEmpty(files)) {
|
|
||||||
return new Response(Collections.emptyList());
|
|
||||||
}
|
|
||||||
return new Response(convertList(Arrays.asList(files), file -> new Response.File()
|
|
||||||
.setDirectory(file.isDirectory()).setName(file.getName())
|
|
||||||
.setSize(file.isFile() ? FileUtil.readableFileSize(file.length()) : null)
|
|
||||||
.setLastModified(
|
|
||||||
LocalDateTimeUtil.format(LocalDateTimeUtil.of(file.lastModified()), NORM_DATETIME_PATTERN))));
|
|
||||||
}
|
|
||||||
|
|
||||||
@Data
|
|
||||||
@AllArgsConstructor
|
|
||||||
@NoArgsConstructor
|
|
||||||
public static class Response {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 目录内容列表
|
|
||||||
*/
|
|
||||||
private List<File> files;
|
|
||||||
|
|
||||||
@Data
|
|
||||||
public static class File {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 是否为目录
|
|
||||||
*/
|
|
||||||
private Boolean directory;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 名称
|
|
||||||
*/
|
|
||||||
private String name;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 大小,仅对文件有效
|
|
||||||
*/
|
|
||||||
private String size;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 最后修改时间
|
|
||||||
*/
|
|
||||||
private String lastModified;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
|
@ -1,10 +1,11 @@
|
||||||
package cn.iocoder.yudao.module.ai.service.tool;
|
package cn.iocoder.yudao.module.ai.service.tool.function;
|
||||||
|
|
||||||
import cn.hutool.core.date.LocalDateTimeUtil;
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
import cn.hutool.core.io.FileUtil;
|
import cn.hutool.core.io.FileUtil;
|
||||||
import cn.hutool.core.util.ArrayUtil;
|
import cn.hutool.core.util.ArrayUtil;
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
import com.fasterxml.jackson.annotation.JsonClassDescription;
|
import com.fasterxml.jackson.annotation.JsonClassDescription;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
|
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
|
||||||
import lombok.AllArgsConstructor;
|
import lombok.AllArgsConstructor;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
@ -12,8 +13,6 @@ import lombok.NoArgsConstructor;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.nio.file.Path;
|
|
||||||
import java.nio.file.Paths;
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
@ -23,21 +22,22 @@ import static cn.hutool.core.date.DatePattern.NORM_DATETIME_PATTERN;
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 目录内容列表工具:列出指定目录的内容
|
* 工具:列出指定目录的文件列表
|
||||||
*
|
*
|
||||||
* @author 芋道源码
|
* @author 芋道源码
|
||||||
*/
|
*/
|
||||||
@Component("listDir")
|
@Component("directory_list")
|
||||||
public class ListDirToolB implements Function<ListDirToolB.Request, ListDirToolB.Response> {
|
public class DirectoryListToolFunction implements Function<DirectoryListToolFunction.Request, DirectoryListToolFunction.Response> {
|
||||||
|
|
||||||
@Data
|
@Data
|
||||||
@JsonClassDescription("列出指定目录的内容")
|
@JsonClassDescription("列出指定目录的文件列表")
|
||||||
public static class Request {
|
public static class Request {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 要列出内容的目录路径
|
* 目录路径
|
||||||
*/
|
*/
|
||||||
@JsonPropertyDescription("要列出内容的目录路径,例如说:/Users/yunai")
|
@JsonProperty(required = true, value = "path")
|
||||||
|
@JsonPropertyDescription("目录路径,例如说:/Users/yunai")
|
||||||
private String path;
|
private String path;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -48,7 +48,7 @@ public class ListDirToolB implements Function<ListDirToolB.Request, ListDirToolB
|
||||||
public static class Response {
|
public static class Response {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 目录内容列表
|
* 文件列表
|
||||||
*/
|
*/
|
||||||
private List<File> files;
|
private List<File> files;
|
||||||
|
|
||||||
|
@ -82,13 +82,12 @@ public class ListDirToolB implements Function<ListDirToolB.Request, ListDirToolB
|
||||||
@Override
|
@Override
|
||||||
public Response apply(Request request) {
|
public Response apply(Request request) {
|
||||||
// 校验目录存在
|
// 校验目录存在
|
||||||
String path = StrUtil.blankToDefault(request.getPath(), ".");
|
String path = StrUtil.blankToDefault(request.getPath(), "/");
|
||||||
Path dirPath = Paths.get(path);
|
if (!FileUtil.exist(path) || !FileUtil.isDirectory(path)) {
|
||||||
if (!FileUtil.exist(dirPath.toString()) || !FileUtil.isDirectory(dirPath.toString())) {
|
|
||||||
return new Response(Collections.emptyList());
|
return new Response(Collections.emptyList());
|
||||||
}
|
}
|
||||||
// 列出目录内容
|
// 列出目录
|
||||||
File[] files = dirPath.toFile().listFiles();
|
File[] files = FileUtil.ls(path);
|
||||||
if (ArrayUtil.isEmpty(files)) {
|
if (ArrayUtil.isEmpty(files)) {
|
||||||
return new Response(Collections.emptyList());
|
return new Response(Collections.emptyList());
|
||||||
}
|
}
|
|
@ -0,0 +1,118 @@
|
||||||
|
package cn.iocoder.yudao.module.ai.service.tool.function;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.LocalDateTimeUtil;
|
||||||
|
import cn.hutool.core.util.RandomUtil;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonClassDescription;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import com.fasterxml.jackson.annotation.JsonPropertyDescription;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.function.Function;
|
||||||
|
|
||||||
|
import static cn.hutool.core.date.DatePattern.NORM_DATETIME_PATTERN;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 工具:查询指定城市的天气信息
|
||||||
|
*
|
||||||
|
* @author 芋道源码
|
||||||
|
*/
|
||||||
|
@Component("weather_query")
|
||||||
|
public class WeatherQueryToolFunction
|
||||||
|
implements Function<WeatherQueryToolFunction.Request, WeatherQueryToolFunction.Response> {
|
||||||
|
|
||||||
|
private static final String[] WEATHER_CONDITIONS = { "晴朗", "多云", "阴天", "小雨", "大雨", "雷雨", "小雪", "大雪" };
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@JsonClassDescription("查询指定城市的天气信息")
|
||||||
|
public static class Request {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 城市名称
|
||||||
|
*/
|
||||||
|
@JsonProperty(required = true, value = "city")
|
||||||
|
@JsonPropertyDescription("城市名称,例如:北京、上海、广州")
|
||||||
|
private String city;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class Response {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 城市名称
|
||||||
|
*/
|
||||||
|
private String city;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天气信息
|
||||||
|
*/
|
||||||
|
private WeatherInfo weatherInfo;
|
||||||
|
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public static class WeatherInfo {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 温度(摄氏度)
|
||||||
|
*/
|
||||||
|
private Integer temperature;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 天气状况
|
||||||
|
*/
|
||||||
|
private String condition;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 湿度百分比
|
||||||
|
*/
|
||||||
|
private Integer humidity;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 风速(km/h)
|
||||||
|
*/
|
||||||
|
private Integer windSpeed;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查询时间
|
||||||
|
*/
|
||||||
|
private String queryTime;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Response apply(Request request) {
|
||||||
|
// 检查城市名称是否为空
|
||||||
|
if (StrUtil.isBlank(request.getCity())) {
|
||||||
|
return new Response("未知城市", null);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 获取天气数据
|
||||||
|
String city = request.getCity();
|
||||||
|
Response.WeatherInfo weatherInfo = generateMockWeatherInfo();
|
||||||
|
return new Response(city, weatherInfo);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 生成模拟的天气数据
|
||||||
|
* 在实际应用中,应替换为真实 API 调用
|
||||||
|
*/
|
||||||
|
private Response.WeatherInfo generateMockWeatherInfo() {
|
||||||
|
int temperature = RandomUtil.randomInt(-5, 30);
|
||||||
|
int humidity = RandomUtil.randomInt(1, 100);
|
||||||
|
int windSpeed = RandomUtil.randomInt(1, 30);
|
||||||
|
String condition = RandomUtil.randomEle(WEATHER_CONDITIONS);
|
||||||
|
return new Response.WeatherInfo(temperature, condition, humidity, windSpeed,
|
||||||
|
LocalDateTimeUtil.format(LocalDateTime.now(), NORM_DATETIME_PATTERN));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1 @@
|
||||||
|
package cn.iocoder.yudao.module.ai.service.tool;
|
|
@ -1,6 +1,7 @@
|
||||||
package cn.iocoder.yudao.framework.ai.config;
|
package cn.iocoder.yudao.framework.ai.config;
|
||||||
|
|
||||||
import cn.hutool.core.util.StrUtil;
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import cn.hutool.extra.spring.SpringUtil;
|
||||||
import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactory;
|
import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactory;
|
||||||
import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactoryImpl;
|
import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactoryImpl;
|
||||||
import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel;
|
import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel;
|
||||||
|
@ -17,6 +18,7 @@ import org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStore
|
||||||
import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreProperties;
|
import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreProperties;
|
||||||
import org.springframework.ai.embedding.BatchingStrategy;
|
import org.springframework.ai.embedding.BatchingStrategy;
|
||||||
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
|
import org.springframework.ai.embedding.TokenCountBatchingStrategy;
|
||||||
|
import org.springframework.ai.model.tool.ToolCallingManager;
|
||||||
import org.springframework.ai.openai.OpenAiChatModel;
|
import org.springframework.ai.openai.OpenAiChatModel;
|
||||||
import org.springframework.ai.openai.OpenAiChatOptions;
|
import org.springframework.ai.openai.OpenAiChatOptions;
|
||||||
import org.springframework.ai.openai.api.OpenAiApi;
|
import org.springframework.ai.openai.api.OpenAiApi;
|
||||||
|
@ -70,6 +72,7 @@ public class YudaoAiAutoConfiguration {
|
||||||
.maxTokens(properties.getMaxTokens())
|
.maxTokens(properties.getMaxTokens())
|
||||||
.topP(properties.getTopP())
|
.topP(properties.getTopP())
|
||||||
.build())
|
.build())
|
||||||
|
.toolCallingManager(getToolCallingManager())
|
||||||
.build();
|
.build();
|
||||||
return new DeepSeekChatModel(openAiChatModel);
|
return new DeepSeekChatModel(openAiChatModel);
|
||||||
}
|
}
|
||||||
|
@ -96,6 +99,7 @@ public class YudaoAiAutoConfiguration {
|
||||||
.maxTokens(properties.getMaxTokens())
|
.maxTokens(properties.getMaxTokens())
|
||||||
.topP(properties.getTopP())
|
.topP(properties.getTopP())
|
||||||
.build())
|
.build())
|
||||||
|
.toolCallingManager(getToolCallingManager())
|
||||||
.build();
|
.build();
|
||||||
return new DouBaoChatModel(openAiChatModel);
|
return new DouBaoChatModel(openAiChatModel);
|
||||||
}
|
}
|
||||||
|
@ -122,6 +126,7 @@ public class YudaoAiAutoConfiguration {
|
||||||
.maxTokens(properties.getMaxTokens())
|
.maxTokens(properties.getMaxTokens())
|
||||||
.topP(properties.getTopP())
|
.topP(properties.getTopP())
|
||||||
.build())
|
.build())
|
||||||
|
.toolCallingManager(getToolCallingManager())
|
||||||
.build();
|
.build();
|
||||||
return new SiliconFlowChatModel(openAiChatModel);
|
return new SiliconFlowChatModel(openAiChatModel);
|
||||||
}
|
}
|
||||||
|
@ -155,6 +160,7 @@ public class YudaoAiAutoConfiguration {
|
||||||
.maxTokens(properties.getMaxTokens())
|
.maxTokens(properties.getMaxTokens())
|
||||||
.topP(properties.getTopP())
|
.topP(properties.getTopP())
|
||||||
.build())
|
.build())
|
||||||
|
.toolCallingManager(getToolCallingManager())
|
||||||
.build();
|
.build();
|
||||||
return new HunYuanChatModel(openAiChatModel);
|
return new HunYuanChatModel(openAiChatModel);
|
||||||
}
|
}
|
||||||
|
@ -181,6 +187,7 @@ public class YudaoAiAutoConfiguration {
|
||||||
.maxTokens(properties.getMaxTokens())
|
.maxTokens(properties.getMaxTokens())
|
||||||
.topP(properties.getTopP())
|
.topP(properties.getTopP())
|
||||||
.build())
|
.build())
|
||||||
|
.toolCallingManager(getToolCallingManager())
|
||||||
.build();
|
.build();
|
||||||
return new XingHuoChatModel(openAiChatModel);
|
return new XingHuoChatModel(openAiChatModel);
|
||||||
}
|
}
|
||||||
|
@ -210,4 +217,8 @@ public class YudaoAiAutoConfiguration {
|
||||||
return new TokenCountBatchingStrategy();
|
return new TokenCountBatchingStrategy();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ToolCallingManager getToolCallingManager() {
|
||||||
|
return SpringUtil.getBean(ToolCallingManager.class);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
|
@ -23,6 +23,7 @@ import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAutoConfiguration;
|
||||||
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
|
import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
|
||||||
import com.alibaba.cloud.ai.dashscope.api.DashScopeImageApi;
|
import com.alibaba.cloud.ai.dashscope.api.DashScopeImageApi;
|
||||||
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
|
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
|
||||||
|
import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
|
||||||
import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingModel;
|
import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingModel;
|
||||||
import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingOptions;
|
import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingOptions;
|
||||||
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageModel;
|
import com.alibaba.cloud.ai.dashscope.image.DashScopeImageModel;
|
||||||
|
@ -58,11 +59,14 @@ import org.springframework.ai.embedding.BatchingStrategy;
|
||||||
import org.springframework.ai.embedding.EmbeddingModel;
|
import org.springframework.ai.embedding.EmbeddingModel;
|
||||||
import org.springframework.ai.image.ImageModel;
|
import org.springframework.ai.image.ImageModel;
|
||||||
import org.springframework.ai.minimax.MiniMaxChatModel;
|
import org.springframework.ai.minimax.MiniMaxChatModel;
|
||||||
|
import org.springframework.ai.minimax.MiniMaxChatOptions;
|
||||||
import org.springframework.ai.minimax.MiniMaxEmbeddingModel;
|
import org.springframework.ai.minimax.MiniMaxEmbeddingModel;
|
||||||
import org.springframework.ai.minimax.MiniMaxEmbeddingOptions;
|
import org.springframework.ai.minimax.MiniMaxEmbeddingOptions;
|
||||||
import org.springframework.ai.minimax.api.MiniMaxApi;
|
import org.springframework.ai.minimax.api.MiniMaxApi;
|
||||||
|
import org.springframework.ai.model.function.FunctionCallbackResolver;
|
||||||
import org.springframework.ai.model.tool.ToolCallingManager;
|
import org.springframework.ai.model.tool.ToolCallingManager;
|
||||||
import org.springframework.ai.moonshot.MoonshotChatModel;
|
import org.springframework.ai.moonshot.MoonshotChatModel;
|
||||||
|
import org.springframework.ai.moonshot.MoonshotChatOptions;
|
||||||
import org.springframework.ai.moonshot.api.MoonshotApi;
|
import org.springframework.ai.moonshot.api.MoonshotApi;
|
||||||
import org.springframework.ai.ollama.OllamaChatModel;
|
import org.springframework.ai.ollama.OllamaChatModel;
|
||||||
import org.springframework.ai.ollama.OllamaEmbeddingModel;
|
import org.springframework.ai.ollama.OllamaEmbeddingModel;
|
||||||
|
@ -90,10 +94,7 @@ import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservat
|
||||||
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
|
import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
|
||||||
import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore;
|
import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore;
|
||||||
import org.springframework.ai.vectorstore.redis.RedisVectorStore;
|
import org.springframework.ai.vectorstore.redis.RedisVectorStore;
|
||||||
import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
|
import org.springframework.ai.zhipuai.*;
|
||||||
import org.springframework.ai.zhipuai.ZhiPuAiEmbeddingModel;
|
|
||||||
import org.springframework.ai.zhipuai.ZhiPuAiEmbeddingOptions;
|
|
||||||
import org.springframework.ai.zhipuai.ZhiPuAiImageModel;
|
|
||||||
import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
|
import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
|
||||||
import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
|
import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
|
@ -110,6 +111,7 @@ import java.util.Timer;
|
||||||
import java.util.TimerTask;
|
import java.util.TimerTask;
|
||||||
|
|
||||||
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
|
||||||
|
import static org.springframework.ai.retry.RetryUtils.DEFAULT_RETRY_TEMPLATE;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* AI Model 模型工厂的实现类
|
* AI Model 模型工厂的实现类
|
||||||
|
@ -308,7 +310,9 @@ public class AiModelFactoryImpl implements AiModelFactory {
|
||||||
*/
|
*/
|
||||||
private static DashScopeChatModel buildTongYiChatModel(String key) {
|
private static DashScopeChatModel buildTongYiChatModel(String key) {
|
||||||
DashScopeApi dashScopeApi = new DashScopeApi(key);
|
DashScopeApi dashScopeApi = new DashScopeApi(key);
|
||||||
return new DashScopeChatModel(dashScopeApi);
|
DashScopeChatOptions options = DashScopeChatOptions.builder().withModel(DashScopeApi.DEFAULT_CHAT_MODEL)
|
||||||
|
.withTemperature(0.7).build();
|
||||||
|
return new DashScopeChatModel(dashScopeApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -385,7 +389,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
|
||||||
private ZhiPuAiChatModel buildZhiPuChatModel(String apiKey, String url) {
|
private ZhiPuAiChatModel buildZhiPuChatModel(String apiKey, String url) {
|
||||||
ZhiPuAiApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiApi(apiKey)
|
ZhiPuAiApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiApi(apiKey)
|
||||||
: new ZhiPuAiApi(url, apiKey);
|
: new ZhiPuAiApi(url, apiKey);
|
||||||
return new ZhiPuAiChatModel(zhiPuAiApi);
|
ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().model(ZhiPuAiApi.DEFAULT_CHAT_MODEL).temperature(0.7).build();
|
||||||
|
return new ZhiPuAiChatModel(zhiPuAiApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -403,7 +408,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
|
||||||
private MiniMaxChatModel buildMiniMaxChatModel(String apiKey, String url) {
|
private MiniMaxChatModel buildMiniMaxChatModel(String apiKey, String url) {
|
||||||
MiniMaxApi miniMaxApi = StrUtil.isEmpty(url) ? new MiniMaxApi(apiKey)
|
MiniMaxApi miniMaxApi = StrUtil.isEmpty(url) ? new MiniMaxApi(apiKey)
|
||||||
: new MiniMaxApi(url, apiKey);
|
: new MiniMaxApi(url, apiKey);
|
||||||
return new MiniMaxChatModel(miniMaxApi);
|
MiniMaxChatOptions options = MiniMaxChatOptions.builder().model(MiniMaxApi.DEFAULT_CHAT_MODEL).temperature(0.7).build();
|
||||||
|
return new MiniMaxChatModel(miniMaxApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -412,7 +418,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
|
||||||
private MoonshotChatModel buildMoonshotChatModel(String apiKey, String url) {
|
private MoonshotChatModel buildMoonshotChatModel(String apiKey, String url) {
|
||||||
MoonshotApi moonshotApi = StrUtil.isEmpty(url)? new MoonshotApi(apiKey)
|
MoonshotApi moonshotApi = StrUtil.isEmpty(url)? new MoonshotApi(apiKey)
|
||||||
: new MoonshotApi(url, apiKey);
|
: new MoonshotApi(url, apiKey);
|
||||||
return new MoonshotChatModel(moonshotApi);
|
MoonshotChatOptions options = MoonshotChatOptions.builder().model(MoonshotApi.DEFAULT_CHAT_MODEL).build();
|
||||||
|
return new MoonshotChatModel(moonshotApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -449,7 +456,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
|
||||||
// 获取 AzureOpenAiChatProperties 对象
|
// 获取 AzureOpenAiChatProperties 对象
|
||||||
AzureOpenAiChatProperties chatProperties = SpringUtil.getBean(AzureOpenAiChatProperties.class);
|
AzureOpenAiChatProperties chatProperties = SpringUtil.getBean(AzureOpenAiChatProperties.class);
|
||||||
return azureOpenAiAutoConfiguration.azureOpenAiChatModel(openAIClient, chatProperties,
|
return azureOpenAiAutoConfiguration.azureOpenAiChatModel(openAIClient, chatProperties,
|
||||||
null, null, null);
|
getToolCallingManager(), null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -704,4 +711,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
|
||||||
return SpringUtil.getBean(ToolCallingManager.class);
|
return SpringUtil.getBean(ToolCallingManager.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static FunctionCallbackResolver getFunctionCallbackResolver() {
|
||||||
|
return SpringUtil.getBean(FunctionCallbackResolver.class);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,6 +13,8 @@ import org.springframework.ai.openai.OpenAiChatOptions;
|
||||||
import org.springframework.ai.qianfan.QianFanChatOptions;
|
import org.springframework.ai.qianfan.QianFanChatOptions;
|
||||||
import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
|
import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
|
||||||
|
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Spring AI 工具类
|
* Spring AI 工具类
|
||||||
*
|
*
|
||||||
|
@ -21,22 +23,27 @@ import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
|
||||||
public class AiUtils {
|
public class AiUtils {
|
||||||
|
|
||||||
public static ChatOptions buildChatOptions(AiPlatformEnum platform, String model, Double temperature, Integer maxTokens) {
|
public static ChatOptions buildChatOptions(AiPlatformEnum platform, String model, Double temperature, Integer maxTokens) {
|
||||||
|
return buildChatOptions(platform, model, temperature, maxTokens, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static ChatOptions buildChatOptions(AiPlatformEnum platform, String model, Double temperature, Integer maxTokens,
|
||||||
|
Set<String> toolNames) {
|
||||||
// noinspection EnhancedSwitchMigration
|
// noinspection EnhancedSwitchMigration
|
||||||
switch (platform) {
|
switch (platform) {
|
||||||
case TONG_YI:
|
case TONG_YI:
|
||||||
// TODO functions
|
return DashScopeChatOptions.builder().withModel(model).withTemperature(temperature).withMaxToken(maxTokens)
|
||||||
return DashScopeChatOptions.builder().withModel(model).withTemperature(temperature).withMaxToken(maxTokens).build();
|
.withFunctions(toolNames).build();
|
||||||
case YI_YAN:
|
case YI_YAN:
|
||||||
return QianFanChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
|
return QianFanChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
|
||||||
case ZHI_PU:
|
case ZHI_PU:
|
||||||
// TODO functions
|
return ZhiPuAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
|
||||||
return ZhiPuAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
|
.functions(toolNames).build();
|
||||||
case MINI_MAX:
|
case MINI_MAX:
|
||||||
// TODO functions
|
return MiniMaxChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
|
||||||
return MiniMaxChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
|
.functions(toolNames).build();
|
||||||
case MOONSHOT:
|
case MOONSHOT:
|
||||||
// TODO functions
|
return MoonshotChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
|
||||||
return MoonshotChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
|
.functions(toolNames).build();
|
||||||
case OPENAI:
|
case OPENAI:
|
||||||
case DEEP_SEEK: // 复用 OpenAI 客户端
|
case DEEP_SEEK: // 复用 OpenAI 客户端
|
||||||
case DOU_BAO: // 复用 OpenAI 客户端
|
case DOU_BAO: // 复用 OpenAI 客户端
|
||||||
|
@ -44,17 +51,14 @@ public class AiUtils {
|
||||||
case XING_HUO: // 复用 OpenAI 客户端
|
case XING_HUO: // 复用 OpenAI 客户端
|
||||||
case SILICON_FLOW: // 复用 OpenAI 客户端
|
case SILICON_FLOW: // 复用 OpenAI 客户端
|
||||||
return OpenAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
|
return OpenAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
|
||||||
// .toolNames() TODO
|
.toolNames(toolNames).build();
|
||||||
.toolNames("listDir")
|
|
||||||
.build();
|
|
||||||
case AZURE_OPENAI:
|
case AZURE_OPENAI:
|
||||||
// TODO 芋艿:貌似没 model 字段???!
|
// TODO 芋艿:貌似没 model 字段???!
|
||||||
// TODO 芋艿:.toolNames() TODO
|
return AzureOpenAiChatOptions.builder().deploymentName(model).temperature(temperature).maxTokens(maxTokens)
|
||||||
return AzureOpenAiChatOptions.builder().deploymentName(model).temperature(temperature).maxTokens(maxTokens).build();
|
.toolNames(toolNames).build();
|
||||||
case OLLAMA:
|
case OLLAMA:
|
||||||
// TODO 芋艿:.toolNames() TODO
|
|
||||||
return OllamaOptions.builder().model(model).temperature(temperature).numPredict(maxTokens)
|
return OllamaOptions.builder().model(model).temperature(temperature).numPredict(maxTokens)
|
||||||
.toolNames("listDir").build();
|
.toolNames(toolNames).build();
|
||||||
default:
|
default:
|
||||||
throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
|
throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue