新增广告计划、用户资产、B2B交易、合规规则等核心模型 实现爬虫工作器、贸易服务、现金流预测等业务服务 添加RBAC权限测试、压力测试等测试用例 完善扩展程序的消息处理与内容脚本功能 重构应用入口与文档生成器 更新项目规则与业务闭环分析文档
339 lines
11 KiB
TypeScript
339 lines
11 KiB
TypeScript
import { Logger } from '../utils/Logger';
|
||
|
||
export interface TestResult {
|
||
testId: string;
|
||
variations: VariationResult[];
|
||
metrics: {
|
||
[metric: string]: number;
|
||
};
|
||
startDate: string;
|
||
endDate: string;
|
||
sampleSize: number;
|
||
statisticalSignificance: number;
|
||
}
|
||
|
||
export interface VariationResult {
|
||
id: string;
|
||
name: string;
|
||
metrics: {
|
||
[metric: string]: number;
|
||
};
|
||
sampleSize: number;
|
||
conversionRate?: number;
|
||
engagementRate?: number;
|
||
revenuePerUser?: number;
|
||
retentionRate?: number;
|
||
}
|
||
|
||
export interface OptimizationGoal {
|
||
type: 'maximize' | 'minimize';
|
||
metric: string;
|
||
targetValue?: number;
|
||
weight?: number;
|
||
}
|
||
|
||
export interface OptimizationRecommendation {
|
||
recommendedVariation: string;
|
||
confidence: number;
|
||
expectedImprovement: number;
|
||
optimizationActions: OptimizationAction[];
|
||
riskAssessment: 'low' | 'medium' | 'high';
|
||
implementationSteps: string[];
|
||
followUpTests: FollowUpTest[];
|
||
}
|
||
|
||
export interface OptimizationAction {
|
||
id: string;
|
||
description: string;
|
||
priority: 'high' | 'medium' | 'low';
|
||
expectedImpact: number;
|
||
implementationEffort: 'low' | 'medium' | 'high';
|
||
}
|
||
|
||
export interface FollowUpTest {
|
||
testName: string;
|
||
description: string;
|
||
recommendedTiming: string;
|
||
estimatedDuration: number;
|
||
}
|
||
|
||
export class ABTestOptimizationService {
|
||
private logger = new Logger('ABTestOptimizationService');
|
||
|
||
async optimizeTest(
|
||
testResult: TestResult,
|
||
optimizationGoals: OptimizationGoal[],
|
||
traceId: string
|
||
): Promise<OptimizationRecommendation> {
|
||
try {
|
||
this.logger.info('开始优化A/B测试', {
|
||
testId: testResult.testId,
|
||
variationCount: testResult.variations.length,
|
||
traceId
|
||
});
|
||
|
||
const bestVariation = this.identifyBestVariation(testResult, optimizationGoals);
|
||
const confidence = this.calculateConfidence(testResult, bestVariation.id);
|
||
const expectedImprovement = this.calculateExpectedImprovement(testResult, bestVariation.id);
|
||
const optimizationActions = this.generateOptimizationActions(testResult, bestVariation, optimizationGoals);
|
||
const risk = this.assessRisk(testResult, bestVariation, optimizationGoals);
|
||
const implementationSteps = this.generateImplementationSteps(optimizationActions);
|
||
const followUpTests = this.recommendFollowUpTests(testResult, bestVariation, optimizationGoals);
|
||
|
||
const recommendation: OptimizationRecommendation = {
|
||
recommendedVariation: bestVariation.id,
|
||
confidence,
|
||
expectedImprovement,
|
||
optimizationActions,
|
||
riskAssessment: risk,
|
||
implementationSteps,
|
||
followUpTests
|
||
};
|
||
|
||
this.logger.info('A/B测试优化完成', {
|
||
recommendedVariation: bestVariation.id,
|
||
confidence,
|
||
expectedImprovement,
|
||
traceId
|
||
});
|
||
|
||
return recommendation;
|
||
} catch (error) {
|
||
this.logger.error('优化A/B测试失败', {
|
||
error: error instanceof Error ? error.message : '未知错误',
|
||
traceId
|
||
});
|
||
throw error;
|
||
}
|
||
}
|
||
|
||
private identifyBestVariation(testResult: TestResult, optimizationGoals: OptimizationGoal[]): VariationResult {
|
||
let bestVariation: VariationResult = testResult.variations[0];
|
||
let bestScore = -Infinity;
|
||
|
||
testResult.variations.forEach(variation => {
|
||
let score = 0;
|
||
|
||
optimizationGoals.forEach(goal => {
|
||
const value = variation.metrics[goal.metric] || 0;
|
||
const weight = goal.weight || 1;
|
||
|
||
if (goal.type === 'maximize') {
|
||
score += value * weight;
|
||
} else {
|
||
score += (1 / (value + 0.001)) * weight;
|
||
}
|
||
});
|
||
|
||
if (score > bestScore) {
|
||
bestScore = score;
|
||
bestVariation = variation;
|
||
}
|
||
});
|
||
|
||
return bestVariation;
|
||
}
|
||
|
||
private calculateConfidence(testResult: TestResult, bestVariationId: string): number {
|
||
const bestVariation = testResult.variations.find(v => v.id === bestVariationId);
|
||
if (!bestVariation) return 0;
|
||
|
||
const otherVariations = testResult.variations.filter(v => v.id !== bestVariationId);
|
||
const significantWins = otherVariations.filter(other => {
|
||
return this.isStatisticallySignificant(bestVariation!, other);
|
||
});
|
||
|
||
return Math.min(1, significantWins.length / otherVariations.length * 0.8 + 0.2);
|
||
}
|
||
|
||
private calculateExpectedImprovement(testResult: TestResult, bestVariationId: string): number {
|
||
const bestVariation = testResult.variations.find(v => v.id === bestVariationId);
|
||
if (!bestVariation) return 0;
|
||
|
||
const otherVariations = testResult.variations.filter(v => v.id !== bestVariationId);
|
||
if (otherVariations.length === 0) return 0;
|
||
|
||
const averagePerformance = otherVariations.reduce((sum, v) => {
|
||
const metricValues = Object.values(v.metrics);
|
||
return sum + metricValues.reduce((sum, val) => sum + val, 0) / metricValues.length;
|
||
}, 0) / otherVariations.length;
|
||
|
||
const bestPerformance = Object.values(bestVariation.metrics).reduce((sum, val) => sum + val, 0) / Object.values(bestVariation.metrics).length;
|
||
|
||
return (bestPerformance - averagePerformance) / averagePerformance;
|
||
}
|
||
|
||
private generateOptimizationActions(
|
||
testResult: TestResult,
|
||
bestVariation: VariationResult,
|
||
optimizationGoals: OptimizationGoal[]
|
||
): OptimizationAction[] {
|
||
const actions: OptimizationAction[] = [];
|
||
|
||
optimizationGoals.forEach(goal => {
|
||
const bestValue = bestVariation.metrics[goal.metric];
|
||
if (bestValue === undefined) return;
|
||
|
||
const otherVariations = testResult.variations.filter(v => v.id !== bestVariation.id);
|
||
const averageValue = otherVariations.reduce((sum, v) => sum + (v.metrics[goal.metric] || 0), 0) / otherVariations.length;
|
||
const improvement = (bestValue - averageValue) / averageValue;
|
||
|
||
if (Math.abs(improvement) > 0.05) {
|
||
actions.push({
|
||
id: `action_${goal.metric}`,
|
||
description: `优化 ${goal.metric} 指标,采用 ${bestVariation.name} 的策略`,
|
||
priority: Math.abs(improvement) > 0.15 ? 'high' : Math.abs(improvement) > 0.08 ? 'medium' : 'low',
|
||
expectedImpact: Math.abs(improvement),
|
||
implementationEffort: Math.abs(improvement) > 0.15 ? 'medium' : 'low'
|
||
});
|
||
}
|
||
});
|
||
|
||
if (actions.length === 0) {
|
||
actions.push({
|
||
id: 'action_no_change',
|
||
description: '保持当前策略,继续监控性能',
|
||
priority: 'low',
|
||
expectedImpact: 0,
|
||
implementationEffort: 'low'
|
||
});
|
||
}
|
||
|
||
return actions.sort((a, b) => {
|
||
const priorityOrder = { high: 3, medium: 2, low: 1 };
|
||
return priorityOrder[b.priority] - priorityOrder[a.priority];
|
||
});
|
||
}
|
||
|
||
private assessRisk(
|
||
testResult: TestResult,
|
||
bestVariation: VariationResult,
|
||
optimizationGoals: OptimizationGoal[]
|
||
): 'low' | 'medium' | 'high' {
|
||
let riskScore = 0;
|
||
|
||
if (testResult.sampleSize < 500) riskScore += 2;
|
||
else if (testResult.sampleSize < 1000) riskScore += 1;
|
||
|
||
if (testResult.statisticalSignificance > 0.1) riskScore += 2;
|
||
else if (testResult.statisticalSignificance > 0.05) riskScore += 1;
|
||
|
||
const otherVariations = testResult.variations.filter(v => v.id !== bestVariation.id);
|
||
const closeCompetitors = otherVariations.filter(other => {
|
||
const bestScore = Object.values(bestVariation.metrics).reduce((sum, val) => sum + val, 0);
|
||
const otherScore = Object.values(other.metrics).reduce((sum, val) => sum + val, 0);
|
||
return (otherScore / bestScore) > 0.95;
|
||
});
|
||
|
||
if (closeCompetitors.length > 0) riskScore += 1;
|
||
|
||
const hasRevenueGoal = optimizationGoals.some(goal => goal.metric.includes('revenue'));
|
||
if (hasRevenueGoal) riskScore += 1;
|
||
|
||
if (riskScore >= 5) return 'high';
|
||
if (riskScore >= 3) return 'medium';
|
||
return 'low';
|
||
}
|
||
|
||
private generateImplementationSteps(actions: OptimizationAction[]): string[] {
|
||
const steps: string[] = [];
|
||
|
||
steps.push('1. 审核优化建议,确认推荐的变体');
|
||
steps.push('2. 制定实施计划,包括时间线和负责人');
|
||
|
||
actions.forEach((action, index) => {
|
||
steps.push(`${index + 3}. 实施 ${action.description}(优先级:${action.priority})`);
|
||
});
|
||
|
||
steps.push(`${actions.length + 3}. 监控实施后的性能指标`);
|
||
steps.push(`${actions.length + 4}. 记录实施结果,用于后续分析`);
|
||
|
||
return steps;
|
||
}
|
||
|
||
private recommendFollowUpTests(
|
||
testResult: TestResult,
|
||
bestVariation: VariationResult,
|
||
optimizationGoals: OptimizationGoal[]
|
||
): FollowUpTest[] {
|
||
const tests: FollowUpTest[] = [];
|
||
|
||
if (optimizationGoals.some(goal => goal.type === 'maximize' && goal.metric.includes('conversion'))) {
|
||
tests.push({
|
||
testName: '转化率优化深度测试',
|
||
description: '进一步优化已识别的高转化率策略',
|
||
recommendedTiming: '2周后',
|
||
estimatedDuration: 7
|
||
});
|
||
}
|
||
|
||
if (optimizationGoals.some(goal => goal.type === 'maximize' && goal.metric.includes('revenue'))) {
|
||
tests.push({
|
||
testName: '收入优化扩展测试',
|
||
description: '测试不同定价策略和促销组合',
|
||
recommendedTiming: '3周后',
|
||
estimatedDuration: 14
|
||
});
|
||
}
|
||
|
||
if (tests.length === 0) {
|
||
tests.push({
|
||
testName: '性能监控测试',
|
||
description: '持续监控实施后的性能变化',
|
||
recommendedTiming: '1周后',
|
||
estimatedDuration: 7
|
||
});
|
||
}
|
||
|
||
return tests;
|
||
}
|
||
|
||
private isStatisticallySignificant(variationA: VariationResult, variationB: VariationResult): boolean {
|
||
const metricsA = Object.values(variationA.metrics);
|
||
const metricsB = Object.values(variationB.metrics);
|
||
|
||
if (metricsA.length === 0 || metricsB.length === 0) return false;
|
||
|
||
const meanA = metricsA.reduce((sum, val) => sum + val, 0) / metricsA.length;
|
||
const meanB = metricsB.reduce((sum, val) => sum + val, 0) / metricsB.length;
|
||
|
||
const varianceA = metricsA.reduce((sum, val) => sum + Math.pow(val - meanA, 2), 0) / metricsA.length;
|
||
const varianceB = metricsB.reduce((sum, val) => sum + Math.pow(val - meanB, 2), 0) / metricsB.length;
|
||
|
||
const standardError = Math.sqrt(varianceA / metricsA.length + varianceB / metricsB.length);
|
||
const zScore = Math.abs(meanA - meanB) / standardError;
|
||
|
||
return zScore > 1.96; // 95% confidence
|
||
}
|
||
|
||
async validateOptimization(recommendation: OptimizationRecommendation, traceId: string): Promise<{ valid: boolean; warnings: string[] }> {
|
||
const warnings: string[] = [];
|
||
|
||
if (recommendation.confidence < 0.7) {
|
||
warnings.push('置信度较低,建议增加样本量或延长测试时间');
|
||
}
|
||
|
||
if (recommendation.expectedImprovement < 0.05) {
|
||
warnings.push('预期改进较小,可能不值得实施');
|
||
}
|
||
|
||
if (recommendation.riskAssessment === 'high') {
|
||
warnings.push('风险评估为高,建议谨慎实施');
|
||
}
|
||
|
||
if (recommendation.optimizationActions.length === 0) {
|
||
warnings.push('未生成优化行动,建议重新评估测试结果');
|
||
}
|
||
|
||
this.logger.info('优化建议验证完成', {
|
||
warningCount: warnings.length,
|
||
traceId
|
||
});
|
||
|
||
return {
|
||
valid: warnings.length < 3,
|
||
warnings
|
||
};
|
||
}
|
||
}
|