| | |
| | | String requestId = request.getRequestId(); |
| | | long startedAt = System.currentTimeMillis(); |
| | | AtomicReference<Long> firstTokenAtRef = new AtomicReference<>(); |
| | | AtomicLong traceSequence = new AtomicLong(0); |
| | | AtomicLong toolCallSequence = new AtomicLong(0); |
| | | AtomicLong toolSuccessCount = new AtomicLong(0); |
| | | AtomicLong toolFailureCount = new AtomicLong(0); |
| | |
| | | Long callLogId = null; |
| | | String model = null; |
| | | String resolvedPromptCode = request.getPromptCode(); |
| | | AiThinkingTraceEmitter thinkingTraceEmitter = null; |
| | | AiChatTraceEmitter traceEmitter = null; |
| | | try { |
| | | ensureIdentity(userId, tenantId); |
| | | AiResolvedConfig config = resolveConfig(request, tenantId); |
| | |
| | | .build()); |
| | | log.info("AI chat started, requestId={}, userId={}, tenantId={}, sessionId={}, model={}", |
| | | requestId, userId, tenantId, session.getId(), resolvedModel); |
| | | thinkingTraceEmitter = new AiThinkingTraceEmitter(aiSseEventPublisher, emitter, requestId, session.getId()); |
| | | thinkingTraceEmitter.startAnalyze(); |
| | | AiThinkingTraceEmitter activeThinkingTraceEmitter = thinkingTraceEmitter; |
| | | traceEmitter = new AiChatTraceEmitter(aiSseEventPublisher, emitter, requestId, session.getId(), traceSequence); |
| | | traceEmitter.startAnalyze(); |
| | | AiChatTraceEmitter activeTraceEmitter = traceEmitter; |
| | | |
| | | ToolCallback[] observableToolCallbacks = aiToolObservationService.wrapToolCallbacks( |
| | | runtime.getToolCallbacks(), emitter, requestId, session.getId(), toolCallSequence, |
| | | toolSuccessCount, toolFailureCount, callLogId, userId, tenantId, activeThinkingTraceEmitter |
| | | runtime.getToolCallbacks(), requestId, session.getId(), toolCallSequence, |
| | | toolSuccessCount, toolFailureCount, callLogId, userId, tenantId, activeTraceEmitter |
| | | ); |
| | | Prompt prompt = new Prompt( |
| | | aiPromptMessageBuilder.buildPromptMessages(memory, mergedMessages, config.getPrompt(), request.getMetadata()), |
| | |
| | | String content = extractContent(response); |
| | | aiChatMemoryService.saveRound(session, userId, tenantId, request.getMessages(), content); |
| | | if (StringUtils.hasText(content)) { |
| | | aiSseEventPublisher.markFirstToken(firstTokenAtRef, emitter, requestId, session.getId(), resolvedModel, startedAt, activeThinkingTraceEmitter); |
| | | aiSseEventPublisher.markFirstToken(firstTokenAtRef, emitter, requestId, session.getId(), resolvedModel, startedAt, activeTraceEmitter); |
| | | aiSseEventPublisher.emitStrict(emitter, "delta", aiSseEventPublisher.buildMessagePayload("requestId", requestId, "content", content)); |
| | | } |
| | | activeThinkingTraceEmitter.completeCurrentPhase(); |
| | | activeTraceEmitter.completeCurrentPhase(); |
| | | aiSseEventPublisher.emitDone(emitter, requestId, response.getMetadata(), config.getAiParam().getModel(), |
| | | session.getId(), startedAt, firstTokenAtRef.get()); |
| | | aiSseEventPublisher.emitSafely(emitter, "status", |
| | |
| | | lastMetadata.set(response.getMetadata()); |
| | | String content = extractContent(response); |
| | | if (StringUtils.hasText(content)) { |
| | | aiSseEventPublisher.markFirstToken(firstTokenAtRef, emitter, requestId, session.getId(), resolvedModel, startedAt, activeThinkingTraceEmitter); |
| | | aiSseEventPublisher.markFirstToken(firstTokenAtRef, emitter, requestId, session.getId(), resolvedModel, startedAt, activeTraceEmitter); |
| | | assistantContent.append(content); |
| | | aiSseEventPublisher.emitStrict(emitter, "delta", |
| | | aiSseEventPublisher.buildMessagePayload("requestId", requestId, "content", content)); |
| | |
| | | e == null ? "AI 模型流式调用失败" : e.getMessage(), e); |
| | | } |
| | | aiChatMemoryService.saveRound(session, userId, tenantId, request.getMessages(), assistantContent.toString()); |
| | | activeThinkingTraceEmitter.completeCurrentPhase(); |
| | | activeTraceEmitter.completeCurrentPhase(); |
| | | aiSseEventPublisher.emitDone(emitter, requestId, lastMetadata.get(), config.getAiParam().getModel(), |
| | | session.getId(), startedAt, firstTokenAtRef.get()); |
| | | aiSseEventPublisher.emitSafely(emitter, "status", |
| | |
| | | } |
| | | } catch (AiChatException e) { |
| | | aiChatFailureHandler.handleStreamFailure(emitter, requestId, sessionId, model, startedAt, firstTokenAtRef.get(), e, |
| | | callLogId, toolSuccessCount.get(), toolFailureCount.get(), thinkingTraceEmitter, |
| | | callLogId, toolSuccessCount.get(), toolFailureCount.get(), traceEmitter, |
| | | tenantId, userId, resolvedPromptCode); |
| | | } catch (Exception e) { |
| | | aiChatFailureHandler.handleStreamFailure(emitter, requestId, sessionId, model, startedAt, firstTokenAtRef.get(), |
| | | aiChatFailureHandler.buildAiException("AI_INTERNAL_ERROR", AiErrorCategory.INTERNAL, "INTERNAL", |
| | | e == null ? "AI 对话失败" : e.getMessage(), e), |
| | | callLogId, toolSuccessCount.get(), toolFailureCount.get(), thinkingTraceEmitter, |
| | | callLogId, toolSuccessCount.get(), toolFailureCount.get(), traceEmitter, |
| | | tenantId, userId, resolvedPromptCode); |
| | | } finally { |
| | | log.debug("AI chat stream finished, requestId={}", requestId); |