|
@@ -12,6 +12,7 @@ import com.zsjz.ai.common.context.CaseContextHolder;
|
|
|
import com.zsjz.ai.common.exception.ServerException;
|
|
import com.zsjz.ai.common.exception.ServerException;
|
|
|
import com.zsjz.ai.module.agent.dto.ChatRequestDTO;
|
|
import com.zsjz.ai.module.agent.dto.ChatRequestDTO;
|
|
|
import com.zsjz.ai.module.agent.dto.CreateChatSessionDTO;
|
|
import com.zsjz.ai.module.agent.dto.CreateChatSessionDTO;
|
|
|
|
|
+import com.zsjz.ai.module.agent.dto.GraphRestoreDTO;
|
|
|
import com.zsjz.ai.module.agent.dto.SendMessageDTO;
|
|
import com.zsjz.ai.module.agent.dto.SendMessageDTO;
|
|
|
import com.zsjz.ai.module.agent.entity.AgentChatSession;
|
|
import com.zsjz.ai.module.agent.entity.AgentChatSession;
|
|
|
import com.zsjz.ai.module.agent.entity.AgentMessage;
|
|
import com.zsjz.ai.module.agent.entity.AgentMessage;
|
|
@@ -309,6 +310,28 @@ public class AgentChatServiceImpl extends ServiceImpl<AgentChatSessionMapper, Ag
|
|
|
log.info("切换消息收藏状态成功: {}", messageId);
|
|
log.info("切换消息收藏状态成功: {}", messageId);
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
+ @Override
|
|
|
|
|
+ public Map<String, Object> restoreGraph(GraphRestoreDTO dto) {
|
|
|
|
|
+ if (dto == null || dto.getSessionId() == null) {
|
|
|
|
|
+ throw new ServerException(400, "缺少会话ID");
|
|
|
|
|
+ }
|
|
|
|
|
+ if (dto.getQuery() == null || dto.getQuery().isEmpty()) {
|
|
|
|
|
+ throw new ServerException(400, "缺少关系图谱查询条件");
|
|
|
|
|
+ }
|
|
|
|
|
+ AgentChatSession session = requireSessionInOpenCase(requireSession(dto.getSessionId()));
|
|
|
|
|
+ try {
|
|
|
|
|
+ String input = MAPPER.writeValueAsString(Map.of("query", dto.getQuery()));
|
|
|
|
|
+ Map<String, Object> graph = buildFullGraphPayload(
|
|
|
|
|
+ input, session.getCaseId(), CaseContextHolder.getUserId());
|
|
|
|
|
+ if (graph == null) {
|
|
|
|
|
+ throw new ServerException(400, "关系图谱条件无法复原,请重新查询");
|
|
|
|
|
+ }
|
|
|
|
|
+ return graph;
|
|
|
|
|
+ } catch (JsonProcessingException e) {
|
|
|
|
|
+ throw new ServerException(400, "关系图谱查询条件格式不正确");
|
|
|
|
|
+ }
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
@Override
|
|
@Override
|
|
|
public Flux<ServerSentEvent<String>> stream(ChatRequestDTO req) {
|
|
public Flux<ServerSentEvent<String>> stream(ChatRequestDTO req) {
|
|
|
if (!StringUtils.hasText(req.getMessage())) {
|
|
if (!StringUtils.hasText(req.getMessage())) {
|
|
@@ -497,7 +520,6 @@ public class AgentChatServiceImpl extends ServiceImpl<AgentChatSessionMapper, Ag
|
|
|
Map<String, Object> fullGraph = buildFullGraphPayload(
|
|
Map<String, Object> fullGraph = buildFullGraphPayload(
|
|
|
input == null ? null : input.toString(), graphCaseId, graphUserId);
|
|
input == null ? null : input.toString(), graphCaseId, graphUserId);
|
|
|
if (fullGraph != null) {
|
|
if (fullGraph != null) {
|
|
|
- process.graphData.put(e.getToolCallId(), fullGraph);
|
|
|
|
|
Map<String, Object> graphFrame = new LinkedHashMap<>();
|
|
Map<String, Object> graphFrame = new LinkedHashMap<>();
|
|
|
graphFrame.put("type", "graph_data");
|
|
graphFrame.put("type", "graph_data");
|
|
|
graphFrame.put("toolCallId", e.getToolCallId());
|
|
graphFrame.put("toolCallId", e.getToolCallId());
|
|
@@ -529,7 +551,7 @@ public class AgentChatServiceImpl extends ServiceImpl<AgentChatSessionMapper, Ag
|
|
|
} else if (event instanceof AgentResultEvent e) {
|
|
} else if (event instanceof AgentResultEvent e) {
|
|
|
// AI 回复落库(异步,不阻塞事件流);工具调用事件与思考过程一并持久化
|
|
// AI 回复落库(异步,不阻塞事件流);工具调用事件与思考过程一并持久化
|
|
|
resultPersisted.set(true);
|
|
resultPersisted.set(true);
|
|
|
- String toolEventsJson = buildToolEventsJson(toolInputs, toolResults, toolNames, process.graphData);
|
|
|
|
|
|
|
+ String toolEventsJson = buildToolEventsJson(toolInputs, toolResults, toolNames);
|
|
|
String thinkingJson = buildThinkingMetadata(accumulatedThinking.get().toString());
|
|
String thinkingJson = buildThinkingMetadata(accumulatedThinking.get().toString());
|
|
|
Mono.fromRunnable(() -> persistAssistantMessage(sessionId, e.getResult(), toolEventsJson, thinkingJson))
|
|
Mono.fromRunnable(() -> persistAssistantMessage(sessionId, e.getResult(), toolEventsJson, thinkingJson))
|
|
|
.subscribeOn(Schedulers.boundedElastic())
|
|
.subscribeOn(Schedulers.boundedElastic())
|
|
@@ -543,7 +565,7 @@ public class AgentChatServiceImpl extends ServiceImpl<AgentChatSessionMapper, Ag
|
|
|
// 用户主动中止:若 AgentResultEvent 尚未到达,保存已流式输出的部分内容
|
|
// 用户主动中止:若 AgentResultEvent 尚未到达,保存已流式输出的部分内容
|
|
|
if (!resultPersisted.get()) {
|
|
if (!resultPersisted.get()) {
|
|
|
String partialText = accumulatedText.get().toString().trim();
|
|
String partialText = accumulatedText.get().toString().trim();
|
|
|
- String toolEventsJson = buildToolEventsJson(toolInputs, toolResults, toolNames, process.graphData);
|
|
|
|
|
|
|
+ String toolEventsJson = buildToolEventsJson(toolInputs, toolResults, toolNames);
|
|
|
String thinkingJson = buildThinkingMetadata(accumulatedThinking.get().toString());
|
|
String thinkingJson = buildThinkingMetadata(accumulatedThinking.get().toString());
|
|
|
if (!partialText.isEmpty() || !toolEventsJson.isEmpty()) {
|
|
if (!partialText.isEmpty() || !toolEventsJson.isEmpty()) {
|
|
|
Mono.fromRunnable(() -> persistPartialMessage(sessionId, partialText, toolEventsJson, thinkingJson))
|
|
Mono.fromRunnable(() -> persistPartialMessage(sessionId, partialText, toolEventsJson, thinkingJson))
|
|
@@ -714,7 +736,7 @@ public class AgentChatServiceImpl extends ServiceImpl<AgentChatSessionMapper, Ag
|
|
|
// 避免同轮的时间线/产物在历史里出现两份
|
|
// 避免同轮的时间线/产物在历史里出现两份
|
|
|
boolean processLost = process != null && !process.resultPersisted.get();
|
|
boolean processLost = process != null && !process.resultPersisted.get();
|
|
|
String toolEventsJson = processLost
|
|
String toolEventsJson = processLost
|
|
|
- ? buildToolEventsJson(process.toolInputs, process.toolResults, process.toolNames, process.graphData) : null;
|
|
|
|
|
|
|
+ ? buildToolEventsJson(process.toolInputs, process.toolResults, process.toolNames) : null;
|
|
|
String thinkingJson = processLost
|
|
String thinkingJson = processLost
|
|
|
? buildThinkingMetadata(process.thinking.get().toString()) : null;
|
|
? buildThinkingMetadata(process.thinking.get().toString()) : null;
|
|
|
AgentMessage msg = new AgentMessage();
|
|
AgentMessage msg = new AgentMessage();
|
|
@@ -865,8 +887,7 @@ public class AgentChatServiceImpl extends ServiceImpl<AgentChatSessionMapper, Ag
|
|
|
*/
|
|
*/
|
|
|
private static String buildToolEventsJson(Map<String, StringBuilder> toolInputs,
|
|
private static String buildToolEventsJson(Map<String, StringBuilder> toolInputs,
|
|
|
Map<String, StringBuilder> toolResults,
|
|
Map<String, StringBuilder> toolResults,
|
|
|
- Map<String, String> toolNames,
|
|
|
|
|
- Map<String, Object> graphData) {
|
|
|
|
|
|
|
+ Map<String, String> toolNames) {
|
|
|
if (toolNames.isEmpty()) {
|
|
if (toolNames.isEmpty()) {
|
|
|
return null;
|
|
return null;
|
|
|
}
|
|
}
|
|
@@ -881,11 +902,6 @@ public class AgentChatServiceImpl extends ServiceImpl<AgentChatSessionMapper, Ag
|
|
|
// 兜底再解一层:个别工具的 delta 可能在累积时才成完整字符串字面量
|
|
// 兜底再解一层:个别工具的 delta 可能在累积时才成完整字符串字面量
|
|
|
ev.put("result", result != null ? unwrapJsonString(result.toString()) : "");
|
|
ev.put("result", result != null ? unwrapJsonString(result.toString()) : "");
|
|
|
ev.put("status", "done");
|
|
ev.put("status", "done");
|
|
|
- Object graph = graphData == null ? null : graphData.get(toolCallId);
|
|
|
|
|
- if (graph != null) {
|
|
|
|
|
- // 会话复原用:把本次查询的全量图谱随 tool_events 落库(查询条件已在 input 里)
|
|
|
|
|
- ev.put("graphData", graph);
|
|
|
|
|
- }
|
|
|
|
|
events.add(ev);
|
|
events.add(ev);
|
|
|
}
|
|
}
|
|
|
try {
|
|
try {
|
|
@@ -1017,8 +1033,6 @@ public class AgentChatServiceImpl extends ServiceImpl<AgentChatSessionMapper, Ag
|
|
|
final Map<String, StringBuilder> toolInputs = new ConcurrentHashMap<>();
|
|
final Map<String, StringBuilder> toolInputs = new ConcurrentHashMap<>();
|
|
|
final Map<String, StringBuilder> toolResults = new ConcurrentHashMap<>();
|
|
final Map<String, StringBuilder> toolResults = new ConcurrentHashMap<>();
|
|
|
final Map<String, String> toolNames = new ConcurrentHashMap<>();
|
|
final Map<String, String> toolNames = new ConcurrentHashMap<>();
|
|
|
- /** 全量图谱按 toolCallId 暂存:随 tool_events 落库,供历史会话复原 */
|
|
|
|
|
- final Map<String, Object> graphData = new ConcurrentHashMap<>();
|
|
|
|
|
final AtomicReference<StringBuilder> text = new AtomicReference<>(new StringBuilder());
|
|
final AtomicReference<StringBuilder> text = new AtomicReference<>(new StringBuilder());
|
|
|
final AtomicReference<StringBuilder> thinking = new AtomicReference<>(new StringBuilder());
|
|
final AtomicReference<StringBuilder> thinking = new AtomicReference<>(new StringBuilder());
|
|
|
/** 完整回答是否已落库(落库后出错不再重复携带过程数据) */
|
|
/** 完整回答是否已落库(落库后出错不再重复携带过程数据) */
|