package com.ard.agent.service; import com.alibaba.cloud.ai.graph.RunnableConfig; import com.alibaba.cloud.ai.graph.agent.ReactAgent; import com.alibaba.cloud.ai.graph.checkpoint.savers.MemorySaver; import com.alibaba.cloud.ai.graph.exception.GraphRunnerException; import com.ard.agent.tool.KnowledgeTools; import com.ard.agent.tool.MonitorTools; import com.ard.agent.tool.SystemTools; import com.ard.common.security.utils.SecurityUtils; import jakarta.annotation.Resource; import lombok.extern.slf4j.Slf4j; import org.springframework.ai.chat.client.ChatClient; import org.springframework.ai.chat.client.advisor.MessageChatMemoryAdvisor; import org.springframework.ai.chat.messages.AssistantMessage; import org.springframework.ai.chat.messages.UserMessage; import org.springframework.ai.chat.model.ChatModel; import org.springframework.ai.chat.model.ChatResponse; import org.springframework.ai.chat.prompt.Prompt; import org.springframework.ai.content.Content; import org.springframework.ai.support.ToolCallbacks; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Service; import reactor.core.publisher.Flux; @Slf4j @Service public class AIChatService { @Resource private ChatClient chatClient; @Resource @Qualifier("ollamaChatModel") private ChatModel chatModel; @Resource private SystemTools systemTools; // 注入工具类 @Resource private MonitorTools monitorTools; // 注入工具类 @Resource private KnowledgeTools knowledgeTools; @Resource private ReactAgent cameraAgent; // 注入配置好的 Agent private static final String SYSTEM_PROMPT = """ 你是摄像头管理助手。请严格遵守以下规则: 1. **工具优先原则**:当用户问题涉及摄像机的实时状态、修改操作、查询具体设备信息时, 必须调用对应的工具(getCameraDetail/searchCameras/updateCameraInfo), 绝对不要使用自己的记忆或上下文中的静态文本来回答。 2. **知识库使用场景**:只有当用户询问操作指南、故障排查手册、产品说明等静态知识时, 才使用知识库中的内容。 3. **冲突处理**:如果知识库中提到了某类操作,但用户要求执行具体操作, 必须以工具调用的结果为准。 ========== 输出格式 ========== 使用 Markdown 格式输出: - ## 标题 - - 列表项 - **加粗** 强调 - 表格用于数据展示 """; /** * 流式对话 */ public Flux streamChat(String userMessage) { Long userId = SecurityUtils.getUserId(); return chatClient.prompt() .system(SYSTEM_PROMPT) .user(userMessage) .advisors(advisor -> advisor.param("chat_memory_conversation_id", userId)) .tools(systemTools,monitorTools, knowledgeTools) .stream() .content(); } /** * 对话服务入口 */ public String chat(String userMessage) throws GraphRunnerException { Long userId = SecurityUtils.getUserId(); // 1. 为每个用户创建唯一的 threadId RunnableConfig config = RunnableConfig.builder() .threadId(userId.toString()) // 比如从 SecurityUtils.getUserId() 获取 .build(); // 3. 调用 Agent 的 call 方法并执行 AssistantMessage response = cameraAgent.call(userMessage,config); // 4. 从响应中提取文本内容 return response.getText(); } private static final String SYSTEM_PROMPT1 = """ 你是智能管理助手,拥有以下能力: ## 可用工具 ### 摄像头管理 - getCameraDetail: 查询摄像机详情 - searchCameras: 搜索摄像机 - updateCameraInfo: 修改摄像机信息 ### 系统管理 - searchUsers: 搜索用户 - searchDepts: 搜索部门 - searchRoles: 搜索角色 - getUserRoles: 查询用户角色 ### 知识库 - searchKnowledgeBase: 查询知识文档 ## 原则 1. 根据问题自动选择工具 2. 数据必须来自工具调用 3. 用 Markdown 格式回复 """; /** * 流式聊天 */ public Flux streamChat1(String userMessage) { Long userId = SecurityUtils.getUserId(); RunnableConfig config = RunnableConfig.builder() .threadId(userId.toString()) .build(); ReactAgent agent = ReactAgent.builder() .name("UnifiedAgent") .model(chatModel) .instruction(SYSTEM_PROMPT1) .tools(ToolCallbacks.from(monitorTools, systemTools, knowledgeTools)) .saver(new MemorySaver()) .build(); try { return agent.streamMessages(userMessage, config) .filter(msg -> msg instanceof AssistantMessage) .map(Content::getText) .doOnError(error -> log.error("Agent执行出错: {}", error.getMessage())); } catch (GraphRunnerException e) { throw new RuntimeException(e); } } }