diff --git a/src/main/java/com/superbiz/agent/hook/AgentLoggingHook.java b/src/main/java/com/superbiz/agent/hook/AgentLoggingHook.java new file mode 100644 index 0000000..9703b5d --- /dev/null +++ b/src/main/java/com/superbiz/agent/hook/AgentLoggingHook.java @@ -0,0 +1,115 @@ +package com.superbiz.agent.hook; + +import com.alibaba.cloud.ai.graph.agent.hook.messages.MessagesModelHook; +import com.alibaba.cloud.ai.graph.agent.hook.messages.AgentCommand; +import com.alibaba.cloud.ai.graph.agent.hook.HookPosition; +import com.alibaba.cloud.ai.graph.agent.hook.HookPositions; +import com.alibaba.cloud.ai.graph.RunnableConfig; +import lombok.extern.slf4j.Slf4j; +import org.springframework.ai.chat.messages.Message; +import org.springframework.ai.chat.messages.AssistantMessage; +import org.springframework.ai.chat.messages.UserMessage; +import org.springframework.ai.chat.messages.ToolResponseMessage; + +import java.util.List; + +/** + * Agent 日志 Hook + * 用于记录 Agent 的思考过程、消息流转 + */ +@Slf4j +@HookPositions({HookPosition.BEFORE_MODEL, HookPosition.AFTER_MODEL}) +public class AgentLoggingHook extends MessagesModelHook { + + private int modelCallCount = 0; + + @Override + public String getName() { + return "agent_logging_hook"; + } + + @Override + public AgentCommand beforeModel(List previousMessages, RunnableConfig config) { + modelCallCount++; + log.info("========================================"); + log.info("*** [Agent 思考] 第 {} 轮思考开始", modelCallCount); + log.info("*** [Agent 思考] 当前消息数量: {}", previousMessages.size()); + + // 打印最后几条消息 + int lastN = Math.min(3, previousMessages.size()); + if (lastN > 0) { + log.info("*** [Agent 思考] 最近 {} 条消息:", lastN); + List recentMessages = previousMessages.subList(previousMessages.size() - lastN, previousMessages.size()); + + for (int i = 0; i < recentMessages.size(); i++) { + Message msg = recentMessages.get(i); + String role = getMessageRole(msg); + + log.info(" [{}] 角色: {}, 类型: {}", i + 1, role, msg.getClass().getSimpleName()); + // Message 接口可能没有直接的 getContent() 方法,跳过内容打印 + // 具体内容会在工具调用日志中体现 + } + } + + log.info("*** [Agent 思考] 准备调用模型..."); + log.info("========================================"); + + // 不修改消息,直接返回 + return new AgentCommand(previousMessages); + } + + @Override + public AgentCommand afterModel(List previousMessages, RunnableConfig config) { + log.info("========================================"); + log.info("*** [Agent 思考] 第 {} 轮思考完成", modelCallCount); + + // 查找最后一条 AssistantMessage(模型的回复) + AssistantMessage lastAssistant = null; + for (int i = previousMessages.size() - 1; i >= 0; i--) { + if (previousMessages.get(i) instanceof AssistantMessage) { + lastAssistant = (AssistantMessage) previousMessages.get(i); + break; + } + } + + if (lastAssistant != null) { + log.info("*** [Agent 思考] 模型输出: "); + // AssistantMessage 的内容通过 toString() 或在工具调用中体现 + + // 检查是否有工具调用 + if (lastAssistant.getToolCalls() != null && !lastAssistant.getToolCalls().isEmpty()) { + log.info("*** [Agent 思考] 模型决定调用 {} 个工具:", + lastAssistant.getToolCalls().size()); + lastAssistant.getToolCalls().forEach(toolCall -> { + log.info(" - 工具: {}, 参数: {}", + toolCall.name(), + toolCall.arguments()); + }); + log.info("*** [Agent 思考] 等待工具执行结果..."); + } else { + log.info("*** [Agent 思考] 模型决定不调用工具"); + log.info("*** [Agent 思考] 这是最终答案,准备返回给用户"); + } + } + + log.info("========================================"); + + // 不修改消息,直接返回 + return new AgentCommand(previousMessages); + } + + /** + * 获取消息角色 + */ + private String getMessageRole(Message message) { + if (message instanceof UserMessage) { + return "User(用户)"; + } else if (message instanceof AssistantMessage) { + return "Assistant(模型)"; + } else if (message instanceof ToolResponseMessage) { + return "Tool(工具返回)"; + } else { + return message.getClass().getSimpleName(); + } + } +} diff --git a/src/main/java/com/superbiz/agent/service/ChatService.java b/src/main/java/com/superbiz/agent/service/ChatService.java index d78c6e9..d42c126 100644 --- a/src/main/java/com/superbiz/agent/service/ChatService.java +++ b/src/main/java/com/superbiz/agent/service/ChatService.java @@ -7,6 +7,7 @@ import com.superbiz.agent.agent.tool.InternalDocsTools; import com.superbiz.agent.agent.tool.QueryLogsTools; import com.superbiz.agent.agent.tool.QueryMetricsTools; import com.superbiz.agent.tool.LookupKnowledgeTool; +import com.superbiz.agent.hook.AgentLoggingHook; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -176,6 +177,7 @@ public class ChatService { .systemPrompt(systemPrompt) .methodTools(buildMethodToolsArray()) .tools(getToolCallbacks()) + .hooks(new AgentLoggingHook()) // 添加日志 Hook .build(); }