|
@@ -436,23 +436,8 @@ public class ToolCallAgent extends ReActAgent {
|
|
|
if (!shouldAct) {
|
|
if (!shouldAct) {
|
|
|
log.info("[ToolCallAgent] 无需行动,直接返回结果");
|
|
log.info("[ToolCallAgent] 无需行动,直接返回结果");
|
|
|
emitEvent(StreamEvent.thinkingEnd());
|
|
emitEvent(StreamEvent.thinkingEnd());
|
|
|
- // 获取最后一条消息作为结果
|
|
|
|
|
- Message lastMsg = CollUtil.getLast(currentConversationMessages);
|
|
|
|
|
- if (lastMsg instanceof AssistantMessage) {
|
|
|
|
|
- String fullText = ((AssistantMessage) lastMsg).getText();
|
|
|
|
|
- if (fullText != null && !fullText.isEmpty()) {
|
|
|
|
|
- // 打字机效果:按单个字符分片发射(模拟打字机)
|
|
|
|
|
- for (int i = 0; i < fullText.length(); i++) {
|
|
|
|
|
- emitEvent(StreamEvent.contentChunk(String.valueOf(fullText.charAt(i))));
|
|
|
|
|
- // 可选:加个小延迟让打字效果更明显(但不要太长影响体验)
|
|
|
|
|
- try {
|
|
|
|
|
- Thread.sleep(10);
|
|
|
|
|
- } catch (InterruptedException e) {
|
|
|
|
|
- Thread.currentThread().interrupt();
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
- }
|
|
|
|
|
|
|
+ // 【流式改造】think() 方法已经实时发射了文本 chunk,这里不需要再发射
|
|
|
|
|
+ // 直接结束即可
|
|
|
state = AgentState.FINISHED;
|
|
state = AgentState.FINISHED;
|
|
|
return false;
|
|
return false;
|
|
|
}
|
|
}
|
|
@@ -510,33 +495,72 @@ public class ToolCallAgent extends ReActAgent {
|
|
|
.internalToolExecutionEnabled(false) // 【关键】禁用自动执行!
|
|
.internalToolExecutionEnabled(false) // 【关键】禁用自动执行!
|
|
|
.build();
|
|
.build();
|
|
|
|
|
|
|
|
- ChatResponse chatResponse = chatClient.prompt()
|
|
|
|
|
|
|
+ // 【流式改造】使用 stream() 实现真正的流式输出
|
|
|
|
|
+ Flux<ChatResponse> responseFlux = chatClient.prompt()
|
|
|
.system(enhancedSystemPrompt)
|
|
.system(enhancedSystemPrompt)
|
|
|
.messages(currentConversationMessages)
|
|
.messages(currentConversationMessages)
|
|
|
.options(chatOptions)
|
|
.options(chatOptions)
|
|
|
- .call()
|
|
|
|
|
|
|
+ .stream()
|
|
|
.chatResponse();
|
|
.chatResponse();
|
|
|
|
|
|
|
|
- this.toolCallChatResponse = chatResponse;
|
|
|
|
|
- AssistantMessage assistantMessage = chatResponse.getResult().getOutput();
|
|
|
|
|
- List<AssistantMessage.ToolCall> toolCallList = assistantMessage.getToolCalls();
|
|
|
|
|
|
|
+ // 累积完整的响应文本和工具调用信息
|
|
|
|
|
+ StringBuilder accumulatedText = new StringBuilder();
|
|
|
|
|
+ AssistantMessage[] lastAssistantMessageRef = new AssistantMessage[1];
|
|
|
|
|
+
|
|
|
|
|
+ // 同步阻塞等待流式输出完成,同时实时发射事件
|
|
|
|
|
+ responseFlux.doOnNext(chatResponse -> {
|
|
|
|
|
+ // 获取当前 chunk 的文本
|
|
|
|
|
+ if (chatResponse.getResult() != null && chatResponse.getResult().getOutput() != null) {
|
|
|
|
|
+ AssistantMessage currentMsg = chatResponse.getResult().getOutput();
|
|
|
|
|
+ String chunkText = currentMsg.getText();
|
|
|
|
|
+ if (chunkText != null && !chunkText.isEmpty()) {
|
|
|
|
|
+ accumulatedText.append(chunkText);
|
|
|
|
|
+ // 【关键】实时发射文本 chunk
|
|
|
|
|
+ emitEvent(StreamEvent.contentChunk(chunkText));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 保存最新的 AssistantMessage(最后一个 chunk 包含完整工具调用信息)
|
|
|
|
|
+ lastAssistantMessageRef[0] = currentMsg;
|
|
|
|
|
+ }
|
|
|
|
|
+ })
|
|
|
|
|
+ .doOnError(error -> {
|
|
|
|
|
+ log.error("[ToolCallAgent] 流式输出错误: {}", error.getMessage(), error);
|
|
|
|
|
+ })
|
|
|
|
|
+ .blockLast(); // 阻塞等待流式输出完成
|
|
|
|
|
+
|
|
|
|
|
+ // 使用流中最后一个 AssistantMessage
|
|
|
|
|
+ AssistantMessage finalAssistantMessage = lastAssistantMessageRef[0];
|
|
|
|
|
+ if (finalAssistantMessage == null) {
|
|
|
|
|
+ log.warn("[ToolCallAgent] 流式输出未返回任何消息");
|
|
|
|
|
+ return false;
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ // 获取工具调用信息
|
|
|
|
|
+ List<AssistantMessage.ToolCall> finalToolCallList = finalAssistantMessage.getToolCalls();
|
|
|
|
|
+
|
|
|
|
|
+ // 保存完整响应供 act() 使用
|
|
|
|
|
+ // 注意:流式返回的 AssistantMessage 已经包含文本和工具调用信息
|
|
|
|
|
+ this.toolCallChatResponse = new ChatResponse(
|
|
|
|
|
+ List.of(new org.springframework.ai.chat.model.Generation(finalAssistantMessage))
|
|
|
|
|
+ );
|
|
|
|
|
+
|
|
|
|
|
+ // 将 AI 的回复添加到对话历史(使用累积的完整文本)
|
|
|
|
|
+ String fullText = accumulatedText.toString();
|
|
|
|
|
+ AssistantMessage messageForHistory = new AssistantMessage(fullText);
|
|
|
|
|
+ currentConversationMessages.add(messageForHistory);
|
|
|
|
|
|
|
|
log.info("[ToolCallAgent] 思考阶段 - 模型回复:{}, 工具调用数:{}",
|
|
log.info("[ToolCallAgent] 思考阶段 - 模型回复:{}, 工具调用数:{}",
|
|
|
- assistantMessage.getText() != null ?
|
|
|
|
|
- assistantMessage.getText().substring(0, Math.min(50, assistantMessage.getText().length())) + "..." : "null",
|
|
|
|
|
- toolCallList != null ? toolCallList.size() : 0);
|
|
|
|
|
-
|
|
|
|
|
- // 将 AI 的回复添加到对话历史
|
|
|
|
|
- currentConversationMessages.add(assistantMessage);
|
|
|
|
|
|
|
+ fullText.length() > 50 ? fullText.substring(0, 50) + "..." : fullText,
|
|
|
|
|
+ finalToolCallList != null ? finalToolCallList.size() : 0);
|
|
|
|
|
|
|
|
// 检查是否有工具调用
|
|
// 检查是否有工具调用
|
|
|
- if (toolCallList != null && !toolCallList.isEmpty()) {
|
|
|
|
|
- log.info("[ToolCallAgent] 检测到 {} 个工具调用", toolCallList.size());
|
|
|
|
|
|
|
+ if (finalToolCallList != null && !finalToolCallList.isEmpty()) {
|
|
|
|
|
+ log.info("[ToolCallAgent] 检测到 {} 个工具调用", finalToolCallList.size());
|
|
|
return true;
|
|
return true;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// 检查是否有 terminate 意图
|
|
// 检查是否有 terminate 意图
|
|
|
- String content = assistantMessage.getText();
|
|
|
|
|
|
|
+ String content = finalAssistantMessage.getText();
|
|
|
if (content != null && isTerminateIntent(content)) {
|
|
if (content != null && isTerminateIntent(content)) {
|
|
|
log.info("[ToolCallAgent] 检测到终止意图");
|
|
log.info("[ToolCallAgent] 检测到终止意图");
|
|
|
state = AgentState.FINISHED;
|
|
state = AgentState.FINISHED;
|