feat(llm): 添加模型列表和状态更新功能

- 新增模型列表获取接口和相关服务
- 实现模型状态更新逻辑,包括启动和禁用模型
-优化模型数据同步,保持本地与远程模型状态一致
- 重构部分代码,提高可维护性
This commit is contained in:
sunxiqing 2025-03-14 16:24:18 +08:00
parent 216378d20d
commit dfcc93cece
11 changed files with 208 additions and 33 deletions

View File

@ -1,12 +1,20 @@
package cn.iocoder.yudao.module.llm.controller.admin.modelservice;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.module.llm.controller.admin.basemodel.vo.BaseModelSaveReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.conversation.vo.ChatApiReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.conversation.vo.ChatReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.conversation.vo.ChatRespVO;
import cn.iocoder.yudao.module.llm.controller.admin.finetuningtask.vo.FineTuningTaskRespVO;
import cn.iocoder.yudao.module.llm.dal.dataobject.basemodel.BaseModelDO;
import cn.iocoder.yudao.module.llm.dal.mysql.basemodel.BaseModelMapper;
import cn.iocoder.yudao.module.llm.service.basemodel.BaseModelService;
import cn.iocoder.yudao.module.llm.service.basemodel.vo.AListOfPedestalModelsVO;
import cn.iocoder.yudao.module.llm.service.conversation.ConversationService;
import cn.iocoder.yudao.module.llm.service.finetuningtask.FineTuningTaskService;
import cn.iocoder.yudao.module.llm.service.http.ModelService;
import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import org.springframework.context.annotation.Lazy;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
@ -20,6 +28,7 @@ import javax.validation.*;
import javax.servlet.http.*;
import java.util.*;
import java.io.IOException;
import java.util.stream.Collectors;
import cn.iocoder.yudao.framework.common.pojo.PageParam;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
@ -52,6 +61,9 @@ public class ModelServiceController {
@Resource
private ConversationService conversationService;
@Resource
@Lazy
private BaseModelService baseModelService;
@PostMapping("/create")
@Operation(summary = "创建模型服务")
@ -126,6 +138,34 @@ public class ModelServiceController {
return success(pageResult);
}
@GetMapping("/get-all-pedestal-models")
@Operation(summary = "获得模型服务")
public CommonResult<List<BaseModelDO>> getAllPedestalModels() {
LambdaQueryWrapper<BaseModelDO> select = new LambdaQueryWrapper<BaseModelDO>()
.select(BaseModelDO::getId, BaseModelDO::getModelName);
List<BaseModelDO> baseModelDOS = baseModelService.selectList(select);
// List<String> differentModelNames = baseModelDOS.stream()
// .map(BaseModelDO::getModelName)
// .collect(Collectors.toList());
return success(baseModelDOS);
}
@PutMapping("/start")
@Operation(summary = "启动模型")
// @PreAuthorize("@ss.hasPermission('llm:base-model:update')")
public CommonResult<Boolean> start(@Valid @RequestBody ModelServiceSaveReqVO updateReqVO) {
modelServiceService.startTheModel(updateReqVO);
return success(true);
}
@PutMapping("/disable")
@Operation(summary = "禁用模型")
// @PreAuthorize("@ss.hasPermission('llm:base-model:update')")
public CommonResult<Boolean> disable(@Valid @RequestBody ModelServiceSaveReqVO updateReqVO) {
modelServiceService.disableTheModel(updateReqVO);
return success(true);
}
@GetMapping("/export-excel")
@Operation(summary = "导出模型服务 Excel")
// @PreAuthorize("@ss.hasPermission('llm:model-service:export')")

View File

@ -118,6 +118,8 @@ public class LLMBackendProperties {
private String deleteModel;
private String aListOfAvailableModels;
/**
* 知识库向量嵌入
*/

View File

@ -4,6 +4,8 @@ import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.module.llm.controller.admin.basemodel.vo.BaseModelPageReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.basemodel.vo.BaseModelSaveReqVO;
import cn.iocoder.yudao.module.llm.dal.dataobject.basemodel.BaseModelDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.finetuningtask.FineTuningTaskDO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import javax.validation.Valid;
import java.util.List;
@ -76,4 +78,8 @@ public interface BaseModelService {
List<BaseModelDO> getAllModels();
void updetatebyIds(List<BaseModelDO> differentModels);
List<BaseModelDO> selectList(LambdaQueryWrapper<BaseModelDO> select);
List<BaseModelDO> selectBatchIds(List<Long> ids);
}

View File

@ -7,6 +7,7 @@ import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.llm.controller.admin.basemodel.vo.BaseModelPageReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.basemodel.vo.BaseModelSaveReqVO;
import cn.iocoder.yudao.module.llm.dal.dataobject.basemodel.BaseModelDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.finetuningtask.FineTuningTaskDO;
import cn.iocoder.yudao.module.llm.dal.mysql.basemodel.BaseModelMapper;
import cn.iocoder.yudao.module.llm.framework.backend.config.LLMBackendProperties;
import cn.iocoder.yudao.module.llm.service.application.ApplicationService;
@ -199,6 +200,16 @@ public class BaseModelServiceImpl implements BaseModelService {
baseModelMapper.updateBatch(differentModels);
}
@Override
public List<BaseModelDO> selectList(LambdaQueryWrapper<BaseModelDO> select) {
return baseModelMapper.selectList(select);
}
@Override
public List<BaseModelDO> selectBatchIds(List<Long> ids) {
return baseModelMapper.selectBatchIds(ids);
}
/**
* 校验模型使用情况
*

View File

@ -1,15 +1,18 @@
package cn.iocoder.yudao.module.llm.service.basemodel;
import cn.hutool.core.util.ObjectUtil;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.module.llm.controller.admin.basemodel.vo.BaseModelSaveReqVO;
import cn.iocoder.yudao.module.llm.dal.dataobject.basemodel.BaseModelDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.modelservice.ModelServiceDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.servername.ServerNameDO;
import cn.iocoder.yudao.module.llm.dal.mysql.basemodel.BaseModelMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.modelservice.ModelServiceMapper;
import cn.iocoder.yudao.module.llm.dal.mysql.servername.ServerNameMapper;
import cn.iocoder.yudao.module.llm.framework.backend.config.LLMBackendProperties;
import cn.iocoder.yudao.module.llm.handler.AigcCustomDateTimeDeserializer;
import cn.iocoder.yudao.module.llm.service.basemodel.vo.AListOfPedestalModelsVO;
import cn.iocoder.yudao.module.llm.service.basemodel.vo.ModelListRes;
import cn.iocoder.yudao.module.llm.service.basemodel.vo.PedestalModelVo;
import cn.iocoder.yudao.module.llm.service.basemodel.vo.PedestalModelVO;
import cn.iocoder.yudao.module.llm.service.http.FineTuningTaskHttpService;
import cn.iocoder.yudao.module.llm.service.http.TrainHttpService;
import cn.iocoder.yudao.module.llm.service.http.vo.AigcModelDeploySaveReq;
@ -45,6 +48,10 @@ public class BaseModelTaskService {
@Resource
BaseModelService baseModelService;
@Resource
private ModelServiceMapper modelServiceMapper;
@Resource
private BaseModelMapper baseModelMapper;
@Resource
ServerNameMapper serverNameMapper;
@Resource
private FineTuningTaskHttpService fineTuningTaskHttpService;
@ -199,54 +206,108 @@ public class BaseModelTaskService {
List<BaseModelDO> baseModelList = baseModelService.getAllModels();
log.info("获取到 {} 个基础模型", baseModelList.size());
// 调用接口获取远程模型状态
String resStr = HttpUtils.get(llmBackendProperties.getAListOfAvailableModels(), null);
log.info("获取aicg模型列表返回数据内容: {}", resStr);
List<AListOfPedestalModelsVO> aListOfPedestalModelsVOS = JSONArray.parseArray(resStr, AListOfPedestalModelsVO.class);
//获取所有名称
List<String> remoteModelNames = aListOfPedestalModelsVOS.stream()
.map(AListOfPedestalModelsVO::getName)
.collect(Collectors.toCollection(HashSet::new))
.stream()
.collect(Collectors.toList());
//获取数据库所有模型名称
List<String> differentModelNames = baseModelList.stream()
.map(BaseModelDO::getModelName)
.collect(Collectors.toList());
//删除不存在的模型
List<BaseModelDO> differentModels = baseModelList.stream()
.filter(baseModel -> !remoteModelNames.contains(baseModel.getModelName()))
.collect(Collectors.toList());
if (differentModels.size()>0) {
for (BaseModelDO baseModel : differentModels){
baseModel.setDeleted(true);
}
baseModelService.updetatebyIds(differentModels);
}
// 筛选出 remoteModelNames 中不在 differentModels 中的模型名称
List<String> uniqueRemoteModelNames = remoteModelNames.stream()
.filter(remoteModelName -> !differentModelNames.contains(remoteModelName))
.collect(Collectors.toList());
if (uniqueRemoteModelNames.size()>0) {
for (String remoteModelName : uniqueRemoteModelNames) {
BaseModelDO baseModelDO = new BaseModelDO();
baseModelDO.setModelName(remoteModelName);
baseModelMapper.insert(baseModelDO);
}
}
} catch (Exception e) {
log.error("更新基础模型状态时发生异常: {}", e.getMessage(), e);
}
}
// @Scheduled(cron = "0 0/5 * * * ?")
public void refreshTheModelService() {
try {
// 获取所有基础模型列表
List<ModelServiceDO> modelServiceDOS = modelServiceMapper.selectList();
log.info("获取到 {} 模型服务", modelServiceDOS.size());
// 调用接口获取远程模型状态
String resStr = HttpUtils.post(llmBackendProperties.getBaseModelStatus(), null, "");
log.info("获取aicg模型列表返回数据内容: {}", resStr);
JSONArray objects = JSONArray.parseArray(resStr);
String s = JSON.toJSONString(objects);
List<PedestalModelVo> modelListRes = JSONObject.parseArray(s, PedestalModelVo.class);
List<PedestalModelVO> modelListRes = JSONObject.parseArray(s, PedestalModelVO.class);
List<String> remoteModelNames = modelListRes.stream()
.map(PedestalModelVo::getDeploymentName)
.map(PedestalModelVO::getDeploymentName)
.collect(Collectors.toCollection(HashSet::new))
.stream()
.collect(Collectors.toList());
List<BaseModelDO> differentModels = baseModelList.stream()
.filter(baseModel -> !remoteModelNames.contains(baseModel.getModelName())&& baseModel.getIsActive()==1)
List<ModelServiceDO> differentModels = modelServiceDOS.stream()
.filter(baseModel -> !remoteModelNames.contains(baseModel.getBaseModelName()) && baseModel.getStatus() == 2)
.collect(Collectors.toList());
for (BaseModelDO baseModel : differentModels){
baseModel.setIsActive(2);
for (ModelServiceDO baseModel : differentModels){
baseModel.setStatus(1);
}
if (differentModels.size()>0) {
baseModelService.updetatebyIds(differentModels);
modelServiceMapper.updateById(differentModels);
}
for (String name : remoteModelNames) {
// JSONObject jsonObject = (JSONObject) object;
// String string = JSON.toJSONString(jsonObject);
// PedestalModelVo pedestalModelVo = JSON.parseObject(string, PedestalModelVo.class);
List<PedestalModelVo> collect = modelListRes.stream().filter(pedestalModelVo -> pedestalModelVo.getDeploymentName().equals(name) && "running".equals(pedestalModelVo.getStatus())).collect(Collectors.toList());
// PedestalModelVO pedestalModelVo = JSON.parseObject(string, PedestalModelVO.class);
List<PedestalModelVO> collect = modelListRes.stream()
.filter(pedestalModelVO -> pedestalModelVO.getDeploymentName()
.equals(name) && "running"
.equals(pedestalModelVO.getStatus()))
.collect(Collectors.toList());
if (collect.size() > 0) {
PedestalModelVo pedestalModelVo = collect.get(0);
PedestalModelVO pedestalModelVo = collect.get(0);
// 查找本地模型
List<BaseModelDO> localModels = baseModelList.stream()
.filter(baseModel -> pedestalModelVo.getDeploymentName().equals(baseModel.getModelName()))
List<ModelServiceDO> localModels = modelServiceDOS.stream()
.filter(baseModel -> pedestalModelVo.getDeploymentName().equals(baseModel.getBaseModelName()))
.collect(Collectors.toList());
if (localModels != null && localModels.size() > 0) {
BaseModelDO localModel = localModels.get(0);
ModelServiceDO localModel = localModels.get(0);
// 如果状态不是 "running"更新本地状态
if (!"running".equals(pedestalModelVo.getStatus())) {
log.info("更新模型状态,模型名称: {}, 状态: {}", pedestalModelVo.getDeploymentName(), pedestalModelVo.getStatus());
localModel.setIsActive(2);
localModel.setModelId((long) pedestalModelVo.getId());
baseModelService.updetatebyId(localModel);
localModel.setStatus(1);
localModel.setJobId((long) pedestalModelVo.getId());
modelServiceMapper.updateById(localModel);
} else {
String string1 = pedestalModelVo.getHost() + "/v1/chat/completions";
localModel.setIsActive(1);
localModel.setChatUrl(string1);
localModel.setApiUrl(string1);
localModel.setModelId((long) pedestalModelVo.getId());
baseModelService.updetatebyId(localModel);
localModel.setStatus(2);
localModel.setModelUrl(string1);
// localModel.setApiUrl(string1);
localModel.setJobId((long) pedestalModelVo.getId());
modelServiceMapper.updateById(localModel);
log.info("模型 {} 状态为 running无需更新", pedestalModelVo.getDeploymentName());
}
}
@ -262,14 +323,14 @@ public class BaseModelTaskService {
// }
// }
} else {
List<BaseModelDO> localModels = baseModelList.stream()
.filter(baseModel -> name.equals(baseModel.getModelName()))
List<ModelServiceDO> localModels = modelServiceDOS.stream()
.filter(baseModel -> name.equals(baseModel.getBaseModelName()))
.collect(Collectors.toList());
if (localModels != null && localModels.size() > 0) {
BaseModelDO localModel = localModels.get(0);
ModelServiceDO localModel = localModels.get(0);
// 如果状态不是 "running"更新本地状态
localModel.setIsActive(2);
baseModelService.updetatebyId(localModel);
localModel.setStatus(1);
modelServiceMapper.updateById(localModel);
}
}
}

View File

@ -0,0 +1,10 @@
package cn.iocoder.yudao.module.llm.service.basemodel.vo;
import lombok.Data;
@Data
public class AListOfPedestalModelsVO {
public String name;
public String path;
}

View File

@ -89,4 +89,8 @@ public interface ModelServiceService {
Map<Long, String> getModelServiceByTaskId (Long taskId);
List<String> queryCheckpoints(Long id);
void startTheModel(ModelServiceSaveReqVO updateReqVO);
void disableTheModel(ModelServiceSaveReqVO updateReqVO);
}

View File

@ -4,10 +4,12 @@ import cn.hutool.json.JSONUtil;
import cn.iocoder.yudao.framework.common.exception.ErrorCode;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.collection.CollectionUtils;
import cn.iocoder.yudao.framework.common.util.http.HttpUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.module.llm.controller.admin.modelservice.vo.ModelServicePageReqVO;
import cn.iocoder.yudao.module.llm.controller.admin.modelservice.vo.ModelServiceRespVO;
import cn.iocoder.yudao.module.llm.controller.admin.modelservice.vo.ModelServiceSaveReqVO;
import cn.iocoder.yudao.module.llm.dal.dataobject.basemodel.BaseModelDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.finetuningtask.FineTuningTaskDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.modelservice.ModelServiceDO;
import cn.iocoder.yudao.module.llm.dal.dataobject.servername.ServerNameDO;
@ -16,6 +18,7 @@ import cn.iocoder.yudao.module.llm.dal.mysql.modelservice.ModelServiceMapper;
import cn.iocoder.yudao.module.llm.framework.backend.config.LLMBackendProperties;
import cn.iocoder.yudao.module.llm.service.application.ApplicationService;
import cn.iocoder.yudao.module.llm.service.async.AsyncModelServiceService;
import cn.iocoder.yudao.module.llm.service.basemodel.BaseModelService;
import cn.iocoder.yudao.module.llm.service.http.ModelService;
import cn.iocoder.yudao.module.llm.service.http.TrainHttpService;
import cn.iocoder.yudao.module.llm.service.modelassesstaskauto.ModelAssessTaskAutoService;
@ -83,6 +86,9 @@ public class ModelServiceServiceImpl implements ModelServiceService {
@Resource
private TrainHttpService trainHttpService;
@Resource
@Lazy
private BaseModelService baseModelService;
@Override
public Long createModelService (ModelServiceSaveReqVO createReqVO) {
@ -113,6 +119,10 @@ public class ModelServiceServiceImpl implements ModelServiceService {
modelService.setApiUrl(replace);
modelService.setStatus(0);
// BaseModelDO byAigcId = baseModelService.getByAigcId(modelService.getFineTuningTask());
// if (byAigcId != null){
// modelService.setBaseModelName(byAigcId.getModelName());
// }
modelServiceMapper.insert(modelService);
// asyncModelServiceService.createModelService(modelService);
// 返回
@ -311,12 +321,12 @@ public class ModelServiceServiceImpl implements ModelServiceService {
List<Long> ids = pageResult.getList().stream()
.map(ModelServiceDO::getFineTuningTask)
.collect(Collectors.toList());
List<FineTuningTaskDO> fineTuningTaskDOS = fineTuningTaskMapper.selectBatchIds(ids);
Map<Long, FineTuningTaskDO> fineTuningTaskMap = CollectionUtils.convertMap(fineTuningTaskDOS, FineTuningTaskDO::getId);
List<BaseModelDO> fineTuningTaskDOS = baseModelService.selectBatchIds(ids);
Map<Long, BaseModelDO> fineTuningTaskMap = CollectionUtils.convertMap(fineTuningTaskDOS, BaseModelDO::getId);
respVo.getList().forEach(item -> {
FineTuningTaskDO fineTuningTaskDO = fineTuningTaskMap.get(item.getFineTuningTask());
BaseModelDO fineTuningTaskDO = fineTuningTaskMap.get(item.getFineTuningTask());
if (fineTuningTaskDO != null) {
item.setFineTuningTaskName(fineTuningTaskDO.getTaskName());
item.setFineTuningTaskName(fineTuningTaskDO.getModelName());
}
});
}
@ -429,4 +439,31 @@ public class ModelServiceServiceImpl implements ModelServiceService {
return res;
}
@Override
public void startTheModel(ModelServiceSaveReqVO updateReqVO) {
try {
Long fineTuningTask = updateReqVO.getFineTuningTask();
BaseModelDO byAigcId = baseModelService.getByAigcId(fineTuningTask);
Map<String,String> map = new HashMap<>();
map.put("model",byAigcId.getModelName());
String resStr = HttpUtils.post(llmBackendProperties.getDeployModel(), null,JSON.toJSONString(map));
}catch (Exception e){
log.error("启动基础模型状态时发生异常: {}", e.getMessage(), e);
}
}
@Override
public void disableTheModel(ModelServiceSaveReqVO updateReqVO) {
try {
Long fineTuningTask = updateReqVO.getFineTuningTask();
BaseModelDO byAigcId = baseModelService.getByAigcId(fineTuningTask);
String resStr = HttpUtils.post(llmBackendProperties.getDeleteModel()+"?deploy_id="+byAigcId.getModelId(), null, "");
log.info(" unActive:{}", resStr);
// 禁用模型
}catch (Exception e){
log.error("禁用基础模型状态时发生异常: {}", e.getMessage(), e);
}
}
}

View File

@ -334,6 +334,8 @@ llm:
deploy_model: http://36.103.199.248:5123/llm/deploy
# 模型删除
delete_model: http://36.103.199.248:5123/llm/deploy/stop
# 模型列表 get
a_list_of_available_models: http://36.103.199.248:5123/llm/list
#################### 30000: 大模型对话相关API。 ###################
#### 大模型对话

View File

@ -334,6 +334,8 @@ llm:
deploy_model: http://127.0.0.1:5123/llm/deploy
# 模型删除
delete_model: http://127.0.0.1:5123/llm/deploy/stop
# 模型列表 get
a_list_of_available_models: http://127.0.0.1:5123/llm/list
#################### 30000: 大模型对话相关API。 ###################
#### 大模型对话