diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java index a4ad0863..c09aa141 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/controller/AgentController.java @@ -44,6 +44,7 @@ import xiaozhi.modules.agent.entity.AgentEntity; import xiaozhi.modules.agent.entity.AgentTemplateEntity; import xiaozhi.modules.agent.service.AgentChatAudioService; 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.AgentTemplateService; @@ -64,6 +65,7 @@ public class AgentController { private final AgentChatHistoryService agentChatHistoryService; private final AgentChatAudioService agentChatAudioService; private final AgentPluginMappingService agentPluginMappingService; + private final AgentContextProviderService agentContextProviderService; private final RedisUtils redisUtils; @GetMapping("/list") @@ -135,6 +137,8 @@ public class AgentController { agentChatHistoryService.deleteByAgentId(id, true, true); // 删除关联的插件 agentPluginMappingService.deleteByAgentId(id); + // 删除关联的上下文源配置 + agentContextProviderService.deleteByAgentId(id); // 再删除智能体 agentService.deleteById(id); return new Result<>(); diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentContextProviderDao.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentContextProviderDao.java new file mode 100644 index 00000000..d46ad3ab --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/dao/AgentContextProviderDao.java @@ -0,0 +1,9 @@ +package xiaozhi.modules.agent.dao; + +import org.apache.ibatis.annotations.Mapper; +import xiaozhi.common.dao.BaseDao; +import xiaozhi.modules.agent.entity.AgentContextProviderEntity; + +@Mapper +public interface AgentContextProviderDao extends BaseDao { +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java index 0e3d9bc3..ebb29fbd 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/AgentUpdateDTO.java @@ -69,6 +69,9 @@ public class AgentUpdateDTO implements Serializable { @Schema(description = "排序", example = "1", nullable = true) private Integer sort; + @Schema(description = "上下文源配置", nullable = true) + private List contextProviders; + @Data @Schema(description = "插件函数信息") public static class FunctionInfo implements Serializable { diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/ContextProviderDTO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/ContextProviderDTO.java new file mode 100644 index 00000000..0b8edfd8 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/dto/ContextProviderDTO.java @@ -0,0 +1,19 @@ +package xiaozhi.modules.agent.dto; + +import java.io.Serializable; +import java.util.Map; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; + +@Data +@Schema(description = "上下文源配置DTO") +public class ContextProviderDTO implements Serializable { + private static final long serialVersionUID = 1L; + + @Schema(description = "URL地址") + private String url; + + @Schema(description = "请求头") + private Map headers; +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentContextProviderEntity.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentContextProviderEntity.java new file mode 100644 index 00000000..937556ef --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/entity/AgentContextProviderEntity.java @@ -0,0 +1,43 @@ +package xiaozhi.modules.agent.entity; + +import java.util.Date; +import java.util.List; + +import com.baomidou.mybatisplus.annotation.IdType; +import com.baomidou.mybatisplus.annotation.TableField; +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableName; +import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; + +import io.swagger.v3.oas.annotations.media.Schema; +import lombok.Data; +import xiaozhi.modules.agent.dto.ContextProviderDTO; + +@Data +@TableName(value = "ai_agent_context_provider", autoResultMap = true) +@Schema(description = "智能体上下文源配置") +public class AgentContextProviderEntity { + + @TableId(type = IdType.ASSIGN_UUID) + @Schema(description = "主键") + private String id; + + @Schema(description = "智能体ID") + private String agentId; + + @Schema(description = "上下文源配置") + @TableField(typeHandler = JacksonTypeHandler.class) + private List contextProviders; + + @Schema(description = "创建者") + private Long creator; + + @Schema(description = "创建时间") + private Date createdAt; + + @Schema(description = "更新者") + private Long updater; + + @Schema(description = "更新时间") + private Date updatedAt; +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentContextProviderService.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentContextProviderService.java new file mode 100644 index 00000000..da759971 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/AgentContextProviderService.java @@ -0,0 +1,25 @@ +package xiaozhi.modules.agent.service; + +import xiaozhi.common.service.BaseService; +import xiaozhi.modules.agent.entity.AgentContextProviderEntity; + +public interface AgentContextProviderService extends BaseService { + /** + * 根据智能体ID获取上下文源配置 + * @param agentId 智能体ID + * @return 上下文源配置实体 + */ + AgentContextProviderEntity getByAgentId(String agentId); + + /** + * 保存或更新上下文源配置 + * @param entity 实体 + */ + void saveOrUpdateByAgentId(AgentContextProviderEntity entity); + + /** + * 根据智能体ID删除上下文源配置 + * @param agentId 智能体ID + */ + void deleteByAgentId(String agentId); +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentContextProviderServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentContextProviderServiceImpl.java new file mode 100644 index 00000000..b68ab8c9 --- /dev/null +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentContextProviderServiceImpl.java @@ -0,0 +1,35 @@ +package xiaozhi.modules.agent.service.impl; + +import org.springframework.stereotype.Service; + +import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; + +import xiaozhi.common.service.impl.BaseServiceImpl; +import xiaozhi.modules.agent.dao.AgentContextProviderDao; +import xiaozhi.modules.agent.entity.AgentContextProviderEntity; +import xiaozhi.modules.agent.service.AgentContextProviderService; + +@Service +public class AgentContextProviderServiceImpl extends BaseServiceImpl implements AgentContextProviderService { + + @Override + public AgentContextProviderEntity getByAgentId(String agentId) { + return baseDao.selectOne(new QueryWrapper().eq("agent_id", agentId)); + } + + @Override + public void saveOrUpdateByAgentId(AgentContextProviderEntity entity) { + AgentContextProviderEntity exist = getByAgentId(entity.getAgentId()); + if (exist != null) { + entity.setId(exist.getId()); + updateById(entity); + } else { + insert(entity); + } + } + + @Override + public void deleteByAgentId(String agentId) { + baseDao.delete(new QueryWrapper().eq("agent_id", agentId)); + } +} diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java index cb550b3e..0adf0873 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/service/impl/AgentServiceImpl.java @@ -32,10 +32,12 @@ import xiaozhi.modules.agent.dao.AgentDao; import xiaozhi.modules.agent.dto.AgentCreateDTO; import xiaozhi.modules.agent.dto.AgentDTO; 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.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.AgentTemplateService; @@ -62,6 +64,7 @@ public class AgentServiceImpl extends BaseServiceImpl imp private final AgentChatHistoryService agentChatHistoryService; private final AgentTemplateService agentTemplateService; private final ModelProviderService modelProviderService; + private final AgentContextProviderService agentContextProviderService; @Override public PageData adminAgentList(Map params) { @@ -85,6 +88,13 @@ public class AgentServiceImpl extends BaseServiceImpl imp agent.setChatHistoryConf(Constant.ChatHistoryConfEnum.RECORD_TEXT_AUDIO.getCode()); } } + + // 查询上下文源配置 + AgentContextProviderEntity contextProviderEntity = agentContextProviderService.getByAgentId(id); + if (contextProviderEntity != null) { + agent.setContextProviders(contextProviderEntity.getContextProviders()); + } + // 无需额外查询插件列表,已通过SQL查询出来 return agent; } @@ -331,6 +341,14 @@ public class AgentServiceImpl extends BaseServiceImpl imp agentChatHistoryService.deleteByAgentId(existingEntity.getId(), true, false); } + // 更新上下文源配置 + if (dto.getContextProviders() != null) { + AgentContextProviderEntity contextEntity = new AgentContextProviderEntity(); + contextEntity.setAgentId(agentId); + contextEntity.setContextProviders(dto.getContextProviders()); + agentContextProviderService.saveOrUpdateByAgentId(contextEntity); + } + boolean b = validateLLMIntentParams(dto.getLlmModelId(), dto.getIntentModelId()); if (!b) { throw new RenException(ErrorCode.LLM_INTENT_PARAMS_MISMATCH); diff --git a/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentInfoVO.java b/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentInfoVO.java index d56c8bb4..3da8b71c 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentInfoVO.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/agent/vo/AgentInfoVO.java @@ -5,6 +5,7 @@ import com.baomidou.mybatisplus.extension.handlers.JacksonTypeHandler; import io.swagger.v3.oas.annotations.media.Schema; import lombok.Data; import lombok.EqualsAndHashCode; +import xiaozhi.modules.agent.dto.ContextProviderDTO; import xiaozhi.modules.agent.entity.AgentEntity; import xiaozhi.modules.agent.entity.AgentPluginMapping; @@ -21,4 +22,7 @@ public class AgentInfoVO extends AgentEntity @Schema(description = "插件列表Id") @TableField(typeHandler = JacksonTypeHandler.class) private List functions; + + @Schema(description = "上下文源配置") + private List contextProviders; } diff --git a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java index 3ab3d977..7ddb4b82 100644 --- a/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java +++ b/main/manager-api/src/main/java/xiaozhi/modules/config/service/impl/ConfigServiceImpl.java @@ -20,10 +20,12 @@ import xiaozhi.common.redis.RedisUtils; import xiaozhi.common.utils.ConvertUtils; import xiaozhi.common.utils.JsonUtils; import xiaozhi.modules.agent.dao.AgentVoicePrintDao; +import xiaozhi.modules.agent.entity.AgentContextProviderEntity; import xiaozhi.modules.agent.entity.AgentEntity; import xiaozhi.modules.agent.entity.AgentPluginMapping; import xiaozhi.modules.agent.entity.AgentTemplateEntity; import xiaozhi.modules.agent.entity.AgentVoicePrintEntity; +import xiaozhi.modules.agent.service.AgentContextProviderService; import xiaozhi.modules.agent.service.AgentMcpAccessPointService; import xiaozhi.modules.agent.service.AgentPluginMappingService; import xiaozhi.modules.agent.service.AgentService; @@ -53,6 +55,7 @@ public class ConfigServiceImpl implements ConfigService { private final TimbreService timbreService; private final AgentPluginMappingService agentPluginMappingService; private final AgentMcpAccessPointService agentMcpAccessPointService; + private final AgentContextProviderService agentContextProviderService; private final VoiceCloneService cloneVoiceService; private final AgentVoicePrintDao agentVoicePrintDao; @@ -178,6 +181,13 @@ public class ConfigServiceImpl implements ConfigService { mcpEndpoint = mcpEndpoint.replace("/mcp/", "/call/"); result.put("mcp_endpoint", mcpEndpoint); } + + // 获取上下文源配置 + AgentContextProviderEntity contextProviderEntity = agentContextProviderService.getByAgentId(agent.getId()); + if (contextProviderEntity != null && contextProviderEntity.getContextProviders() != null && !contextProviderEntity.getContextProviders().isEmpty()) { + result.put("context_providers", contextProviderEntity.getContextProviders()); + } + // 获取声纹信息 buildVoiceprintConfig(agent.getId(), result); diff --git a/main/manager-api/src/main/resources/db/changelog/202512041515.sql b/main/manager-api/src/main/resources/db/changelog/202512041515.sql new file mode 100644 index 00000000..5e26b99f --- /dev/null +++ b/main/manager-api/src/main/resources/db/changelog/202512041515.sql @@ -0,0 +1,14 @@ +-- liquibase formatted sql + +-- changeset xiaozhi:202512041515 +CREATE TABLE ai_agent_context_provider ( + id VARCHAR(32) NOT NULL COMMENT '主键', + agent_id VARCHAR(32) NOT NULL COMMENT '智能体ID', + context_providers JSON COMMENT '上下文源配置', + creator BIGINT COMMENT '创建者', + created_at DATETIME COMMENT '创建时间', + updater BIGINT COMMENT '更新者', + updated_at DATETIME COMMENT '更新时间', + PRIMARY KEY (id), + INDEX idx_agent_id (agent_id) +) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='智能体上下文源配置表'; diff --git a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml index 3c14eb7f..e0eb949b 100755 --- a/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml +++ b/main/manager-api/src/main/resources/db/changelog/db.changelog-master.yaml @@ -423,3 +423,10 @@ databaseChangeLog: - sqlFile: encoding: utf8 path: classpath:db/changelog/202511131023.sql + - changeSet: + id: 202512041515 + author: cgd + changes: + - sqlFile: + encoding: utf8 + path: classpath:db/changelog/202512041515.sql diff --git a/main/xiaozhi-server/core/connection.py b/main/xiaozhi-server/core/connection.py index 31bfa0c6..6b34e32f 100644 --- a/main/xiaozhi-server/core/connection.py +++ b/main/xiaozhi-server/core/connection.py @@ -162,7 +162,7 @@ class ConnectionHandler: self.conn_from_mqtt_gateway = False # 初始化提示词管理器 - self.prompt_manager = PromptManager(config, self.logger) + self.prompt_manager = PromptManager(self.config, self.logger) async def handle_connection(self, ws): try: @@ -630,6 +630,8 @@ class ConnectionHandler: self.chat_history_conf = int(private_config["chat_history_conf"]) if private_config.get("mcp_endpoint", None) is not None: self.config["mcp_endpoint"] = private_config["mcp_endpoint"] + if private_config.get("context_providers", None) is not None: + self.config["context_providers"] = private_config["context_providers"] # 使用 run_in_executor 在线程池中执行 initialize_modules,避免阻塞主循环 try: diff --git a/main/xiaozhi-server/core/utils/prompt_manager.py b/main/xiaozhi-server/core/utils/prompt_manager.py index 4ec952ae..96fbf624 100644 --- a/main/xiaozhi-server/core/utils/prompt_manager.py +++ b/main/xiaozhi-server/core/utils/prompt_manager.py @@ -191,7 +191,10 @@ class PromptManager: # 获取配置的上下文数据 if hasattr(conn, "device_id") and conn.device_id: - self.context_data = self.context_provider.fetch_all(conn.device_id) + if self.base_prompt_template and "dynamic_context" in self.base_prompt_template: + self.context_data = self.context_provider.fetch_all(conn.device_id) + else: + self.context_data = "" self.logger.bind(tag=TAG).debug(f"上下文信息更新完成")