一、传统 A/B 测试 vs AI A/B 测试传统 A/B 测试 AI A/B 测试 ──────────────────────────────────────────────────── 按钮颜色/文案变化 Prompt 措辞/结构变化 页面布局调整 检索策略/切片粒度变化 推荐算法参数 模型版本/供应商切换 转化率/点击率可复现 LLM 输出具有随机性 样本量容易估算 需要更多样本抵消方差 结果立即可见 需要端到端评估链条核心挑战LLM 的非确定性输出使得传统假设检验方法失效——同一个 Prompt 跑两次可能得到不同答案如何判断哪个版本真正更好二、AI 应用中哪些东西需要 A/B 测试层级可测对象典型变量Prompt指令措辞、示例数量、格式要求system prompt 风格、few-shot 数量模型供应商、版本、参数GPT-4 vs Claude 3、temperatureRAG切片策略、检索算法、Top-K语义切分 vs 固定长度、BM25 vs 向量工具调用Function Calling 描述、触发条件工具名描述、参数约束严格度后处理格式化、摘要、过滤Markdown vs JSON、阈值高低交互UI 展示、流式 vs 非流式逐字显示 vs 块状输出三、整体架构┌──────────────────────────────────────────────────────────────┐ │ 实验管理平台 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │实验创建 │ │流量分配 │ │指标配置 │ │结果查看 │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ └──────────────────────────┬───────────────────────────────────┘ │ ┌──────────────────────────▼───────────────────────────────────┐ │ 分流网关 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │用户哈希 │ │分层分流 │ │流量染色 │ │版本路由 │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ └───────┬──────────────────────────────────────────────────────┘ │ ┌───────▼──────────────────────────────────────────────────────┐ │ AI 应用服务 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │版本 A │ │版本 B │ │版本 C │ │对照组 │ │ │ │(控制组) │ │(实验组1) │ │(实验组2) │ │(基线) │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ └───────┬──────────────────────────────────────────────────────┘ │ ┌───────▼──────────────────────────────────────────────────────┐ │ 评估与采集 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │在线指标 │ │离线评估 │ │人工标注 │ │用户反馈 │ │ │ │(埋点) │ │(数据集) │ │(众包) │ │(点赞/踩) │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ └──────────────────────────┬───────────────────────────────────┘ │ ┌──────────────────────────▼───────────────────────────────────┐ │ 统计分析 │ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐ │ │ │显著性检验│ │效应量计算│ │置信区间 │ │决策建议 │ │ │ └──────────┘ └──────────┘ └──────────┘ └──────────┘ │ └──────────────────────────────────────────────────────────────┘四、核心数据结构// experiment/types.go package experiment import ( time crypto/md5 encoding/binary ) // ─── 实验定义 ─── // Experiment 实验 type Experiment struct { ID string json:id Name string json:name Description string json:description Status ExperimentStatus json:status Layer string json:layer // 分层标识 CreatedAt time.Time json:created_at StartedAt *time.Time json:started_at EndedAt *time.Time json:ended_at Variants []Variant json:variants // 变体列表 Traffic TrafficConfig json:traffic // 流量配置 Metrics []MetricDef json:metrics // 指标定义 Criteria DecisionCriteria json:criteria // 决策标准 } type ExperimentStatus string const ( StatusDraft ExperimentStatus draft StatusRunning ExperimentStatus running StatusPaused ExperimentStatus paused StatusCompleted ExperimentStatus completed StatusRolledOut ExperimentStatus rolled_out ) // Variant 实验变体 type Variant struct { ID string json:id // A, B, C... Name string json:name // control, treatment_v1... Weight int json:weight // 权重百分比 (0-100) IsControl bool json:is_control // 是否为对照组 // 变体配置具体内容取决于实验类型 Config map[string]interface{} json:config } // TrafficConfig 流量配置 type TrafficConfig struct { TotalPercent int json:total_percent // 参与实验的总流量百分比 PerLayer int json:per_layer // 每层可用的流量百分比 } // MetricDef 指标定义 type MetricDef struct { Key string json:key Name string json:name Type MetricType json:type Direction MetricDir json:direction // higher_is_better / lower_is_better Aggregation string json:aggregation // avg, p50, p95, p99, rate } type MetricType string const ( MetricCounter MetricType counter // 计数 MetricTimer MetricType timer // 耗时 MetricGauge MetricType gauge // 瞬时值 MetricRatio MetricType ratio // 比率 MetricScore MetricType score // 评分 (0-1) ) type MetricDir string const ( HigherIsBetter MetricDir higher_is_better LowerIsBetter MetricDir lower_is_better ) // DecisionCriteria 决策标准 type DecisionCriteria struct { SignificanceLevel float64 json:significance_level // 显著性水平 (默认 0.05) MinEffectSize float64 json:min_effect_size // 最小效应量 MinSampleSize int json:min_sample_size // 最小样本量 RunDurationMin int json:run_duration_min // 最短运行天数 } // ─── 分流 ─── // TrafficSplitter 流量分配器 type TrafficSplitter struct { experiments []*Experiment } // AssignResult 分配结果 type AssignResult struct { ExperimentID string VariantID string IsInExperiment bool } // Assign 为用户分配实验变体 func (ts *TrafficSplitter) Assign(userID string, layer string) []AssignResult { var results []AssignResult for _, exp : range ts.experiments { if exp.Status ! StatusRunning || exp.Layer ! layer { continue } // 1. 判断用户是否在实验流量内 hash : hashUser(userID, exp.ID) totalWeight : sumWeights(exp.Variants) // 取模判断是否命中实验 if hash%100 exp.Traffic.TotalPercent { continue } // 2. 分配变体 bucket : hash % uint32(totalWeight) variantID : selectVariant(exp.Variants, bucket) results append(results, AssignResult{ ExperimentID: exp.ID, VariantID: variantID, IsInExperiment: true, }) } return results } // hashUser 一致性哈希保证同一用户始终进入同一变体 func hashUser(userID string, salt string) uint32 { h : md5.New() h.Write([]byte(userID : salt)) return binary.BigEndian.Uint32(h.Sum(nil)[:4]) } func sumWeights(variants []Variant) int { total : 0 for _, v : range variants { total v.Weight } return total } func selectVariant(variants []Variant, bucket uint32) string { cumulative : 0 for _, v : range variants { cumulative v.Weight if bucket uint32(cumulative) { return v.ID } } return variants[len(variants)-1].ID } // ─── 指标采集 ─── // MetricEvent 指标事件 type MetricEvent struct { Timestamp time.Time json:timestamp UserID string json:user_id SessionID string json:session_id ExperimentID string json:experiment_id VariantID string json:variant_id MetricKey string json:metric_key Value float64 json:value Tags map[string]string json:tags,omitempty } // MetricCollector 指标采集器 type MetricCollector struct { buffer []MetricEvent } func (mc *MetricCollector) Record(event MetricEvent) { mc.buffer append(mc.buffer, event) } func (mc *MetricCollector) Flush() []MetricEvent { events : mc.buffer mc.buffer nil return events }五、分层分流策略// experiment/layering.go package experiment // LayerManager 分层管理器 type LayerManager struct { layers map[string]*Layer } type Layer struct { Name string Priority int Experiments []*Experiment Mutex bool // 互斥同层实验不能同时运行 } // 分层设计 // // Layer 1: 模型层 (互斥) // ├── Experiment: GPT-4 vs Claude 3 // └── Experiment: temperature0.7 vs 1.0 // // Layer 2: Prompt 层 // ├── Experiment: system prompt 风格 // └── Experiment: few-shot 数量 // // Layer 3: RAG 层 // ├── Experiment: 切片策略 // └── Experiment: Top-K 数量 // // Layer 4: UI 层 // ├── Experiment: 展示格式 // └── Experiment: 按钮文案 // 分层原则 // 1. 正交层之间可以并行实验用户同时参与多个层的实验 // 2. 互斥层内的实验不能同时运行避免相互干扰 // 3. 每层独立分配流量各层使用不同的盐值哈希六、在线指标设计// experiment/metrics.go package experiment // ─── AI 应用专用指标 ─── // AIMetrics AI 应用指标集合 type AIMetrics struct { // 质量指标 RelevanceScore float64 // 相关性评分 (0-1) AccuracyScore float64 // 准确性评分 (0-1) CompletenessScore float64 // 完整性评分 (0-1) HallucinationRate float64 // 幻觉率 // 体验指标 FirstTokenLatency float64 // 首 token 延迟 (ms) TotalLatency float64 // 总响应时间 (ms) TokenPerSecond float64 // 生成速度 StreamInterruptRate float64 // 流中断率 // 业务指标 TaskCompletionRate float64 // 任务完成率 UserSatisfaction float64 // 用户满意度 (1-5) ConversionRate float64 // 转化率 RetentionRate float64 // 次日留存 // 成本指标 TokenCost float64 // Token 消耗成本 ($) APICallCount int64 // API 调用次数 CacheHitRate float64 // 缓存命中率 } // ─── 离线评估指标 ─── // OfflineEvaluation 离线评估结果 type OfflineEvaluation struct { DatasetName string SampleCount int // 自动评估 BleuScore float64 RougeScore float64 BertScore float64 SemanticSim float64 // LLM-as-Judge LLMJudgeScore float64 Consistency float64 // 人工评估 HumanAccuracy float64 HumanPreference float64 // 偏好比例 }七、完整实验流程阶段 1: 假设提出 ├── 定义要验证的问题 ├── 提出改进假设 └── 设定成功标准 阶段 2: 实验设计 ├── 确定变量和变体 ├── 选择分层和流量比例 ├── 配置指标和采集点 └── 计算所需样本量 阶段 3: 离线验证 ├── 准备测试数据集 ├── 运行离线评估 └── 确认无明显退化 阶段 4: 小流量上线 ├── 1% 流量灰度观察 ├── 监控异常指标 └── 确认系统稳定 阶段 5: 正式实验 ├── 按计划分配流量 ├── 持续采集指标 └── 监控实验健康度 阶段 6: 统计分析 ├── 检查样本量充足性 ├── 运行显著性检验 ├── 计算效应量和置信区间 └── 考虑多重比较校正 阶段 7: 决策与行动 ├── 显著正向 → 全量发布 ├── 显著负向 → 终止实验 ├── 不显著 → 延长/终止/重新设计 └── 记录实验结论八、本讲坑位#坑位现象解决方案1Novelty Effect新版本刚上线效果好随时间衰减实验至少运行 1-2 个完整周期2Carryover Effect用户在不同实验间交叉污染使用用户级哈希同一用户固定变体3Interference不同层的实验互相影响结果严格分层隔离互斥层加锁4Sample Ratio Mismatch实际分流比例偏离预期检查哈希算法和分流逻辑5Peeking Problem提前看结果导致误判预设最小样本量禁止中途查看6多重比较陷阱同时测 20 个指标总有显著的Bonferroni 校正 / FDR 控制九、本讲小结┌─────────────────────────────────────────────────────────────┐ │ 第1讲 核心收获 │ │ │ │ ✅ 理解了 AI A/B 测试与传统 A/B 测试的核心区别 │ │ ✅ 明确了 AI 应用中 6 大可测层次 │ │ ✅ 掌握了实验系统的核心数据结构实验/变体/指标/决策标准 │ │ ✅ 实现了用户级一致性哈希分流 │ │ ✅ 理解了分层分流策略的设计原则 │ │ ✅ 了解了 AI 专用的在线/离线指标体系 │ │ ✅ 掌握了完整的 7 阶段实验流程 │ │ ✅ 知道了 6 个常见坑位及其应对方案 │ │ │ │ 核心理念没有评估就没有优化没有实验就没有进步 │ └─────────────────────────────────────────────────────────────┘下一讲预告《分流系统——如何精准地把用户分到不同的实验组》深入实现哈希分流、分层隔离、流量染色、实时配置下发以及如何处理用户粘性和实验组均衡性问题。
阅读完成 · 觉得有帮助?