1. 为什么一个杀熟案例值得AI工程师反复琢磨我在算法团队做过几年推荐和定价相关的事情最怕的不是模型跑不动而是某天运营群里甩来一张截图两台手机、同一个收货地址、同一家店、同一份餐一个显示28.5元一个显示21元。然后有人全体成员问一句这是怎么回事。那一刻你会发现所有的离线指标、AUC、召回率、GMV提升曲线在这张截图面前都没有说服力。这就是大数据杀熟这四个字为什么总能引爆舆论的原因。它不是一个纯技术问题也不是一个纯商业问题而是人工智能、大数据与工程伦理三者交汇处最典型的一个断面。外卖平台是这个议题被讨论得最多的场景因为它高频、刚需、价格构成复杂商品价、包装费、配送费、红包、满减、会员权益混在一起用户又很难横向比价。对于做算法、做数据、做产品的同学来说这个案例的价值在于它把我的模型选择和别人多付了几块钱之间的因果链条第一次拉得足够短、足够清晰。这篇东西主要写给三类人。一类是在校学生尤其是做人工智能大作业、大数据毕设、准备人工智能导论课程论文的同学你们需要一个能撑起论证深度的真实案例而不是空谈AI要讲道德。第二类是刚入行的算法、数据、产品岗从业者你们需要一套能落地的方法把伦理审查嵌进日常研发流程而不是等出事了再写检讨。第三类是做技术管理的人你们需要在需求评审会上有底气问出几个关键问题。我会尽量避开两种写法一种是把伦理写成口号满篇应当必须另一种是把技术写成挡箭牌说模型自己学出来的我也控制不了。前者没用后者不负责任。1.1 先分清现象层、算法层和责任层讨论这个问题最容易犯的错误是把三个层次混成一锅粥。现象层说的是用户看到的结果同样的服务不同的人付不同的钱而且这个差异和成本无关、和用户身份有关。用户感知到的被针对就发生在这个层次。算法层说的是这个结果是怎么产生的它通常不是某一个模型单独决定的而是用户画像、价格敏感度预测、优惠券分配策略、运筹优化求解器、A/B实验平台这一整条链路协同的产物。你很难指着某一行代码说就是它杀的熟。责任层说的是谁该为这个结果负责是写特征工程的工程师是设定目标函数的产品经理是批准上线的业务负责人还是设计实验方案的算法科学家这个问题不解决伦理讨论就会变成互相甩锅。把这三层拆开之后你会发现工程伦理介入口其实在中间那一层。因为现象层是结果责任层是事后追认只有算法层是工程师真正有权限、有能力做出不同选择的地方。特征选不选历史客单价目标函数里加不加老用户价格保护约束实验分组怎么设计这些都发生在键盘前面。1.2 这个案例的三处不适感从哪来为什么同样是差别定价机票淡旺季浮动大家能接受外卖的差异化定价却让人愤怒我琢磨了很久觉得有三处结构性的不适感。第一处是信息不对称的方向反了。机票涨价是公开的、可预期的、和你的身份无关你可以提前买、可以换航班。而外卖的差异化定价对用户是黑箱你不知道自己是不是被分到了高支付意愿那一组也不知道换个账号会不会更便宜。当信息优势完全落在平台一侧用户的第一反应必然是不信任。第二处是关系的不对等被放大了。老用户之所以是老用户是因为信任和习惯这在很多商业逻辑里会被视为忠诚度资产。但如果模型把忠诚度高翻译成价格敏感度低进而翻译成可以少给优惠那忠诚就变成了被惩罚的理由。用户能隐约感觉到这个转换虽然他说不出价格弹性这个词。第三处是生活场景的脆弱性。点外卖这件事实在太日常了它不像买机票那样是一个决策事件而是肌肉记忆。在肌肉记忆的领域里被算法悄悄区别对待那种不适感会直接转化为道德判断。理解了这三处不适感你就能明白为什么这个案例在课堂上、在面试里、在技术社区里被反复提起。它是一个绝佳的载体让人工智能偏见这个抽象概念落到了一份麻辣烫的价格上。2. 大数据杀熟到底是怎么被算出来的外行看这件事容易想象成程序员写了个if语句是老用户就加价。真做这行的人都知道没人会这么写。真实的链路要文明得多也隐蔽得多。这一章我把技术路径拆开讲因为不理解技术伦理讨论就只能停留在表层。2.1 用户画像与价格敏感度分层是地基任何差异化定价策略的第一步都是把用户分群。这一步在技术上叫用户分层在商业上叫精细化运营在舆论里叫贴标签。常用的特征大概能分成几类。交易类特征包括历史客单价、月下单频次、优惠券使用率、退款率、加购未支付次数。行为类特征包括比价行为是否频繁来回切换商家、点击深度、浏览时段、对配送费变动的反应速度。账户类特征包括注册时长、会员状态、支付方式绑定情况、设备型号和系统版本。把这些特征喂给一个模型预测目标通常是用户对价格的敏感程度也就是价格弹性。弹性的定义不难价格变动1%需求量变动多少百分比。弹性绝对值大说明这个人一贵就跑叫高弹性弹性绝对值小说明贵一点他照样买叫低弹性。生活化的类比就是菜市场。老练的摊主看人报价看的是你问价的语气、犹豫的时间、有没有转身要走。算法做的事情本质上一样只不过它用的是几百个维度的特征而且永不疲倦、永远一致、可复制到每一单。这就是大数据三个字在这件事里的分量不是数据本身有恶意而是数据的密度让看人下菜碟这件事第一次具备了工业级的可执行性。提示价格弹性不是一个固定值它是随场景、时段、品类变化的。同一用户在深夜点夜宵时的弹性可能远低于中午点工作餐时的弹性。2.2 三种典型技术路径风险等级完全不同业内讨论这个话题时经常笼统地说差异化定价但不同实现方式的性质差异很大。我按自己的经验整理成一张表。实现路径技术做法用户可感知度可解释性伦理风险差异化优惠券投放对高弹性用户多发券低弹性用户少发或不发中等较高券是显性的中差异化配送费/动态加价按时段、运力、区域动态调整配送费高明码显示高可归因到供需较低个性化展示价同一商品对不同用户展示不同基础价低最隐蔽低难以归因高第一类路径最常见也最有争议空间。因为发券本身是给好处问题在于给谁不给谁。如果模型系统性地让老用户拿到更少的券那在用户视角里就是我越忠诚越吃亏。第二类路径反而是这三类里最经得起推敲的。动态配送费可以解释为运力调度手段雨天、高峰期、偏远区域加价目的是引导订单在时间和空间上分散。它符合成本逻辑用户也能理解虽然不爽。第三类路径风险最高。基础商品价对所有人应该是一致的这是用户心理的底线。一旦基础价开始因人而异任何解释都显得苍白因为用户找不到任何和自身付出相关的合理依据。我做过的项目里内部有一条不成文的红线优惠可以个性化标价不能个性化。这条红线不写在任何规范里但它是很多团队能睡得着觉的原因。2.3 一段可复现的弹性建模示例为了让大家看清楚数学上正确和伦理上有问题之间的距离有多近我用一段简化代码演示弹性估计。数据是模拟的逻辑是真的。import numpy as np import pandas as pd import statsmodels.api as sm # 模拟每个用户的订单金额与对应优惠力度 # discount_rate 表示优惠占原价比例price_ratio 1 - discount_rate np.random.seed(42) n 20000 user_price_sensitivity np.random.beta(2, 5, n) # 隐变量越低越不敏感 base_fee np.random.normal(30, 5, n) discount_rate np.random.uniform(0, 0.3, n) price_ratio 1 - discount_rate # 需求量弹性越大的用户涨幅对其需求抑制越明显 qty 10 * price_ratio ** (-user_price_sensitivity * 5) qty np.maximum(qty, 0.1) df pd.DataFrame({ price_ratio: price_ratio, qty: qty, user_id: np.arange(n) }) # 对整体做 log-log 回归回归系数即价格弹性 X sm.add_constant(np.log(df[price_ratio])) y np.log(df[qty]) model sm.OLS(y, X).fit() print(整体价格弹性估计:, model.params[price_ratio]) # 按用户分组估计弹性真实系统里按画像分群 df[group] pd.qcut(user_price_sensitivity, 5, labelsFalse) for g, sub in df.groupby(group): Xg sm.add_constant(np.log(sub[price_ratio])) yg np.log(sub[qty]) m sm.OLS(yg, Xg).fit() print(f第{g}组弹性: {m.params[price_ratio]:.3f})跑完你会发现不同群体的弹性估计值差异明显。一个理性的定价系统拿到这个结果下一步动作几乎是必然的对弹性绝对值小的群体减少补贴对弹性绝对值大的群体加大补贴。从优化目标看这一步完全正确——它让每一块钱补贴都花在最能撬动订单的人身上补贴效率最大化。但从伦理看恰恰是这一步把忠诚和低弹性划了等号让老用户成了被减少补贴的那一批。注意这里的问题不在于模型错了而在于目标函数里只有效率没有公平约束。这是工程师真正能改变的地方后面第5章会讲具体怎么加。3. 工程伦理的几把尺子以及它们各自的盲区聊伦理最怕空对空。我的经验是准备三到四把尺子遇到具体决策时轮着量一遍哪把尺子量出来都不舒服那就该停下来重新设计了。这一章我把最常用的几把尺子讲清楚同时说明它们各自在什么情况下会失灵。3.1 后果论算总福利但算不出谁在承担代价后果论的核心思路是看结果一个决策让总体福利增加了还是减少了。放到差异化定价上支持方的论证通常是补贴总额固定把补贴给更需要的价格敏感人群能带来更多订单平台、商家、骑手、用户的总福利都上升。这个论证在数学上成立。问题在于它只关心总量不关心分布。如果总福利上升100但代价是让1000万老用户每人多付2块钱后果论本身没有给出这能不能接受的答案。它只是把问题转化成了这100和那1000万怎么折算而折算规则是人定的不是算出来的。所以后果论有用但只能当第一把尺子。它帮你确认这事确实有效率收益但不能帮你确认这收益值得拿。我见过太多团队止步于此拿一份GMV提升报告就去上线了。3.2 义务论与知情同意用户到底同意了什么义务论关心的是行为本身是否违反了某种义务不管结果好坏。在数据伦理里它最常落到的落点是知情同意。用户注册时勾选的那份用户协议通常包含我们可能根据您的使用情况提供个性化服务这类表述。这句话覆盖的范围很宽但它能不能覆盖对同一种商品向你展示不同价格我的判断是在绝大多数情况下不能。因为用户在勾选时脑子里想的是推荐更合口味的店不是我可能因为这个勾选而多付钱。知情同意要成立有三个条件知道、理解、自愿。协议文本做到了知道虽然没人读做不到理解至于自愿就更勉强了——在一个已经高度依赖外卖的生活节奏里不同意就别用算不算自愿是很难回答的问题。做工程的人从中能得到一条非常具体的启发个性化推荐和个性化定价应该分开授权。前者风险低可以用默认开启加显式说明后者风险高应该有独立、清晰、可撤回的开关。我不能说现在的产品都做到了这一点但这个方向是对的。3.3 美德伦理与工程师的职业责任前面两把尺子都在看外部第三把尺子看内部作为一个手艺人你愿不愿意公开说明你做了什么。这条自测标准非常锋利。设想你要在技术评审会上用十分钟向一群非技术同事解释你设计的定价逻辑你用了哪些特征、目标函数是什么、约束条件是什么、实验是怎么分组的。如果这个过程中有几处你会下意识地含糊过去那么这几处就是问题所在。我在团队里推过一个很土的办法叫家属测试假设你爸妈用的就是这个产品你能不能坦然告诉他们您的价格是按这个规则算出来的。这个测试不能替代正式的伦理审查但它能在五秒钟内告诉你自己心里有没有数。3.4 价值敏感设计把伦理从事后审查挪到事前设计上面三把尺子都是判断工具价值敏感设计Value Sensitive Design则是流程工具。它的核心主张是伦理价值不应该等产品做完了再评估而应该在概念设计阶段就被当作设计需求之一和性能、成本、工期并列。具体到外卖定价场景这意味着公平不是一句口号而是要翻译成可测量的设计指标。比如老用户与新用户在同一条件下的价格差异不超过某个阈值同一城市同一时段内同类商品的展示价方差控制在某个范围内补贴覆盖率的基尼系数不高于某个值。一旦翻译成指标它就能进实验平台、进监控大盘、进上线卡点。这才是工程师能真正使上劲的地方。伦理一旦能被度量它就从理念变成了工程约束。4. 边界在哪个性化服务、差异化定价与杀熟的三方关系讨论到这一步必须处理一个绕不开的问题个性化服务和差异化定价本身不是坏事那杀熟的边界到底在哪如果答案模糊所有讨论都会变成站队。4.1 用四个维度把三个概念切开我的经验是用四个维度做判定定价依据、信息透明度、用户选择权、代价归属。做成一张对照表会清晰很多。维度合理的个性化服务合理的差异化定价大数据杀熟定价依据口味偏好、配送时间偏好供需关系、运力成本、时段用户身份、忠诚度、支付意愿信息透明度推荐理由可见价格规则公开可查规则不公开用户无法归因用户选择权可关闭、可调整可选择时段、可换渠道无实质退出选项代价归属平台承担让利需求方承担但可预期忠诚用户承担且不可预期这张表最好用的地方是第四行。代价由谁承担、承担者能不能预期这是最锋利的一刀。高峰期配送费上涨代价由需求方承担但用户能预期、能选择避开而杀熟的代价由最信任平台的那批用户承担且他们完全无法预期。4.2 五个可以在评审会上直接问的问题我把这套判断压缩成五个问题用起来比表格快。这个价格差异能不能用成本差异解释清楚如果解释不了差异的依据是什么用户如果知道自己被分到了哪一组会不会觉得受骗用户有没有一个现实可操作的方式避免支付这个差异如果这个策略被完整公开在首页上业务还做得下去吗承担这个差异的是新用户、随机用户还是最忠诚的那批用户这五个问题里第五个最有杀伤力。很多方案在1到4上都勉强能自圆其说一到第5个就露馅了。4.3 为什么这件事特别容易误判需要说明的是舆论里被指认为杀熟的案例有一部分其实是误判。我见过几种常见的混淆源。第一种是优惠券的随机发放。平台做A/B实验时会给不同用户发不同面额的券这在统计上看起来就是同物不同价但它的目的不是收割而是测试。这种方案在合规和伦理上的问题在于测试期没有向用户说明差异性且测试结束后的策略选择可能被最优转化这个单一指标绑架。第二种是缓存与时效差异。同一个商品在不同时间点被加载商家可能刚好调价或者满减活动刚好切换。用户截图时间差了几分钟结果看起来像杀熟。第三种是会员权益的叠加逻辑。会员费和权益是两笔账当权益计算方式复杂到用户算不清时用户会默认自己吃亏。这是表达问题不是定价问题但杀伤力一样大。区分这三类对工程师有实际意义前两类需要在产品层面做说明和补偿第三类需要把权益计算做成一张用户能看懂的账单。我个人的看法是可解释性本身就应该是一项产品需求而不是等出了舆情再补的公关材料。5. 把伦理审查嵌进研发流程的落地方案前面几章都在讲判断这一章讲操作。我按研发流程的时间顺序走一遍每一步给出可以直接抄的清单、脚本或指标。这部分是我认为最有价值的部分因为它把伦理从讨论变成了工序。5.1 需求评审阶段一份十问清单需求评审是成本最低的拦截点。一个方案在这个阶段被拦下损失几乎为零上线后再回滚损失的是用户信任。我在团队里推过一份十问清单评审定价类需求时必须逐条回答。这个策略的收益来自哪里是新增订单还是存量订单的价格提升价格差异的判定依据里有没有包含用户身份、注册时长、会员状态这类非成本特征是否设置了价格差异上限上限是怎么算出来的老用户和新用户在同一条件下的价格是否存在系统性差异实验组和对照组的分组方式是什么会不会导致特定群体长期处在被测试状态用户能否感知到这个差异如果感知到我们的解释是什么有没有一个用户可以实际操作的退出路径策略的监控指标里除了转化率有没有价格公平类指标一旦出现舆情或投诉回滚方案是什么回滚需要多长时间这套逻辑如果被完整公开我们的对外说明会怎么写最后一条是压力测试。如果第10条写不出来或者写出来自己都觉得牵强那这个方案就不该往前走。5.2 开发阶段可解释性埋点和约束条件到了写代码这一步有两件事必须做进系统。第一件是可解释性埋点。每一次价格计算都要把为什么是这个价记录下来命中了哪些特征、折扣是怎么来的、被哪些规则调整过。这些日志平时没人看出事的时候就是唯一的证据链。没有它你既证明不了自己清白也发现不了自己的问题。第二件是把公平写成约束条件。这是本文最想传递的一条操作建议。原来的优化目标可能是maximize 总订单量 - λ * 补贴总额加上公平约束后变成maximize 总订单量 - λ * 补贴总额 subject to 同一条件下老用户价格 ≤ 新用户价格 * (1 ε) 同类商品展示价方差 ≤ σ² 补贴覆盖率的基尼系数 ≤ Gε、σ²、G 这三个参数就是伦理讨论最终的落点。它们不该由算法同学单独拍而应该由产品、法务、数据和业务共同确定并且写进文档。参数一旦确定它就变成了一个普通的工程约束可以测试、可以监控、可以回归。我在实际项目里的体会是把伦理翻译成参数这件事比开十次伦理研讨会都有用。5.3 上线前价格一致性回归测试脚本上线前一定要跑一遍跨账号、跨设备、跨地域的价格一致性测试。这类测试的价值在于它能把我们觉得没问题变成我们测过没问题。import time import statistics import requests BASE_URL https://example-api.internal/price/quote def fetch_price(token, store_id, item_id, address_id): headers {Authorization: fBearer {token}} params { store_id: store_id, item_id: item_id, address_id: address_id, } resp requests.get(BASE_URL, headersheaders, paramsparams, timeout5) resp.raise_for_status() data resp.json() return { base: data[base_price], delivery: data[delivery_fee], final: data[final_price], coupon: data.get(coupon_amount, 0), } def audit(tokens, store_id, item_id, address_id, rounds5): results {} for round_idx in range(rounds): for name, token in tokens.items(): results.setdefault(name, []).append( fetch_price(token, store_id, item_id, address_id) ) time.sleep(2) # 避开瞬时波动也降低对线上接口的压力 print(f{账号:12}{平均终价:10}{基础价:10}{配送费:10}{券:8}) base_prices [] final_prices [] for name, rows in results.items(): avg_final statistics.mean(r[final] for r in rows) avg_base statistics.mean(r[base] for r in rows) avg_delivery statistics.mean(r[delivery] for r in rows) avg_coupon statistics.mean(r[coupon] for r in rows) base_prices.append(avg_base) final_prices.append(avg_final) print(f{name:12}{avg_final:10.2f}{avg_base:10.2f} f{avg_delivery:10.2f}{avg_coupon:8.2f}) # 基础价必须完全一致这是红线 if max(base_prices) - min(base_prices) 0.01: raise AssertionError( f基础价不一致极差 {max(base_prices) - min(base_prices):.2f} f这属于标价个性化必须阻断上线 ) # 终价允许有差异来自券但差异要有上限 spread max(final_prices) - min(final_prices) if spread 8: print(f警告终价极差 {spread:.2f}超过预设阈值 8 元需人工复核) return results if __name__ __main__: tokens { 新用户A: token_new_a, 老用户B: token_old_b, 老用户C: token_old_c, 会员D: token_vip_d, } audit(tokens, store_id10086, item_id555, address_id999)这段脚本的核心设计思路是把红线和不红线分开测。基础价必须完全一致这是零容忍项一旦超出直接阻断终价允许因券而不同但要有极差阈值超出就报警让人看。这样既不会因为正常的营销差异频繁误报也不会漏掉真正的问题。5.4 上线后监控指标与熔断机制上线不是终点。我的经验是至少要盯三组指标。第一组是价格公平指标同一条件下跨用户群的终价极差、老用户与新用户的平均价格比、补贴覆盖率的基尼系数。这三个指标画成时间序列一旦出现趋势性偏移就要查。第二组是用户感知指标关于价格的客诉量、客服话术中为什么我和朋友价格不一样的命中次数、退款申请中的价格相关理由占比。这组指标是前哨比舆情早得多。第三组是策略漂移指标模型的特征重要性排序变化、被高频命中的特征列表变化。因为有很多问题是模型在持续训练中慢慢学坏的——初始版本可能是干净的跑三个月之后它自己发现了注册时长这个强特征然后系统性地开始区别对待。这种漂移最危险因为它没有责任人只有时间。熔断机制也简单价格公平指标一旦越过阈值自动把定价策略降级到统一券池模式也就是所有人发同样的券先止血再排查。6. 常见问题与排查技巧实录这一章整理我在实际工作中遇到和听说过的典型问题。表格形式方便速查。现象常见原因排查思路处理建议老用户价格系统性偏高模型学到了注册时长作为低弹性代理特征导出特征重要性看是否含身份类特征从特征集中移除身份代理特征或加入公平约束同一时刻不同账号基础价不同缓存不一致或灰度配置错乱对比不同节点返回、检查灰度规则基础价走统一配置源禁止个性化券面额差异过大实验分组不均或策略过激检查各组样本量和券额分布设置券额极差上限实验期同步白名单用户投诉变多但数据看着没问题权益账单不可读让客服复现用户视角的完整价格构成把价格构成做成可读账单主动展示模型上线后逐步变坏策略漂移定期回归价格一致性测试建立月度审计机制纳入上线流程舆情爆发但定位不到逻辑缺少价格计算日志查埋点覆盖情况补全可解释性埋点作为长期基建除了表格还有几个我踩过的坑值得单独说。第一个坑以为公平约束会拖垮效果。我一开始也担心加约束会让优化效果大幅下降实际测下来把价格差异上限设在一个合理区间对总订单量的影响通常在1%到3%之间而客诉和退款率的改善会明显得多。这笔账长期看是划算的只是短期KPI不好看。第二个坑把告知做成了免责。有一阵子我们在用户协议里加了一段关于个性化定价的说明写得非常专业结果是没人看而且投诉的时候用户会说你们就是靠这个免责的。后来改成了在订单页用一句话说明本单优惠由系统按活动规则发放效果反而好一些。告知的关键不是法律上站得住而是用户能看懂。第三个坑指标定义本身有争议。我们内部一开始用平均价格做公平监控后来发现平均值会掩盖结构性问题——如果只有10%的用户价格明显偏高平均值看不出来。后来改成同时看均值、极差和分位数才算能抓住问题。第四个坑跨部门的分歧无法用数据解决。有些争论本质上是价值判断不是技术判断。比如老用户价格比新用户高多少算过分这个问题没有唯一答案。我的经验是把这类分歧摆到台面上让业务负责人拍板并留下文档记录而不是让算法同学自己背着。留痕这件事在事后非常重要它保护的是做技术的人。7. 踩过坑之后我的几点体会做这行时间长了我对人工智能伦理这个说法的理解一直在变。刚入行时觉得它是务虚的是给论文和会议准备的做过几个真实项目之后我越来越觉得它是这行最难、也最见功力的一部分。因为技术问题有标准答案伦理问题没有。我现在比较确信的一点是伦理问题的落点永远在具体参数上。不是要公平而是老用户价格不得超过新用户价格的1.05倍不是要透明而是订单页必须能展开看到价格构成的每一行。凡是不能落到参数和界面上的伦理讨论最后都会变成会议纪要里的一段漂亮话。第二点是工程师在这件事上的处境其实比想象中主动。很多人觉得这是老板定的我只是执行。但实际操作中特征怎么选、约束怎么加、日志怎么埋、测试怎么写这些决定权确实在工程师手上。把身份类特征从模型里拿掉把公平约束加进目标函数把价格一致性测试接进发布流水线这些事情不需要谁批准就能做。真做了之后你才有资格在更上游的决策里说话。第三点是关于表达。很多价格争议之所以升级不是因为定价本身有多离谱而是因为用户看不懂、问不到、找不着人解释。把价格构成做得让一个普通人三十秒内看明白这件事的技术难度远低于模型调优但对信任的价值高出很多。我甚至觉得可解释性的投入产出比在这类产品里被严重低估了。至于这个案例本身我把它当作一面镜子。每次做定价、推荐、风控相关的项目我都会拿那五个问题自问一遍成本能不能解释、用户知道后会不会觉得受骗、有没有退出路径、敢不敢公开、承担代价的是不是最信任平台的那批人。这五个问题不能让我做出正确的决定但至少能让我在做决定之前清楚自己在做什么。如果你正在写相关的课程论文或者人工智能大作业我的建议是不要停在应该加强监管这种结论上。往下一层去写清楚算法链路是怎么形成价格差异的去给出一个可以量化的公平约束去设计一个能跑的审计脚本。把伦理问题写成工程问题这篇东西才算有分量。