/// LLM可观测性相关数据模型 /// 用于管理后台查看和分析大模型调用日志 import 'package:equatable/equatable.dart'; import 'package:json_annotation/json_annotation.dart'; import '../../utils/date_time_parser.dart'; part 'llm_observability_models.g.dart'; /// 自定义时间戳转换器 class TimestampConverter implements JsonConverter { const TimestampConverter(); @override DateTime fromJson(dynamic timestamp) { return parseBackendDateTime(timestamp); } @override dynamic toJson(DateTime timestamp) { return timestamp.toIso8601String(); } } /// LLM调用日志 @JsonSerializable() class LLMTrace extends Equatable { final String id; final String traceId; final String provider; final String model; final String? userId; final String? sessionId; @JsonKey(name: 'createdAt') @TimestampConverter() final DateTime timestamp; // 请求信息 final LLMRequest request; // 响应信息 final LLMResponse? response; // 性能指标 final LLMPerformanceMetrics? performance; // 错误信息 final LLMError? error; // 工具调用 final List? toolCalls; // 元数据 final Map? metadata; // 状态 @JsonKey(defaultValue: LLMTraceStatus.pending) final LLMTraceStatus status; @JsonKey(defaultValue: false) final bool isStreaming; const LLMTrace({ required this.id, required this.traceId, required this.provider, required this.model, this.userId, this.sessionId, required this.timestamp, required this.request, this.response, this.performance, this.error, this.toolCalls, this.metadata, this.status = LLMTraceStatus.pending, this.isStreaming = false, }); factory LLMTrace.fromJson(Map json) => _$LLMTraceFromJson(json); Map toJson() => _$LLMTraceToJson(this); @override List get props => [id, traceId, provider, model, userId, sessionId, timestamp, request, response, performance, error, toolCalls, metadata, status, isStreaming]; } /// LLM请求信息 @JsonSerializable() class LLMRequest extends Equatable { final List? messages; // 模型参数 final double? temperature; final double? topP; final int? topK; final int? maxTokens; final int? seed; // 工具调用 final List? tools; final String? toolChoice; // 格式设置 final String? responseFormat; // 其他参数 final Map? additionalParameters; const LLMRequest({ this.messages, this.temperature, this.topP, this.topK, this.maxTokens, this.seed, this.tools, this.toolChoice, this.responseFormat, this.additionalParameters, }); factory LLMRequest.fromJson(Map json) => _$LLMRequestFromJson(json); Map toJson() => _$LLMRequestToJson(this); @override List get props => [messages, temperature, topP, topK, maxTokens, seed, tools, toolChoice, responseFormat, additionalParameters]; } /// LLM响应信息 @JsonSerializable() class LLMResponse extends Equatable { final String? id; final String? content; // Token使用情况 final LLMTokenUsage? tokenUsage; // 完成原因 final String? finishReason; // 工具调用结果 final List? toolCallResults; // 元数据 final Map? metadata; // 流式数据 final List? streamChunks; const LLMResponse({ this.id, this.content, this.tokenUsage, this.finishReason, this.toolCallResults, this.metadata, this.streamChunks, }); factory LLMResponse.fromJson(Map json) => _$LLMResponseFromJson(json); Map toJson() => _$LLMResponseToJson(this); @override List get props => [id, content, tokenUsage, finishReason, toolCallResults, metadata, streamChunks]; } /// LLM消息 @JsonSerializable() class LLMMessage extends Equatable { final String role; final String? content; final String? name; final Map? metadata; const LLMMessage({ required this.role, this.content, this.name, this.metadata, }); factory LLMMessage.fromJson(Map json) => _$LLMMessageFromJson(json); Map toJson() => _$LLMMessageToJson(this); @override List get props => [role, content, name, metadata]; } /// LLM工具定义 @JsonSerializable() class LLMTool extends Equatable { final String name; final String? description; final Map? parameters; const LLMTool({ required this.name, this.description, this.parameters, }); factory LLMTool.fromJson(Map json) => _$LLMToolFromJson(json); Map toJson() => _$LLMToolToJson(this); @override List get props => [name, description, parameters]; } /// LLM工具调用 @JsonSerializable() class LLMToolCall extends Equatable { final String id; final String name; final Map? arguments; final DateTime? timestamp; const LLMToolCall({ required this.id, required this.name, this.arguments, this.timestamp, }); factory LLMToolCall.fromJson(Map json) => _$LLMToolCallFromJson(json); Map toJson() => _$LLMToolCallToJson(this); @override List get props => [id, name, arguments, timestamp]; } /// LLM工具调用结果 @JsonSerializable() class LLMToolCallResult extends Equatable { final String toolCallId; final String? result; final LLMError? error; const LLMToolCallResult({ required this.toolCallId, this.result, this.error, }); factory LLMToolCallResult.fromJson(Map json) => _$LLMToolCallResultFromJson(json); Map toJson() => _$LLMToolCallResultToJson(this); @override List get props => [toolCallId, result, error]; } /// Token使用情况 @JsonSerializable() class LLMTokenUsage extends Equatable { final int? promptTokens; final int? completionTokens; final int? totalTokens; // 详细分解 final int? inputTokens; final int? outputTokens; final int? reasoningTokens; final int? cachedTokens; const LLMTokenUsage({ this.promptTokens, this.completionTokens, this.totalTokens, this.inputTokens, this.outputTokens, this.reasoningTokens, this.cachedTokens, }); factory LLMTokenUsage.fromJson(Map json) => _$LLMTokenUsageFromJson(json); Map toJson() => _$LLMTokenUsageToJson(this); @override List get props => [promptTokens, completionTokens, totalTokens, inputTokens, outputTokens, reasoningTokens, cachedTokens]; } /// 性能指标 @JsonSerializable() class LLMPerformanceMetrics extends Equatable { final int? requestLatencyMs; final int? firstTokenLatencyMs; final int? totalDurationMs; // 吞吐量 final double? tokensPerSecond; final double? charactersPerSecond; // 队列时间 final int? queueTimeMs; final int? processingTimeMs; const LLMPerformanceMetrics({ this.requestLatencyMs, this.firstTokenLatencyMs, this.totalDurationMs, this.tokensPerSecond, this.charactersPerSecond, this.queueTimeMs, this.processingTimeMs, }); factory LLMPerformanceMetrics.fromJson(Map json) => _$LLMPerformanceMetricsFromJson(json); Map toJson() => _$LLMPerformanceMetricsToJson(this); @override List get props => [requestLatencyMs, firstTokenLatencyMs, totalDurationMs, tokensPerSecond, charactersPerSecond, queueTimeMs, processingTimeMs]; } /// 错误信息 @JsonSerializable() class LLMError extends Equatable { final String? type; final String? message; final String? code; final String? stackTrace; final Map? details; const LLMError({ this.type, this.message, this.code, this.stackTrace, this.details, }); factory LLMError.fromJson(Map json) => _$LLMErrorFromJson(json); Map toJson() => _$LLMErrorToJson(this); @override List get props => [type, message, code, stackTrace, details]; } /// LLM调用状态 enum LLMTraceStatus { @JsonValue('pending') pending, @JsonValue('success') success, @JsonValue('error') error, @JsonValue('timeout') timeout, @JsonValue('cancelled') cancelled, } /// 统计信息基类 @JsonSerializable() class LLMStatistics extends Equatable { final int totalCalls; final int successfulCalls; final int failedCalls; final double successRate; final double averageLatency; final int totalTokens; // 时间范围 final DateTime? startTime; final DateTime? endTime; // 详细统计 final Map? details; const LLMStatistics({ required this.totalCalls, required this.successfulCalls, required this.failedCalls, required this.successRate, required this.averageLatency, required this.totalTokens, this.startTime, this.endTime, this.details, }); factory LLMStatistics.fromJson(Map json) => _$LLMStatisticsFromJson(json); Map toJson() => _$LLMStatisticsToJson(this); @override List get props => [totalCalls, successfulCalls, failedCalls, successRate, averageLatency, totalTokens, startTime, endTime, details]; } /// 提供商统计 @JsonSerializable() class ProviderStatistics extends Equatable { final String provider; final LLMStatistics statistics; final List models; const ProviderStatistics({ required this.provider, required this.statistics, required this.models, }); factory ProviderStatistics.fromJson(Map json) => _$ProviderStatisticsFromJson(json); Map toJson() => _$ProviderStatisticsToJson(this); @override List get props => [provider, statistics, models]; } /// 模型统计 @JsonSerializable() class ModelStatistics extends Equatable { final String modelName; final String provider; final LLMStatistics statistics; const ModelStatistics({ required this.modelName, required this.provider, required this.statistics, }); factory ModelStatistics.fromJson(Map json) => _$ModelStatisticsFromJson(json); Map toJson() => _$ModelStatisticsToJson(this); @override List get props => [modelName, provider, statistics]; } /// 用户统计 @JsonSerializable() class UserStatistics extends Equatable { final String userId; final String? username; final LLMStatistics statistics; final List topModels; final List topProviders; const UserStatistics({ required this.userId, this.username, required this.statistics, required this.topModels, required this.topProviders, }); factory UserStatistics.fromJson(Map json) => _$UserStatisticsFromJson(json); Map toJson() => _$UserStatisticsToJson(this); @override List get props => [userId, username, statistics, topModels, topProviders]; } /// 错误统计 @JsonSerializable() class ErrorStatistics extends Equatable { final String errorType; final int count; final double percentage; final List topErrorMessages; final List affectedModels; const ErrorStatistics({ required this.errorType, required this.count, required this.percentage, required this.topErrorMessages, required this.affectedModels, }); factory ErrorStatistics.fromJson(Map json) => _$ErrorStatisticsFromJson(json); Map toJson() => _$ErrorStatisticsToJson(this); @override List get props => [errorType, count, percentage, topErrorMessages, affectedModels]; } /// 性能统计 @JsonSerializable() class PerformanceStatistics extends Equatable { final double averageLatency; final double medianLatency; final double p95Latency; final double p99Latency; final double averageThroughput; // 按时间分组的统计 final List latencyTrends; final List throughputTrends; const PerformanceStatistics({ required this.averageLatency, required this.medianLatency, required this.p95Latency, required this.p99Latency, required this.averageThroughput, required this.latencyTrends, required this.throughputTrends, }); factory PerformanceStatistics.fromJson(Map json) => _$PerformanceStatisticsFromJson(json); Map toJson() => _$PerformanceStatisticsToJson(this); @override List get props => [averageLatency, medianLatency, p95Latency, p99Latency, averageThroughput, latencyTrends, throughputTrends]; } /// 基于时间的指标 @JsonSerializable() class TimeBasedMetric extends Equatable { final DateTime timestamp; final double value; final String? label; const TimeBasedMetric({ required this.timestamp, required this.value, this.label, }); factory TimeBasedMetric.fromJson(Map json) => _$TimeBasedMetricFromJson(json); Map toJson() => _$TimeBasedMetricToJson(this); @override List get props => [timestamp, value, label]; } /// 系统健康状态 @JsonSerializable() class SystemHealthStatus extends Equatable { @JsonKey(defaultValue: HealthStatus.healthy) final HealthStatus status; final Map components; final String? message; final DateTime? lastChecked; const SystemHealthStatus({ this.status = HealthStatus.healthy, required this.components, this.message, this.lastChecked, }); factory SystemHealthStatus.fromJson(Map json) => _$SystemHealthStatusFromJson(json); Map toJson() => _$SystemHealthStatusToJson(this); @override List get props => [status, components, message, lastChecked]; } /// 组件健康状态 @JsonSerializable() class ComponentHealth extends Equatable { @JsonKey(defaultValue: HealthStatus.healthy) final HealthStatus status; final String? message; final Map? metrics; const ComponentHealth({ this.status = HealthStatus.healthy, this.message, this.metrics, }); factory ComponentHealth.fromJson(Map json) => _$ComponentHealthFromJson(json); Map toJson() => _$ComponentHealthToJson(this); @override List get props => [status, message, metrics]; } /// 健康状态枚举 enum HealthStatus { @JsonValue('healthy') healthy, @JsonValue('degraded') degraded, @JsonValue('unhealthy') unhealthy, @JsonValue('unknown') unknown, } /// LLM日志搜索条件 @JsonSerializable() class LLMTraceSearchCriteria extends Equatable { final String? userId; final String? provider; final String? model; final String? sessionId; final bool? hasError; final LLMTraceStatus? status; final DateTime? startTime; final DateTime? endTime; // 分页 @JsonKey(defaultValue: 0) final int page; @JsonKey(defaultValue: 20) final int size; @JsonKey(defaultValue: 'timestamp') final String sortBy; @JsonKey(defaultValue: 'desc') final String sortDir; const LLMTraceSearchCriteria({ this.userId, this.provider, this.model, this.sessionId, this.hasError, this.status, this.startTime, this.endTime, this.page = 0, this.size = 20, this.sortBy = 'timestamp', this.sortDir = 'desc', }); factory LLMTraceSearchCriteria.fromJson(Map json) => _$LLMTraceSearchCriteriaFromJson(json); Map toJson() => _$LLMTraceSearchCriteriaToJson(this); @override List get props => [userId, provider, model, sessionId, hasError, status, startTime, endTime, page, size, sortBy, sortDir]; } /// API响应包装类 @JsonSerializable(genericArgumentFactories: true) class ApiResponse extends Equatable { final bool success; final String? message; final T? data; final String? error; const ApiResponse({ required this.success, this.message, this.data, this.error, }); factory ApiResponse.fromJson(Map json, T Function(Object? json) fromJsonT) => _$ApiResponseFromJson(json, fromJsonT); Map toJson(Object? Function(T value) toJsonT) => _$ApiResponseToJson(this, toJsonT); @override List get props => [success, message, data, error]; } /// 分页响应 @JsonSerializable(genericArgumentFactories: true) class PagedResponse extends Equatable { final List content; final int page; final int size; final int totalElements; final int totalPages; @JsonKey(defaultValue: false) final bool first; @JsonKey(defaultValue: false) final bool last; const PagedResponse({ required this.content, required this.page, required this.size, required this.totalElements, required this.totalPages, this.first = false, this.last = false, }); factory PagedResponse.fromJson(Map json, T Function(Object? json) fromJsonT) => _$PagedResponseFromJson(json, fromJsonT); Map toJson(Object? Function(T value) toJsonT) => _$PagedResponseToJson(this, toJsonT); @override List get props => [content, page, size, totalElements, totalPages, first, last]; } /// 游标分页响应 @JsonSerializable(genericArgumentFactories: true) class CursorPageResponse extends Equatable { final List items; final String? nextCursor; @JsonKey(defaultValue: false) final bool hasMore; const CursorPageResponse({ required this.items, this.nextCursor, this.hasMore = false, }); factory CursorPageResponse.fromJson(Map json, T Function(Object? json) fromJsonT) => _$CursorPageResponseFromJson(json, fromJsonT); Map toJson(Object? Function(T value) toJsonT) => _$CursorPageResponseToJson(this, toJsonT); @override List get props => [items, nextCursor, hasMore]; }