import db from '../../config/database'; import { logger } from '../../utils/logger'; export interface DecisionFactor { name: string; value: any; weight: number; impact: 'POSITIVE' | 'NEGATIVE' | 'NEUTRAL'; } /** * [UX_XAI_01] AGI 决策可解释性引擎 (Explainable AI / XAI) * @description 核心逻辑:记录 AGI 决策的因果链 (Causal Chain),支持流式叙述生成与证据链溯源。 */ export class DecisionExplainabilityEngine { private static readonly TABLE_NAME = 'cf_decision_logs'; /** * 初始化数据库表 */ static async initTable() { 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.increments('id').primary(); table.string('tenant_id', 64).index(); table.string('module', 32).index(); // e.g., PRICING, SOURCING, ADS table.string('resource_id', 64).index(); table.string('decision_type', 64); table.text('causal_chain'); // 因果叙述 table.json('factors'); // 影响因子 [{name, value, weight, impact}] table.string('trace_id', 64); table.timestamp('created_at').defaultTo(db.fn.now()); }); } } /** * 记录决策证据链 */ static async logDecision(params: { tenantId: string; module: string; resourceId: string; decisionType: string; causalChain: string; factors: DecisionFactor[]; traceId: string; }) { try { await db(this.TABLE_NAME).insert({ tenant_id: params.tenantId, module: params.module, resource_id: params.resourceId, decision_type: params.decisionType, causal_chain: params.causalChain, factors: JSON.stringify(params.factors), trace_id: params.traceId, created_at: new Date() }); logger.debug(`[XAI] Decision logged for ${params.module}:${params.resourceId}`); } catch (err: any) { // [CORE_DIAG_01] Agent 异常自省 logger.error(`[XAI][WARN] Failed to log decision: ${err.message}`); } } /** * 获取决策证据链 (用于 Sandbox ROI 评估) */ static async getDecisionByResourceId(resourceId: string) { const record = await db(this.TABLE_NAME) .where({ resource_id: resourceId }) .orderBy('created_at', 'desc') .first(); if (!record) return null; return { ...record, factors: record.factors ? JSON.parse(record.factors) : [] }; } /** * 获取决策叙述 (用于前端 Console 展示) */ static async getDecisionNarrative(tenantId: string, resourceId: string) { return await db(this.TABLE_NAME) .where({ tenant_id: tenantId, resource_id: resourceId }) .orderBy('created_at', 'desc') .first(); } /** * [BIZ_GOV_05] 获取建议采纳 ROI 统计 */ static async getRoiStats(tenantId: string) { logger.info(`[XAI] Calculating ROI stats for tenant: ${tenantId}`); // 1. 调价建议 ROI (基于已执行的 cf_pricing_audit) const pricingRoi = await db('cf_pricing_audit') .join('cf_product', 'cf_pricing_audit.product_id', 'cf_product.id') .where('cf_pricing_audit.status', 'EXECUTED') .where('cf_product.tenant_id', tenantId) .select(db.raw('SUM((new_price - old_price) * 100) as total_profit_delta')); // 假设估算 100 销量 // 2. 采购建议 ROI (基于已执行的 cf_sourcing_audit) const sourcingRoi = await db('cf_sourcing_audit') .where('status', 'EXECUTED') .where('tenant_id', tenantId) .select(db.raw('SUM(price * 0.1) as total_savings')); // 假设估算节省 10% (示例) return { pricing: { estimatedProfitDelta: Number(pricingRoi[0]?.total_profit_delta || 0), executedCount: await db('cf_pricing_audit').where({ status: 'EXECUTED' }).count('id as count') }, sourcing: { estimatedSavings: Number(sourcingRoi[0]?.total_savings || 0), executedCount: await db('cf_sourcing_audit').where({ status: 'EXECUTED', tenant_id: tenantId }).count('id as count') }, totalRoi: Number(pricingRoi[0]?.total_profit_delta || 0) + Number(sourcingRoi[0]?.total_savings || 0) }; } }