1. 为什么传统的模型评测指标正在失效
做过模型选型的人大概都有过这种体验:花了两周时间跑完一轮评测,准确率、F1、AUC 各项指标都列得整整齐齐,团队开会一看,A 模型比 B 模型高了 1.2 个百分点,于是拍板选了 A。结果上线跑了三个月,账单出来傻眼了——A 模型的调用成本是 B 模型的四倍,而那 1.2 个百分点的提升在业务侧几乎感知不到。
这不是个例。我参与过好几次模型选型的评审,发现一个很普遍的问题:大家习惯用学术 benchmark 的思维来做工程决策。学术评测关心的是模型在固定数据集上的表现上限,但工程选型关心的是在给定预算下,这个模型能不能稳定地把事情办成。这两个目标之间的差距,就是 cost-per-success 这个指标要填的坑。
先说清楚它是什么。Cost-per-success,直译过来就是“每次成功成本”,核心公式很简单:
Cost-per-success = 总投入成本 / 成功完成的任务次数
这里的“成功”不是模型输出了一个看起来像样的回答,而是这个回答在业务链路上真正被采纳、被消费、产生了预期效果。比如客服场景里,用户没有转人工、没有二次追问、对话正常结束,这才算一次 success。内容生成场景里,生成结果直接可用、不需要人工返工修改,才算一次 success。
它解决的核心问题是:把模型的语言能力指标,翻译成业务侧能算清楚账的经济指标。适合谁来用?三类人最需要:一是做 AI 应用落地的工程负责人,二是需要向管理层汇报选型依据的技术管理者,三是自己搭产品、每一分 API 费用都要精打细算的独立开发者。哪怕你只是偶尔调几个模型做对比,理解这个思路也能帮你少花冤枉钱。
2. 拆解 cost-per-success 的构成要素
2.1 成本侧到底该算哪些账
很多人一算成本就只盯着 API 的 token 单价,这是最容易踩的坑。真实的成本结构至少包含四层,我按从显性到隐性的顺序列一下:
| 成本层级 | 具体内容 | 是否常被忽略 |
|---|---|---|
| 直接调用成本 | 输入/输出 token 费用、图片/音频处理费 | 否,大家都会算 |
| 重试与纠错成本 | 失败重试、格式修复、二次调用 | 经常被忽略 |
| 后处理成本 | 结果校验、人工审核、格式转换 | 经常被忽略 |
| 机会成本 | 延迟导致的用户流失、并发受限的扩容费 | 几乎没人算 |
直接调用成本最好算,按官方定价乘以实际消耗量就行。但重试成本往往被低估得厉害。我实测过一个结构化抽取任务,某模型首次输出 JSON 格式正确的概率只有 70% 左右,剩下 30% 需要重试或者用规则修补。这意味着它的实际成本是标称价格的 1.4 倍以上,而另一个格式稳定性更好的模型虽然单价贵 20%,综合下来反而更便宜。
后处理成本更隐蔽。如果模型输出需要人工抽检,那这部分人力成本必须摊进去。我一般会用一个粗略系数:需要人工介入的比例乘以单次人工处理的时间成本,再除以总任务量。机会成本则要看业务场景,实时对话场景里延迟每增加一秒,用户放弃率可能上升几个百分点,这部分损失很难精确量化,但选型时至少要有个定性判断。
2.2 成功侧怎么定义才算合理
“成功”的定义是整个指标里最需要和业务方对齐的部分,定义错了,后面算得再精确都是白搭。我通常把成功判定分成三个层次:
- 硬性成功:结果完全符合预期,可直接使用,无需任何人工干预。这是最严格的定义。
- 软性成功:结果基本可用,但需要轻微调整(比如改个措辞、补个字段),人工介入时间在可接受阈值内。
- 业务成功:从最终业务结果倒推,比如用户满意度达标、任务闭环完成,中间可能有多次模型调用。
选哪个层次取决于你的场景容忍度。做批量数据处理,我建议用硬性成功,因为人工返工的成本会吃掉所有收益。做创意辅助类工具,软性成功更合理,因为本来就需要人来把关。做端到端的自动化流程,业务成功才是唯一有意义的定义。
这里有个实操心得:定义成功时一定要写清楚判定规则,最好能自动化判定。我见过团队用“感觉还行”来标注成功,结果两个人标同一批数据,一致率不到 60%,这种数据算出来的 cost-per-success 完全没有参考价值。能自动判定的就写脚本判定,不能自动判定的就制定明确的评分卡,把主观判断压缩到最小。
2.3 为什么这个指标比单一维度更有决策力
单看准确率,你会选那个分数最高的。单看成本,你会选那个最便宜的。但现实决策往往是在两者之间找平衡点,而 cost-per-success 天然就是这个平衡点的量化表达。
举个我实际遇到的例子。三个模型做同一批工单分类任务,各跑 1000 条:
| 模型 | 单价(相对值) | 准确率 | 格式合规率 | 综合成功率 | 总成本 | Cost-per-success |
|---|---|---|---|---|---|---|
| 模型甲 | 1.0 | 92% | 95% | 87.4% | 100 | 0.114 |
| 模型乙 | 2.5 | 95% | 98% | 93.1% | 250 | 0.268 |
| 模型丙 | 0.6 | 88% | 90% | 79.2% | 60 | 0.076 |
单看准确率,模型乙最好。单看成本,模型丙最便宜。但 cost-per-success 告诉你,模型丙每成功处理一个工单只要 0.076 个单位成本,是模型乙的三分之一不到。如果业务对准确率的要求不是极端苛刻,模型丙显然是更理性的选择。这个结论用单一指标是得不出来的。
3. 搭建一套可复现的评测流程
3.1 评测集的设计原则
评测集的质量直接决定结论的可信度。我的经验是遵循三个原则:代表性、分层性、可判定性。
代表性指的是评测样本要覆盖真实流量的分布。很多人图省事,从网上找一个公开数据集就开始跑,但公开数据集的分布和你的业务分布可能差很远。我一般会从真实业务日志里随机抽样,如果历史数据不够,就人工构造一批贴近真实场景的样本。样本量不用特别大,200 到 500 条通常就能看出趋势,但一定要覆盖主要的使用模式。
分层性是指把评测集按难度或类型分层。比如对话任务可以分成简单问答、多轮推理、边界情况三层,分别统计各层的成功率。这样你不仅知道哪个模型整体更好,还知道它在哪类任务上更强,选型时可以针对性取舍。
可判定性是最容易被忽视的。每条样本都要有明确的预期输出或者判定标准,能自动判定的优先自动判定。对于开放式生成任务,可以设计一个评分卡,从相关性、完整性、格式合规等维度打分,设定及格线。我通常会把判定脚本和评测集一起维护,这样换模型重跑时不需要重新标注。
3.2 成本数据的采集方法
成本采集要做到颗粒度足够细,才能支撑后续分析。我一般会记录每次调用的以下字段:
# 单次调用成本记录结构示例 call_record = { "task_id": "task_001", "model_name": "model_a", "input_tokens": 850, "output_tokens": 320, "retry_count": 1, # 重试次数 "latency_ms": 2400, # 延迟 "is_success": True, # 是否成功 "post_process_time": 0, # 后处理耗时(秒) "timestamp": "2024-01-15T10:30:00" }有了这些原始记录,成本计算就是简单的聚合。直接成本按 token 单价算,重试成本把重试次数乘上去,后处理成本按人工时薪折算。延迟数据单独统计,用于评估机会成本。
注意:不同模型的计费方式可能不一样,有的按 token 计费,有的按调用次数计费,有的对输入输出分别定价。采集前一定要把计费规则搞清楚,否则算出来的成本会失真。
3.3 成功判定的自动化实现
成功判定能自动化就自动化,这是保证评测可复现的关键。对于结构化输出任务,判定逻辑很直接:解析输出,检查字段是否齐全、类型是否正确、值是否在合理范围内。对于文本生成任务,可以用规则加模型结合的方式判定。
我常用的一个模式是“规则初筛 + 模型复核”。先用规则快速过滤掉明显不合格的输出(比如格式错误、长度异常、包含禁用词),剩下的用一个小模型或者评分脚本做质量打分。这样既保证了效率,又比纯规则判定更准确。
def judge_success(output, expected, task_type): """成功判定示例""" if task_type == "structured": try: parsed = json.loads(output) # 检查必需字段 for field in expected["required_fields"]: if field not in parsed: return False, "missing_field" # 检查字段值范围 if not validate_ranges(parsed, expected["ranges"]): return False, "out_of_range" return True, "ok" except json.JSONDecodeError: return False, "invalid_json" elif task_type == "open_ended": score = quality_score(output, expected["criteria"]) return score >= expected["threshold"], f"score_{score}"判定脚本要跟着评测集一起版本管理,每次修改判定逻辑都要记录,否则不同时间跑出来的结果没法对比。
4. 实操中的关键细节与避坑经验
4.1 样本量不足时的处理策略
理想情况下评测集越大越好,但现实中经常面临样本不够的问题。我的做法是:先跑小样本看趋势,再决定是否扩大。如果两个模型的 cost-per-success 差距在 20% 以上,200 条样本通常就能稳定区分。如果差距在 5% 以内,那可能需要上千条样本才能确认差异是否显著,这时候就要权衡评测成本了。
另一个技巧是用置信区间代替单点估计。不要只报一个 cost-per-success 数值,而是报一个区间。比如“模型甲的 cost-per-success 在 0.10 到 0.13 之间”,这样决策者能直观看到不确定性。计算方法可以用 bootstrap 重采样,跑个几百次就能得到比较稳定的区间。
4.2 模型版本漂移的应对
模型是会变的。服务商可能悄悄更新模型权重,或者调整默认参数,导致你上个月测的结果这个月就不准了。我踩过这个坑:一个模型连续三个月评测都是最优,第四个月突然成功率掉了 8 个百分点,排查半天才发现是服务商更新了版本。
应对方法有两个。一是在评测记录里固定模型版本号,如果服务商支持指定版本就指定,不支持就在评测时记录调用日期,方便追溯。二是建立定期复测机制,重要的选型决策不要一测定终身,每隔一段时间用同一套评测集重跑一次,监控指标变化。如果发现明显漂移,及时重新评估。
4.3 多模型组合的成本优化
有时候最优解不是选一个模型,而是组合使用。比如用便宜模型处理简单任务,用贵模型处理复杂任务,整体 cost-per-success 可能比单用任何一个都低。这个思路叫“模型路由”或“级联”。
实现方式很简单:先用一个轻量分类器或者规则判断任务难度,简单任务走便宜模型,复杂任务走贵模型。关键是找到合适的分流阈值。我的做法是画一条曲线,横轴是分流比例,纵轴是整体 cost-per-success,找到曲线的最低点对应的分流比例。
| 分流策略 | 简单任务占比 | 整体成功率 | 整体成本 | Cost-per-success |
|---|---|---|---|---|
| 全用便宜模型 | 100% | 79.2% | 60 | 0.076 |
| 全用贵模型 | 0% | 93.1% | 250 | 0.268 |
| 分流(阈值A) | 60% | 85.3% | 136 | 0.159 |
| 分流(阈值B) | 75% | 82.1% | 108 | 0.132 |
这个例子里,分流策略 B 的 cost-per-success 是 0.132,虽然比全用便宜模型的 0.076 高,但成功率从 79.2% 提升到了 82.1%。如果业务对成功率有底线要求,这个组合就是更合理的选择。具体选哪个点,取决于你对成功率的容忍下限。
4.4 常见问题速查表
| 问题现象 | 可能原因 | 排查方向 | 解决建议 |
|---|---|---|---|
| 成本算出来远高于预期 | 重试成本未计入 | 检查重试日志 | 把重试次数纳入成本公式 |
| 成功率异常高 | 判定标准太宽松 | 复核判定脚本 | 收紧成功定义,增加校验维度 |
| 不同模型对比结果不稳定 | 样本量不足或分布偏差 | 扩大样本、分层统计 | 增加样本量,按任务类型分层 |
| 评测结果与线上表现不符 | 评测集与真实流量分布不一致 | 对比评测集和线上日志分布 | 重新采样,贴近真实分布 |
| 模型表现突然下降 | 模型版本更新 | 检查版本号和调用日期 | 固定版本,建立复测机制 |
提示:评测过程中遇到任何异常数据,先别急着删掉。异常样本往往藏着最有价值的信息,比如某个模型在特定类型的输入上系统性失败,这种发现比整体指标更有指导意义。
5. 从评测结果到选型决策
5.1 如何解读 cost-per-success 的差异
算出数值只是第一步,关键是解读。我的经验是分三步走:看绝对水平、看相对差距、看业务容忍度。
绝对水平告诉你这个方案在经济上是否可行。如果 cost-per-success 换算成实际货币后,已经超过了业务能承受的上限,那这个方案直接出局,不用再比了。相对差距告诉你模型之间的优劣是否显著。如果两个模型差距在 10% 以内,我一般会认为它们在经济性上属于同一档,这时候可以引入其他因素(比如延迟、稳定性、生态支持)来做决策。业务容忍度则是最后的调节阀,如果业务对成功率极其敏感,那就不能只看 cost-per-success,还要设一个成功率的下限门槛。
5.2 多维度决策矩阵的构建
Cost-per-success 是核心指标,但不应该是唯一指标。我通常会构建一个简单的决策矩阵,把几个关键维度都列进去,给每个维度赋权重,最后算加权得分。
| 维度 | 权重 | 模型甲 | 模型乙 | 模型丙 |
|---|---|---|---|---|
| Cost-per-success | 40% | 0.114 | 0.268 | 0.076 |
| 平均延迟 | 20% | 1.8s | 1.2s | 2.5s |
| 格式稳定性 | 20% | 95% | 98% | 90% |
| 生态与文档 | 10% | 好 | 很好 | 一般 |
| 服务稳定性 | 10% | 高 | 高 | 中 |
权重的设定没有标准答案,取决于你的业务特点。实时交互场景延迟权重要高,批量处理场景成本权重要高。关键是把权重和理由写下来,这样决策过程可追溯,后续复盘也有依据。
5.3 决策后的持续监控
选型不是终点,而是起点。上线之后要持续监控实际运行数据,验证评测结论是否成立。我一般会关注三个指标:实际 cost-per-success 与评测值的偏差、成功率的变化趋势、成本结构的变化。
如果实际值比评测值差很多,说明评测环境和真实环境有差距,需要回头检查评测集和判定逻辑。如果成功率持续下降,可能是模型漂移或者业务场景变化,需要重新评测。如果成本结构变化(比如重试率上升),说明模型的稳定性在下降,也要引起注意。
监控数据积累多了之后,你甚至可以建立一个预测模型,根据历史数据预估不同模型在未来流量下的表现,让选型决策从一次性动作变成持续优化的过程。
6. 一些实操中的个人体会
这套方法我用了挺长时间,踩过的坑也不少,分享几个印象比较深的。
第一个体会是:评测集的质量比评测方法的复杂度重要得多。我早期花了很多精力设计复杂的评分算法,结果发现评测集本身就有偏差,算出来的结论自然不准。后来我把重心放到评测集的构建上,从真实日志里采样、分层标注、定期更新,结论的可信度一下子就上来了。
第二个体会是:成本核算要保守一点。我倾向于把能算进去的成本都算进去,宁可高估也不要低估。因为选型时低估成本,上线后超支的代价更大。特别是重试成本和后处理成本,很多人不算,但这两块在实际运行中占比可能很高。
第三个体会是:不要追求一次评测就找到最优解。模型在变,业务在变,最优解也在变。把评测当成一个持续的过程,建立好基础设施,定期复跑,比一次性投入大量精力做完美评测更实际。
最后一个建议:把评测结果和决策理由文档化。我当时选某个模型的时候,把评测数据、决策矩阵、权重理由都写进了一个文档。半年后业务方问为什么选这个模型,我直接把文档翻出来,省了很多解释成本。而且后来模型更新时,这份文档也成了重新评估的基线,非常有用。
这套方法不复杂,但需要耐心和细致。真正跑通一轮之后,你会发现模型选型从“凭感觉”变成了“看数据”,决策质量会有明显提升。