Files
MaliangAINovalWriter/AINoval/lib/models/admin/llm_observability_models.dart
2025-09-10 00:07:52 +08:00

702 lines
18 KiB
Dart

/// 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<DateTime, dynamic> {
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<LLMToolCall>? toolCalls;
// 元数据
final Map<String, dynamic>? 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<String, dynamic> json) => _$LLMTraceFromJson(json);
Map<String, dynamic> toJson() => _$LLMTraceToJson(this);
@override
List<Object?> 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<LLMMessage>? messages;
// 模型参数
final double? temperature;
final double? topP;
final int? topK;
final int? maxTokens;
final int? seed;
// 工具调用
final List<LLMTool>? tools;
final String? toolChoice;
// 格式设置
final String? responseFormat;
// 其他参数
final Map<String, dynamic>? 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<String, dynamic> json) => _$LLMRequestFromJson(json);
Map<String, dynamic> toJson() => _$LLMRequestToJson(this);
@override
List<Object?> 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<LLMToolCallResult>? toolCallResults;
// 元数据
final Map<String, dynamic>? metadata;
// 流式数据
final List<String>? streamChunks;
const LLMResponse({
this.id,
this.content,
this.tokenUsage,
this.finishReason,
this.toolCallResults,
this.metadata,
this.streamChunks,
});
factory LLMResponse.fromJson(Map<String, dynamic> json) => _$LLMResponseFromJson(json);
Map<String, dynamic> toJson() => _$LLMResponseToJson(this);
@override
List<Object?> 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<String, dynamic>? metadata;
const LLMMessage({
required this.role,
this.content,
this.name,
this.metadata,
});
factory LLMMessage.fromJson(Map<String, dynamic> json) => _$LLMMessageFromJson(json);
Map<String, dynamic> toJson() => _$LLMMessageToJson(this);
@override
List<Object?> get props => [role, content, name, metadata];
}
/// LLM工具定义
@JsonSerializable()
class LLMTool extends Equatable {
final String name;
final String? description;
final Map<String, dynamic>? parameters;
const LLMTool({
required this.name,
this.description,
this.parameters,
});
factory LLMTool.fromJson(Map<String, dynamic> json) => _$LLMToolFromJson(json);
Map<String, dynamic> toJson() => _$LLMToolToJson(this);
@override
List<Object?> get props => [name, description, parameters];
}
/// LLM工具调用
@JsonSerializable()
class LLMToolCall extends Equatable {
final String id;
final String name;
final Map<String, dynamic>? arguments;
final DateTime? timestamp;
const LLMToolCall({
required this.id,
required this.name,
this.arguments,
this.timestamp,
});
factory LLMToolCall.fromJson(Map<String, dynamic> json) => _$LLMToolCallFromJson(json);
Map<String, dynamic> toJson() => _$LLMToolCallToJson(this);
@override
List<Object?> 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<String, dynamic> json) => _$LLMToolCallResultFromJson(json);
Map<String, dynamic> toJson() => _$LLMToolCallResultToJson(this);
@override
List<Object?> 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<String, dynamic> json) => _$LLMTokenUsageFromJson(json);
Map<String, dynamic> toJson() => _$LLMTokenUsageToJson(this);
@override
List<Object?> 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<String, dynamic> json) => _$LLMPerformanceMetricsFromJson(json);
Map<String, dynamic> toJson() => _$LLMPerformanceMetricsToJson(this);
@override
List<Object?> 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<String, dynamic>? details;
const LLMError({
this.type,
this.message,
this.code,
this.stackTrace,
this.details,
});
factory LLMError.fromJson(Map<String, dynamic> json) => _$LLMErrorFromJson(json);
Map<String, dynamic> toJson() => _$LLMErrorToJson(this);
@override
List<Object?> 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<String, dynamic>? 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<String, dynamic> json) => _$LLMStatisticsFromJson(json);
Map<String, dynamic> toJson() => _$LLMStatisticsToJson(this);
@override
List<Object?> get props => [totalCalls, successfulCalls, failedCalls, successRate, averageLatency, totalTokens, startTime, endTime, details];
}
/// 提供商统计
@JsonSerializable()
class ProviderStatistics extends Equatable {
final String provider;
final LLMStatistics statistics;
final List<ModelStatistics> models;
const ProviderStatistics({
required this.provider,
required this.statistics,
required this.models,
});
factory ProviderStatistics.fromJson(Map<String, dynamic> json) => _$ProviderStatisticsFromJson(json);
Map<String, dynamic> toJson() => _$ProviderStatisticsToJson(this);
@override
List<Object?> 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<String, dynamic> json) => _$ModelStatisticsFromJson(json);
Map<String, dynamic> toJson() => _$ModelStatisticsToJson(this);
@override
List<Object?> get props => [modelName, provider, statistics];
}
/// 用户统计
@JsonSerializable()
class UserStatistics extends Equatable {
final String userId;
final String? username;
final LLMStatistics statistics;
final List<String> topModels;
final List<String> topProviders;
const UserStatistics({
required this.userId,
this.username,
required this.statistics,
required this.topModels,
required this.topProviders,
});
factory UserStatistics.fromJson(Map<String, dynamic> json) => _$UserStatisticsFromJson(json);
Map<String, dynamic> toJson() => _$UserStatisticsToJson(this);
@override
List<Object?> get props => [userId, username, statistics, topModels, topProviders];
}
/// 错误统计
@JsonSerializable()
class ErrorStatistics extends Equatable {
final String errorType;
final int count;
final double percentage;
final List<String> topErrorMessages;
final List<String> affectedModels;
const ErrorStatistics({
required this.errorType,
required this.count,
required this.percentage,
required this.topErrorMessages,
required this.affectedModels,
});
factory ErrorStatistics.fromJson(Map<String, dynamic> json) => _$ErrorStatisticsFromJson(json);
Map<String, dynamic> toJson() => _$ErrorStatisticsToJson(this);
@override
List<Object?> 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<TimeBasedMetric> latencyTrends;
final List<TimeBasedMetric> 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<String, dynamic> json) => _$PerformanceStatisticsFromJson(json);
Map<String, dynamic> toJson() => _$PerformanceStatisticsToJson(this);
@override
List<Object?> 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<String, dynamic> json) => _$TimeBasedMetricFromJson(json);
Map<String, dynamic> toJson() => _$TimeBasedMetricToJson(this);
@override
List<Object?> get props => [timestamp, value, label];
}
/// 系统健康状态
@JsonSerializable()
class SystemHealthStatus extends Equatable {
@JsonKey(defaultValue: HealthStatus.healthy)
final HealthStatus status;
final Map<String, ComponentHealth> components;
final String? message;
final DateTime? lastChecked;
const SystemHealthStatus({
this.status = HealthStatus.healthy,
required this.components,
this.message,
this.lastChecked,
});
factory SystemHealthStatus.fromJson(Map<String, dynamic> json) => _$SystemHealthStatusFromJson(json);
Map<String, dynamic> toJson() => _$SystemHealthStatusToJson(this);
@override
List<Object?> get props => [status, components, message, lastChecked];
}
/// 组件健康状态
@JsonSerializable()
class ComponentHealth extends Equatable {
@JsonKey(defaultValue: HealthStatus.healthy)
final HealthStatus status;
final String? message;
final Map<String, dynamic>? metrics;
const ComponentHealth({
this.status = HealthStatus.healthy,
this.message,
this.metrics,
});
factory ComponentHealth.fromJson(Map<String, dynamic> json) => _$ComponentHealthFromJson(json);
Map<String, dynamic> toJson() => _$ComponentHealthToJson(this);
@override
List<Object?> 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<String, dynamic> json) => _$LLMTraceSearchCriteriaFromJson(json);
Map<String, dynamic> toJson() => _$LLMTraceSearchCriteriaToJson(this);
@override
List<Object?> get props => [userId, provider, model, sessionId, hasError, status, startTime, endTime, page, size, sortBy, sortDir];
}
/// API响应包装类
@JsonSerializable(genericArgumentFactories: true)
class ApiResponse<T> 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<String, dynamic> json, T Function(Object? json) fromJsonT) =>
_$ApiResponseFromJson(json, fromJsonT);
Map<String, dynamic> toJson(Object? Function(T value) toJsonT) =>
_$ApiResponseToJson(this, toJsonT);
@override
List<Object?> get props => [success, message, data, error];
}
/// 分页响应
@JsonSerializable(genericArgumentFactories: true)
class PagedResponse<T> extends Equatable {
final List<T> 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<String, dynamic> json, T Function(Object? json) fromJsonT) =>
_$PagedResponseFromJson(json, fromJsonT);
Map<String, dynamic> toJson(Object? Function(T value) toJsonT) =>
_$PagedResponseToJson(this, toJsonT);
@override
List<Object?> get props => [content, page, size, totalElements, totalPages, first, last];
}
/// 游标分页响应
@JsonSerializable(genericArgumentFactories: true)
class CursorPageResponse<T> extends Equatable {
final List<T> items;
final String? nextCursor;
@JsonKey(defaultValue: false)
final bool hasMore;
const CursorPageResponse({
required this.items,
this.nextCursor,
this.hasMore = false,
});
factory CursorPageResponse.fromJson(Map<String, dynamic> json, T Function(Object? json) fromJsonT) =>
_$CursorPageResponseFromJson(json, fromJsonT);
Map<String, dynamic> toJson(Object? Function(T value) toJsonT) =>
_$CursorPageResponseToJson(this, toJsonT);
@override
List<Object?> get props => [items, nextCursor, hasMore];
}