mirror of
https://github.com/xinnan-tech/xiaozhi-esp32-server.git
synced 2026-07-22 15:13:55 +08:00
Add agent configuration history
This commit is contained in:
+6
-3
@@ -127,7 +127,7 @@ public class AgentController {
|
||||
}
|
||||
AgentUpdateDTO agentUpdateDTO = new AgentUpdateDTO();
|
||||
agentUpdateDTO.setSummaryMemory(dto.getSummaryMemory());
|
||||
agentService.updateAgentById(device.getAgentId(), agentUpdateDTO);
|
||||
agentService.updateAgentById(device.getAgentId(), agentUpdateDTO, false);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
@@ -332,8 +332,11 @@ public class AgentController {
|
||||
public Result<Void> saveAgentTags(@PathVariable String id, @RequestBody Map<String, Object> params) {
|
||||
List<String> tagIds = (List<String>) params.get("tagIds");
|
||||
List<String> tagNames = (List<String>) params.get("tagNames");
|
||||
agentTagService.saveAgentTags(id, tagIds, tagNames);
|
||||
AgentUpdateDTO dto = new AgentUpdateDTO();
|
||||
dto.setTagIds(tagIds);
|
||||
dto.setTagNames(tagNames);
|
||||
agentService.updateAgentById(id, dto);
|
||||
return new Result<Void>().ok(null);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+66
@@ -0,0 +1,66 @@
|
||||
package xiaozhi.modules.agent.controller;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import org.apache.shiro.authz.annotation.RequiresPermissions;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PathVariable;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import lombok.AllArgsConstructor;
|
||||
import xiaozhi.common.exception.RenException;
|
||||
import xiaozhi.common.page.PageData;
|
||||
import xiaozhi.common.user.UserDetail;
|
||||
import xiaozhi.common.utils.Result;
|
||||
import xiaozhi.modules.agent.service.AgentService;
|
||||
import xiaozhi.modules.agent.service.AgentSnapshotService;
|
||||
import xiaozhi.modules.agent.vo.AgentSnapshotVO;
|
||||
import xiaozhi.modules.security.user.SecurityUser;
|
||||
|
||||
@Tag(name = "智能体快照")
|
||||
@AllArgsConstructor
|
||||
@RestController
|
||||
@RequestMapping("/agent/{agentId}/snapshots")
|
||||
public class AgentSnapshotController {
|
||||
private final AgentSnapshotService agentSnapshotService;
|
||||
private final AgentService agentService;
|
||||
|
||||
@GetMapping
|
||||
@Operation(summary = "获取智能体快照列表")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<PageData<AgentSnapshotVO>> page(
|
||||
@PathVariable String agentId,
|
||||
@RequestParam Map<String, Object> params) {
|
||||
checkPermission(agentId);
|
||||
return new Result<PageData<AgentSnapshotVO>>().ok(agentSnapshotService.page(agentId, params));
|
||||
}
|
||||
|
||||
@GetMapping("/{snapshotId}")
|
||||
@Operation(summary = "获取智能体快照详情")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<AgentSnapshotVO> getSnapshot(@PathVariable String agentId, @PathVariable String snapshotId) {
|
||||
checkPermission(agentId);
|
||||
return new Result<AgentSnapshotVO>().ok(agentSnapshotService.getSnapshot(agentId, snapshotId));
|
||||
}
|
||||
|
||||
@PostMapping("/{snapshotId}/restore")
|
||||
@Operation(summary = "恢复智能体快照")
|
||||
@RequiresPermissions("sys:role:normal")
|
||||
public Result<Void> restore(@PathVariable String agentId, @PathVariable String snapshotId) {
|
||||
checkPermission(agentId);
|
||||
agentSnapshotService.restoreSnapshot(agentId, snapshotId);
|
||||
return new Result<>();
|
||||
}
|
||||
|
||||
private void checkPermission(String agentId) {
|
||||
UserDetail user = SecurityUser.getUser();
|
||||
if (user == null || !agentService.checkAgentPermission(agentId, user.getId())) {
|
||||
throw new RenException("没有权限访问该智能体快照");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package xiaozhi.modules.agent.dao;
|
||||
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
import org.apache.ibatis.annotations.Param;
|
||||
|
||||
import xiaozhi.common.dao.BaseDao;
|
||||
import xiaozhi.modules.agent.entity.AgentSnapshotEntity;
|
||||
|
||||
@Mapper
|
||||
public interface AgentSnapshotDao extends BaseDao<AgentSnapshotEntity> {
|
||||
Integer selectMaxVersionNo(@Param("agentId") String agentId);
|
||||
|
||||
AgentSnapshotEntity selectNextSnapshot(@Param("agentId") String agentId, @Param("versionNo") Integer versionNo);
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package xiaozhi.modules.agent.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "智能体快照数据")
|
||||
public class AgentSnapshotDataDTO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String agentCode;
|
||||
private String agentName;
|
||||
private String asrModelId;
|
||||
private String vadModelId;
|
||||
private String llmModelId;
|
||||
private String slmModelId;
|
||||
private String vllmModelId;
|
||||
private String ttsModelId;
|
||||
private String ttsVoiceId;
|
||||
private String ttsLanguage;
|
||||
private Integer ttsVolume;
|
||||
private Integer ttsRate;
|
||||
private Integer ttsPitch;
|
||||
private String memModelId;
|
||||
private String intentModelId;
|
||||
private Integer chatHistoryConf;
|
||||
private String systemPrompt;
|
||||
private String summaryMemory;
|
||||
private String langCode;
|
||||
private String language;
|
||||
private Integer sort;
|
||||
private List<AgentUpdateDTO.FunctionInfo> functions;
|
||||
private List<ContextProviderDTO> contextProviders;
|
||||
private List<String> correctWordFileIds;
|
||||
private List<String> tagNames;
|
||||
private List<AgentSnapshotTagDTO> tags;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package xiaozhi.modules.agent.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@Schema(description = "智能体快照标签")
|
||||
public class AgentSnapshotTagDTO implements Serializable {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
private String id;
|
||||
private String tagName;
|
||||
private Integer sort;
|
||||
}
|
||||
@@ -4,9 +4,12 @@ import java.io.Serializable;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import xiaozhi.common.utils.JsonUtils;
|
||||
|
||||
/**
|
||||
* 智能体更新DTO
|
||||
@@ -91,15 +94,50 @@ public class AgentUpdateDTO implements Serializable {
|
||||
@Schema(description = "替换词文件ID列表", nullable = true)
|
||||
private List<String> correctWordFileIds;
|
||||
|
||||
@Schema(description = "标签名称列表", nullable = true)
|
||||
private List<String> tagNames;
|
||||
|
||||
@Schema(description = "标签ID列表", nullable = true)
|
||||
private List<String> tagIds;
|
||||
|
||||
@Data
|
||||
@Schema(description = "插件函数信息")
|
||||
public static class FunctionInfo implements Serializable {
|
||||
private static final TypeReference<HashMap<String, Object>> PARAM_INFO_TYPE = new TypeReference<>() {
|
||||
};
|
||||
|
||||
@Schema(description = "插件ID", example = "plugin_01")
|
||||
private String pluginId;
|
||||
|
||||
@Schema(description = "函数参数信息", nullable = true)
|
||||
private HashMap<String, Object> paramInfo;
|
||||
private HashMap<String, Object> paramInfo = new HashMap<>();
|
||||
|
||||
public void setParamInfo(Object paramInfo) {
|
||||
this.paramInfo = normalizeParamInfo(paramInfo);
|
||||
}
|
||||
|
||||
private static HashMap<String, Object> normalizeParamInfo(Object paramInfo) {
|
||||
if (paramInfo == null) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
if (paramInfo instanceof String value) {
|
||||
if (value.trim().isEmpty()) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return JsonUtils.parseObject(value, PARAM_INFO_TYPE);
|
||||
}
|
||||
if (paramInfo instanceof Map<?, ?> value) {
|
||||
HashMap<String, Object> normalized = new HashMap<>();
|
||||
value.forEach((key, val) -> {
|
||||
if (key != null) {
|
||||
normalized.put(String.valueOf(key), val);
|
||||
}
|
||||
});
|
||||
return normalized;
|
||||
}
|
||||
return JsonUtils.parseObject(JsonUtils.toJsonString(paramInfo), PARAM_INFO_TYPE);
|
||||
}
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package xiaozhi.modules.agent.entity;
|
||||
|
||||
import java.util.Date;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
@TableName("ai_agent_snapshot")
|
||||
@Schema(description = "智能体配置快照")
|
||||
public class AgentSnapshotEntity {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_UUID)
|
||||
@Schema(description = "快照ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "智能体ID")
|
||||
private String agentId;
|
||||
|
||||
@Schema(description = "所属用户ID")
|
||||
private Long userId;
|
||||
|
||||
@Schema(description = "版本号")
|
||||
private Integer versionNo;
|
||||
|
||||
@Schema(description = "快照数据JSON")
|
||||
private String snapshotData;
|
||||
|
||||
@Schema(description = "变更字段JSON")
|
||||
private String changedFields;
|
||||
|
||||
@Schema(description = "快照来源")
|
||||
private String source;
|
||||
|
||||
@Schema(description = "创建者")
|
||||
private Long creator;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private Date createdAt;
|
||||
}
|
||||
@@ -93,6 +93,15 @@ public interface AgentService extends BaseService<AgentEntity> {
|
||||
*/
|
||||
void updateAgentById(String agentId, AgentUpdateDTO dto);
|
||||
|
||||
/**
|
||||
* 更新智能体
|
||||
*
|
||||
* @param agentId 智能体ID
|
||||
* @param dto 更新智能体所需的信息
|
||||
* @param createSnapshot 是否创建配置快照
|
||||
*/
|
||||
void updateAgentById(String agentId, AgentUpdateDTO dto, boolean createSnapshot);
|
||||
|
||||
/**
|
||||
* 创建智能体
|
||||
*
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
package xiaozhi.modules.agent.service;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import xiaozhi.common.page.PageData;
|
||||
import xiaozhi.common.service.BaseService;
|
||||
import xiaozhi.modules.agent.dto.AgentUpdateDTO;
|
||||
import xiaozhi.modules.agent.entity.AgentSnapshotEntity;
|
||||
import xiaozhi.modules.agent.vo.AgentSnapshotVO;
|
||||
|
||||
public interface AgentSnapshotService extends BaseService<AgentSnapshotEntity> {
|
||||
void createSnapshot(String agentId, String source, AgentUpdateDTO pendingUpdate);
|
||||
|
||||
PageData<AgentSnapshotVO> page(String agentId, Map<String, Object> params);
|
||||
|
||||
AgentSnapshotVO getSnapshot(String agentId, String snapshotId);
|
||||
|
||||
void restoreSnapshot(String agentId, String snapshotId);
|
||||
}
|
||||
+2
-2
@@ -118,7 +118,7 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService {
|
||||
{
|
||||
setSummaryMemory(summaryDTO.getSummary());
|
||||
}
|
||||
});
|
||||
}, false);
|
||||
log.info("成功保存会话 {} 的聊天记录总结到智能体 {}", sessionId, agentId);
|
||||
} else {
|
||||
log.info("生成总结失败: {}", summaryDTO.getErrorMessage());
|
||||
@@ -518,4 +518,4 @@ public class AgentChatSummaryServiceImpl implements AgentChatSummaryService {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+41
-23
@@ -43,9 +43,10 @@ import xiaozhi.modules.agent.entity.AgentTagEntity;
|
||||
import xiaozhi.modules.agent.entity.AgentTemplateEntity;
|
||||
import xiaozhi.modules.agent.service.AgentChatHistoryService;
|
||||
import xiaozhi.modules.agent.service.AgentContextProviderService;
|
||||
import xiaozhi.modules.agent.service.AgentPluginMappingService;
|
||||
import xiaozhi.modules.agent.service.AgentService;
|
||||
import xiaozhi.modules.agent.service.AgentTagService;
|
||||
import xiaozhi.modules.agent.service.AgentPluginMappingService;
|
||||
import xiaozhi.modules.agent.service.AgentService;
|
||||
import xiaozhi.modules.agent.service.AgentSnapshotService;
|
||||
import xiaozhi.modules.agent.service.AgentTagService;
|
||||
import xiaozhi.modules.agent.service.AgentTemplateService;
|
||||
import xiaozhi.modules.agent.vo.AgentInfoVO;
|
||||
import xiaozhi.modules.correctword.service.CorrectWordFileService;
|
||||
@@ -73,9 +74,10 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
private final AgentChatHistoryService agentChatHistoryService;
|
||||
private final AgentTemplateService agentTemplateService;
|
||||
private final ModelProviderService modelProviderService;
|
||||
private final AgentContextProviderService agentContextProviderService;
|
||||
private final AgentTagService agentTagService;
|
||||
private final CorrectWordFileService correctWordFileService;
|
||||
private final AgentContextProviderService agentContextProviderService;
|
||||
private final AgentTagService agentTagService;
|
||||
private final CorrectWordFileService correctWordFileService;
|
||||
private final AgentSnapshotService agentSnapshotService;
|
||||
|
||||
@Override
|
||||
public PageData<AgentEntity> adminAgentList(Map<String, Object> params) {
|
||||
@@ -272,17 +274,28 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
return userId.equals(agent.getUserId());
|
||||
}
|
||||
|
||||
// 根据id更新智能体信息
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateAgentById(String agentId, AgentUpdateDTO dto) {
|
||||
// 先查询现有实体
|
||||
AgentEntity existingEntity = this.getAgentById(agentId);
|
||||
if (existingEntity == null) {
|
||||
throw new RenException(ErrorCode.AGENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
// 只更新提供的非空字段
|
||||
// 根据id更新智能体信息
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateAgentById(String agentId, AgentUpdateDTO dto) {
|
||||
updateAgentById(agentId, dto, true);
|
||||
}
|
||||
|
||||
// 根据id更新智能体信息
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateAgentById(String agentId, AgentUpdateDTO dto, boolean createSnapshot) {
|
||||
// 先查询现有实体
|
||||
AgentEntity existingEntity = this.getAgentById(agentId);
|
||||
if (existingEntity == null) {
|
||||
throw new RenException(ErrorCode.AGENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
if (createSnapshot) {
|
||||
agentSnapshotService.createSnapshot(agentId, "config", dto);
|
||||
}
|
||||
|
||||
// 只更新提供的非空字段
|
||||
if (dto.getAgentName() != null) {
|
||||
existingEntity.setAgentName(dto.getAgentName());
|
||||
}
|
||||
@@ -426,11 +439,16 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
}
|
||||
|
||||
// 更新替换词文件关联
|
||||
if (dto.getCorrectWordFileIds() != null) {
|
||||
correctWordFileService.saveAgentCorrectWords(agentId, dto.getCorrectWordFileIds());
|
||||
}
|
||||
|
||||
boolean b = validateLLMIntentParams(dto.getLlmModelId(), dto.getIntentModelId());
|
||||
if (dto.getCorrectWordFileIds() != null) {
|
||||
correctWordFileService.saveAgentCorrectWords(agentId, dto.getCorrectWordFileIds());
|
||||
}
|
||||
|
||||
// 更新智能体标签
|
||||
if (dto.getTagNames() != null || dto.getTagIds() != null) {
|
||||
agentTagService.saveAgentTags(agentId, dto.getTagIds(), dto.getTagNames());
|
||||
}
|
||||
|
||||
boolean b = validateLLMIntentParams(dto.getLlmModelId(), dto.getIntentModelId());
|
||||
if (!b) {
|
||||
throw new RenException(ErrorCode.LLM_INTENT_PARAMS_MISMATCH);
|
||||
}
|
||||
@@ -576,4 +594,4 @@ public class AgentServiceImpl extends BaseServiceImpl<AgentDao, AgentEntity> imp
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+475
@@ -0,0 +1,475 @@
|
||||
package xiaozhi.modules.agent.service.impl;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
import org.springframework.dao.DuplicateKeyException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
|
||||
import com.baomidou.mybatisplus.core.metadata.IPage;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import xiaozhi.common.constant.Constant;
|
||||
import xiaozhi.common.exception.ErrorCode;
|
||||
import xiaozhi.common.exception.RenException;
|
||||
import xiaozhi.common.page.PageData;
|
||||
import xiaozhi.common.service.impl.BaseServiceImpl;
|
||||
import xiaozhi.common.utils.JsonUtils;
|
||||
import xiaozhi.modules.agent.dao.AgentDao;
|
||||
import xiaozhi.modules.agent.dao.AgentSnapshotDao;
|
||||
import xiaozhi.modules.agent.dao.AgentTagDao;
|
||||
import xiaozhi.modules.agent.dao.AgentTagRelationDao;
|
||||
import xiaozhi.modules.agent.dto.AgentSnapshotDataDTO;
|
||||
import xiaozhi.modules.agent.dto.AgentSnapshotTagDTO;
|
||||
import xiaozhi.modules.agent.dto.AgentUpdateDTO;
|
||||
import xiaozhi.modules.agent.entity.AgentContextProviderEntity;
|
||||
import xiaozhi.modules.agent.entity.AgentEntity;
|
||||
import xiaozhi.modules.agent.entity.AgentPluginMapping;
|
||||
import xiaozhi.modules.agent.entity.AgentSnapshotEntity;
|
||||
import xiaozhi.modules.agent.entity.AgentTagEntity;
|
||||
import xiaozhi.modules.agent.entity.AgentTagRelationEntity;
|
||||
import xiaozhi.modules.agent.service.AgentChatHistoryService;
|
||||
import xiaozhi.modules.agent.service.AgentContextProviderService;
|
||||
import xiaozhi.modules.agent.service.AgentPluginMappingService;
|
||||
import xiaozhi.modules.agent.service.AgentSnapshotService;
|
||||
import xiaozhi.modules.agent.service.AgentTagService;
|
||||
import xiaozhi.modules.agent.vo.AgentInfoVO;
|
||||
import xiaozhi.modules.agent.vo.AgentSnapshotVO;
|
||||
import xiaozhi.modules.correctword.service.CorrectWordFileService;
|
||||
import xiaozhi.modules.model.entity.ModelConfigEntity;
|
||||
import xiaozhi.modules.model.service.ModelConfigService;
|
||||
import xiaozhi.modules.security.user.SecurityUser;
|
||||
|
||||
@Service
|
||||
@AllArgsConstructor
|
||||
public class AgentSnapshotServiceImpl extends BaseServiceImpl<AgentSnapshotDao, AgentSnapshotEntity>
|
||||
implements AgentSnapshotService {
|
||||
private static final TypeReference<List<String>> STRING_LIST_TYPE = new TypeReference<>() {
|
||||
};
|
||||
private static final TypeReference<HashMap<String, Object>> PARAM_INFO_TYPE = new TypeReference<>() {
|
||||
};
|
||||
|
||||
private final AgentSnapshotDao agentSnapshotDao;
|
||||
private final AgentDao agentDao;
|
||||
private final AgentTagDao agentTagDao;
|
||||
private final AgentTagRelationDao agentTagRelationDao;
|
||||
private final AgentPluginMappingService agentPluginMappingService;
|
||||
private final AgentContextProviderService agentContextProviderService;
|
||||
private final AgentTagService agentTagService;
|
||||
private final AgentChatHistoryService agentChatHistoryService;
|
||||
private final ModelConfigService modelConfigService;
|
||||
private final CorrectWordFileService correctWordFileService;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void createSnapshot(String agentId, String source, AgentUpdateDTO pendingUpdate) {
|
||||
AgentSnapshotDataDTO snapshotData = buildSnapshotData(agentId);
|
||||
List<String> changedFields = getChangedFields(snapshotData, pendingUpdate);
|
||||
if (pendingUpdate != null && changedFields.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
AgentInfoVO agent = agentDao.selectAgentInfoById(agentId);
|
||||
if (agent == null) {
|
||||
throw new RenException(ErrorCode.AGENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
AgentSnapshotEntity entity = new AgentSnapshotEntity();
|
||||
entity.setAgentId(agentId);
|
||||
entity.setUserId(agent.getUserId());
|
||||
entity.setSnapshotData(JsonUtils.toJsonString(snapshotData));
|
||||
entity.setChangedFields(JsonUtils.toJsonString(changedFields));
|
||||
entity.setSource(StringUtils.defaultIfBlank(source, "config"));
|
||||
entity.setCreator(SecurityUser.getUserId());
|
||||
entity.setCreatedAt(new Date());
|
||||
insertSnapshotWithRetry(entity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageData<AgentSnapshotVO> page(String agentId, Map<String, Object> params) {
|
||||
IPage<AgentSnapshotEntity> page = getPage(params, "created_at", false);
|
||||
IPage<AgentSnapshotEntity> result = agentSnapshotDao.selectPage(page,
|
||||
new QueryWrapper<AgentSnapshotEntity>().eq("agent_id", agentId));
|
||||
List<AgentSnapshotVO> list = result.getRecords().stream()
|
||||
.map(entity -> toVO(entity, false))
|
||||
.toList();
|
||||
return new PageData<>(list, result.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public AgentSnapshotVO getSnapshot(String agentId, String snapshotId) {
|
||||
AgentSnapshotEntity entity = getSnapshotEntity(agentId, snapshotId);
|
||||
return toVO(entity, true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void restoreSnapshot(String agentId, String snapshotId) {
|
||||
AgentSnapshotEntity snapshot = getSnapshotEntity(agentId, snapshotId);
|
||||
AgentSnapshotDataDTO data = JsonUtils.parseObject(snapshot.getSnapshotData(), AgentSnapshotDataDTO.class);
|
||||
if (data == null) {
|
||||
throw new RenException("快照数据为空,无法恢复");
|
||||
}
|
||||
|
||||
createSnapshot(agentId, "restore", null);
|
||||
|
||||
AgentEntity agent = agentDao.selectById(agentId);
|
||||
if (agent == null) {
|
||||
throw new RenException(ErrorCode.AGENT_NOT_FOUND);
|
||||
}
|
||||
applyAgentFields(agent, data);
|
||||
validateRestoreParams(agent);
|
||||
applyMemoryPolicy(agent);
|
||||
agent.setUpdater(SecurityUser.getUserId());
|
||||
agent.setUpdatedAt(new Date());
|
||||
agentDao.updateById(agent);
|
||||
|
||||
restoreFunctions(agentId, data.getFunctions());
|
||||
restoreContextProviders(agentId, data.getContextProviders());
|
||||
correctWordFileService.saveAgentCorrectWords(agentId, nullToEmpty(data.getCorrectWordFileIds()));
|
||||
restoreTags(agentId, data);
|
||||
}
|
||||
|
||||
private void insertSnapshotWithRetry(AgentSnapshotEntity entity) {
|
||||
for (int attempt = 0; attempt < 3; attempt++) {
|
||||
Integer maxVersionNo = agentSnapshotDao.selectMaxVersionNo(entity.getAgentId());
|
||||
entity.setVersionNo((maxVersionNo == null ? 0 : maxVersionNo) + 1);
|
||||
try {
|
||||
agentSnapshotDao.insert(entity);
|
||||
return;
|
||||
} catch (DuplicateKeyException e) {
|
||||
if (attempt == 2) {
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private AgentSnapshotEntity getSnapshotEntity(String agentId, String snapshotId) {
|
||||
AgentSnapshotEntity entity = selectById(snapshotId);
|
||||
if (entity == null || !Objects.equals(agentId, entity.getAgentId())) {
|
||||
throw new RenException("快照不存在");
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
|
||||
private AgentSnapshotDataDTO buildSnapshotData(String agentId) {
|
||||
AgentInfoVO agent = agentDao.selectAgentInfoById(agentId);
|
||||
if (agent == null) {
|
||||
throw new RenException(ErrorCode.AGENT_NOT_FOUND);
|
||||
}
|
||||
|
||||
AgentSnapshotDataDTO data = new AgentSnapshotDataDTO();
|
||||
data.setAgentCode(agent.getAgentCode());
|
||||
data.setAgentName(agent.getAgentName());
|
||||
data.setAsrModelId(agent.getAsrModelId());
|
||||
data.setVadModelId(agent.getVadModelId());
|
||||
data.setLlmModelId(agent.getLlmModelId());
|
||||
data.setSlmModelId(agent.getSlmModelId());
|
||||
data.setVllmModelId(agent.getVllmModelId());
|
||||
data.setTtsModelId(agent.getTtsModelId());
|
||||
data.setTtsVoiceId(agent.getTtsVoiceId());
|
||||
data.setTtsLanguage(agent.getTtsLanguage());
|
||||
data.setTtsVolume(agent.getTtsVolume());
|
||||
data.setTtsRate(agent.getTtsRate());
|
||||
data.setTtsPitch(agent.getTtsPitch());
|
||||
data.setMemModelId(agent.getMemModelId());
|
||||
data.setIntentModelId(agent.getIntentModelId());
|
||||
data.setChatHistoryConf(agent.getChatHistoryConf());
|
||||
data.setSystemPrompt(agent.getSystemPrompt());
|
||||
data.setSummaryMemory(agent.getSummaryMemory());
|
||||
data.setLangCode(agent.getLangCode());
|
||||
data.setLanguage(agent.getLanguage());
|
||||
data.setSort(agent.getSort());
|
||||
data.setFunctions(toFunctionInfo(agent.getFunctions()));
|
||||
data.setContextProviders(getContextProviders(agentId));
|
||||
data.setCorrectWordFileIds(nullToEmpty(correctWordFileService.getAgentCorrectWordFileIds(agentId)));
|
||||
List<AgentSnapshotTagDTO> tags = getSnapshotTags(agentId);
|
||||
data.setTags(tags);
|
||||
data.setTagNames(tags.stream().map(AgentSnapshotTagDTO::getTagName).toList());
|
||||
return data;
|
||||
}
|
||||
|
||||
private List<AgentSnapshotTagDTO> getSnapshotTags(String agentId) {
|
||||
List<AgentTagEntity> tags = agentTagDao.selectByAgentId(agentId);
|
||||
if (tags == null || tags.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
List<AgentSnapshotTagDTO> snapshotTags = new ArrayList<>();
|
||||
for (int i = 0; i < tags.size(); i++) {
|
||||
AgentTagEntity tag = tags.get(i);
|
||||
AgentSnapshotTagDTO snapshotTag = new AgentSnapshotTagDTO();
|
||||
snapshotTag.setId(tag.getId());
|
||||
snapshotTag.setTagName(tag.getTagName());
|
||||
snapshotTag.setSort(i);
|
||||
snapshotTags.add(snapshotTag);
|
||||
}
|
||||
return snapshotTags;
|
||||
}
|
||||
|
||||
private List<AgentUpdateDTO.FunctionInfo> toFunctionInfo(List<AgentPluginMapping> mappings) {
|
||||
if (mappings == null || mappings.isEmpty()) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return mappings.stream().map(mapping -> {
|
||||
AgentUpdateDTO.FunctionInfo info = new AgentUpdateDTO.FunctionInfo();
|
||||
info.setPluginId(mapping.getPluginId());
|
||||
info.setParamInfo(parseParamInfo(mapping.getParamInfo()));
|
||||
return info;
|
||||
}).toList();
|
||||
}
|
||||
|
||||
private HashMap<String, Object> parseParamInfo(String paramInfo) {
|
||||
if (StringUtils.isBlank(paramInfo)) {
|
||||
return new HashMap<>();
|
||||
}
|
||||
return JsonUtils.parseObject(paramInfo, PARAM_INFO_TYPE);
|
||||
}
|
||||
|
||||
private List<xiaozhi.modules.agent.dto.ContextProviderDTO> getContextProviders(String agentId) {
|
||||
AgentContextProviderEntity contextEntity = agentContextProviderService.getByAgentId(agentId);
|
||||
if (contextEntity == null || contextEntity.getContextProviders() == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return contextEntity.getContextProviders();
|
||||
}
|
||||
|
||||
private List<String> getChangedFields(AgentSnapshotDataDTO current, AgentUpdateDTO pendingUpdate) {
|
||||
if (pendingUpdate == null) {
|
||||
return List.of("restore");
|
||||
}
|
||||
|
||||
List<String> fields = new ArrayList<>();
|
||||
compare(fields, "agentCode", current.getAgentCode(), pendingUpdate.getAgentCode());
|
||||
compare(fields, "agentName", current.getAgentName(), pendingUpdate.getAgentName());
|
||||
compare(fields, "asrModelId", current.getAsrModelId(), pendingUpdate.getAsrModelId());
|
||||
compare(fields, "vadModelId", current.getVadModelId(), pendingUpdate.getVadModelId());
|
||||
compare(fields, "llmModelId", current.getLlmModelId(), pendingUpdate.getLlmModelId());
|
||||
compare(fields, "slmModelId", current.getSlmModelId(), pendingUpdate.getSlmModelId());
|
||||
compare(fields, "vllmModelId", current.getVllmModelId(), pendingUpdate.getVllmModelId());
|
||||
compare(fields, "ttsModelId", current.getTtsModelId(), pendingUpdate.getTtsModelId());
|
||||
compare(fields, "ttsVoiceId", current.getTtsVoiceId(), pendingUpdate.getTtsVoiceId());
|
||||
compare(fields, "ttsLanguage", current.getTtsLanguage(), pendingUpdate.getTtsLanguage());
|
||||
compare(fields, "ttsVolume", current.getTtsVolume(), pendingUpdate.getTtsVolume());
|
||||
compare(fields, "ttsRate", current.getTtsRate(), pendingUpdate.getTtsRate());
|
||||
compare(fields, "ttsPitch", current.getTtsPitch(), pendingUpdate.getTtsPitch());
|
||||
compare(fields, "memModelId", current.getMemModelId(), pendingUpdate.getMemModelId());
|
||||
compare(fields, "intentModelId", current.getIntentModelId(), pendingUpdate.getIntentModelId());
|
||||
compare(fields, "chatHistoryConf", current.getChatHistoryConf(), pendingUpdate.getChatHistoryConf());
|
||||
compare(fields, "systemPrompt", current.getSystemPrompt(), pendingUpdate.getSystemPrompt());
|
||||
compare(fields, "summaryMemory", current.getSummaryMemory(), pendingUpdate.getSummaryMemory());
|
||||
compare(fields, "langCode", current.getLangCode(), pendingUpdate.getLangCode());
|
||||
compare(fields, "language", current.getLanguage(), pendingUpdate.getLanguage());
|
||||
compare(fields, "sort", current.getSort(), pendingUpdate.getSort());
|
||||
compare(fields, "functions", current.getFunctions(), pendingUpdate.getFunctions());
|
||||
compare(fields, "contextProviders", current.getContextProviders(), pendingUpdate.getContextProviders());
|
||||
compare(fields, "correctWordFileIds", current.getCorrectWordFileIds(), pendingUpdate.getCorrectWordFileIds());
|
||||
compare(fields, "tagNames", current.getTagNames(), pendingUpdate.getTagNames());
|
||||
compare(fields, "tagIds", current.getTags().stream().map(AgentSnapshotTagDTO::getId).toList(),
|
||||
pendingUpdate.getTagIds());
|
||||
return fields;
|
||||
}
|
||||
|
||||
private <T> void compare(List<String> fields, String name, T current, T next) {
|
||||
if (next != null && !Objects.equals(current, next)) {
|
||||
fields.add(name);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyAgentFields(AgentEntity agent, AgentSnapshotDataDTO data) {
|
||||
agent.setAgentCode(data.getAgentCode());
|
||||
agent.setAgentName(data.getAgentName());
|
||||
agent.setAsrModelId(data.getAsrModelId());
|
||||
agent.setVadModelId(data.getVadModelId());
|
||||
agent.setLlmModelId(data.getLlmModelId());
|
||||
agent.setSlmModelId(data.getSlmModelId());
|
||||
agent.setVllmModelId(data.getVllmModelId());
|
||||
agent.setTtsModelId(data.getTtsModelId());
|
||||
agent.setTtsVoiceId(data.getTtsVoiceId());
|
||||
agent.setTtsLanguage(data.getTtsLanguage());
|
||||
agent.setTtsVolume(data.getTtsVolume());
|
||||
agent.setTtsRate(data.getTtsRate());
|
||||
agent.setTtsPitch(data.getTtsPitch());
|
||||
agent.setMemModelId(data.getMemModelId());
|
||||
agent.setIntentModelId(data.getIntentModelId());
|
||||
agent.setChatHistoryConf(data.getChatHistoryConf());
|
||||
agent.setSystemPrompt(data.getSystemPrompt());
|
||||
agent.setSummaryMemory(data.getSummaryMemory());
|
||||
agent.setLangCode(data.getLangCode());
|
||||
agent.setLanguage(data.getLanguage());
|
||||
agent.setSort(data.getSort());
|
||||
}
|
||||
|
||||
private void validateRestoreParams(AgentEntity agent) {
|
||||
if (agent == null || StringUtils.isBlank(agent.getLlmModelId())) {
|
||||
return;
|
||||
}
|
||||
|
||||
ModelConfigEntity llmModelData = modelConfigService.selectById(agent.getLlmModelId());
|
||||
if (llmModelData == null || llmModelData.getConfigJson() == null) {
|
||||
throw new RenException(ErrorCode.LLM_INTENT_PARAMS_MISMATCH);
|
||||
}
|
||||
Object typeValue = llmModelData.getConfigJson().get("type");
|
||||
String type = typeValue == null ? "" : typeValue.toString();
|
||||
if ("openai".equals(type) || "ollama".equals(type)) {
|
||||
return;
|
||||
}
|
||||
if ("Intent_function_call".equals(agent.getIntentModelId())) {
|
||||
throw new RenException(ErrorCode.LLM_INTENT_PARAMS_MISMATCH);
|
||||
}
|
||||
}
|
||||
|
||||
private void applyMemoryPolicy(AgentEntity agent) {
|
||||
if (agent == null || StringUtils.isBlank(agent.getMemModelId())) {
|
||||
return;
|
||||
}
|
||||
if (Constant.MEMORY_NO_MEM.equals(agent.getMemModelId())) {
|
||||
agentChatHistoryService.deleteByAgentId(agent.getId(), true, true);
|
||||
agent.setSummaryMemory("");
|
||||
} else if (Constant.MEMORY_MEM_REPORT_ONLY.equals(agent.getMemModelId())) {
|
||||
agent.setSummaryMemory("");
|
||||
}
|
||||
}
|
||||
|
||||
private void restoreFunctions(String agentId, List<AgentUpdateDTO.FunctionInfo> functions) {
|
||||
agentPluginMappingService.deleteByAgentId(agentId);
|
||||
if (functions == null || functions.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
List<AgentPluginMapping> mappings = functions.stream().map(info -> {
|
||||
AgentPluginMapping mapping = new AgentPluginMapping();
|
||||
mapping.setAgentId(agentId);
|
||||
mapping.setPluginId(info.getPluginId());
|
||||
mapping.setParamInfo(JsonUtils.toJsonString(info.getParamInfo()));
|
||||
return mapping;
|
||||
}).toList();
|
||||
agentPluginMappingService.saveBatch(mappings);
|
||||
}
|
||||
|
||||
private void restoreContextProviders(String agentId,
|
||||
List<xiaozhi.modules.agent.dto.ContextProviderDTO> contextProviders) {
|
||||
AgentContextProviderEntity entity = new AgentContextProviderEntity();
|
||||
entity.setAgentId(agentId);
|
||||
entity.setContextProviders(nullToEmpty(contextProviders));
|
||||
entity.setUpdater(SecurityUser.getUserId());
|
||||
entity.setUpdatedAt(new Date());
|
||||
agentContextProviderService.saveOrUpdateByAgentId(entity);
|
||||
}
|
||||
|
||||
private void restoreTags(String agentId, AgentSnapshotDataDTO data) {
|
||||
List<AgentSnapshotTagDTO> tags = data.getTags();
|
||||
if (tags == null || tags.isEmpty()) {
|
||||
agentTagService.saveAgentTags(agentId, null, nullToEmpty(data.getTagNames()));
|
||||
return;
|
||||
}
|
||||
|
||||
agentTagRelationDao.deleteByAgentId(agentId);
|
||||
List<AgentTagRelationEntity> relations = new ArrayList<>();
|
||||
Date now = new Date();
|
||||
for (int i = 0; i < tags.size(); i++) {
|
||||
AgentSnapshotTagDTO snapshotTag = tags.get(i);
|
||||
String tagId = restoreTag(snapshotTag, now);
|
||||
if (StringUtils.isBlank(tagId)) {
|
||||
continue;
|
||||
}
|
||||
AgentTagRelationEntity relation = new AgentTagRelationEntity();
|
||||
relation.setId(UUID.randomUUID().toString().replace("-", ""));
|
||||
relation.setAgentId(agentId);
|
||||
relation.setTagId(tagId);
|
||||
relation.setSort(i);
|
||||
relation.setCreator(SecurityUser.getUserId());
|
||||
relation.setCreatedAt(now);
|
||||
relation.setUpdater(SecurityUser.getUserId());
|
||||
relation.setUpdatedAt(now);
|
||||
relations.add(relation);
|
||||
}
|
||||
if (!relations.isEmpty()) {
|
||||
agentTagRelationDao.batchInsertRelation(relations);
|
||||
}
|
||||
}
|
||||
|
||||
private String restoreTag(AgentSnapshotTagDTO snapshotTag, Date now) {
|
||||
if (snapshotTag == null || StringUtils.isBlank(snapshotTag.getTagName())) {
|
||||
return null;
|
||||
}
|
||||
|
||||
AgentTagEntity tag = null;
|
||||
if (StringUtils.isNotBlank(snapshotTag.getId())) {
|
||||
tag = agentTagDao.selectById(snapshotTag.getId());
|
||||
}
|
||||
if (tag == null) {
|
||||
tag = agentTagDao.selectOne(new QueryWrapper<AgentTagEntity>()
|
||||
.eq("tag_name", snapshotTag.getTagName())
|
||||
.last("LIMIT 1"));
|
||||
}
|
||||
if (tag != null) {
|
||||
if (Objects.equals(tag.getDeleted(), 1)) {
|
||||
tag.setDeleted(0);
|
||||
tag.setUpdater(SecurityUser.getUserId());
|
||||
tag.setUpdatedAt(now);
|
||||
agentTagDao.updateById(tag);
|
||||
}
|
||||
return tag.getId();
|
||||
}
|
||||
|
||||
AgentTagEntity newTag = new AgentTagEntity();
|
||||
if (StringUtils.isNotBlank(snapshotTag.getId())) {
|
||||
newTag.setId(snapshotTag.getId());
|
||||
}
|
||||
newTag.setTagName(snapshotTag.getTagName());
|
||||
newTag.setSort(snapshotTag.getSort() == null ? 0 : snapshotTag.getSort());
|
||||
newTag.setDeleted(0);
|
||||
newTag.setCreator(SecurityUser.getUserId());
|
||||
newTag.setCreatedAt(now);
|
||||
newTag.setUpdater(SecurityUser.getUserId());
|
||||
newTag.setUpdatedAt(now);
|
||||
agentTagDao.insert(newTag);
|
||||
return newTag.getId();
|
||||
}
|
||||
|
||||
private AgentSnapshotVO toVO(AgentSnapshotEntity entity, boolean includeData) {
|
||||
AgentSnapshotVO vo = new AgentSnapshotVO();
|
||||
vo.setId(entity.getId());
|
||||
vo.setAgentId(entity.getAgentId());
|
||||
vo.setUserId(entity.getUserId());
|
||||
vo.setVersionNo(entity.getVersionNo());
|
||||
vo.setChangedFields(parseChangedFields(entity.getChangedFields()));
|
||||
vo.setSource(entity.getSource());
|
||||
vo.setCreator(entity.getCreator());
|
||||
vo.setCreatedAt(entity.getCreatedAt());
|
||||
if (includeData) {
|
||||
vo.setSnapshotData(JsonUtils.parseObject(entity.getSnapshotData(), AgentSnapshotDataDTO.class));
|
||||
vo.setAfterSnapshotData(getAfterSnapshotData(entity));
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
private AgentSnapshotDataDTO getAfterSnapshotData(AgentSnapshotEntity entity) {
|
||||
AgentSnapshotEntity nextSnapshot = agentSnapshotDao.selectNextSnapshot(entity.getAgentId(), entity.getVersionNo());
|
||||
if (nextSnapshot != null) {
|
||||
return JsonUtils.parseObject(nextSnapshot.getSnapshotData(), AgentSnapshotDataDTO.class);
|
||||
}
|
||||
return buildSnapshotData(entity.getAgentId());
|
||||
}
|
||||
|
||||
private List<String> parseChangedFields(String changedFields) {
|
||||
if (StringUtils.isBlank(changedFields)) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return JsonUtils.parseObject(changedFields, STRING_LIST_TYPE);
|
||||
}
|
||||
|
||||
private <T> List<T> nullToEmpty(List<T> list) {
|
||||
return list == null ? Collections.emptyList() : list;
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,5 @@
|
||||
package xiaozhi.modules.agent.vo;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
@@ -20,7 +18,6 @@ import java.util.List;
|
||||
public class AgentInfoVO extends AgentEntity
|
||||
{
|
||||
@Schema(description = "插件列表Id")
|
||||
@TableField(typeHandler = JacksonTypeHandler.class)
|
||||
private List<AgentPluginMapping> functions;
|
||||
|
||||
@Schema(description = "上下文源配置")
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
package xiaozhi.modules.agent.vo;
|
||||
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import xiaozhi.modules.agent.dto.AgentSnapshotDataDTO;
|
||||
|
||||
@Data
|
||||
@Schema(description = "智能体配置快照")
|
||||
public class AgentSnapshotVO {
|
||||
private String id;
|
||||
private String agentId;
|
||||
private Long userId;
|
||||
private Integer versionNo;
|
||||
private List<String> changedFields;
|
||||
private String source;
|
||||
private Long creator;
|
||||
private Date createdAt;
|
||||
private AgentSnapshotDataDTO snapshotData;
|
||||
private AgentSnapshotDataDTO afterSnapshotData;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
-- liquibase formatted sql
|
||||
|
||||
-- changeset xiaozhi:202607071530
|
||||
CREATE TABLE IF NOT EXISTS `ai_agent_snapshot` (
|
||||
`id` VARCHAR(32) NOT NULL COMMENT '快照ID',
|
||||
`agent_id` VARCHAR(32) NOT NULL COMMENT '智能体ID',
|
||||
`user_id` BIGINT DEFAULT NULL COMMENT '所属用户ID',
|
||||
`version_no` INT UNSIGNED NOT NULL COMMENT '版本号',
|
||||
`snapshot_data` JSON NOT NULL COMMENT '快照数据',
|
||||
`changed_fields` JSON DEFAULT NULL COMMENT '变更字段',
|
||||
`source` VARCHAR(32) DEFAULT 'config' COMMENT '快照来源',
|
||||
`creator` BIGINT DEFAULT NULL COMMENT '创建者',
|
||||
`created_at` DATETIME DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `uk_agent_version` (`agent_id`, `version_no`),
|
||||
INDEX `idx_agent_created_at` (`agent_id`, `created_at`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='智能体配置快照表';
|
||||
@@ -697,3 +697,10 @@ databaseChangeLog:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202607011405.sql
|
||||
- changeSet:
|
||||
id: 202607071530
|
||||
author: Codex
|
||||
changes:
|
||||
- sqlFile:
|
||||
encoding: utf8
|
||||
path: classpath:db/changelog/202607071530.sql
|
||||
|
||||
@@ -25,9 +25,6 @@
|
||||
<result column="memModelId" property="memModelId"/>
|
||||
<result column="intentModelId" property="intentModelId"/>
|
||||
|
||||
<result column="functions" property="functions"
|
||||
typeHandler="com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler"/>
|
||||
|
||||
<result column="chatHistoryConf" property="chatHistoryConf"/>
|
||||
<result column="systemPrompt" property="systemPrompt"/>
|
||||
<result column="summaryMemory" property="summaryMemory"/>
|
||||
@@ -38,6 +35,10 @@
|
||||
<result column="createdAt" property="createdAt"/>
|
||||
<result column="updater" property="updater"/>
|
||||
<result column="updatedAt" property="updatedAt"/>
|
||||
<collection property="functions"
|
||||
ofType="xiaozhi.modules.agent.entity.AgentPluginMapping"
|
||||
column="{agentId=id}"
|
||||
select="selectAgentFunctionsByAgentId"/>
|
||||
</resultMap>
|
||||
|
||||
<select id="selectAgentInfoById" resultMap="AgentInfoMap">
|
||||
@@ -58,19 +59,6 @@
|
||||
a.tts_pitch AS ttsPitch,
|
||||
a.mem_model_id AS memModelId,
|
||||
a.intent_model_id AS intentModelId,
|
||||
COALESCE(
|
||||
(SELECT JSON_ARRAYAGG(
|
||||
JSON_OBJECT(
|
||||
'id', m.id,
|
||||
'agentId', m.agent_id,
|
||||
'pluginId', m.plugin_id,
|
||||
'paramInfo', m.param_info
|
||||
)
|
||||
)
|
||||
FROM ai_agent_plugin_mapping m
|
||||
WHERE m.agent_id = a.id),
|
||||
JSON_ARRAY()
|
||||
) AS functions,
|
||||
a.chat_history_conf AS chatHistoryConf,
|
||||
a.system_prompt AS systemPrompt,
|
||||
a.summary_memory AS summaryMemory,
|
||||
@@ -84,4 +72,13 @@
|
||||
FROM ai_agent a
|
||||
WHERE a.id = #{agentId}
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
<select id="selectAgentFunctionsByAgentId" resultType="xiaozhi.modules.agent.entity.AgentPluginMapping">
|
||||
SELECT id,
|
||||
agent_id AS agentId,
|
||||
plugin_id AS pluginId,
|
||||
param_info AS paramInfo
|
||||
FROM ai_agent_plugin_mapping
|
||||
WHERE agent_id = #{agentId}
|
||||
</select>
|
||||
</mapper>
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
|
||||
<mapper namespace="xiaozhi.modules.agent.dao.AgentSnapshotDao">
|
||||
|
||||
<select id="selectMaxVersionNo" resultType="java.lang.Integer">
|
||||
SELECT COALESCE(MAX(version_no), 0)
|
||||
FROM ai_agent_snapshot
|
||||
WHERE agent_id = #{agentId}
|
||||
</select>
|
||||
|
||||
<select id="selectNextSnapshot" resultType="xiaozhi.modules.agent.entity.AgentSnapshotEntity">
|
||||
SELECT id,
|
||||
agent_id AS agentId,
|
||||
user_id AS userId,
|
||||
version_no AS versionNo,
|
||||
snapshot_data AS snapshotData,
|
||||
changed_fields AS changedFields,
|
||||
source,
|
||||
creator,
|
||||
created_at AS createdAt
|
||||
FROM ai_agent_snapshot
|
||||
WHERE agent_id = #{agentId}
|
||||
AND version_no > #{versionNo}
|
||||
ORDER BY version_no ASC
|
||||
LIMIT 1
|
||||
</select>
|
||||
|
||||
</mapper>
|
||||
Reference in New Issue
Block a user