zhou zhou
20 小时以前 4954d3978cf1967729a5a2d5b90f6baef18974da
rsf-server/src/main/java/com/vincent/rsf/server/ai/service/impl/AiCallLogServiceImpl.java
@@ -26,6 +26,7 @@
    private static final Pattern BEARER_PATTERN = Pattern.compile("(?i)(bearer\\s+)([a-z0-9._-]+)");
    private final AiMcpCallLogMapper aiMcpCallLogMapper;
    private final AiRedisSupport aiRedisSupport;
    @Override
    public AiCallLog startCallLog(String requestId, Long sessionId, Long userId, Long tenantId, String promptCode,
@@ -51,6 +52,7 @@
                .setCreateTime(now)
                .setUpdateTime(now);
        this.save(callLog);
        aiRedisSupport.recordObserveCallStarted(tenantId);
        return callLog;
    }
@@ -73,6 +75,10 @@
                .set(AiCallLog::getToolFailureCount, (int) toolFailureCount)
                .set(AiCallLog::getToolCallCount, (int) (toolSuccessCount + toolFailureCount))
                .set(AiCallLog::getUpdateTime, new Date()));
        AiCallLog latest = this.getById(callLogId);
        if (latest != null) {
            aiRedisSupport.recordObserveCallFinished(latest.getTenantId(), status, elapsedMs, firstTokenLatencyMs, totalTokens);
        }
    }
    @Override
@@ -93,6 +99,10 @@
                .set(AiCallLog::getToolFailureCount, (int) toolFailureCount)
                .set(AiCallLog::getToolCallCount, (int) (toolSuccessCount + toolFailureCount))
                .set(AiCallLog::getUpdateTime, new Date()));
        AiCallLog latest = this.getById(callLogId);
        if (latest != null) {
            aiRedisSupport.recordObserveCallFinished(latest.getTenantId(), status, elapsedMs, firstTokenLatencyMs, null);
        }
    }
    @Override
@@ -117,10 +127,16 @@
                .setUserId(userId)
                .setTenantId(tenantId)
                .setCreateTime(new Date()));
        aiRedisSupport.recordObserveToolCall(tenantId, toolName, status);
    }
    @Override
    public AiObserveStatsDto getObserveStats(Long tenantId) {
        return aiRedisSupport.getObserveStats(tenantId, () -> loadObserveStatsFromDatabase(tenantId));
    }
    private AiObserveStatsDto loadObserveStatsFromDatabase(Long tenantId) {
        // 数据库聚合只作为 Redis 冷启动兜底,正常情况下看板应直接消费实时计数。
        List<AiCallLog> callLogs = this.list(new LambdaQueryWrapper<AiCallLog>()
                .eq(AiCallLog::getTenantId, tenantId)
                .eq(AiCallLog::getDeleted, 0)