ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

算法与基础设施协同实战:从特征一致性到模型稳定上线

算法与基础设施协同实战:从特征一致性到模型稳定上线 先从一个上线事故说起。去年我们算法团队优化了一版用户意图识别模型离线AUC在验证集上比旧模型高出一截领导已经准备好宣传稿了。结果灰度三天线上核心指标纹丝不动数据一对比还略降。排查了两周最终定位到一个特别尴尬的原因问题根本不在模型而在特征——离线训练时用的用户行为序列和线上实时拼接出来的特征在排序规则和截断长度上不一致。模型再强吃进去的东西变了效果自然垮掉。这个案例特别典型也是我觉得聊“算法-infra协同”最好的一个入口。很多人以为算法工程师的工作在模型训练完就结束了实际上真正的挑战才刚刚开始。“算法-infra协同”说白了就是算法侧的模型逻辑、特征逻辑、实验逻辑和基础设施侧的数据管道、调度、推理服务、监控告警之间如何定接口、定边界、定流程让整个系统稳定高效地跑起来。这篇文章面向正在做算法系统落地的工程师或者准备从纯算法转向工程化的朋友把我这几年的经验做一个系统梳理。1. 算法-infra协同到底在协同什么1.1 算法交付的不是模型而是一套系统我在刚带项目的时候也有过“模型交出去就完事”的心态。后来被现实教育了模型文件只是整个算法系统里很小的一块。数据管道要持续产出训练样本特征服务要保证离线和在线吃到的东西一模一样的推理服务要扛住峰值流量监控要能及时发现模型打分异常。你训练一个模型可能只需要一周但把它做成一个稳定、可回滚、可观测的线上能力至少要几倍的精力。所以在聊协同之前先把认知对齐算法工程师在工业界不是“写模型”的而是“交付决策能力”的。这个能力的载体是系统模型只是系统里的一张“配方”。配方再好厨房不行、供应链不行、出菜流程不行顾客吃到的依然不是好东西。infra就是这个厨房和供应链。1.2 算法和infra的边界在哪里边界的画法每个团队不完全一样但大体上可以分成三层层面算法负责infra负责需要协同的部分数据层定义特征、设计样本、评估数据质量采集、清洗、存储、调度数据管道特征一致性、数据时效性、样本版本实验层设计实验假设、选择指标、分析结果分流服务、指标计算、报表可视化分流策略、指标口径、实验周期推理层模型结构、推理逻辑、性能预算服务框架、资源隔离、监控告警模型发布、降级策略、延迟与吞吐折中一句话总结算法对结果负责infra对过程负责。但这个切分不能太机械因为线上故障绝大多数发生在边界接缝处。最常见的例子是离线训练得很好的模型一上线效果就崩算法说是infra特征给得不对infra说是算法特征定义没说清楚。两边都委屈但问题本质是“边界上没有契约”。1.3 为什么这个词这两年特别热算法-infra协同不是新概念但这两年特别被频繁提起我理解有三个现实原因。第一模型复杂度上来了。早年间用LR、GBDT这类模型单机就能搞定训练和预测算法工程师自己写个服务也能跑。现在深度学习、大模型、多模态模型动辄需要分布式训练、GPU集群、专门的推理引擎个人英雄主义玩不转了。第二数据时效性要求上来了。以前离线跑天级任务就能接受现在做个性化推荐、实时风控、智能营销特征延迟十几分钟效果就会打折扣。离线和在线的数据管道必须深度协同不是简单跑个脚本的事。第三算法岗位数量上来了。大量算法工程师进入工业界后才发现面试时考的排序算法、数据结构与算法、算法设计与分析和实际干活时的难点不太一样。真正的难点不是设计一个精妙的A*算法或者贪心策略而是怎么让你设计的算法在别人的基础设施上稳定运行。2. 关键接口怎么设计特征、实验、调度三张牌2.1 特征层的协同同一份逻辑两条链路特征层是算法-infra协同里最容易出问题的地方也是我吃过亏最多的地方。核心矛盾在于离线训练和在线推理本质上是两条独立的链路但必须产出语义完全一致的特征。离线通常用Spark、Hive做大规模批量计算在线则是通过Flink、Redis、远程调用做实时拼接技术栈完全不同稍有不慎就对不上。解决思路的关键是“定义统一”。我们现在的做法是特征逻辑用一套配置文件描述包括特征来源、聚合方式、窗口大小、截断规则、默认值离线任务和在线服务都从这份配置生成代码。以用户行为序列为例大家约定按时间倒序截取最近50条超过50条的扔掉不足50条的用固定值补齐。这个规则看似简单但如果不统一到一个配置里离线同学按小时窗口聚合在线同学按“最近50条”截断两边算出来的特征分布就会漂移。这里我想特别提一个容易被忽略的细节排序稳定性。很多特征依赖排序取topN比如用户最近浏览的10个商品。离线用大数据量外部排序在线可能用一个堆来维护topN如果两种排序算法对相同时间戳的记录不能保证稳定顺序那同一个用户在离线和在线拿到的特征就可能不同。这个坑非常隐蔽性能测试看不出来只有抽样对比特征时才会暴露。所以我的建议是特征定义里明确写上“当排序键相同时按第二个键排序”并且离线在线复用同一套排序逻辑。2.2 实验层的协同不会做AB实验等于白做很多算法团队有一个误区模型效果好就急着全量上线。实际上没有严谨的AB实验你根本分不清线上效果变化到底是模型带来的还是运气带来的。而做好AB实验光靠算法意愿不够需要infra搭好实验平台。实验平台的第一个关键是分流。我们用的是基于一致性哈希的分桶方案用户ID经过哈希后落到固定的桶里同一个用户在同一个实验里永远看到同一种策略。这里有一个深坑哈希因子不能变。如果你今天用user_id哈希明天改成user_iddevice_id哈希所有历史实验数据就全部作废没法做长期跟踪。第二个关键是指标口径。曝光、点击、成交这些指标定义必须前后端完全一致。我们踩过这样的坑算法团队认为点击率的分母是“推荐卡片曝光数”前端埋点统计的却是“页面曝光数”两边数值差距巨大导致实验结论完全不可信。后来我们定了规矩指标口径由算法团队输出文档infra团队负责实现上线前必须用历史数据做口径校验。第三个关键是分层正交。多个实验同时在线时要保证流量在层与层之间均匀打散避免实验之间互相污染。这一块牵涉到实验平台的底层架构算法同学可以不用深究实现但必须理解分层的含义并在实验设计阶段就和infra确认当前平台支持多少层、每层能否独立调流量。2.3 调度层的协同资源分配也是算法策略训练任务和数据任务都是吃资源的。在资源有限的情况下谁先跑、谁能抢占、谁可以等这不是纯infra的事而是需要算法参与决策的。我之前负责过一个推荐项目每天晚上要跑特征任务、训练任务、评估任务高峰期集群资源严重紧张。一开始大家各抢各的导致所有任务都在排队凌晨两点才跑完第二天早上的模型更新直接延误。后来算法和infra一起坐下来梳理每个任务的时间窗口和优先级特征任务最早启动因为它是一切的上游训练任务等特征完成后立刻申请GPU评估任务错峰到训练之后跑不跟特征任务抢CPU。这本质上是一个任务调度问题你可以用贪心策略去做一个粗糙的版本按依赖关系和截止时间排序优先执行关键路径上的任务。但真正上线时比这复杂要考虑数据倾斜导致的长尾任务、资源配额、队列等等。我的经验是算法团队至少要能说清楚每个任务“什么时候必须完成”“最晚能等多久”“缺资源时谁可以被牺牲”infra团队才能制定合理的调度策略。别只说“我要跑任务”要说清优先级和容忍度。3. 从模型到线上服务完整落地的实操记录3.1 先定性能预算再谈模型效果很多算法工程师一上来就追求离线指标提升很少想过线上能不能扛得住。我在项目初期就吃了这个亏。当时为了刷一个点数的AUC模型结构做得特别复杂离线测试效果确实好结果上线前评估发现单次推理需要80毫秒而我们产品要求p99延迟不能超过50毫秒。最后只能压着时间重构模型得不偿失。现在我的做法是在项目启动时就和infra、产品三方一起确定一份性能预算表指标预算值说明p99延迟≤50ms从请求进来响应的最长链路QPS峰值2000大促期间的最大流量单实例内存≤4GB模型文件特征缓存单实例显存≤8GB深度学习模型使用模型文件大小≤500MB影响发布速度和加载时间有了这份预算算法在做模型结构设计时就有了边界不会放飞自我。infra也能根据预算去选机型、定副本数、设计弹性伸缩策略。我特别想强调性能预算不是infra单方面压给算法的而是算法和infra共同商量出来的。算法要说清楚“如果延迟要求放宽50%离线指标能提升多少”infra要说清楚“为了再降20毫秒需要增加多少机器成本”。两边信息对称才能做出对公司最有利的折中。3.2 模型产物与版本管理模型训练完成不等于可以上线。你需要保证这个模型产物可以被追溯、被回滚、被审计。我们现在的做法是每次训练产出一个模型包里面除了模型文件还包含一份元信息清单训练数据版本、特征版本、代码commit号、离线指标、训练耗时、模型大小。这些信息在下发到线上服务时都会被注册到模型仓库里方便随时查看。模型发布流程我们走过不少弯路现在稳定下来的是这样先部署一台新实例加载新模型做CPU/内存/显存的冒烟测试接着切1%的流量做金丝雀验证观察特征覆盖率、打分分布、业务指标确认没问题后灰度到10%、50%最后全量。每一层灰度都有自动回滚机制一旦监控指标超过阈值旧模型自动顶上。有一个细节值得提醒模型文件如果特别大比如几张GB的embedding表发布时加载时间会很长可能在加载期间导致服务不可用。我们遇到过一次新模型发布时内存飙到接近上限触发了OOM实例反复重启。后来infra同学在发布流程里加了一个“预加载原子切换”的机制新模型先加载到一块独立内存区域准备就绪后再把流量指针切过去避免加载过程影响在线服务。3.3 推理服务关键参数与调优笔记在线推理服务的形态差异很大。树模型、逻辑回归这类传统模型用原生服务或者ONNX转换一下就可以深度学习模型通常要走TensorRT、ONNX Runtime这些专门引擎纯规则类的算法比如RETE规则引擎更注重规则的匹配效率。这里我想分享几个通用的性能调优点。第一是batch size的取值。批量推理能显著提升吞吐但会增大单次请求的延迟。我们当时用一个深度学习模型跑YOLO类的检测逻辑单张图片推理10毫秒GPU利用率只有15%。infra同学提出把batch size调到16吞吐立刻上去了GPU利用率到70%但p99延迟也从15毫秒涨到40毫秒。收益和代价都很明显。最后的折中方案是固定batch size为8并设置一个等待窗口允许请求在5毫秒内攒批超时则立即推理。这个逻辑不复杂但必须由算法同学提供延迟和吞吐的权衡曲线infra才能定参数。第二是预测服务的降级策略。模型打分不是永远可信的。当输入特征大量缺失、请求超时、模型服务不可用时必须有一套降级逻辑。我们给推荐系统设计的方案是模型打不出来分的时候用规则策略兜底比如按热度排序、按品类轮播。这套规则我们用了一个简化版的RETE引擎来实现匹配效率不错也方便运营在后台调整。算法和infra在这里的关键协同是算法要明确哪些场景允许降级、降级后可以牺牲多少指标infra要保证降级路径的稳定性和自动触发能力。第三是加密和鉴权的开销。如果算法服务涉及敏感数据通信层要加密。我们有一个风控项目算法同学坚持用国密SM4做数据传输加密理由是合规。这个出发点没问题但SM4在软实现下加解密的开销不小对延迟预算很紧张。后来infra团队在网关层做了硬件加速适配才把加解密时间压下去。这件事的教训是算法工程师选择的加密算法、签名算法不能只看安全强度还要考虑infra侧是否有硬件加速能力、密钥管理是否成熟。AES-CMAC、SM2、SM3、SM4这类算法在TypeScript、Java、C不同语言底座的实现性能差异很大跨团队协同时要提前做压测。3.4 监控预警算法工程师必须看的几个指标很多算法团队上线后只看业务指标比如点击率、转化率这是不够的。你需要监控“模型健康度”也就是模型在当前数据分布下的表现是否还正常。我常用的几组监控指标包括特征覆盖率、特征值分布、打分分布、正负样本比、推理超时率。特征覆盖率特别容易被忽略。有一回我们发现某个新上线的模型对老用户的推荐效果下降查了半天结果是特征服务里一个新增的特征字段在老用户画像里基本为空覆盖率只有20%。模型看到一大片缺失值只能靠默认值硬扛效果自然崩。从那以后我们要求每个模型上线前算法必须列出特征覆盖率的最低要求infra在监控大盘上实时展示低于阈值就告警。另外打分分布的漂移也是一个重要信号。如果今天线上请求的平均打分比昨天高了20%可能不是模型变好了而是特征分布发生了漂移或者线上流量结构变了。算法要定期对比打分分布和离线评估时的分布出现显著差异就要回溯排查。数据反馈闭环也要跟上线上日志回流、样本清洗、增量训练这个闭环跑得越顺畅模型持续迭代的成本越低。4. 高频问题排查与避坑实录4.1 离线在线不一致一套标准的排查路径这是算法-infra协同里发生率最高的问题而且特别浪费人力。我整理了排查路径建议遇到先按顺序来不要靠猜。第一步找一条确定的样本。从线上日志里抽一个真实请求用离线训练时的特征管道对这条请求重新生成特征和线上实际使用的特征做逐字段diff。这里建议做一个自动化的特征对比工具每隔一段时间抽样几条线上数据回放到离线管道里比对而不是等出了问题再翻日志。第二步检查配置版本。最大的概率是线上特征配置和离线特征配置不是同一版。我们有一次是最新的特征配置改了一个字段的截断规则改完后离线代码同步了但线上服务因为没有触发重新加载还在用旧规则。两边特征对不上模型效果自然下降。解决办法就是前面说的统一配置中心配置变更要带版本号服务启动时展示当前使用的配置版本出问题第一时间能对比。第三步盯住边界条件。特征为空、长度为0、时间戳超出窗口、枚举值不再枚举范围这些边界条件最容易导致差异。在线系统里请求到来时如果某个特征源还没准备好通常会用默认值填充离线训练时同样的样本因为数据已经落库默认值逻辑完全不同。这种差异靠人工一轮轮排查效率很低最好是在特征定义里明确规定每个字段的“在线缺失处理规则”并定期用模拟边界样本做回归。排查工具方面有些团队用二分查找定位变更点先对比一周前的特征如果一致说明问题是在最近一周某次变更引入的再对半分时间窗口找。这个方法比肉眼翻代码高效得多。4.2 推理性能瓶颈先定位问题再谈优化推理性能问题最大的忌讳是一上来就优化模型。我见过不少团队的做法线上延迟超标算法同学第一反应是模型剪枝、量化infra同学第一反应是加机器。两边都在努力但都没先搞清楚瓶颈到底在哪。正确的顺序是先做链路耗时分解。把一次请求从进入到返回拆成几个环节网络传输、特征获取、预处理、模型推理、后处理、序列化返回。用RPC链路追踪和火焰图去量每个环节的耗时。我之前遇到一个案例模型推理只占了20毫秒特征服务远程调用占了120毫秒结果大家还都在模型侧做文章怎么优化都超预算。后来把特征调用改成批量接口加本地缓存延迟立刻降到60毫秒以下。真正需要做模型优化时也有一个顺序建议。先从推理框架侧入手比如打开算子融合、调整线程数、开启动态shape优化这些都是“免费午餐”。然后是精度优化比如INT8量化但要提前评估精度损失。有些视觉模型转成TensorRT的FP16后精度损失可以忽略延迟能降一半。最后才是结构性改动比如模型剪枝、蒸馏这些改动大、回归成本高放在最后考虑。模型压缩里的“剪枝”是个热门词但我要提醒一句剪枝算法不是简单的“把不重要的权重置零”它涉及到稀疏计算库是否支持、硬件利用是否高效。如果你们的推理引擎跑稠密算子都很流畅但稀疏支持不完善那剪枝可能反而更慢。算法和infra在性能优化上必须共同验证不能各自闭门造车。4.3 数据延迟与时效性实时特征不等于实时有效实时特征一直是算法系统的重点和难点。所谓实时往往是相对概念。Flink算出来的特征从事件发生到能被模型使用中间有时间差。如果你的模型依赖“用户最近10分钟点击序列”但管道延迟了15分钟那模型看到的其实是过去25分钟的行为效果会发生肉眼可见的下降。应对这个问题的常用方案是“延迟容忍设计”。算法在特征定义里明确每个特征允许的最大延迟比如实时点击序列要求延迟小于5分钟用户画像特征可以接受小时级延迟。infra按这个要求建设管道并给每个特征打上时间戳。模型侧在特征缺失时按“旧但可用”的原则处理而不是直接用默认值可以减少数据延迟带来的扰动。还有一个坑是数据补偿。实时管道偶尔延迟、丢数据事后会做回填补偿。但回填任务必须幂等否则重复执行会把特征值覆盖成错误数据。我们有过一次太惨痛的教训补偿任务重复跑了两遍把用户的历史累计消费金额翻倍了导致推荐结果全面异常排查了整整两天。从此定了一条铁律所有回填任务必须设计成幂等操作。4.4 协作流程上的坑比技术问题更致命技术问题再难总能定位解决。协作流程上的问题才是真正消耗团队信任的。典型场景一infra同学升级了特征服务接口新增了一个必填参数但没同步给算法团队。线上请求全量报错流量直接跌到0。这种问题不怪技术怪变更管理。我们的做法是任何不兼容变更都必须经过评审并且要提供兼容期两套接口并存至少两个版本周期。典型场景二算法改了特征定义但没通知infra刷新缓存。缓存里还是旧特征导致新旧模型混跑时数据口径不一致。现在我们的策略是“配置变更双人复核”一个算法同学提变更一个infra同学负责检查缓存和下游依赖确认无影响才放行。典型场景三模型发布失败的指标口径不统一算法说自己没问题infra说自己也没问题最后发现两边看的监控窗口不同——算法看的是小时级平均infra看的是分钟级峰值。这个最搞笑也最贴近现实。所以我现在强烈建议线上监控大盘必须统一关键指标只看同一个面板、同一个时间窗口避免各说各话。5. 工具选型与协作规范建议5.1 让算法和infra“说同一种语言”的工具把协同落到工具上能省掉大量沟通成本。我按使用频率列几个值得投入的方向。特征平台Feature Store值得优先建设。它解决的就是离线在线特征一致性问题一份特征定义两边共用特征版本化管理追溯方便特征计算逻辑可以复用。小团队可以从轻量方案开始比如用Git管理特征配置配合一个简单的生成工具不用一上来就上重型平台。实验平台是第二个值得投入的。算法能不能快速试错就看实验平台顺不顺手。分流、埋点、指标报表、显著性检验这些能力成熟后算法可以自主完成大部分实验流程不用每次依赖infra手动切流量。再就是模型仓库。模型不是train完就结束了它需要版本、审批、发布、回滚的一整套流程。模型仓库可以串联起算法训练和infra部署让发布过程可追溯。现在很多公司把这个能力做进了MLOps平台但即使没有平台也可以用一套简单的目录结构和版本清单顶一阵子。5.2 流程规范算法和infra各自必须守住的底线工具只是手段流程规范才是协同的骨架。我把这几年沉淀下来的底线写在这里供大家参考。算法侧的底线是可复现、可解释、可回滚。训练用的代码、数据版本、特征版本、超参数全部有记录每个实验有明确的假设和成功指标任何时候模型出现异常都能快速切回上一版。哪怕慢一点也要保证这三点。infra侧的底线是可观测、有SLA、变更可审计。线上系统的状态必须能实时看到每个下游依赖要有明确的SLA承诺任何配置变更要有审计日志。有的infra团队为了敏捷忽略了审计出了问题复盘时连谁改了什么都不知道这种团队很难和算法建立信任。算法和infra共同遵守的底线是契约先行。接口、指标、性能预算、发布流程先定文档再动手写代码。这听起来很“重”但实际做下来文档一次性写清楚比事后反复扯皮成本低得多。契约测试也要加进发布流程比如特征接口的schema校验、模型产物的完整性校验自动化检查能解决大部分人为疏漏。5.3 我个人认为最值得投入的一件事如果你想从这套协同方法论里只挑一件事落地我的建议是把“从数据到上线”的链路图画出来并让算法和infra在这个图上对齐。我在每个项目启动时都会和infra同学坐在一起花半天时间把链路画完数据源有哪些、谁负责采集、清洗后存到哪里、特征在哪一步生成、训练任务怎么调度、模型怎么发布、线上请求怎么走、监控看哪些指标。链路图上每一个节点标注负责人和SLA。这根线画完后项目接下来的推进速度快非常多因为大部分争议在链路图阶段就暴露了。模型效果提升10%可能是你的亮点但让整个系统稳定跑上一年才是算法和infra协同的底线价值。我经历过那个离线好到爆、线上崩到哭的项目之后现在做任何算法事情第一反应已经不是“模型能怎么做强”而是“这套系统怎么才能不拖累模型”。这种思维上的转变才是“算法-infra协同”最根本的收获。
返回列表