Commit 1e8845ce6d229130ae4a804e578d52cf20f5fa15

Authored by YunaiV
1 parent e869aaee

【功能新增】AI:增加 AI 对话,与 tool 的打通

yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/AiToolController.java
1 package cn.iocoder.yudao.module.ai.controller.admin.model; 1 package cn.iocoder.yudao.module.ai.controller.admin.model;
2 2
  3 +import cn.iocoder.yudao.framework.common.enums.CommonStatusEnum;
3 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 4 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
4 import cn.iocoder.yudao.framework.common.pojo.PageResult; 5 import cn.iocoder.yudao.framework.common.pojo.PageResult;
5 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
@@ -17,8 +18,10 @@ import org.springframework.security.access.prepost.PreAuthorize; @@ -17,8 +18,10 @@ import org.springframework.security.access.prepost.PreAuthorize;
17 import org.springframework.validation.annotation.Validated; 18 import org.springframework.validation.annotation.Validated;
18 import org.springframework.web.bind.annotation.*; 19 import org.springframework.web.bind.annotation.*;
19 20
20 -import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 21 +import java.util.List;
21 22
  23 +import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
  24 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
22 25
23 @Tag(name = "管理后台 - AI 工具") 26 @Tag(name = "管理后台 - AI 工具")
24 @RestController 27 @RestController
@@ -30,14 +33,14 @@ public class AiToolController { @@ -30,14 +33,14 @@ public class AiToolController {
30 private AiToolService toolService; 33 private AiToolService toolService;
31 34
32 @PostMapping("/create") 35 @PostMapping("/create")
33 - @Operation(summary = "创建AI 工具") 36 + @Operation(summary = "创建工具")
34 @PreAuthorize("@ss.hasPermission('ai:tool:create')") 37 @PreAuthorize("@ss.hasPermission('ai:tool:create')")
35 public CommonResult<Long> createTool(@Valid @RequestBody AiToolSaveReqVO createReqVO) { 38 public CommonResult<Long> createTool(@Valid @RequestBody AiToolSaveReqVO createReqVO) {
36 return success(toolService.createTool(createReqVO)); 39 return success(toolService.createTool(createReqVO));
37 } 40 }
38 41
39 @PutMapping("/update") 42 @PutMapping("/update")
40 - @Operation(summary = "更新AI 工具") 43 + @Operation(summary = "更新工具")
41 @PreAuthorize("@ss.hasPermission('ai:tool:update')") 44 @PreAuthorize("@ss.hasPermission('ai:tool:update')")
42 public CommonResult<Boolean> updateTool(@Valid @RequestBody AiToolSaveReqVO updateReqVO) { 45 public CommonResult<Boolean> updateTool(@Valid @RequestBody AiToolSaveReqVO updateReqVO) {
43 toolService.updateTool(updateReqVO); 46 toolService.updateTool(updateReqVO);
@@ -45,7 +48,7 @@ public class AiToolController { @@ -45,7 +48,7 @@ public class AiToolController {
45 } 48 }
46 49
47 @DeleteMapping("/delete") 50 @DeleteMapping("/delete")
48 - @Operation(summary = "删除AI 工具") 51 + @Operation(summary = "删除工具")
49 @Parameter(name = "id", description = "编号", required = true) 52 @Parameter(name = "id", description = "编号", required = true)
50 @PreAuthorize("@ss.hasPermission('ai:tool:delete')") 53 @PreAuthorize("@ss.hasPermission('ai:tool:delete')")
51 public CommonResult<Boolean> deleteTool(@RequestParam("id") Long id) { 54 public CommonResult<Boolean> deleteTool(@RequestParam("id") Long id) {
@@ -54,7 +57,7 @@ public class AiToolController { @@ -54,7 +57,7 @@ public class AiToolController {
54 } 57 }
55 58
56 @GetMapping("/get") 59 @GetMapping("/get")
57 - @Operation(summary = "获得AI 工具") 60 + @Operation(summary = "获得工具")
58 @Parameter(name = "id", description = "编号", required = true, example = "1024") 61 @Parameter(name = "id", description = "编号", required = true, example = "1024")
59 @PreAuthorize("@ss.hasPermission('ai:tool:query')") 62 @PreAuthorize("@ss.hasPermission('ai:tool:query')")
60 public CommonResult<AiToolRespVO> getTool(@RequestParam("id") Long id) { 63 public CommonResult<AiToolRespVO> getTool(@RequestParam("id") Long id) {
@@ -63,11 +66,19 @@ public class AiToolController { @@ -63,11 +66,19 @@ public class AiToolController {
63 } 66 }
64 67
65 @GetMapping("/page") 68 @GetMapping("/page")
66 - @Operation(summary = "获得AI 工具分页") 69 + @Operation(summary = "获得工具分页")
67 @PreAuthorize("@ss.hasPermission('ai:tool:query')") 70 @PreAuthorize("@ss.hasPermission('ai:tool:query')")
68 public CommonResult<PageResult<AiToolRespVO>> getToolPage(@Valid AiToolPageReqVO pageReqVO) { 71 public CommonResult<PageResult<AiToolRespVO>> getToolPage(@Valid AiToolPageReqVO pageReqVO) {
69 PageResult<AiToolDO> pageResult = toolService.getToolPage(pageReqVO); 72 PageResult<AiToolDO> pageResult = toolService.getToolPage(pageReqVO);
70 return success(BeanUtils.toBean(pageResult, AiToolRespVO.class)); 73 return success(BeanUtils.toBean(pageResult, AiToolRespVO.class));
71 } 74 }
72 75
  76 + @GetMapping("/simple-list")
  77 + @Operation(summary = "获得工具列表")
  78 + public CommonResult<List<AiToolRespVO>> getToolSimpleList() {
  79 + List<AiToolDO> list = toolService.getToolListByStatus(CommonStatusEnum.ENABLE.getStatus());
  80 + return success(convertList(list, tool -> new AiToolRespVO()
  81 + .setId(tool.getId()).setName(tool.getName())));
  82 + }
  83 +
73 } 84 }
74 \ No newline at end of file 85 \ No newline at end of file
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleRespVO.java
@@ -49,6 +49,9 @@ public class AiChatRoleRespVO implements VO { @@ -49,6 +49,9 @@ public class AiChatRoleRespVO implements VO {
49 @Schema(description = "引用的知识库编号列表", example = "1,2,3") 49 @Schema(description = "引用的知识库编号列表", example = "1,2,3")
50 private List<Long> knowledgeIds; 50 private List<Long> knowledgeIds;
51 51
  52 + @Schema(description = "引用的工具编号列表", example = "1,2,3")
  53 + private List<Long> toolIds;
  54 +
52 @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 55 @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
53 private Boolean publicStatus; 56 private Boolean publicStatus;
54 57
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleSaveMyReqVO.java
@@ -34,4 +34,7 @@ public class AiChatRoleSaveMyReqVO { @@ -34,4 +34,7 @@ public class AiChatRoleSaveMyReqVO {
34 @Schema(description = "引用的知识库编号列表", example = "1,2,3") 34 @Schema(description = "引用的知识库编号列表", example = "1,2,3")
35 private List<Long> knowledgeIds; 35 private List<Long> knowledgeIds;
36 36
  37 + @Schema(description = "引用的工具编号列表", example = "1,2,3")
  38 + private List<Long> toolIds;
  39 +
37 } 40 }
38 \ No newline at end of file 41 \ No newline at end of file
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/controller/admin/model/vo/chatRole/AiChatRoleSaveReqVO.java
@@ -47,6 +47,9 @@ public class AiChatRoleSaveReqVO { @@ -47,6 +47,9 @@ public class AiChatRoleSaveReqVO {
47 @Schema(description = "引用的知识库编号列表", example = "1,2,3") 47 @Schema(description = "引用的知识库编号列表", example = "1,2,3")
48 private List<Long> knowledgeIds; 48 private List<Long> knowledgeIds;
49 49
  50 + @Schema(description = "引用的工具编号列表", example = "1,2,3")
  51 + private List<Long> toolIds;
  52 +
50 @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1") 53 @Schema(description = "是否公开", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
51 @NotNull(message = "是否公开不能为空") 54 @NotNull(message = "是否公开不能为空")
52 private Boolean publicStatus; 55 private Boolean publicStatus;
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/dataobject/model/AiChatRoleDO.java
@@ -74,6 +74,13 @@ public class AiChatRoleDO extends BaseDO { @@ -74,6 +74,13 @@ public class AiChatRoleDO extends BaseDO {
74 */ 74 */
75 @TableField(typeHandler = LongListTypeHandler.class) 75 @TableField(typeHandler = LongListTypeHandler.class)
76 private List<Long> knowledgeIds; 76 private List<Long> knowledgeIds;
  77 + /**
  78 + * 引用的工具编号列表
  79 + *
  80 + * 关联 {@link AiToolDO#getId()} 字段
  81 + */
  82 + @TableField(typeHandler = LongListTypeHandler.class)
  83 + private List<Long> toolIds;
77 84
78 /** 85 /**
79 * 是否公开 86 * 是否公开
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/dal/mysql/model/AiToolMapper.java
@@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool.AiToolPageReqVO @@ -7,6 +7,8 @@ import cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool.AiToolPageReqVO
7 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO; 7 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO;
8 import org.apache.ibatis.annotations.Mapper; 8 import org.apache.ibatis.annotations.Mapper;
9 9
  10 +import java.util.List;
  11 +
10 /** 12 /**
11 * AI 工具 Mapper 13 * AI 工具 Mapper
12 * 14 *
@@ -24,4 +26,10 @@ public interface AiToolMapper extends BaseMapperX&lt;AiToolDO&gt; { @@ -24,4 +26,10 @@ public interface AiToolMapper extends BaseMapperX&lt;AiToolDO&gt; {
24 .orderByDesc(AiToolDO::getId)); 26 .orderByDesc(AiToolDO::getId));
25 } 27 }
26 28
  29 + default List<AiToolDO> selectListByStatus(Integer status) {
  30 + return selectList(new LambdaQueryWrapperX<AiToolDO>()
  31 + .eq(AiToolDO::getStatus, status)
  32 + .orderByDesc(AiToolDO::getId));
  33 + }
  34 +
27 } 35 }
28 \ No newline at end of file 36 \ No newline at end of file
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/chat/AiChatMessageServiceImpl.java
@@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum; @@ -7,7 +7,6 @@ import cn.iocoder.yudao.framework.ai.core.enums.AiPlatformEnum;
7 import cn.iocoder.yudao.framework.ai.core.util.AiUtils; 7 import cn.iocoder.yudao.framework.ai.core.util.AiUtils;
8 import cn.iocoder.yudao.framework.common.pojo.CommonResult; 8 import cn.iocoder.yudao.framework.common.pojo.CommonResult;
9 import cn.iocoder.yudao.framework.common.pojo.PageResult; 9 import cn.iocoder.yudao.framework.common.pojo.PageResult;
10 -import cn.iocoder.yudao.framework.common.util.collection.SetUtils;  
11 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 10 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
12 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils; 11 import cn.iocoder.yudao.framework.tenant.core.util.TenantUtils;
13 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO; 12 import cn.iocoder.yudao.module.ai.controller.admin.chat.vo.message.AiChatMessagePageReqVO;
@@ -19,6 +18,7 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO; @@ -19,6 +18,7 @@ import cn.iocoder.yudao.module.ai.dal.dataobject.chat.AiChatMessageDO;
19 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO; 18 import cn.iocoder.yudao.module.ai.dal.dataobject.knowledge.AiKnowledgeDocumentDO;
20 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO; 19 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiChatRoleDO;
21 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO; 20 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiModelDO;
  21 +import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO;
22 import cn.iocoder.yudao.module.ai.dal.mysql.chat.AiChatMessageMapper; 22 import cn.iocoder.yudao.module.ai.dal.mysql.chat.AiChatMessageMapper;
23 import cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants; 23 import cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants;
24 import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService; 24 import cn.iocoder.yudao.module.ai.service.knowledge.AiKnowledgeDocumentService;
@@ -27,6 +27,7 @@ import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchR @@ -27,6 +27,7 @@ import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchR
27 import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchRespBO; 27 import cn.iocoder.yudao.module.ai.service.knowledge.bo.AiKnowledgeSegmentSearchRespBO;
28 import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService; 28 import cn.iocoder.yudao.module.ai.service.model.AiChatRoleService;
29 import cn.iocoder.yudao.module.ai.service.model.AiModelService; 29 import cn.iocoder.yudao.module.ai.service.model.AiModelService;
  30 +import cn.iocoder.yudao.module.ai.service.model.AiToolService;
30 import jakarta.annotation.Resource; 31 import jakarta.annotation.Resource;
31 import lombok.extern.slf4j.Slf4j; 32 import lombok.extern.slf4j.Slf4j;
32 import org.springframework.ai.chat.messages.Message; 33 import org.springframework.ai.chat.messages.Message;
@@ -50,6 +51,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU @@ -50,6 +51,7 @@ import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionU
50 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error; 51 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.error;
51 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success; 52 import static cn.iocoder.yudao.framework.common.pojo.CommonResult.success;
52 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList; 53 import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertList;
  54 +import static cn.iocoder.yudao.framework.common.util.collection.CollectionUtils.convertSet;
53 import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS; 55 import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_CONVERSATION_NOT_EXISTS;
54 import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_MESSAGE_NOT_EXIST; 56 import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.CHAT_MESSAGE_NOT_EXIST;
55 57
@@ -82,6 +84,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -82,6 +84,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
82 private AiKnowledgeSegmentService knowledgeSegmentService; 84 private AiKnowledgeSegmentService knowledgeSegmentService;
83 @Resource 85 @Resource
84 private AiKnowledgeDocumentService knowledgeDocumentService; 86 private AiKnowledgeDocumentService knowledgeDocumentService;
  87 + @Resource
  88 + private AiToolService toolService;
85 89
86 @Transactional(rollbackFor = Exception.class) 90 @Transactional(rollbackFor = Exception.class)
87 public AiChatMessageSendRespVO sendMessage(AiChatMessageSendReqVO sendReqVO, Long userId) { 91 public AiChatMessageSendRespVO sendMessage(AiChatMessageSendReqVO sendReqVO, Long userId) {
@@ -118,11 +122,13 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -118,11 +122,13 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
118 String newContent = chatResponse.getResult().getOutput().getText(); 122 String newContent = chatResponse.getResult().getOutput().getText();
119 chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(newContent)); 123 chatMessageMapper.updateById(new AiChatMessageDO().setId(assistantMessage.getId()).setContent(newContent));
120 // 3.4 响应结果 124 // 3.4 响应结果
121 - List<AiChatMessageRespVO.KnowledgeSegment> segments = BeanUtils.toBean(knowledgeSegments, AiChatMessageRespVO.KnowledgeSegment.class, 125 + List<AiChatMessageRespVO.KnowledgeSegment> segments = BeanUtils.toBean(knowledgeSegments,
  126 + AiChatMessageRespVO.KnowledgeSegment.class,
122 segment -> { 127 segment -> {
123 - AiKnowledgeDocumentDO document = knowledgeDocumentService.getKnowledgeDocument(segment.getDocumentId());  
124 - segment.setDocumentName(document != null ? document.getName() : null);  
125 - }); 128 + AiKnowledgeDocumentDO document = knowledgeDocumentService
  129 + .getKnowledgeDocument(segment.getDocumentId());
  130 + segment.setDocumentName(document != null ? document.getName() : null);
  131 + });
126 return new AiChatMessageSendRespVO() 132 return new AiChatMessageSendRespVO()
127 .setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class)) 133 .setSend(BeanUtils.toBean(userMessage, AiChatMessageSendRespVO.Message.class))
128 .setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class) 134 .setReceive(BeanUtils.toBean(assistantMessage, AiChatMessageSendRespVO.Message.class)
@@ -130,7 +136,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -130,7 +136,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
130 } 136 }
131 137
132 @Override 138 @Override
133 - public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO, Long userId) { 139 + public Flux<CommonResult<AiChatMessageSendRespVO>> sendChatMessageStream(AiChatMessageSendReqVO sendReqVO,
  140 + Long userId) {
134 // 1.1 校验对话存在 141 // 1.1 校验对话存在
135 AiChatConversationDO conversation = chatConversationService 142 AiChatConversationDO conversation = chatConversationService
136 .validateChatConversationExists(sendReqVO.getConversationId()); 143 .validateChatConversationExists(sendReqVO.getConversationId());
@@ -143,7 +150,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -143,7 +150,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
143 StreamingChatModel chatModel = modalService.getChatModel(model.getId()); 150 StreamingChatModel chatModel = modalService.getChatModel(model.getId());
144 151
145 // 2. 知识库找回 152 // 2. 知识库找回
146 - List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments = recallKnowledgeSegment(sendReqVO.getContent(), conversation); 153 + List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments = recallKnowledgeSegment(sendReqVO.getContent(),
  154 + conversation);
147 155
148 // 3. 插入 user 发送消息 156 // 3. 插入 user 发送消息
149 AiChatMessageDO userMessage = createChatMessage(conversation.getId(), null, model, 157 AiChatMessageDO userMessage = createChatMessage(conversation.getId(), null, model,
@@ -167,7 +175,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -167,7 +175,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
167 if (StrUtil.isEmpty(contentBuffer)) { 175 if (StrUtil.isEmpty(contentBuffer)) {
168 segments = BeanUtils.toBean(knowledgeSegments, AiChatMessageRespVO.KnowledgeSegment.class, 176 segments = BeanUtils.toBean(knowledgeSegments, AiChatMessageRespVO.KnowledgeSegment.class,
169 segment -> TenantUtils.executeIgnore(() -> { 177 segment -> TenantUtils.executeIgnore(() -> {
170 - AiKnowledgeDocumentDO document = knowledgeDocumentService.getKnowledgeDocument(segment.getDocumentId()); 178 + AiKnowledgeDocumentDO document = knowledgeDocumentService
  179 + .getKnowledgeDocument(segment.getDocumentId());
171 segment.setDocumentName(document != null ? document.getName() : null); 180 segment.setDocumentName(document != null ? document.getName() : null);
172 })); 181 }));
173 } 182 }
@@ -192,7 +201,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -192,7 +201,7 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
192 } 201 }
193 202
194 private List<AiKnowledgeSegmentSearchRespBO> recallKnowledgeSegment(String content, 203 private List<AiKnowledgeSegmentSearchRespBO> recallKnowledgeSegment(String content,
195 - AiChatConversationDO conversation) { 204 + AiChatConversationDO conversation) {
196 // 1. 查询聊天角色 205 // 1. 查询聊天角色
197 if (conversation == null || conversation.getRoleId() == null) { 206 if (conversation == null || conversation.getRoleId() == null) {
198 return Collections.emptyList(); 207 return Collections.emptyList();
@@ -212,8 +221,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -212,8 +221,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
212 } 221 }
213 222
214 private Prompt buildPrompt(AiChatConversationDO conversation, List<AiChatMessageDO> messages, 223 private Prompt buildPrompt(AiChatConversationDO conversation, List<AiChatMessageDO> messages,
215 - List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments,  
216 - AiModelDO model, AiChatMessageSendReqVO sendReqVO) { 224 + List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments,
  225 + AiModelDO model, AiChatMessageSendReqVO sendReqVO) {
217 List<Message> chatMessages = new ArrayList<>(); 226 List<Message> chatMessages = new ArrayList<>();
218 // 1.1 System Context 角色设定 227 // 1.1 System Context 角色设定
219 if (StrUtil.isNotBlank(conversation.getSystemMessage())) { 228 if (StrUtil.isNotBlank(conversation.getSystemMessage())) {
@@ -236,11 +245,18 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -236,11 +245,18 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
236 chatMessages.add(new UserMessage(String.format(KNOWLEDGE_USER_MESSAGE_TEMPLATE, reference))); 245 chatMessages.add(new UserMessage(String.format(KNOWLEDGE_USER_MESSAGE_TEMPLATE, reference)));
237 } 246 }
238 247
239 - // 2. 构建 ChatOptions 对象 248 + // 2.1 查询 tool 工具
  249 + Set<String> toolNames = null;
  250 + if (conversation.getRoleId() != null) {
  251 + AiChatRoleDO chatRole = chatRoleService.getChatRole(conversation.getRoleId());
  252 + if (chatRole != null && CollUtil.isNotEmpty(chatRole.getToolIds())) {
  253 + toolNames = convertSet(toolService.getToolList(chatRole.getToolIds()), AiToolDO::getName);
  254 + }
  255 + }
  256 + // 2.2 构建 ChatOptions 对象
240 AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform()); 257 AiPlatformEnum platform = AiPlatformEnum.validatePlatform(model.getPlatform());
241 ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(), 258 ChatOptions chatOptions = AiUtils.buildChatOptions(platform, model.getModel(),
242 - conversation.getTemperature(), conversation.getMaxTokens(),  
243 - SetUtils.asSet("directory_list", "weather_query")); 259 + conversation.getTemperature(), conversation.getMaxTokens(), toolNames);
244 return new Prompt(chatMessages, chatOptions); 260 return new Prompt(chatMessages, chatOptions);
245 } 261 }
246 262
@@ -255,8 +271,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -255,8 +271,8 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
255 * @return 消息上下文 271 * @return 消息上下文
256 */ 272 */
257 private List<AiChatMessageDO> filterContextMessages(List<AiChatMessageDO> messages, 273 private List<AiChatMessageDO> filterContextMessages(List<AiChatMessageDO> messages,
258 - AiChatConversationDO conversation,  
259 - AiChatMessageSendReqVO sendReqVO) { 274 + AiChatConversationDO conversation,
  275 + AiChatMessageSendReqVO sendReqVO) {
260 if (conversation.getMaxContexts() == null || ObjUtil.notEqual(sendReqVO.getUseContext(), Boolean.TRUE)) { 276 if (conversation.getMaxContexts() == null || ObjUtil.notEqual(sendReqVO.getUseContext(), Boolean.TRUE)) {
261 return Collections.emptyList(); 277 return Collections.emptyList();
262 } 278 }
@@ -285,9 +301,9 @@ public class AiChatMessageServiceImpl implements AiChatMessageService { @@ -285,9 +301,9 @@ public class AiChatMessageServiceImpl implements AiChatMessageService {
285 } 301 }
286 302
287 private AiChatMessageDO createChatMessage(Long conversationId, Long replyId, 303 private AiChatMessageDO createChatMessage(Long conversationId, Long replyId,
288 - AiModelDO model, Long userId, Long roleId,  
289 - MessageType messageType, String content, Boolean useContext,  
290 - List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments) { 304 + AiModelDO model, Long userId, Long roleId,
  305 + MessageType messageType, String content, Boolean useContext,
  306 + List<AiKnowledgeSegmentSearchRespBO> knowledgeSegments) {
291 AiChatMessageDO message = new AiChatMessageDO().setConversationId(conversationId).setReplyId(replyId) 307 AiChatMessageDO message = new AiChatMessageDO().setConversationId(conversationId).setReplyId(replyId)
292 .setModel(model.getModel()).setModelId(model.getId()).setUserId(userId).setRoleId(roleId) 308 .setModel(model.getModel()).setModelId(model.getId()).setUserId(userId).setRoleId(roleId)
293 .setType(messageType.getValue()).setContent(content).setUseContext(useContext) 309 .setType(messageType.getValue()).setContent(content).setUseContext(useContext)
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiChatRoleServiceImpl.java
@@ -39,11 +39,15 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { @@ -39,11 +39,15 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
39 39
40 @Resource 40 @Resource
41 private AiKnowledgeService knowledgeService; 41 private AiKnowledgeService knowledgeService;
  42 + @Resource
  43 + private AiToolService toolService;
42 44
43 @Override 45 @Override
44 public Long createChatRole(AiChatRoleSaveReqVO createReqVO) { 46 public Long createChatRole(AiChatRoleSaveReqVO createReqVO) {
45 // 校验文档 47 // 校验文档
46 validateDocuments(createReqVO.getKnowledgeIds()); 48 validateDocuments(createReqVO.getKnowledgeIds());
  49 + // 校验工具
  50 + validateTools(createReqVO.getToolIds());
47 51
48 // 保存角色 52 // 保存角色
49 AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class); 53 AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class);
@@ -55,6 +59,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { @@ -55,6 +59,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
55 public Long createChatRoleMy(AiChatRoleSaveMyReqVO createReqVO, Long userId) { 59 public Long createChatRoleMy(AiChatRoleSaveMyReqVO createReqVO, Long userId) {
56 // 校验文档 60 // 校验文档
57 validateDocuments(createReqVO.getKnowledgeIds()); 61 validateDocuments(createReqVO.getKnowledgeIds());
  62 + // 校验工具
  63 + validateTools(createReqVO.getToolIds());
58 64
59 // 保存角色 65 // 保存角色
60 AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class).setUserId(userId) 66 AiChatRoleDO chatRole = BeanUtils.toBean(createReqVO, AiChatRoleDO.class).setUserId(userId)
@@ -69,6 +75,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { @@ -69,6 +75,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
69 validateChatRoleExists(updateReqVO.getId()); 75 validateChatRoleExists(updateReqVO.getId());
70 // 校验文档 76 // 校验文档
71 validateDocuments(updateReqVO.getKnowledgeIds()); 77 validateDocuments(updateReqVO.getKnowledgeIds());
  78 + // 校验工具
  79 + validateTools(updateReqVO.getToolIds());
72 80
73 // 更新角色 81 // 更新角色
74 AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class); 82 AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class);
@@ -84,6 +92,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { @@ -84,6 +92,8 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
84 } 92 }
85 // 校验文档 93 // 校验文档
86 validateDocuments(updateReqVO.getKnowledgeIds()); 94 validateDocuments(updateReqVO.getKnowledgeIds());
  95 + // 校验工具
  96 + validateTools(updateReqVO.getToolIds());
87 97
88 // 更新 98 // 更新
89 AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class); 99 AiChatRoleDO updateObj = BeanUtils.toBean(updateReqVO, AiChatRoleDO.class);
@@ -103,6 +113,19 @@ public class AiChatRoleServiceImpl implements AiChatRoleService { @@ -103,6 +113,19 @@ public class AiChatRoleServiceImpl implements AiChatRoleService {
103 knowledgeIds.forEach(knowledgeService::validateKnowledgeExists); 113 knowledgeIds.forEach(knowledgeService::validateKnowledgeExists);
104 } 114 }
105 115
  116 + /**
  117 + * 校验工具是否存在
  118 + *
  119 + * @param toolIds 工具编号列表
  120 + */
  121 + private void validateTools(List<Long> toolIds) {
  122 + if (CollUtil.isEmpty(toolIds)) {
  123 + return;
  124 + }
  125 + // 遍历校验每个工具是否存在
  126 + toolIds.forEach(toolService::validateToolExists);
  127 + }
  128 +
106 @Override 129 @Override
107 public void deleteChatRole(Long id) { 130 public void deleteChatRole(Long id) {
108 // 校验存在 131 // 校验存在
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiToolService.java
@@ -6,6 +6,9 @@ import cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool.AiToolSaveReqVO @@ -6,6 +6,9 @@ import cn.iocoder.yudao.module.ai.controller.admin.model.vo.tool.AiToolSaveReqVO
6 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO; 6 import cn.iocoder.yudao.module.ai.dal.dataobject.model.AiToolDO;
7 import jakarta.validation.Valid; 7 import jakarta.validation.Valid;
8 8
  9 +import java.util.Collection;
  10 +import java.util.List;
  11 +
9 /** 12 /**
10 * AI 工具 Service 接口 13 * AI 工具 Service 接口
11 * 14 *
@@ -14,7 +17,7 @@ import jakarta.validation.Valid; @@ -14,7 +17,7 @@ import jakarta.validation.Valid;
14 public interface AiToolService { 17 public interface AiToolService {
15 18
16 /** 19 /**
17 - * 创建AI 工具 20 + * 创建工具
18 * 21 *
19 * @param createReqVO 创建信息 22 * @param createReqVO 创建信息
20 * @return 编号 23 * @return 编号
@@ -22,33 +25,56 @@ public interface AiToolService { @@ -22,33 +25,56 @@ public interface AiToolService {
22 Long createTool(@Valid AiToolSaveReqVO createReqVO); 25 Long createTool(@Valid AiToolSaveReqVO createReqVO);
23 26
24 /** 27 /**
25 - * 更新AI 工具 28 + * 更新工具
26 * 29 *
27 * @param updateReqVO 更新信息 30 * @param updateReqVO 更新信息
28 */ 31 */
29 void updateTool(@Valid AiToolSaveReqVO updateReqVO); 32 void updateTool(@Valid AiToolSaveReqVO updateReqVO);
30 33
31 /** 34 /**
32 - * 删除AI 工具 35 + * 删除工具
33 * 36 *
34 * @param id 编号 37 * @param id 编号
35 */ 38 */
36 void deleteTool(Long id); 39 void deleteTool(Long id);
37 40
38 /** 41 /**
39 - * 获得AI 工具 42 + * 校验工具是否存在
40 * 43 *
41 * @param id 编号 44 * @param id 编号
42 - * @return AI 工具 45 + */
  46 + void validateToolExists(Long id);
  47 +
  48 + /**
  49 + * 获得工具
  50 + *
  51 + * @param id 编号
  52 + * @return 工具
43 */ 53 */
44 AiToolDO getTool(Long id); 54 AiToolDO getTool(Long id);
45 55
46 /** 56 /**
47 - * 获得AI 工具分页 57 + * 获得工具列表
  58 + *
  59 + * @param ids 编号列表
  60 + * @return 工具列表
  61 + */
  62 + List<AiToolDO> getToolList(Collection<Long> ids);
  63 +
  64 + /**
  65 + * 获得工具分页
48 * 66 *
49 * @param pageReqVO 分页查询 67 * @param pageReqVO 分页查询
50 - * @return AI 工具分页 68 + * @return 工具分页
51 */ 69 */
52 PageResult<AiToolDO> getToolPage(AiToolPageReqVO pageReqVO); 70 PageResult<AiToolDO> getToolPage(AiToolPageReqVO pageReqVO);
53 71
  72 + /**
  73 + * 获得工具列表
  74 + *
  75 + * @param status 状态
  76 + * @return 工具列表
  77 + */
  78 + List<AiToolDO> getToolListByStatus(Integer status);
  79 +
54 } 80 }
55 \ No newline at end of file 81 \ No newline at end of file
yudao-module-ai/yudao-module-ai-biz/src/main/java/cn/iocoder/yudao/module/ai/service/model/AiToolServiceImpl.java
@@ -12,6 +12,9 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException; @@ -12,6 +12,9 @@ import org.springframework.beans.factory.NoSuchBeanDefinitionException;
12 import org.springframework.stereotype.Service; 12 import org.springframework.stereotype.Service;
13 import org.springframework.validation.annotation.Validated; 13 import org.springframework.validation.annotation.Validated;
14 14
  15 +import java.util.Collection;
  16 +import java.util.List;
  17 +
15 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 18 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
16 import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.TOOL_NAME_NOT_EXISTS; 19 import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.TOOL_NAME_NOT_EXISTS;
17 import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.TOOL_NOT_EXISTS; 20 import static cn.iocoder.yudao.module.ai.enums.ErrorCodeConstants.TOOL_NOT_EXISTS;
@@ -59,7 +62,8 @@ public class AiToolServiceImpl implements AiToolService { @@ -59,7 +62,8 @@ public class AiToolServiceImpl implements AiToolService {
59 toolMapper.deleteById(id); 62 toolMapper.deleteById(id);
60 } 63 }
61 64
62 - private void validateToolExists(Long id) { 65 + @Override
  66 + public void validateToolExists(Long id) {
63 if (toolMapper.selectById(id) == null) { 67 if (toolMapper.selectById(id) == null) {
64 throw exception(TOOL_NOT_EXISTS); 68 throw exception(TOOL_NOT_EXISTS);
65 } 69 }
@@ -79,8 +83,18 @@ public class AiToolServiceImpl implements AiToolService { @@ -79,8 +83,18 @@ public class AiToolServiceImpl implements AiToolService {
79 } 83 }
80 84
81 @Override 85 @Override
  86 + public List<AiToolDO> getToolList(Collection<Long> ids) {
  87 + return toolMapper.selectBatchIds(ids);
  88 + }
  89 +
  90 + @Override
82 public PageResult<AiToolDO> getToolPage(AiToolPageReqVO pageReqVO) { 91 public PageResult<AiToolDO> getToolPage(AiToolPageReqVO pageReqVO) {
83 return toolMapper.selectPage(pageReqVO); 92 return toolMapper.selectPage(pageReqVO);
84 } 93 }
85 94
  95 + @Override
  96 + public List<AiToolDO> getToolListByStatus(Integer status) {
  97 + return toolMapper.selectListByStatus(status);
  98 + }
  99 +
86 } 100 }
87 \ No newline at end of file 101 \ No newline at end of file