Commit ffe4afaaafea38e1c4ca54f1f64025b63fd23ac7

Authored by YunaiV
1 parent 25a0fe90

【功能新增】AI:新增 function call 示例,完成所有模型的测试 = = 累

yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
... ... @@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
7 7 import cn.iocoder.yudao.framework.ai.core.util.AiUtils;
8 8 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
9 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
  10 +import cn.iocoder.yudao.framework.common.util.collection.SetUtils;
10 11 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
11 12 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
12 13 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO;
... ... @@ -238,7 +239,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
238 239 // 2. 构建 ChatOptions 对象
239 240 AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform());
240 241 ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(),
241   - conversation.getTemperature(), conversation.getMaxTokens());
  242 + conversation.getTemperature(), conversation.getMaxTokens(),
  243 + SetUtils.asSet("directory_list", "weather_query"));
242 244 return new Prompt(chatMessages, chatOptions);
243 245 }
244 246  
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/tool/ListDirTool.java deleted
1   -package cn.iocoder.yudao.module.ai.service.tool;
2   -
3   -import cn.hutool.core.date.LocalDateTimeUtil;
4   -import cn.hutool.core.io.FileUtil;
5   -import cn.hutool.core.util.ArrayUtil;
6   -import cn.hutool.core.util.StrUtil;
7   -import lombok.AllArgsConstructor;
8   -import lombok.Data;
9   -import lombok.NoArgsConstructor;
10   -import org.springframework.ai.tool.annotation.Tool;
11   -import org.springframework.ai.tool.annotation.ToolParam;
12   -import org.springframework.stereotype.Component;
13   -
14   -import java.io.File;
15   -import java.nio.file.Path;
16   -import java.nio.file.Paths;
17   -import java.util.Arrays;
18   -import java.util.Collections;
19   -import java.util.List;
20   -
21   -import static cn.hutool.core.date.DatePattern.NORM_DATETIME_PATTERN;
22   -import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
23   -
24   -/**
25   - * 目录内容列表工具:列出指定目录的内容
26   - *
27   - * @author 芋道源码
28   - */
29   -@Component
30   -public class ListDirTool {
31   -
32   - /**
33   - * 列出指定目录的内容
34   - *
35   - * @param relativePath 要列出内容的目录路径,相对于工作区根目录
36   - * @return 目录内容列表
37   - */
38   - @Tool(name = "listDir", description = "列出指定目录的内容")
39   - public Response listDir(@ToolParam(description = "要列出内容的目录路径,相对于工作区根目录") String relativePath) {
40   - // 校验目录存在
41   - String path = StrUtil.blankToDefault(relativePath, ".");
42   - Path dirPath = Paths.get(path);
43   - if (!FileUtil.exist(dirPath.toString()) || !FileUtil.isDirectory(dirPath.toString())) {
44   - return new Response(Collections.emptyList());
45   - }
46   - // 列出目录内容
47   - File[] files = dirPath.toFile().listFiles();
48   - if (ArrayUtil.isEmpty(files)) {
49   - return new Response(Collections.emptyList());
50   - }
51   - return new Response(convertList(Arrays.asList(files), file -> new Response.File()
52   - .setDirectory(file.isDirectory()).setName(file.getName())
53   - .setSize(file.isFile() ? FileUtil.readableFileSize(file.length()) : null)
54   - .setLastModified(
55   - LocalDateTimeUtil.format(LocalDateTimeUtil.of(file.lastModified()), NORM_DATETIME_PATTERN))));
56   - }
57   -
58   - @Data
59   - @AllArgsConstructor
60   - @NoArgsConstructor
61   - public static class Response {
62   -
63   - /**
64   - * 目录内容列表
65   - */
66   - private List<File> files;
67   -
68   - @Data
69   - public static class File {
70   -
71   - /**
72   - * 是否为目录
73   - */
74   - private Boolean directory;
75   -
76   - /**
77   - * 名称
78   - */
79   - private String name;
80   -
81   - /**
82   - * 大小,仅对文件有效
83   - */
84   - private String size;
85   -
86   - /**
87   - * 最后修改时间
88   - */
89   - private String lastModified;
90   -
91   - }
92   -
93   - }
94   -
95   -}
96 0 \ No newline at end of file
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/tool/ListDirToolB.java renamed to yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/tool/function/DirectoryListToolFunction.java
1   -package cn.iocoder.yudao.module.ai.service.tool;
  1 +package cn.iocoder.yudao.module.ai.service.tool.function;
2 2  
3 3 import cn.hutool.core.date.LocalDateTimeUtil;
4 4 import cn.hutool.core.io.FileUtil;
5 5 import cn.hutool.core.util.ArrayUtil;
6 6 import cn.hutool.core.util.StrUtil;
7 7 import com.fasterxml.jackson.annotation.JsonClassDescription;
  8 +import com.fasterxml.jackson.annotation.JsonProperty;
8 9 import com.fasterxml.jackson.annotation.JsonPropertyDescription;
9 10 import lombok.AllArgsConstructor;
10 11 import lombok.Data;
... ... @@ -12,8 +13,6 @@ import lombok.NoArgsConstructor;
12 13 import org.springframework.stereotype.Component;
13 14  
14 15 import java.io.File;
15   -import java.nio.file.Path;
16   -import java.nio.file.Paths;
17 16 import java.util.Arrays;
18 17 import java.util.Collections;
19 18 import java.util.List;
... ... @@ -23,21 +22,22 @@ import static cn.hutool.core.date.DatePattern.NORM_DATETIME_PATTERN;
23 22 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
24 23  
25 24 /**
26   - * 目录内容列表工具:列出指定目录的内容
  25 + * 工具:列出指定目录的文件列表
27 26 *
28 27 * @author 芋道源码
29 28 */
30   -@Component("listDir")
31   -public class ListDirToolB implements Function<ListDirToolB.Request, ListDirToolB.Response> {
  29 +@Component("directory_list")
  30 +public class DirectoryListToolFunction implements Function<DirectoryListToolFunction.Request, DirectoryListToolFunction.Response> {
32 31  
33 32 @Data
34   - @JsonClassDescription("列出指定目录的内容")
  33 + @JsonClassDescription("列出指定目录的文件列表")
35 34 public static class Request {
36 35  
37 36 /**
38   - * 要列出内容的目录路径
  37 + * 目录路径
39 38 */
40   - @JsonPropertyDescription("要列出内容的目录路径,例如说:/Users/yunai")
  39 + @JsonProperty(required = true, value = "path")
  40 + @JsonPropertyDescription("目录路径,例如说:/Users/yunai")
41 41 private String path;
42 42  
43 43 }
... ... @@ -48,7 +48,7 @@ public class ListDirToolB implements Function&lt;ListDirToolB.Request, ListDirToolB
48 48 public static class Response {
49 49  
50 50 /**
51   - * 目录内容列表
  51 + * 文件列表
52 52 */
53 53 private List<File> files;
54 54  
... ... @@ -82,13 +82,12 @@ public class ListDirToolB implements Function&lt;ListDirToolB.Request, ListDirToolB
82 82 @Override
83 83 public Response apply(Request request) {
84 84 // 校验目录存在
85   - String path = StrUtil.blankToDefault(request.getPath(), ".");
86   - Path dirPath = Paths.get(path);
87   - if (!FileUtil.exist(dirPath.toString()) || !FileUtil.isDirectory(dirPath.toString())) {
  85 + String path = StrUtil.blankToDefault(request.getPath(), "/");
  86 + if (!FileUtil.exist(path) || !FileUtil.isDirectory(path)) {
88 87 return new Response(Collections.emptyList());
89 88 }
90   - // 列出目录内容
91   - File[] files = dirPath.toFile().listFiles();
  89 + // 列出目录
  90 + File[] files = FileUtil.ls(path);
92 91 if (ArrayUtil.isEmpty(files)) {
93 92 return new Response(Collections.emptyList());
94 93 }
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/tool/function/WeatherQueryToolFunction.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.service.tool.function;
  2 +
  3 +import cn.hutool.core.date.LocalDateTimeUtil;
  4 +import cn.hutool.core.util.RandomUtil;
  5 +import cn.hutool.core.util.StrUtil;
  6 +import com.fasterxml.jackson.annotation.JsonClassDescription;
  7 +import com.fasterxml.jackson.annotation.JsonProperty;
  8 +import com.fasterxml.jackson.annotation.JsonPropertyDescription;
  9 +import lombok.AllArgsConstructor;
  10 +import lombok.Data;
  11 +import lombok.NoArgsConstructor;
  12 +import org.springframework.stereotype.Component;
  13 +
  14 +import java.time.LocalDateTime;
  15 +import java.util.function.Function;
  16 +
  17 +import static cn.hutool.core.date.DatePattern.NORM_DATETIME_PATTERN;
  18 +
  19 +/**
  20 + * 工具:查询指定城市的天气信息
  21 + *
  22 + * @author 芋道源码
  23 + */
  24 +@Component("weather_query")
  25 +public class WeatherQueryToolFunction
  26 + implements Function<WeatherQueryToolFunction.Request, WeatherQueryToolFunction.Response> {
  27 +
  28 + private static final String[] WEATHER_CONDITIONS = { "晴朗", "多云", "阴天", "小雨", "大雨", "雷雨", "小雪", "大雪" };
  29 +
  30 + @Data
  31 + @JsonClassDescription("查询指定城市的天气信息")
  32 + public static class Request {
  33 +
  34 + /**
  35 + * 城市名称
  36 + */
  37 + @JsonProperty(required = true, value = "city")
  38 + @JsonPropertyDescription("城市名称,例如:北京、上海、广州")
  39 + private String city;
  40 +
  41 + }
  42 +
  43 + @Data
  44 + @AllArgsConstructor
  45 + @NoArgsConstructor
  46 + public static class Response {
  47 +
  48 + /**
  49 + * 城市名称
  50 + */
  51 + private String city;
  52 +
  53 + /**
  54 + * 天气信息
  55 + */
  56 + private WeatherInfo weatherInfo;
  57 +
  58 + @Data
  59 + @AllArgsConstructor
  60 + @NoArgsConstructor
  61 + public static class WeatherInfo {
  62 +
  63 + /**
  64 + * 温度(摄氏度)
  65 + */
  66 + private Integer temperature;
  67 +
  68 + /**
  69 + * 天气状况
  70 + */
  71 + private String condition;
  72 +
  73 + /**
  74 + * 湿度百分比
  75 + */
  76 + private Integer humidity;
  77 +
  78 + /**
  79 + * 风速(km/h)
  80 + */
  81 + private Integer windSpeed;
  82 +
  83 + /**
  84 + * 查询时间
  85 + */
  86 + private String queryTime;
  87 +
  88 + }
  89 +
  90 + }
  91 +
  92 + @Override
  93 + public Response apply(Request request) {
  94 + // 检查城市名称是否为空
  95 + if (StrUtil.isBlank(request.getCity())) {
  96 + return new Response("未知城市", null);
  97 + }
  98 +
  99 + // 获取天气数据
  100 + String city = request.getCity();
  101 + Response.WeatherInfo weatherInfo = generateMockWeatherInfo();
  102 + return new Response(city, weatherInfo);
  103 + }
  104 +
  105 + /**
  106 + * 生成模拟的天气数据
  107 + * 在实际应用中,应替换为真实 API 调用
  108 + */
  109 + private Response.WeatherInfo generateMockWeatherInfo() {
  110 + int temperature = RandomUtil.randomInt(-5, 30);
  111 + int humidity = RandomUtil.randomInt(1, 100);
  112 + int windSpeed = RandomUtil.randomInt(1, 30);
  113 + String condition = RandomUtil.randomEle(WEATHER_CONDITIONS);
  114 + return new Response.WeatherInfo(temperature, condition, humidity, windSpeed,
  115 + LocalDateTimeUtil.format(LocalDateTime.now(), NORM_DATETIME_PATTERN));
  116 + }
  117 +
  118 +}
0 119 \ No newline at end of file
... ...
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/tool/package-info.java 0 → 100644
  1 +package cn.iocoder.yudao.module.ai.service.tool;
0 2 \ No newline at end of file
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/config/YudaoAiAutoConfiguration.java
1 1 package cn.iocoder.yudao.framework.ai.config;
2 2  
3 3 import cn.hutool.core.util.StrUtil;
  4 +import cn.hutool.extra.spring.SpringUtil;
4 5 import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactory;
5 6 import cn.iocoder.yudao.framework.ai.core.factory.AiModelFactoryImpl;
6 7 import cn.iocoder.yudao.framework.ai.core.model.deepseek.DeepSeekChatModel;
... ... @@ -17,6 +18,7 @@ import org.springframework.ai.autoconfigure.vectorstore.qdrant.QdrantVectorStore
17 18 import org.springframework.ai.autoconfigure.vectorstore.redis.RedisVectorStoreProperties;
18 19 import org.springframework.ai.embedding.BatchingStrategy;
19 20 import org.springframework.ai.embedding.TokenCountBatchingStrategy;
  21 +import org.springframework.ai.model.tool.ToolCallingManager;
20 22 import org.springframework.ai.openai.OpenAiChatModel;
21 23 import org.springframework.ai.openai.OpenAiChatOptions;
22 24 import org.springframework.ai.openai.api.OpenAiApi;
... ... @@ -70,6 +72,7 @@ public class YudaoAiAutoConfiguration {
70 72 .maxTokens(properties.getMaxTokens())
71 73 .topP(properties.getTopP())
72 74 .build())
  75 + .toolCallingManager(getToolCallingManager())
73 76 .build();
74 77 return new DeepSeekChatModel(openAiChatModel);
75 78 }
... ... @@ -96,6 +99,7 @@ public class YudaoAiAutoConfiguration {
96 99 .maxTokens(properties.getMaxTokens())
97 100 .topP(properties.getTopP())
98 101 .build())
  102 + .toolCallingManager(getToolCallingManager())
99 103 .build();
100 104 return new DouBaoChatModel(openAiChatModel);
101 105 }
... ... @@ -122,6 +126,7 @@ public class YudaoAiAutoConfiguration {
122 126 .maxTokens(properties.getMaxTokens())
123 127 .topP(properties.getTopP())
124 128 .build())
  129 + .toolCallingManager(getToolCallingManager())
125 130 .build();
126 131 return new SiliconFlowChatModel(openAiChatModel);
127 132 }
... ... @@ -155,6 +160,7 @@ public class YudaoAiAutoConfiguration {
155 160 .maxTokens(properties.getMaxTokens())
156 161 .topP(properties.getTopP())
157 162 .build())
  163 + .toolCallingManager(getToolCallingManager())
158 164 .build();
159 165 return new HunYuanChatModel(openAiChatModel);
160 166 }
... ... @@ -181,6 +187,7 @@ public class YudaoAiAutoConfiguration {
181 187 .maxTokens(properties.getMaxTokens())
182 188 .topP(properties.getTopP())
183 189 .build())
  190 + .toolCallingManager(getToolCallingManager())
184 191 .build();
185 192 return new XingHuoChatModel(openAiChatModel);
186 193 }
... ... @@ -210,4 +217,8 @@ public class YudaoAiAutoConfiguration {
210 217 return new TokenCountBatchingStrategy();
211 218 }
212 219  
  220 + private static ToolCallingManager getToolCallingManager() {
  221 + return SpringUtil.getBean(ToolCallingManager.class);
  222 + }
  223 +
213 224 }
214 225 \ No newline at end of file
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/factory/AiModelFactoryImpl.java
... ... @@ -23,6 +23,7 @@ import com.alibaba.cloud.ai.autoconfigure.dashscope.DashScopeAutoConfiguration;
23 23 import com.alibaba.cloud.ai.dashscope.api.DashScopeApi;
24 24 import com.alibaba.cloud.ai.dashscope.api.DashScopeImageApi;
25 25 import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatModel;
  26 +import com.alibaba.cloud.ai.dashscope.chat.DashScopeChatOptions;
26 27 import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingModel;
27 28 import com.alibaba.cloud.ai.dashscope.embedding.DashScopeEmbeddingOptions;
28 29 import com.alibaba.cloud.ai.dashscope.image.DashScopeImageModel;
... ... @@ -58,11 +59,14 @@ import org.springframework.ai.embedding.BatchingStrategy;
58 59 import org.springframework.ai.embedding.EmbeddingModel;
59 60 import org.springframework.ai.image.ImageModel;
60 61 import org.springframework.ai.minimax.MiniMaxChatModel;
  62 +import org.springframework.ai.minimax.MiniMaxChatOptions;
61 63 import org.springframework.ai.minimax.MiniMaxEmbeddingModel;
62 64 import org.springframework.ai.minimax.MiniMaxEmbeddingOptions;
63 65 import org.springframework.ai.minimax.api.MiniMaxApi;
  66 +import org.springframework.ai.model.function.FunctionCallbackResolver;
64 67 import org.springframework.ai.model.tool.ToolCallingManager;
65 68 import org.springframework.ai.moonshot.MoonshotChatModel;
  69 +import org.springframework.ai.moonshot.MoonshotChatOptions;
66 70 import org.springframework.ai.moonshot.api.MoonshotApi;
67 71 import org.springframework.ai.ollama.OllamaChatModel;
68 72 import org.springframework.ai.ollama.OllamaEmbeddingModel;
... ... @@ -90,10 +94,7 @@ import org.springframework.ai.vectorstore.observation.DefaultVectorStoreObservat
90 94 import org.springframework.ai.vectorstore.observation.VectorStoreObservationConvention;
91 95 import org.springframework.ai.vectorstore.qdrant.QdrantVectorStore;
92 96 import org.springframework.ai.vectorstore.redis.RedisVectorStore;
93   -import org.springframework.ai.zhipuai.ZhiPuAiChatModel;
94   -import org.springframework.ai.zhipuai.ZhiPuAiEmbeddingModel;
95   -import org.springframework.ai.zhipuai.ZhiPuAiEmbeddingOptions;
96   -import org.springframework.ai.zhipuai.ZhiPuAiImageModel;
  97 +import org.springframework.ai.zhipuai.*;
97 98 import org.springframework.ai.zhipuai.api.ZhiPuAiApi;
98 99 import org.springframework.ai.zhipuai.api.ZhiPuAiImageApi;
99 100 import org.springframework.beans.BeansException;
... ... @@ -110,6 +111,7 @@ import java.util.Timer;
110 111 import java.util.TimerTask;
111 112  
112 113 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  114 +import static org.springframework.ai.retry.RetryUtils.DEFAULT_RETRY_TEMPLATE;
113 115  
114 116 /**
115 117 * AI Model 模型工厂的实现类
... ... @@ -308,7 +310,9 @@ public class AiModelFactoryImpl implements AiModelFactory {
308 310 */
309 311 private static DashScopeChatModel buildTongYiChatModel(String key) {
310 312 DashScopeApi dashScopeApi = new DashScopeApi(key);
311   - return new DashScopeChatModel(dashScopeApi);
  313 + DashScopeChatOptions options = DashScopeChatOptions.builder().withModel(DashScopeApi.DEFAULT_CHAT_MODEL)
  314 + .withTemperature(0.7).build();
  315 + return new DashScopeChatModel(dashScopeApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE);
312 316 }
313 317  
314 318 /**
... ... @@ -385,7 +389,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
385 389 private ZhiPuAiChatModel buildZhiPuChatModel(String apiKey, String url) {
386 390 ZhiPuAiApi zhiPuAiApi = StrUtil.isEmpty(url) ? new ZhiPuAiApi(apiKey)
387 391 : new ZhiPuAiApi(url, apiKey);
388   - return new ZhiPuAiChatModel(zhiPuAiApi);
  392 + ZhiPuAiChatOptions options = ZhiPuAiChatOptions.builder().model(ZhiPuAiApi.DEFAULT_CHAT_MODEL).temperature(0.7).build();
  393 + return new ZhiPuAiChatModel(zhiPuAiApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE);
389 394 }
390 395  
391 396 /**
... ... @@ -403,7 +408,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
403 408 private MiniMaxChatModel buildMiniMaxChatModel(String apiKey, String url) {
404 409 MiniMaxApi miniMaxApi = StrUtil.isEmpty(url) ? new MiniMaxApi(apiKey)
405 410 : new MiniMaxApi(url, apiKey);
406   - return new MiniMaxChatModel(miniMaxApi);
  411 + MiniMaxChatOptions options = MiniMaxChatOptions.builder().model(MiniMaxApi.DEFAULT_CHAT_MODEL).temperature(0.7).build();
  412 + return new MiniMaxChatModel(miniMaxApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE);
407 413 }
408 414  
409 415 /**
... ... @@ -412,7 +418,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
412 418 private MoonshotChatModel buildMoonshotChatModel(String apiKey, String url) {
413 419 MoonshotApi moonshotApi = StrUtil.isEmpty(url)? new MoonshotApi(apiKey)
414 420 : new MoonshotApi(url, apiKey);
415   - return new MoonshotChatModel(moonshotApi);
  421 + MoonshotChatOptions options = MoonshotChatOptions.builder().model(MoonshotApi.DEFAULT_CHAT_MODEL).build();
  422 + return new MoonshotChatModel(moonshotApi, options, getFunctionCallbackResolver(), DEFAULT_RETRY_TEMPLATE);
416 423 }
417 424  
418 425 /**
... ... @@ -449,7 +456,7 @@ public class AiModelFactoryImpl implements AiModelFactory {
449 456 // 获取 AzureOpenAiChatProperties 对象
450 457 AzureOpenAiChatProperties chatProperties = SpringUtil.getBean(AzureOpenAiChatProperties.class);
451 458 return azureOpenAiAutoConfiguration.azureOpenAiChatModel(openAIClient, chatProperties,
452   - null, null, null);
  459 + getToolCallingManager(), null, null);
453 460 }
454 461  
455 462 /**
... ... @@ -704,4 +711,8 @@ public class AiModelFactoryImpl implements AiModelFactory {
704 711 return SpringUtil.getBean(ToolCallingManager.class);
705 712 }
706 713  
  714 + private static FunctionCallbackResolver getFunctionCallbackResolver() {
  715 + return SpringUtil.getBean(FunctionCallbackResolver.class);
  716 + }
  717 +
707 718 }
... ...
yudao-module-ai/yudao-spring-boot-starter-ai/src/main/java/cn/iocoder/yudao/framework/ai/core/util/AiUtils.java
... ... @@ -13,6 +13,8 @@ import org.springframework.ai.openai.OpenAiChatOptions;
13 13 import org.springframework.ai.qianfan.QianFanChatOptions;
14 14 import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
15 15  
  16 +import java.util.Set;
  17 +
16 18 /**
17 19 * Spring AI 工具类
18 20 *
... ... @@ -21,22 +23,27 @@ import org.springframework.ai.zhipuai.ZhiPuAiChatOptions;
21 23 public class AiUtils {
22 24  
23 25 public static ChatOptions buildChatOptions(AiPlatformEnum platform, String model, Double temperature, Integer maxTokens) {
  26 + return buildChatOptions(platform, model, temperature, maxTokens, null);
  27 + }
  28 +
  29 + public static ChatOptions buildChatOptions(AiPlatformEnum platform, String model, Double temperature, Integer maxTokens,
  30 + Set<String> toolNames) {
24 31 // noinspection EnhancedSwitchMigration
25 32 switch (platform) {
26 33 case TONG_YI:
27   - // TODO functions
28   - return DashScopeChatOptions.builder().withModel(model).withTemperature(temperature).withMaxToken(maxTokens).build();
  34 + return DashScopeChatOptions.builder().withModel(model).withTemperature(temperature).withMaxToken(maxTokens)
  35 + .withFunctions(toolNames).build();
29 36 case YI_YAN:
30 37 return QianFanChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
31 38 case ZHI_PU:
32   - // TODO functions
33   - return ZhiPuAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
  39 + return ZhiPuAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
  40 + .functions(toolNames).build();
34 41 case MINI_MAX:
35   - // TODO functions
36   - return MiniMaxChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
  42 + return MiniMaxChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
  43 + .functions(toolNames).build();
37 44 case MOONSHOT:
38   - // TODO functions
39   - return MoonshotChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens).build();
  45 + return MoonshotChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
  46 + .functions(toolNames).build();
40 47 case OPENAI:
41 48 case DEEP_SEEK: // 复用 OpenAI 客户端
42 49 case DOU_BAO: // 复用 OpenAI 客户端
... ... @@ -44,17 +51,14 @@ public class AiUtils {
44 51 case XING_HUO: // 复用 OpenAI 客户端
45 52 case SILICON_FLOW: // 复用 OpenAI 客户端
46 53 return OpenAiChatOptions.builder().model(model).temperature(temperature).maxTokens(maxTokens)
47   -// .toolNames() TODO
48   - .toolNames("listDir")
49   - .build();
  54 + .toolNames(toolNames).build();
50 55 case AZURE_OPENAI:
51 56 // TODO 芋艿:貌似没 model 字段???!
52   - // TODO 芋艿:.toolNames() TODO
53   - return AzureOpenAiChatOptions.builder().deploymentName(model).temperature(temperature).maxTokens(maxTokens).build();
  57 + return AzureOpenAiChatOptions.builder().deploymentName(model).temperature(temperature).maxTokens(maxTokens)
  58 + .toolNames(toolNames).build();
54 59 case OLLAMA:
55   - // TODO 芋艿:.toolNames() TODO
56 60 return OllamaOptions.builder().model(model).temperature(temperature).numPredict(maxTokens)
57   - .toolNames("listDir").build();
  61 + .toolNames(toolNames).build();
58 62 default:
59 63 throw new IllegalArgumentException(StrUtil.format("未知平台({})", platform));
60 64 }
... ...