把每个请求都发给最强的模型,能以最高价格获得好答案,因为你会为那些更便宜的模型本可以正确回答的请求支付前沿模型的价格。固定路由规则,例如按关键词或任务类型选择模型,成本更低,但会随着流量变化而需要重写。

基于置信度的升级介于两者之间。你让模型给自己的答案打分,然后根据这个分数进行路由。分数高的答案留在便宜的模型上。分数低的答案则交给更强的模型。本指南用五个步骤来实现这一点。

Tl;dr

  • 基于置信度的升级根据模型为其自身答案报告的分数来路由每个请求,因此便宜的模型处理它有把握的请求,而更强的模型只会看到它没把握的那些。
  • 用结构化输出强制给出分数。一个要求数值型置信度字段的 JSON schema 能让你从每个模型获得相同的信号,而不是从自由文本中的含糊措辞去猜测。
  • 使用排名,而不是绝对数值。0.85 并不是经过校准的 85% 正确概率。在你自己的流量上验证,分数较低的答案确实比分数较高的答案更常出错,并基于这种排序进行路由。
  • 根据你自己的数据设定阈值。让有代表性的流量通过便宜的模型,查看每个分数区间的错误率,把截断点设在错误率攀升的地方。
  • 把阈值当作一个需要重新审视的设置。记录分数分布、升级率,以及未升级答案的错误率,并在你的模型或流量变化时重新调整。

Flow diagram of confidence-based escalation. A request goes to the cheap model, which returns an answer and a confidence score. A decision node checks whether the confidence is at or above the threshold. If yes, the answer is returned. If no, the request goes to a stronger model for a second call, and that answer is returned.

置信度分数是什么,以及不是什么

这个分数是一种自我报告。模型生成它的方式与生成答案其余部分的方式相同,因此它带有同样的不确定性。两个相同的分数并不保证相同的正确几率。一个提示词上的 0.85 与另一个提示词上或来自另一个模型的 0.85 不可互换,而且这个数字不是经过校准的概率。

你能用的是排名,一旦你检查过它。把你自己的请求批量跑过便宜模型,给答案打分,并按分数分组。如果低分段的答案比高分段的答案错得更频繁,那么这个排序就可以用于路由,即使绝对数字不可用。你要找的不是等于 90% 正确的那个分数。你要找的是排名中那个把可以发布的答案和需要二次调用的答案分开的点。第 2 步就是那个测量。

第 1 步:用结构化输出获得一个数值置信度字段

不要从自由文本中读出不确定性。没有什么要求模型在不确定时必须在行文中含糊其辞,也没有固定的模糊词词汇表可供解析。

让模型改为在 schema 校验的响应中返回一个置信度字段,使用结构化输出。你传入一个response_format类型为json_schema的,并要求同时给出一个答案和一个 0 到 1 之间的数值置信度:

{
"model":"openai/gpt-5.6-luna",
"messages":[
{
"role":"user",
"content":"..."
}
],
"provider":{
"require_parameters":true
},
"response_format":{
"type":"json_schema",
"json_schema":{
"name":"answer_with_confidence",
"strict":true,
"schema":{
"type":"object",
"properties":{
"answer":{
"type":"string"
},
"confidence":{
"type":"number",
"description":"答案正确的可能性,从 0(猜测)到 1(确定)。"
}
},
"required":["answer","confidence"],
"additionalProperties":false
}
}
}
}

现在每个响应都带有一个数值置信度,你的路由代码可以直接读取,无论哪个模型作答。决定升级什么变成了数字的比较,而不是解析语言。

schema 在字段的description中说明 0 到 1 的范围,而不是用minimum和maximum关键字。Anthropic 的结构化输出文档将诸如minimum和maximum之类的数值约束列为不支持,因此 description 形式是跨提供商可用的那一种。strict: true要求具有原生严格模式的提供商精确执行 schema。执行情况因提供商而异,有些将 schema 视为强烈提示而非保证,因此在基于它路由之前先校验解析出的 JSON。

在你依赖它之前,有两项检查。首先,结构化输出支持是按提供商端点设置的,而不是按模型设置的,同一个模型可能由支持和不支持它的提供商提供服务。筛选模型页面到至少有一个支持端点的模型,并检查structured_outputs模型页面 Providers 部分中的参数。其次,设置require_parameters: true在你的提供商偏好中,这样我们只会将请求路由到支持其中每个参数的端点。没有这个标志,response_format是一种软偏好。当一个模型有一些支持端点时,我们会路由到支持端点,但如果一个模型没有任何端点支持它,我们仍然会发送请求,而该参数会被忽略。

第 2 步:根据你自己的错误率设置起始阈值

阈值来自对你自己的流量进行测量,而不是从指南中照搬一个数字。用上面的 schema 通过你的廉价模型运行一组有代表性的请求样本,记录置信度分数以及每个答案是否正确,并在错误率开始攀升的地方设置截止值。高于这条线的请求由廉价模型解决。低于这条线的请求升级到更强的模型。

从保守的一侧开始。一开始过度升级、之后再放宽阈值会花钱。升级不足则会交付自信的错误答案。

这里有一个示例。假设你通过廉价模型运行 200 个有代表性的请求,并按分数区间对结果分组。该表是一个内部算术一致的示例,不是目标。你自己的分布会有所不同。

分数区间请求占比观察到的错误率
0.95 到 1.0041%1%
0.85 到 0.9427%4%
0.70 到 0.8418%11%
0.50 到 0.699%34%
低于 0.505%61%

错误率在低于 0.70 时急剧攀升,因此 0.7 是候选截止值。0.7 的阈值会升级其下方的两个区间,即 14% 的请求,并让其余 86% 由廉价模型解决。

在这个样本中,廉价模型的总体错误率略低于 10%。升级底部 14% 会将你保留的答案的错误率降到约 4%,代价是大约每七个请求中就有一次进行第二次调用。在你自己的流量上运行这个的意义是找到你自己的截止值,而不是采用 0.7。

第 3 步:根据准确率、成本和延迟调整阈值

阈值以升级量换取错误率。提高阈值,更多请求会进行第二次调用,这能捕获更多错误,但成本更高、运行更慢。降低阈值,更多请求会留在廉价模型上,这更快、更便宜,但会让更多错误答案通过。把阈值设在哪里,取决于错误答案对你的产品意味着多大代价。有三个因素会影响这一选择。

准确率。更高的阈值会把更多处于临界地带的答案送去进行第二次调用,因此漏出的错误更少。在示例中,把截断值从 0.7 移到 0.85 也会升级 0.70 到 0.84 这一区间,该区间的错误率为 11%。升级比例从请求量的 14% 上升到 32%,而保留答案的错误率从约 4% 降至约 2%。

成本。每次升级都是一次额外的模型调用,叠加在你已经付费的廉价调用之上。其成本取决于廉价模型与升级目标之间的价格差,以及你升级的频率。在确定目标升级率之前,请查看当前的各模型定价。随着新模型发布,层级之间的价格差和价格本身都会变化。

延迟。被升级的请求会多一次往返,因此更慢。如果很大一部分流量被升级,这条慢路径可能会逼近延迟预算。当你的产品有硬性的响应时间上限时,这个上限可能会先于成本或准确率,限制你能升级多少。

Bar chart of escalation share and error rate on kept answers at five cutoffs, computed from the worked-example table. With no escalation, 0 percent of requests escalate and 9.6 percent of kept answers are wrong. At a cutoff of 0.50, 5 percent escalate and 6.9 percent of kept answers are wrong. At 0.70, 14 percent escalate and 4.0 percent are wrong. At 0.85, 32 percent escalate and 2.2 percent are wrong. At 0.95, 59 percent escalate and 1.0 percent are wrong.

该图表将每个候选截断值应用到示例表格中。提高截断值会降低保留答案的错误率,并提高为第二次调用付费的流量占比。这三个因素并非独立变化。为提高准确率而提高阈值,总会在被升级的那部分流量上增加成本和延迟,因此正确的阈值就是你对错误答案的容忍度、你的预算和你的响应时间限制三者相交之处。

第 4 步:在代码中路由低置信度请求

阈值设定后,由你的代码做出升级决策。它读取置信度字段,当分数低于该线时,将请求发送给更强的模型。我们不会替你做出这个决定。我们的模型回退当模型返回错误时触发,而不是当它返回一个置信度分数较低的有效答案时触发。有两种方式组织这个决策。

在同一个函数中重试。把调用包在一个函数里。把请求发送给便宜模型,读取置信度,如果低于阈值,就把相同的消息发送给更强的模型并返回那个答案。升级策略集中在一处,所以当你更改阈值或升级目标时只需改一次,不会再有调用点继续做出旧决策。

单独运行一次首轮处理。把便宜模型的调用当作首轮处理。记录它的答案和分数,然后只在分数低于界线时才调用更强的模型。这需要更多代码,但它记录了便宜模型升级的频率,以及它的分数是否仍与真实错误相符,而这些正是你在第 5 步中用来重新调优的数据。

模型 ID 是字符串,所以你可以通过配置而非代码来更改任一层级。浏览我们的模型目录来挑选便宜和强大的模型,因为每个层级的正确选择会随着新模型的发布而变化。

你可以在任一模式下叠加错误故障转移。传入一个models数组,当列表中的第一个模型返回错误时,调用可以故障转移到下一个模型。默认情况下,任何错误都可以触发回退,包括提供商宕机、速率限制、被过滤模型上的审核标记,以及上下文长度验证错误。我们按最终作答的模型来计价该请求,并在响应的model字段中返回该模型。这与你的置信度升级是相互独立的机制。它在错误时触发,而不是在有效的低置信度答案上触发,所以两者可以组合使用。回退让每次调用保持存活,而你的阈值决定何时一个存活的答案需要更强的模型。

第 5 步:在生产环境中监控并重新调优

在启动时合适的阈值可能会变得不再合适。从第一天起就记录三件事。

  • 分数分布,这样当模型或流量变化时,你可以重新运行第 2 步的校准。
  • 随时间变化的升级率。
  • 未升级答案的错误率,这个数字能告诉你截断值是否仍在发挥作用。

当情况发生变化时重新调整。更换廉价模型或升级目标为新版本会改变分数分布。流量向更难或更容易的请求偏移会移动你的误差带。成本压力可能促使你接受更高的错误率以换取更低的升级率。阈值是一个随着这些变化而不断调整的设置。

常见错误

将自报分数当作校准后的概率。该方法适用于排序,而非字面意义上的可能性。按分数对一批答案排序,错误答案会聚集在低端,但 0.9 并不意味着答案有 90% 的概率是正确的。应根据第 2 步中按分数段统计错误率的练习来设定阈值,而不是根据原始数字。

对所有任务类型使用同一个阈值。一个回答“你们的退款政策是什么”的客服机器人和一个回答“如果我今天取消会被收费吗”的客服机器人,错误答案的成本并不相同。单一的全局截断值要么对简单情况过度升级,要么对高风险情况升级不足。在你知道任务类型的地方,给每个类型各自的阈值。

上线后不关注升级率。一个适合你校准批次的阈值可能会随着流量偏移或底层模型变化而不再适用,而且没有任何错误会提醒你。

结论

基于置信度的升级让请求在廉价模型报告高置信度时留在该模型上,只在置信度不高时才为更强的模型付费,无需关键词或任务类型规则。这个循环很小。用结构化输出强制一个数值型置信度字段。根据你自己按分数段统计的错误率来找到截断值,而不是随便选一个数字。选择适合你想要追踪方式的路由模式,用一个函数实现策略,或为第一遍单独记录日志。然后在上线后关注未升级答案的错误率,并随着模型和流量的变化进行调整。

常见问题

什么是置信度阈值?

置信度阈值是一个分数,低于该分数时,你会把请求发送给更强的模型,而不是接受廉价模型的答案。高于这条线,答案就按原样发出。低于它,请求就升级。这条线要根据你自己的错误率数据来设定,而不是用一个默认数字。

AI 中的置信度分数是什么?

置信度分数是一个数字,通常在 0 到 1 之间,模型会随答案一起报告它,以表明自己有多确定。这是一种自我报告,不是经过校准的概率,所以 0.9 并不意味着有 90% 的概率是正确的。你能测量并依赖的是它的排序。在你自己的请求批次上,先确认得分较低的答案比得分较高的答案更常出错,然后再根据分数进行路由。

设置置信度阈值最可靠的方法是什么,以便让轻量级模型处理大多数请求,只在置信度低时才交给高级模型?

用你自己的流量来测量它。让一批有代表性的请求通过轻量级模型,记录每个置信度分数以及答案是否正确,并按分数区间对结果分组。把阈值设在错误率急剧上升的位置。这样轻量级模型就处理这条线以上的每个请求,只有线以下那些低置信度的请求才会交给高级模型。先保守设置,然后在观察你保留的答案的错误率时再调整。

如何自动从小模型升级到前沿模型?

让小模型通过结构化输出返回一个数值型置信度字段,然后让你的代码根据它进行路由。当分数低于你的阈值时,把同一个请求发送给前沿模型,可以在同一个函数内联完成,也可以作为一次显式的第二次调用。OpenRouter 的模型回退是一个单独的功能。它们是在提供商宕机或速率限制等错误发生时把调用故障转移到另一个模型,而不是因为置信度分数低,所以要把这两种机制区分开。

参考资料