其他测试框架 货拉拉装卸货推荐点评测平台化的探索与实践

货拉拉质量星火 · 2025年06月25日 · 42 次阅读

作者简介:春亚敏,来自货拉拉/技术中心/质量保障部,资深测试工程师,主要负责地图服务端测试及相关质效能力建设

一、背景与挑战

货拉拉作为领先的同城货运平台,致力于提供高效便捷的运输服务。装卸货推荐点是为了缩短履约过程中的装/卸货时间、帮助货主和司机降低沟通成本,所推出的一个基于大数据和 LBS 的功能。装卸货推荐点的质量直接影响车货碰面效率,是提升用户体验和优化运营效率的关键环节。然而装卸货推荐点的准确性、及时性以及合理性,在质量保障上却面临以下三大难题:

  • 评测标准模糊化
    • 当前针对装卸货推荐点的评测指标尚未形成统一、量化的评判体系,缺乏能准确衡量用户真实使用体验的评测标准;
    • 评测过程更多依赖于人工经验或主观判断,缺少数据驱动的客观判定依据,导致推荐点质量良莠不齐、评测结果不具可复用性和可比性,难以有效支撑策略优化与产品迭代。
  • 评测平台空白化
    • 目前尚未建立系统化的评测平台用于支持装卸货推荐点的全面验证与质量分析;
    • 评测流程分散于多个环节,数据采集、验证评估、问题追踪等依赖线下沟通或工具组合,缺乏一体化、自动化的支撑平台。这不仅降低了评测效率,也影响了问题的快速定位与闭环处理能力,难以形成规模化、持续性的质量保障机制。
  • 环境仿真静态化
    • 离线评测与线上环境存在显著差异:生产环境中的实时动态特征(如 h3 网格聚合、POI 上的总单量和用户量、装卸货衰减热度、装卸货订单数等)会显著影响模型表现,导致离线评测指标往往带有 “数据温室” 效应。

二、面向平台化的解决框架

针对装卸货推荐点面临的质量难题,我们深入调研了业内常见的测试方案以及碰面产品的诉求,并结合货拉拉现状,给出了装卸货推荐点的效果评测解决框架及目标:

  • 解决框架 我们构建了一个 “多层能力 + 双层驱动” 的评测框架,皆在实现装卸货推荐点从评估到优化的全流程平台化支撑。整体框架包含四大核心层和两个支撑引擎:

  • 目标
    • 研发一套完善的评测指标体系 构建覆盖准确性、可达性、便捷性、安全性等核心维度的多层次指标体系,为推荐点质量评估提供标准化、量化的依据。
    • 构建效果评测平台 打造一套集任务管理、评测执行、结果分析、问题回溯于一体的评测平台,提升评测流程的系统性与可视化能力。
    • 支持离线和在线评测 同时建立批量离线分析能力与实时在线监测机制,确保推荐点在不同场景下的评估覆盖全面、响应及时。
    • 构建智能反馈机制 通过自动识别异常点、分类分析问题原因,并联动策略优化,实现从评测到调整的闭环智能反馈链路。

三、评测平台能力建设

3.1 平台架构设计

效果评测平台架构由展示层、业务层、存储层和数据层组成。这些模块协同工作,支持装卸货推荐点场景模型自动更新能力。

3.2 设计流程

算法测试相比其他服务端测试的难点:

  • 算法的测试输出是预估值
  • 模型问题抽象度高,难分析定位
  • 模型版本会自更新,随时间变化模型预估效果可能会出现偏差,所以在模型上线后还需持续关注 为了解决上述难点,装卸货推荐点评测平台支持线下和线上两种评测模式,以达到需求提测前完成研发自测效果、挖掘潜在效果问题的目标。 ### 3.2.1 离线评测
  • 评测对象:装卸货推荐点服务
  • 评测样本:抽取用户装卸货推荐行为的最后一条请求
  • 评测指标:不定点率(用户下单时创建地址的经纬度与该订单实际的装、卸货点经纬度的距离)
  • 评测频次:每次上线调整模型、策略、数据发版
  • 评测时机:模型/策略/数据完成开发后,提测前

3.2.2 线上评测


依赖算法侧自动生成模型的平台,搭建一套完整的在线评测平台,支持模型自动更新。

3.3 核心功能实现

接下来我们将按照评测指标、样本选取、评测方法、结果分析、反馈预警五个部分进行详细介绍。

3.3.1 评测指标

传统指标盲区:最初的算法迭代仅关注准确率、精准率、召回率指标,这样很容易掉进 “指标陷阱”!

  • 准确率 85% → 但用户投诉率上升 20%
  • 响应时间 <200ms → 但转化率下降 15%
  • 召回率 90% → 但装卸货推荐点不定点率反而增加

业务指标设计:本次评测指标体系的设计由产品团队牵头,聚焦于 “用户体验、业务收益、系统性能” 三大核心维度,通过 “两步法” 构建了覆盖重点业务场景的指标体系。

  • 指标解耦
    • 指标权重分配
      • 用户体验:45
      • 业务收益:40
      • 系统性能:15
  • 场景化定制

在无推荐点、宽泛/低热区域、推荐过远等推荐效果较差的场景,需提升用户关注度,并转化为有效修改,提升碰面效率。针对典型场景,应适当加强策略与前端引导的联动,减少下单成本。同时监测技术指标和业务指标偏移、验证业务影响,选取合适的业务指标反向驱动产品创新,以达到最优解。
业务衡量指标:可反应真实用户体验的评测指标,指标即体验!

  • Xm 不定点率:用户下单时创建地址的经纬度与该订单实际的装、卸货点经纬度的距离大于 Xm 的占比
  • 无推荐点率:装卸货推荐点服务未返回推荐点位的占比
  • 有推荐不吸附率:装卸货推荐点服务返回推荐点位但推荐的点位未进行强吸附的占比
private LalamapMetric calcMetric(List<LalamapCompareResult> compareResults) {
    LalamapMetric lalamapMetric = new LalamapMetric();
    lalamapMetric.addTotal(compareResults.size());
    for (LalamapCompareResult compareResult : compareResults) {
        metric(compareResult, lalamapMetric);
    }
    return lalamapMetric;
}

补充说明:测试团队在此过程中主要负责评测指标在平台侧的落地与实现工作,包括数据采集、指标计算、偏移监控及可视化支持,确保业务视角下的指标体系能够有效转化为评测平台中的可执行能力。

3.3.2 样本选取

模型效果验证依赖于准确的评测指标计算,而指标本身又高度依赖于客户端的埋点数据(如用户点击行为、下单数据等)。因此,样本选取的合理性直接决定评测结果的代表性与可信度。具体样本选取需满足以下三项原则:

  • 贴近真实场景:优先选取线上用户真实下单过程中产生的装卸货点数据,确保样本行为具备代表性与业务相关性。
  • 保证足够规模:样本量级需覆盖足够的用户行为以保证统计稳定性,当前评测默认选取约 10 万条样本,具体规模根据评测任务耗时动态调整。
  • 避开训练集、覆盖更广区域:为避免评估结果与训练数据产生耦合,测试样本应与模型训练样本保持时间/区间隔离,同时扩大覆盖城市、车型等多样性维度,提升评测的泛化能力。

为保障大规模评测效率,采用分布式评测框架设计:

  1. 数据分片:按时空维度切分测试样本
  2. 流式处理:采用 Kafka+Spark Streaming 实现实时指标计算


实施该架构后,单次处理能力从 2 万样本提升至百万样本,P99 延迟控制在 300ms 内,且成功缩小了评测指标和线上数据的差距,由原来的 0.38pp 降至 0.12pp。

3.3.3 评测方法

离线效果评测阶段,采用 “二阶段验证法”

3.3.3.1 离线仿真:通过历史数据回放构建基准测试集

如下图所示,人工评测支持自定义选取不同类型的回放数据,用于离线仿真

3.3.3.2 影子模式:将新策略模型与线上实际模型并行记录对比

人工评测的模式强依赖测试人员经验积累,门槛高,且每次只能评测单个用户的推荐效果,效率较低、用户覆盖面有限,因此需要寻求低门槛、更高效、高覆盖的模型线下效果验证能力。通过平台选择批量的用户生成批量的测试结果,自动计算模型评测指标,自动筛选出 badcase,最后再人工确认高风险结果,通过这样的方式提高测试用户覆盖,提高测试效率。
时机:每当上线调整模型、策略,新老数据替换时我们都需要对模型、策略、数据进行一个效果的评测。

线上效果评测阶段,采用 AB 测试验证法

3.3.3.3 AB 测试:在隔离流量中验证策略效果

随着业务体量增长与用户行为变化,模型效果出现退化趋势,对模型进行天级微调以适应最新数据分布的诉求越来越强烈。当前系统已支持新模型的天级自动生成,并在上线前通过自动化质检对新旧模型并进行指标比对,确保效果不回退再执行更新替换,从而保障线上服务效果的稳定性。

public ApiReModule lalamapsuggest(LalamapsuggestDto lalamapsuggestDto) {
    final ApiReModule result = new ApiReModule();
    final StopWatch stopWatch = new StopWatch();
    // 数据准备
    final QueryWrapper<OrderRecpointsLog> queryWrapper = new QueryWrapper<>();
    queryWrapper.eq("dt", lalamapsuggestDto.getDt());
    if (!"all".equalsIgnoreCase(lalamapsuggestDto.getAddrType())) {
        queryWrapper.eq("addr_type", lalamapsuggestDto.getAddrType());
    }
    int total = Math.max(lalamapsuggestDto.getNum(), lalamapsuggestDto.getMaxLine());
    int pageSize = Math.min(100, total);
    stopWatch.stop();
    DataLogRecordDispatch<OrderRecpointsLog> recordDispatch = new DataLogRecordDispatch<>(pageSize, total, queryWrapper, (w, i, s) -> {
        Page<OrderRecpointsLog> page = new Page<>(i, s);
        return recPointsLogMapper.selectPage(page, w);
    });
    RemoteServerWrapper remoteServer = new RemoteServerWrapper("map-lalamap-svc", lalamapsuggestDto.getEnv());
    RateLimiter rateLimiter = RateLimiter.create(getLimit(lalamapsuggestDto.getEnv()));
    List<LalamapCompareRecord> lalaCompareResult = new ArrayList<>(lalamapsuggestDto.getNum());
    List<ScheduledFuture<Void>> secondDelay = new ArrayList<>(lalamapsuggestDto.getNum());
    while (!recordDispatch.isDone()) {
        List<OrderRecpointsLog> records = recordDispatch.records();
        List<LalamapCompareRecord> recods = new ArrayList<>(records.size());
        for (OrderRecpointsLog record : records) {
            if (StringUtils.isEmpty(record.getAnchorLat())) {
                continue;
            }
            LalamapCompareRecord compareRecord = new LalamapCompareRecord();
            compareRecord.setOriginRecord(record);
            recods.add(compareRecord);
        }
        lalaCompareResult.addAll(recods);
        // 第一次请求
        List<CompletableFuture<Void>> firstCollector = new ArrayList<>(recods.size());
        for (LalamapCompareRecord recod : recods) {
            String host = remoteServer.nextHost();
            firstCollector.add(CompletableFuture.runAsync(() -> sendReq(host, recod, lalamapsuggestDto.getControlAbParam(), 0, lalamapsuggestDto.getTriggerId(), rateLimiter, lalamapsuggestDto.getHeader()), REQ_POOL));
        }
        CompletableFuture[] firstArray = firstCollector.toArray(new CompletableFuture[recods.size()]);
        for (LalamapCompareRecord recod : recods) {
            // 第二次请求
            String host = remoteServer.nextHost();
            ScheduledFuture<Void> schedule = REQ_DELAY_POOL.schedule(() -> scheduleSendReq(host, recod, lalamapsuggestDto.getTestAbParam(), 1, lalamapsuggestDto.getTriggerId(), rateLimiter, lalamapsuggestDto.getHeader()), 61L, TimeUnit.SECONDS);
            secondDelay.add(schedule);
        }
    }
}

评测执行后的关键代码如下:

{
    List<LalamapCompareResult> compareResults = fireCompare(lalaCompareResult);
    LalamapMetric metric = calcMetric(compareResults);
    stopWatch.stop();
    //获取质检是否通过结果
    String prdRes = getPrdRes(metric, diffAbsolute, checkNonZeroDiff, prdDiffThreshold);
    String fileUrl = "";
    if (lalamapsuggestDto.getNum() <= this.writeLimit) {
        String filePath = toExcel(compareResults);
        fileUrl = upload(filePath);
    }
    String sum = recordCompareResult(lalamapsuggestDto, metric, fileUrl, prdRes);
    // 发送飞书群通知
    sendLark(metric, fileUrl, lalamapsuggestDto.getOptPerson(), feishuUrl, lalamapsuggestDto.getAddrType(), lalamapsuggestDto.getModelKey());
    callBack(metric, diffAbsolute, callBackUrl, lalamapsuggestDto.getServiceAppId(), lalamapsuggestDto.getModelKey(), lalamapsuggestDto.getEnv(), checkNonZeroDiff, prdDiffThreshold, lalamapsuggestDto.getModelVersion());
    return result;

3.3.4 结果分析

在 badcase 分析维度,传统方法依赖人工抽样检测效率低下,通过使用规则引擎层,基于业务经验定义硬性违规规则(如推荐点超出服务范围),构建智能化的 badcase 挖掘系统。
badcase 挖掘依据:

  • 通过新旧模型在服务应用中的表现,根据不定点分析货拉拉未覆盖的 badcase,试图给出未覆盖数据的获取来源,从竞品结果中分析,提供参考截图;
  • 评测结果文件智能 diff,识别无推荐点、宽泛/低热区域、推荐过远等推荐效果较差的 case,辅助产研聚焦关键问题,提升问题分析效率;
  • 给出后续覆盖率、排序优化、杂质去重改善的意见。
private LalamapMetric calcMetric(List<LalamapCompareResult> compareResults) {
    LalamapMetric lalamapMetric = new LalamapMetric();
    lalamapMetric.addTotal(compareResults.size());
    for (LalamapCompareResult compareResult : compareResults) {
        metric(compareResult, lalamapMetric);
    }
    return lalamapMetric;
}

3.3.5 智能质检反馈与预警系统架构

  • 多渠道通知体系
    • 结构化消息推送,基于飞书 OpenAPI 构建实现
    • 多模态告警策略,采用状态机模式监控模型生命周期
  • 异常检测智能预警机制


四、效果评测收益

赋能研发自测,提升提测质量,拉高用户满意度;badcase 挖掘提前暴露存在问题,为后续需求迭代指明提升方向 。

  • 评测质量:将质检的支持能力从原来的 1 万数据提升到全天百万 + 数据量,成功缩小了评测指标和线上数据的差距,由原来的 0.38pp 降至 0.12pp。
  • 提测质量:工具成功支持 30 个需求的评测,提测前发现并成功定位了 45 个 bug,大大提升了提测质量。
  • 效率提升:百万样本评测时间由 33.3h 降至 2.7h,节省时间 30.6h。产研共进行 356 次有效线下质检,共节省 119 人日。
  • 业务效果提升:共进行 1065 次有效的自动线上质检
    • 司机满意度
      • 装货:正向 0.06pp(91.37%->91.44%)
      • 卸货:持平(91.45%->91.45%)
    • 30m 不定点率
      • 装货:正向 0.21pp(18.72%->18.51%)
      • 卸货:正向 0.12pp(31.66%->31.55%)

上述业务收益来自产品、研发与测试团队的协同推动。其中,测试团队搭建的装卸货推荐点评测平台在效果验证中发挥了较好的推动作用,是此次收益实现的重要组成力量。

  • 稳定性提升:回放成功率达到 99.06%,无因工具平台问题导致的自测阻塞。

五、未来规划

目前,效果评测平台已具备高度自动化、工具化、服务化与可视化等能力,初步形成了装卸货推荐点评测的系统化支撑平台。面向未来,我们希望进一步延伸平台能力,构建覆盖 “模型训练—模型评估—模型预测—模型应用” 的全流程质量保障闭环,持续提升装卸货推荐点的智能化水平。
具体规划包括以下三个方向:

  • 评测能力下沉至模型核心
    • 当前评测聚焦于服务层,缺乏对底层模型的直接评估。未来将通过分层机制将评测能力下沉至模型,提升问题发现与定位效率。
  • 评测流程深度融入 CI/CD 体系
    • 为了提升效果评测在模型开发及效果验证中的覆盖度与使用率,我们计划将评测平台与公司现有的 CI/CD 流水线打通,在模型上线前设置质量卡口,形成可配置、可复用的评测任务组件,推动效果评估成为模型生命周期管理中的标准步骤。
  • 智能 badcase 挖掘能力升级
    • 模式识别层:通过聚类与异常检测算法,识别如特定用户群体、选址习惯等造成的非典型偏差模式;
    • 因果推断层:引入反事实分析框架,挖掘决策链中关键变量的敏感性与失效路径,为模型优化提供精准参考。
暂无回复。
需要 登录 后方可回复, 如果你还没有账号请点击这里 注册