/** * [BE-AIAUTO-001~002] AI决策自动化配置服务 * 负责管理AI决策自动执行的配置、阈值和等级 * AI注意: 所有自动执行决策必须通过此服务校验 */ import db from '../config/database'; import { logger } from '../utils/logger'; import { EventBusService } from './EventBusService'; import { RedisService } from './RedisService'; // 自动化等级 (L1-L4) export type AutomationLevel = 'L1' | 'L2' | 'L3' | 'L4'; // 风险等级 export type RiskLevel = 'LOW' | 'MEDIUM' | 'HIGH' | 'CRITICAL'; // 决策模块类型 export type DecisionModule = | 'PRICING' // 定价模块 | 'INVENTORY' // 库存模块 | 'AD_OPTIMIZE' // 广告优化 | 'PRODUCT_SELECT' // 选品模块 | 'LOGISTICS' // 物流模块 | 'RISK_CONTROL' // 风控模块 | 'CUSTOMER_SERVICE' // 客服模块 | 'SETTLEMENT'; // 结算模块 // 自动执行配置实体 export interface AutoExecutionConfig { id: string; tenant_id: string; shop_id: string; module: DecisionModule; // 自动化等级 automation_level: AutomationLevel; // 置信度阈值配置 confidence_thresholds: { auto_execute: number; // 自动执行阈值 pending_review: number; // 待审核阈值 auto_reject: number; // 自动拒绝阈值 }; // 风险限制配置 risk_limits: { max_amount: number; // 最大金额限制 max_quantity: number; // 最大数量限制 allowed_risk_levels: RiskLevel[]; // 允许的风险等级 }; // 时间限制 time_restrictions: { allowed_hours: number[]; // 允许执行的小时 (0-23) excluded_dates: string[]; // 排除的日期 (YYYY-MM-DD) }; // 回滚配置 rollback_config: { enabled: boolean; max_attempts: number; cooldown_minutes: number; }; // 通知配置 notification_config: { on_execute: boolean; on_fail: boolean; on_rollback: boolean; channels: ('EMAIL' | 'SMS' | 'WEBHOOK')[]; }; // 统计数据 statistics: { total_executions: number; success_count: number; fail_count: number; rollback_count: number; avg_confidence: number; last_execution_at?: Date; }; // 状态 status: 'ACTIVE' | 'INACTIVE' | 'SUSPENDED'; // 审计 created_by: string; updated_by: string; created_at: Date; updated_at: Date; } // 执行请求 export interface ExecutionRequest { tenant_id: string; shop_id: string; module: DecisionModule; decision_id: string; confidence: number; risk_level: RiskLevel; estimated_impact: { amount?: number; quantity?: number; }; metadata?: Record; } // 执行结果 export interface ExecutionResult { allowed: boolean; reason: string; required_action: 'AUTO_EXECUTE' | 'PENDING_REVIEW' | 'AUTO_REJECT'; config_snapshot: Partial; warnings: string[]; } // 等级演进记录 export interface LevelEvolutionRecord { id: string; tenant_id: string; shop_id: string; module: DecisionModule; from_level: AutomationLevel; to_level: AutomationLevel; reason: string; metrics: { success_rate: number; total_executions: number; avg_confidence: number; }; approved_by: string; created_at: Date; } // 模块默认配置 const MODULE_DEFAULT_CONFIGS: Record> = { PRICING: { confidence_thresholds: { auto_execute: 0.85, pending_review: 0.60, auto_reject: 0.40 }, risk_limits: { max_amount: 5000, max_quantity: 100, allowed_risk_levels: ['LOW', 'MEDIUM'] }, }, INVENTORY: { confidence_thresholds: { auto_execute: 0.90, pending_review: 0.70, auto_reject: 0.50 }, risk_limits: { max_amount: 10000, max_quantity: 500, allowed_risk_levels: ['LOW', 'MEDIUM'] }, }, AD_OPTIMIZE: { confidence_thresholds: { auto_execute: 0.80, pending_review: 0.55, auto_reject: 0.35 }, risk_limits: { max_amount: 2000, max_quantity: 50, allowed_risk_levels: ['LOW', 'MEDIUM', 'HIGH'] }, }, PRODUCT_SELECT: { confidence_thresholds: { auto_execute: 0.75, pending_review: 0.50, auto_reject: 0.30 }, risk_limits: { max_amount: 3000, max_quantity: 200, allowed_risk_levels: ['LOW', 'MEDIUM'] }, }, LOGISTICS: { confidence_thresholds: { auto_execute: 0.88, pending_review: 0.65, auto_reject: 0.45 }, risk_limits: { max_amount: 1000, max_quantity: 100, allowed_risk_levels: ['LOW', 'MEDIUM'] }, }, RISK_CONTROL: { confidence_thresholds: { auto_execute: 0.95, pending_review: 0.80, auto_reject: 0.60 }, risk_limits: { max_amount: 50000, max_quantity: 1000, allowed_risk_levels: ['LOW'] }, }, CUSTOMER_SERVICE: { confidence_thresholds: { auto_execute: 0.82, pending_review: 0.60, auto_reject: 0.40 }, risk_limits: { max_amount: 500, max_quantity: 10, allowed_risk_levels: ['LOW', 'MEDIUM'] }, }, SETTLEMENT: { confidence_thresholds: { auto_execute: 0.98, pending_review: 0.90, auto_reject: 0.70 }, risk_limits: { max_amount: 100000, max_quantity: 100, allowed_risk_levels: ['LOW'] }, }, }; // 等级能力矩阵 const LEVEL_CAPABILITIES: Record = { L1: { max_risk_level: 'LOW', max_amount_multiplier: 0.5, requires_approval: true, description: '仅建议,所有操作需人工确认', }, L2: { max_risk_level: 'MEDIUM', max_amount_multiplier: 1.0, requires_approval: false, description: '低风险操作可自动执行,中高风险需审核', }, L3: { max_risk_level: 'HIGH', max_amount_multiplier: 2.0, requires_approval: false, description: '大部分操作可自动执行,仅高风险需审核', }, L4: { max_risk_level: 'CRITICAL', max_amount_multiplier: 5.0, requires_approval: false, description: '全自动化,包含关键操作,需严格监控', }, }; export class AutoExecutionConfigService { private static readonly TABLE_NAME = 'cf_auto_execution_config'; private static readonly EVOLUTION_TABLE = 'cf_automation_level_evolution'; private static readonly CACHE_PREFIX = 'auto_exec_config:'; private static readonly CACHE_TTL = 1800; // 30分钟 /** * [BE-AIAUTO-001] 初始化数据库表 */ static async initTables() { // 主配置表 const hasTable = await db.schema.hasTable(this.TABLE_NAME); if (!hasTable) { logger.info(`Creating ${this.TABLE_NAME} table...`); await db.schema.createTable(this.TABLE_NAME, (table) => { table.string('id', 50).primary(); table.string('tenant_id', 50).notNullable().index(); table.string('shop_id', 50).notNullable().index(); table.enum('module', [ 'PRICING', 'INVENTORY', 'AD_OPTIMIZE', 'PRODUCT_SELECT', 'LOGISTICS', 'RISK_CONTROL', 'CUSTOMER_SERVICE', 'SETTLEMENT' ]).notNullable(); // 自动化等级 table.enum('automation_level', ['L1', 'L2', 'L3', 'L4']).notNullable().defaultTo('L1'); // JSON配置字段 table.json('confidence_thresholds').notNullable(); table.json('risk_limits').notNullable(); table.json('time_restrictions').notNullable(); table.json('rollback_config').notNullable(); table.json('notification_config').notNullable(); table.json('statistics').notNullable(); // 状态 table.enum('status', ['ACTIVE', 'INACTIVE', 'SUSPENDED']).notNullable().defaultTo('ACTIVE'); // 审计 table.string('created_by', 50).notNullable(); table.string('updated_by', 50).notNullable(); table.timestamp('created_at').notNullable().defaultTo(db.fn.now()); table.timestamp('updated_at').notNullable().defaultTo(db.fn.now()); // 唯一约束 table.unique(['tenant_id', 'shop_id', 'module']); table.index(['tenant_id', 'status']); }); logger.info(`${this.TABLE_NAME} table created successfully`); } // 等级演进记录表 const hasEvolutionTable = await db.schema.hasTable(this.EVOLUTION_TABLE); if (!hasEvolutionTable) { logger.info(`Creating ${this.EVOLUTION_TABLE} table...`); await db.schema.createTable(this.EVOLUTION_TABLE, (table) => { table.string('id', 50).primary(); table.string('tenant_id', 50).notNullable().index(); table.string('shop_id', 50).notNullable().index(); table.enum('module', [ 'PRICING', 'INVENTORY', 'AD_OPTIMIZE', 'PRODUCT_SELECT', 'LOGISTICS', 'RISK_CONTROL', 'CUSTOMER_SERVICE', 'SETTLEMENT' ]).notNullable(); table.enum('from_level', ['L1', 'L2', 'L3', 'L4']).notNullable(); table.enum('to_level', ['L1', 'L2', 'L3', 'L4']).notNullable(); table.text('reason').notNullable(); table.json('metrics').notNullable(); table.string('approved_by', 50).notNullable(); table.timestamp('created_at').notNullable().defaultTo(db.fn.now()); table.index(['tenant_id', 'module', 'created_at']); }); logger.info(`${this.EVOLUTION_TABLE} table created successfully`); } } /** * [BE-AIAUTO-002] 获取或创建模块配置 */ static async getOrCreateConfig( tenantId: string, shopId: string, module: DecisionModule, userId: string ): Promise { // 尝试从缓存获取 const cacheKey = `${this.CACHE_PREFIX}${tenantId}:${shopId}:${module}`; const cached = await RedisService.get(cacheKey); if (cached) { return JSON.parse(cached); } // 查询数据库 let config = await db(this.TABLE_NAME) .where({ tenant_id: tenantId, shop_id: shopId, module }) .first(); if (!config) { // 创建默认配置 const defaultConfig = MODULE_DEFAULT_CONFIGS[module]; const id = `AEC-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const newConfig = { id, tenant_id: tenantId, shop_id: shopId, module, automation_level: 'L1' as AutomationLevel, confidence_thresholds: JSON.stringify(defaultConfig.confidence_thresholds || { auto_execute: 0.80, pending_review: 0.50, auto_reject: 0.30, }), risk_limits: JSON.stringify(defaultConfig.risk_limits || { max_amount: 1000, max_quantity: 100, allowed_risk_levels: ['LOW', 'MEDIUM'], }), time_restrictions: JSON.stringify({ allowed_hours: Array.from({ length: 24 }, (_, i) => i), excluded_dates: [], }), rollback_config: JSON.stringify({ enabled: true, max_attempts: 3, cooldown_minutes: 30, }), notification_config: JSON.stringify({ on_execute: true, on_fail: true, on_rollback: true, channels: ['EMAIL'] as ('EMAIL' | 'SMS' | 'WEBHOOK')[], }), statistics: JSON.stringify({ total_executions: 0, success_count: 0, fail_count: 0, rollback_count: 0, avg_confidence: 0, }), status: 'ACTIVE', created_by: userId, updated_by: userId, created_at: new Date(), updated_at: new Date(), }; await db(this.TABLE_NAME).insert(newConfig); config = newConfig; logger.info(`[AutoExecutionConfig] Created default config for ${module}`); } const result = this.parseConfigRecord(config); // 缓存结果 await RedisService.setex(cacheKey, this.CACHE_TTL, JSON.stringify(result)); return result; } /** * [BE-AIAUTO-002] 校验执行请求 */ static async validateExecution(request: ExecutionRequest): Promise { const config = await this.getOrCreateConfig( request.tenant_id, request.shop_id, request.module, 'SYSTEM' ); const warnings: string[] = []; let allowed = true; let reason = ''; let requiredAction: 'AUTO_EXECUTE' | 'PENDING_REVIEW' | 'AUTO_REJECT' = 'AUTO_EXECUTE'; // 检查配置状态 if (config.status !== 'ACTIVE') { return { allowed: false, reason: `配置状态为 ${config.status},不允许自动执行`, required_action: 'PENDING_REVIEW', config_snapshot: { status: config.status }, warnings: ['模块配置未激活'], }; } // 检查置信度阈值 const { confidence_thresholds } = config; if (request.confidence >= confidence_thresholds.auto_execute) { requiredAction = 'AUTO_EXECUTE'; reason = '置信度达到自动执行阈值'; } else if (request.confidence >= confidence_thresholds.pending_review) { requiredAction = 'PENDING_REVIEW'; reason = '置信度处于待审核区间'; allowed = false; } else { requiredAction = 'AUTO_REJECT'; reason = '置信度低于最低阈值,自动拒绝'; allowed = false; } // 检查风险等级 const { risk_limits } = config; if (!risk_limits.allowed_risk_levels.includes(request.risk_level)) { warnings.push(`风险等级 ${request.risk_level} 不在允许范围内`); if (request.risk_level === 'CRITICAL' || request.risk_level === 'HIGH') { requiredAction = 'PENDING_REVIEW'; allowed = false; reason = '风险等级过高,需要人工审核'; } } // 检查等级能力限制 const levelCapability = LEVEL_CAPABILITIES[config.automation_level]; const riskLevelOrder: RiskLevel[] = ['LOW', 'MEDIUM', 'HIGH', 'CRITICAL']; const requestRiskIndex = riskLevelOrder.indexOf(request.risk_level); const maxRiskIndex = riskLevelOrder.indexOf(levelCapability.max_risk_level); if (requestRiskIndex > maxRiskIndex) { warnings.push(`当前等级 ${config.automation_level} 不支持风险等级 ${request.risk_level}`); requiredAction = 'PENDING_REVIEW'; allowed = false; reason = '超出当前自动化等级的风险承受能力'; } // 检查金额/数量限制 const maxAmount = risk_limits.max_amount * levelCapability.max_amount_multiplier; if (request.estimated_impact.amount && request.estimated_impact.amount > maxAmount) { warnings.push(`预估金额 ${request.estimated_impact.amount} 超出限制 ${maxAmount}`); requiredAction = 'PENDING_REVIEW'; allowed = false; reason = '预估影响金额超出当前等级限制'; } if (request.estimated_impact.quantity && request.estimated_impact.quantity > risk_limits.max_quantity) { warnings.push(`预估数量 ${request.estimated_impact.quantity} 超出限制 ${risk_limits.max_quantity}`); requiredAction = 'PENDING_REVIEW'; allowed = false; reason = '预估影响数量超出限制'; } // 检查时间限制 const { time_restrictions } = config; const now = new Date(); const currentHour = now.getHours(); const currentDate = now.toISOString().split('T')[0]; if (!time_restrictions.allowed_hours.includes(currentHour)) { warnings.push(`当前时间 ${currentHour}:00 不在允许执行的时间段内`); requiredAction = 'PENDING_REVIEW'; allowed = false; reason = '不在允许执行的时间段'; } if (time_restrictions.excluded_dates.includes(currentDate)) { warnings.push(`当前日期 ${currentDate} 被排除执行`); requiredAction = 'PENDING_REVIEW'; allowed = false; reason = '当前日期不允许自动执行'; } // L1等级始终需要审核 if (config.automation_level === 'L1' && requiredAction === 'AUTO_EXECUTE') { requiredAction = 'PENDING_REVIEW'; allowed = false; reason = 'L1等级所有操作都需要人工确认'; } return { allowed, reason, required_action: requiredAction, config_snapshot: { automation_level: config.automation_level, confidence_thresholds: config.confidence_thresholds, risk_limits: config.risk_limits, }, warnings, }; } /** * [BE-AIAUTO-002] 更新配置 */ static async updateConfig( configId: string, updates: Partial, userId: string ): Promise { const updateData: any = { updated_by: userId, updated_at: new Date(), }; // 处理JSON字段 if (updates.confidence_thresholds) { updateData.confidence_thresholds = JSON.stringify(updates.confidence_thresholds); } if (updates.risk_limits) { updateData.risk_limits = JSON.stringify(updates.risk_limits); } if (updates.time_restrictions) { updateData.time_restrictions = JSON.stringify(updates.time_restrictions); } if (updates.rollback_config) { updateData.rollback_config = JSON.stringify(updates.rollback_config); } if (updates.notification_config) { updateData.notification_config = JSON.stringify(updates.notification_config); } if (updates.automation_level) { updateData.automation_level = updates.automation_level; } if (updates.status) { updateData.status = updates.status; } await db(this.TABLE_NAME) .where('id', configId) .update(updateData); // 清除缓存 const config = await db(this.TABLE_NAME).where('id', configId).first(); if (config) { const cacheKey = `${this.CACHE_PREFIX}${config.tenant_id}:${config.shop_id}:${config.module}`; await RedisService.del(cacheKey); } // 发布事件 await EventBusService.publish('auto_execution.config_updated', { configId, updates, userId, timestamp: new Date(), }); logger.info(`[AutoExecutionConfig] Updated config ${configId}`); return this.parseConfigRecord(config); } /** * [BE-AIAUTO-002] 记录执行结果并更新统计 */ static async recordExecution( tenantId: string, shopId: string, module: DecisionModule, success: boolean, confidence: number, rolledBack: boolean = false ): Promise { const config = await this.getOrCreateConfig(tenantId, shopId, module, 'SYSTEM'); const stats = config.statistics; stats.total_executions += 1; if (success) { stats.success_count += 1; } else { stats.fail_count += 1; } if (rolledBack) { stats.rollback_count += 1; } stats.avg_confidence = ((stats.avg_confidence * (stats.total_executions - 1)) + confidence) / stats.total_executions; stats.last_execution_at = new Date(); await db(this.TABLE_NAME) .where('id', config.id) .update({ statistics: JSON.stringify(stats), updated_at: new Date(), }); // 清除缓存 const cacheKey = `${this.CACHE_PREFIX}${tenantId}:${shopId}:${module}`; await RedisService.del(cacheKey); } /** * [BE-AIAUTO-002] 升级自动化等级 */ static async upgradeLevel( tenantId: string, shopId: string, module: DecisionModule, targetLevel: AutomationLevel, reason: string, approvedBy: string ): Promise { const config = await this.getOrCreateConfig(tenantId, shopId, module, approvedBy); const currentLevel = config.automation_level; // 验证等级演进顺序 const levelOrder: AutomationLevel[] = ['L1', 'L2', 'L3', 'L4']; const currentIndex = levelOrder.indexOf(currentLevel); const targetIndex = levelOrder.indexOf(targetLevel); if (targetIndex !== currentIndex + 1) { throw new Error(`只能逐级升级,当前等级 ${currentLevel},目标等级 ${targetLevel}`); } // 检查升级条件 const stats = config.statistics; if (stats.total_executions < 100) { throw new Error(`执行次数不足100次,当前 ${stats.total_executions} 次`); } const successRate = stats.success_count / stats.total_executions; if (successRate < 0.95) { throw new Error(`成功率不足95%,当前 ${(successRate * 100).toFixed(1)}%`); } // 更新配置 await this.updateConfig(config.id, { automation_level: targetLevel }, approvedBy); // 记录演进 const evolutionId = `EVO-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const evolution: LevelEvolutionRecord = { id: evolutionId, tenant_id: tenantId, shop_id: shopId, module, from_level: currentLevel, to_level: targetLevel, reason, metrics: { success_rate: successRate, total_executions: stats.total_executions, avg_confidence: stats.avg_confidence, }, approved_by: approvedBy, created_at: new Date(), }; await db(this.EVOLUTION_TABLE).insert({ ...evolution, metrics: JSON.stringify(evolution.metrics), }); // 发布事件 await EventBusService.publish('auto_execution.level_upgraded', { tenantId, shopId, module, fromLevel: currentLevel, toLevel: targetLevel, approvedBy, timestamp: new Date(), }); logger.info(`[AutoExecutionConfig] Upgraded ${module} from ${currentLevel} to ${targetLevel}`); return evolution; } /** * [BE-AIAUTO-002] 降级自动化等级 */ static async downgradeLevel( tenantId: string, shopId: string, module: DecisionModule, targetLevel: AutomationLevel, reason: string, approvedBy: string ): Promise { const config = await this.getOrCreateConfig(tenantId, shopId, module, approvedBy); const currentLevel = config.automation_level; // 验证等级演进顺序 const levelOrder: AutomationLevel[] = ['L1', 'L2', 'L3', 'L4']; const currentIndex = levelOrder.indexOf(currentLevel); const targetIndex = levelOrder.indexOf(targetLevel); if (targetIndex >= currentIndex) { throw new Error(`降级目标等级必须低于当前等级`); } // 更新配置 await this.updateConfig(config.id, { automation_level: targetLevel }, approvedBy); // 记录演进 const evolutionId = `EVO-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`; const stats = config.statistics; const successRate = stats.total_executions > 0 ? stats.success_count / stats.total_executions : 0; const evolution: LevelEvolutionRecord = { id: evolutionId, tenant_id: tenantId, shop_id: shopId, module, from_level: currentLevel, to_level: targetLevel, reason, metrics: { success_rate: successRate, total_executions: stats.total_executions, avg_confidence: stats.avg_confidence, }, approved_by: approvedBy, created_at: new Date(), }; await db(this.EVOLUTION_TABLE).insert({ ...evolution, metrics: JSON.stringify(evolution.metrics), }); // 发布事件 await EventBusService.publish('auto_execution.level_downgraded', { tenantId, shopId, module, fromLevel: currentLevel, toLevel: targetLevel, approvedBy, reason, timestamp: new Date(), }); logger.info(`[AutoExecutionConfig] Downgraded ${module} from ${currentLevel} to ${targetLevel}`); return evolution; } /** * [BE-AIAUTO-002] 获取所有模块配置 */ static async getAllConfigs( tenantId: string, shopId?: string ): Promise { let query = db(this.TABLE_NAME).where('tenant_id', tenantId); if (shopId) { query = query.where('shop_id', shopId); } const records = await query.orderBy('module', 'asc'); return records.map(this.parseConfigRecord); } /** * [BE-AIAUTO-002] 获取等级演进历史 */ static async getEvolutionHistory( tenantId: string, shopId?: string, module?: DecisionModule ): Promise { let query = db(this.EVOLUTION_TABLE).where('tenant_id', tenantId); if (shopId) { query = query.where('shop_id', shopId); } if (module) { query = query.where('module', module); } const records = await query.orderBy('created_at', 'desc'); return records.map(r => ({ ...r, metrics: typeof r.metrics === 'string' ? JSON.parse(r.metrics) : r.metrics, })); } /** * [BE-AIAUTO-002] 获取等级能力说明 */ static getLevelCapabilities(): Record { return LEVEL_CAPABILITIES; } /** * [BE-AIAUTO-002] 获取模块默认配置 */ static getModuleDefaults(): Record> { return MODULE_DEFAULT_CONFIGS; } /** * 解析数据库记录 */ private static parseConfigRecord(record: any): AutoExecutionConfig { return { ...record, confidence_thresholds: typeof record.confidence_thresholds === 'string' ? JSON.parse(record.confidence_thresholds) : record.confidence_thresholds, risk_limits: typeof record.risk_limits === 'string' ? JSON.parse(record.risk_limits) : record.risk_limits, time_restrictions: typeof record.time_restrictions === 'string' ? JSON.parse(record.time_restrictions) : record.time_restrictions, rollback_config: typeof record.rollback_config === 'string' ? JSON.parse(record.rollback_config) : record.rollback_config, notification_config: typeof record.notification_config === 'string' ? JSON.parse(record.notification_config) : record.notification_config, statistics: typeof record.statistics === 'string' ? JSON.parse(record.statistics) : record.statistics, }; } }