Jev 置信度与兜底策略实战

更新于 适用版本 Jev 1.13

Jev 的每个响应都带 confidence 分数——这一个字段,把模型从”尝鲜”变成”生产组件”。分数告诉你模型哪里有把握、哪里在猜,你就可以自动化有把握的、分流剩下的。这篇讲阈值怎么定、三条兜底路径怎么设计、没有标注数据时怎么冷启动、批量场景怎么处理,以及整个回路怎么监控才不会悄悄烂掉。

TL;DR: 阈值从 0.8 起步:以上自动化,以下分流。低置信度条目三选一——换更锋利的问法重试、升级人工、或给通用 LLM 做一次完整判断。持续盯 confidence 分布:整体往低漂移,是输入或问题措辞变化最早的警报。

confidence 在响应里是什么

每种题型的 Jev 答案都带同一形态。打分题示例——示例数据(example fixture),正式字段名以官方文档为准:

{
  "answer": 8,
  "scale": [1, 10],
  "confidence": 0.86,
  "rationale": "The answer addresses the core question but omits the setup step."
}

判断题(是/否)时 answer 是 "yes"、"no" 或 "unclear"。选择题时 answer 是所选选项的标签。所有题型下 confidence 都是 0.0 到 1.0 的浮点数,rationale 是模型的自然语言说明。

把它当路由信号读,不要当真理。有用的心智模型:confidence 把条目按”能否安全自动化”排序。分布的顶部给自动化,底部给人审,具体的切线由你的错误代价决定。

有一件事 confidence 不告诉你:答案是否客观正确。高置信度的错误答案完全可能存在——当问题措辞清晰但源文档本身有误导性时就会发生。confidence 衡量的是模型自身的确信程度,这与准确率相关但不等同。这正是为什么在自动化任何有实际后果的决策之前,必须先用标注数据验证阈值。

阈值怎么定:0.8 起步,用数据调

场景建议起步阈值理由
垃圾信息 / 审核标记0.80误伤惹恼用户;复核队列很便宜
工单分流0.85分错要花人工交接时间
简历 / 线索筛选0.85–0.90风险高;只自动化清晰段
发票审批闸口0.90+财务错误代价大;几乎不自动化
内部排序 / 重排0.70错误便宜、量大

这些数字是起点,不是法律。真正要紧的调参回路:

  1. 先跑一周,把每个答案连同 confidence 记日志,暂不对低置信度做动作。
  2. 人工标注低置信度样本的一部分。
  3. 算出错误实际从哪里开始——安全切线经常比 0.8 高或低。
  4. 把阈值定在那里,每季度回看。

没有标注数据时的冷启动

多数团队想在有标注数据之前就把阈值定好。一个可靠的冷启动方案:

  1. 影子模式跑五到七天。 在生产里正常调用,但不执行兜底逻辑——只把 confidence 分数连同输入和答案一起记日志。
  2. 抽分层样本。 从 confidence 的每个十分位各取约 50 条。你需要覆盖整个分布,而不只是尾部。
  3. 人工标注。 对每条样本,按自己的判断标记答案是否正确。
  4. 按分段画错误率折线图。 把样本分成 0.0–0.69、0.70–0.79、0.80–0.89、0.90–1.0 四段,看各段的错误率。错误率越过你可接受水平的那一段,就是你的阈值所在。
  5. 第一次上线时定得保守一点。 把 20% 的条目送去人审、事后发现太谨慎——这种情况很容易修正;自动化过多就不一样了。

如果影子模式做不到(这个任务还没上生产),用合成保留集代替:人工准备 200–500 条有代表性的样本,全部手工打分,用这些标注定阈值。比猜要准得多,虽然不如真实流量精准。

三条兜底路径

confidence 低于阈值时,应该发生且只发生以下三件事之一:

import json, os, requests

def judge_with_fallback(prompt: str, threshold: float = 0.8) -> dict:
    # Confirm the exact model slug on the OpenRouter model page
    resp = requests.post(
        "https://openrouter.ai/api/v1/chat/completions",
        headers={"Authorization": f"Bearer {os.environ['OPENROUTER_API_KEY']}"},
        json={
            "model": "typesafe/jev-1.13",
            "messages": [{"role": "user", "content": prompt}],
        },
        timeout=30,
    )
    result = json.loads(resp.json()["choices"][0]["message"]["content"])

    if result["confidence"] >= threshold:
        return result  # 自动化
    if result["answer"] == "unclear" or result["confidence"] < threshold / 2:
        return {"route": "human"}  # 深度不确定:绝不重试循环
    return {"route": "llm_review", "jev": result}  # 中间段:完整 LLM 判断

封装函数在置信时返回 fixture 形态的答案,否则返回路由决策;这里展示的形态都是示例数据(example fixture),正式字段名以官方文档为准。三条路按顺序:

正确实现重试路径

重试不是把同一个 prompt 再发一遍。目的是给模型更多信息,让问题能以更高确信度得到回答。常见的问题锐化方式:

一定要在代码里硬性限制只重试一次。第二次仍然低置信度时再触发重试的逻辑,只会白烧成本、延迟条目处理。一次重试,然后路由到人工或 LLM:

def judge_with_one_retry(original_prompt: str, sharpened_prompt: str, threshold: float = 0.8) -> dict:
    first = call_jev(original_prompt)
    if first["confidence"] >= threshold:
        return first
    second = call_jev(sharpened_prompt)
    if second["confidence"] >= threshold:
        return second
    # 两次都低于阈值——路由,不再重试
    return {"route": "human", "attempts": [first, second]}

把 Jev 上下文传给 LLM 兜底

路由到通用 LLM 时,把 Jev 的低置信度答案作为先验上下文一并发过去,而不是让 LLM 从头开始。这样 LLM 能聚焦在解决不确定性上,而不是重做完整评估:

def llm_review_with_jev_context(item: str, jev_result: dict) -> str:
    system = (
        "You are reviewing a judgment made by a specialized AI model. "
        "The model returned a low-confidence answer. Your task is to confirm, "
        "correct, or override it with a full rationale."
    )
    user = (
        f"Item: {item}\n\n"
        f"Model answer: {jev_result['answer']}\n"
        f"Model confidence: {jev_result['confidence']}\n"
        f"Model rationale: {jev_result.get('rationale', '')}\n\n"
        "Please provide your final judgment and reasoning."
    )
    # 在这里调用你的通用 LLM —— GPT-4o、Claude 等
    ...

批量处理时的 confidence 管理

单条调用的处理很直接。批量评估带来两个额外问题:需要逐条追踪 confidence,同时又不想因为批次里有几条低置信度的就对整批触发 LLM 兜底。

把批量循环设计成先分离高置信度(直接执行)和低置信度(路由到兜底),分别处理后按原始顺序合并结果,再交给下游消费者:

from concurrent.futures import ThreadPoolExecutor, as_completed

def process_batch(items: list[str], threshold: float = 0.8) -> list[dict]:
    results = [None] * len(items)
    needs_fallback = []

    # 第一轮:对所有条目调用 Jev
    for i, item in enumerate(items):
        r = call_jev(item)
        if r["confidence"] >= threshold:
            results[i] = {"source": "jev", "result": r}
        else:
            needs_fallback.append((i, item, r))

    # 第二轮:只对低置信度子集走兜底
    with ThreadPoolExecutor(max_workers=5) as ex:
        futures = {
            ex.submit(llm_review_with_jev_context, item, jev_r): idx
            for idx, item, jev_r in needs_fallback
        }
        for future in as_completed(futures):
            idx = futures[future]
            results[idx] = {"source": "llm_fallback", "result": future.result()}

    return results

给 source 字段打上标记("jev" 对 "llm_fallback"),这样你就能按时间追踪每批次的兜底率。某类条目的兜底率突然上升,是问题需要改写的信号。

常见反模式

循环重试直到 confidence 够高。 这是最常见的错误。如果模型在同一输入上两次返回低置信度,第三次大概率还是低置信度。循环无法解决结构性的不确定性,只会烧钱加延迟。设一次重试上限,之后路由出去。

对所有题型用同一个阈值。 是/否判断题的 0.8 阈值,和 1–10 打分题的 0.8 阈值不是一回事。打分题在量表中段本身就有更多歧义,平均 confidence 分布会偏低。按题型分别校准,不要按部署整体校准。

丢掉 rationale 字段。 rationale 字段记录起来很便宜,丢了很贵。当一个高置信度答案事后证明是错的,rationale 通常是最快理解”模型为什么对错误答案这么确信”的地方。

把 unclear 和低置信度混为一谈。 unclear 是结构性拒绝——问题无法从提供的上下文中得到回答。低置信度是不确定的回答。把两者路由到同一个兜底路径,会把”需要改问题”的条目白白浪费成人工复核时间。

阈值定一次就不管了。 输入分布会漂移。上游数据源会改格式。新的边界案例会出现。六个月前正确的阈值今天可能已经错了。下面讲到的平均 confidence 指标,就是专门用来捕捉这种情况的。

监控回路

三个指标能在用户之前抓住大多数故障:

指标能发现什么告警条件
平均 confidence问题或输入漂移连续数天下滑
升级率阈值失配或流量变难没有发版却突然跳升
兜底路径占比形成重试循环重试占比逐周上升

每个答案都要把走的路由(automate、retry、human、llm_review)一起记录下来。每周汇总兜底路径占比能捕捉重试循环——如果重试占比逐周上升,说明你的问题措辞已经漂移,锐化后的问题其实并没有更锋利。

升级率是触达人工的条目比例。如果没有发版却突然跳升,通常是三件事之一:上游数据变了、涌进来了你的问题没有覆盖到的新类型输入、或者读取 confidence 的代码有 bug 导致路由错误。按这个顺序排查。

LLM 兜底的成本预算,参见《成本与延迟》。经验法则:平均 confidence 在 0.85 以上,LLM 兜底影响的调用不到 15%,相对于准确率的提升,增量成本通常可以接受。

发票审批闸口的 case 是保守阈值的典型样本——几乎全审、几乎不自动化;工单分流场景则是高流量下相反的平衡。当”报错”其实是响应形态读错了而不是置信度低,《Jev 常见报错排查》有对应的修复。

本文适用版本 Jev 1.13。

常见问题

+ Jev 的 confidence 阈值定多少合适?

从 0.8 起步:高于阈值自动执行,低于阈值转复核,再根据自己业务的分布调整——正确的阈值取决于错误自动决策的代价。

+ 低置信度的答案该怎么处理?

三条兜底路里选一条:换更锋利的问法重试一次、升级人工、或交给通用 LLM 做完整判断。按流量和风险等级选。

+ confidence 能当概率直接信吗?

把它当用于分流的排序信号,而不是校准过的概率;在自动化高风险决策之前,先用自己的标注数据验证。

+ 没有标注数据之前怎么定阈值?

跑一周影子模式:把每个答案连同 confidence 记日志,但不触发任何自动动作。然后人工标注 100–200 条样本,画出各分段的错误率曲线,错误率穿过你能接受水平的那个分段就是起步阈值。

+ unclear 答案是什么意思,什么时候会出现?

Jev 在问题无法从给定上下文中得到回答时返回 unclear——文档缺失、评判标准相互矛盾、量表未定义。它不是低置信度答案,而是拒绝回答。unclear 必须路由到人工或改写问题,不要自动重试。

+ confidence 能用来控制成本吗?

可以。只对低置信度部分触发昂贵的 LLM 兜底。如果 90% 的流量置信度在 0.85 以上,你只在 10% 的调用上花 LLM 的钱。结合《成本与延迟》那篇讲的逐字段缓存,兜底路径的增量成本通常很小。

继续阅读