liusuyi
2026-05-18 0b8c8d8986a35c3e36db1503125e2dff79d6d10e
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
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<String> 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<String> 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);
        }
    }
}