文件導航

置信度

TypeSafe 如何報告確定性、它與機率有何區別,以及如何用它控制系統的行為。

TypeSafe 返回的每個 score(評分)和 choice(選擇)答案都帶一個 probabilities 屬性,表示各選項(choice)或各檔位(score)上的機率分佈。這個分佈的形狀說明了模型有多確定:集中在一個結果上,就是有把握的答案;鋪得很開,就是沒把握的答案。

答案的 confidence 屬性把那個形狀壓縮成 0 到 1 之間的一個數,讓你直接拿它做閾值判斷,不用自己算。當所有機率都落在一個結果上時,它等於 1;當機率均勻鋪開時,它等於 0。(noul 答案不帶這個屬性;見下文 Noul。)

置信度由機率分佈推導而來

confidence 是一個統計量,由答案已經給出的機率分佈算出。TypeSafe 替你算好,並在每個 choice 和 score 答案上返回,所以常見場景你這邊不用額外做任何事。

示例:三個選項的 choice 問題

看機率分佈如何改變置信度

置信度

0.85

拖動滑塊改變某個選項的機率。其它機率會自動調整,使總和保持 100%。

選中:選項 A

這個演示怎麼算置信度

TypeSafe 根據機率在各選項上的鋪開程度來計算置信度。全部集中在一個選項上就是 1.0;鋪得越均勻,置信度越低。這個演示用 (3 × 最大機率 − 1) / 2 來近似三個選項下的置信度。

對 Choice 來說,分佈就是各選項上的 probabilities。對 Score 來說,就是各檔位上的分佈。兩種情況裡,分佈越平就意味著置信度越低:Choice 上置信度低,通常說明沒有一個選項明顯勝過其它選項;Score 上置信度低,通常說明檔位含義模糊、涉及多個維度,或者狀態裡給的資訊不夠。

每種問題型別的精確公式都在置信度如何計算一節,你可以看到任何 confidence 值是如何從答案自身的 probabilities 推匯出來的。

「我不知道」是個有用的訊號

一個智慧系統,不管是人還是機器,如果不能誠實地表達不確定,就不值得信任。

置信度給模型提供了一個內建機制,讓它能說「這個我沒把握」。這樣你的程式碼就能針對不同的確定程度採取不同的行為 —— 這是構建真正可靠系統的基礎。

在程式碼裡使用置信度的三條路徑

一個有用的起步模式,是把置信度劃成三段,每段觸發不同的系統行為:

高置信度: 直接行動。模型判斷明確,你可以不用人工介入就繼續。

中等置信度: 謹慎推進。模型的答案合理,但並不確定。視上下文而定,你可以讓使用者確認、標記待複核,或者先收集更多資訊再行動。

低置信度: 不要行動。路由給人工、請求澄清,或者回退到別的系統。模型是在告訴你:資訊不夠,或者這個問題不適合它。

這些邊界畫在哪裡,取決於風險有多大。

閾值隨風險變化

置信度閾值不是一個數。同一個系統裡的不同動作,應該根據出錯的後果,按不同水平來設閘。

response = client.system_one(
    state=user_message,
    questions={
        "action": Choice(
            instructions="What is the user trying to do?",
            criteria={
                "check_balance": "View account balance",
                "approve_transfer": "Approve the pending withdrawal request",
                "support": "Get help with an issue",
            },
        ),
    },
)

action = response.answers["action"]
confidence = action.confidence

if confidence < 0.5:
    # Model is genuinely unsure. Don't guess.
    route_to_human(user_message)

elif action.choice == "check_balance":
    # Low stakes. Showing the wrong screen is recoverable.
    show_balance(account_id)

elif action.choice == "approve_transfer":
    if confidence > 0.9:
        # High stakes, high confidence. Proceed with confirmation.
        confirm_then_execute(account_id)
    else:
        # High stakes, moderate confidence. Verify first.
        ask_user_to_confirm(account_id)

0.5 這個置信度下限,能兜住模型確實沒把握的一切。在這之上,無需確認即可行動的閾值,對破壞性操作要比只讀操作更高。風險容忍度就寫在你的程式碼裡。

置信度如何計算

每種問題型別概括自身分佈的方式略有不同。noul 只有兩個結果,choice 的選項個數不限、也沒有先後順序,而 score 的各檔位是有序的,所以下面每個公式都建立在前一個之上。

TypeSafe 的 confidence 是一種合理的概括分佈的方式,但不是唯一的一種。我們返回一個固定的度量,讓每個答案都帶一個穩妥的預設值:你從第一次呼叫起就能拿 confidence 做閘控,所有問題都在同一個 0 到 1 的尺度上,不必先去挑選並驗證屬於自己的統計量。因為下面的公式是精確的,而且每個答案都帶著完整的 probabilities,你完全可以改算對你應用最重要的那種度量。

Noul

noul 答案就是一個表示「答案為是」的機率 $p$,TypeSafe 不為它單獨返回 confidence。這個機率本身已經承載了不確定性:接近 0.5 的值,就是模型在說自己拿不準,Noul 頁面講了如何直接對它做閾值判斷。

如果你還是想要一個置信度式的數字,比如想用同一段程式碼同時閘控 noul 和 choice,就用它到 0.5 的距離:

$$ \text{confidence} = |2p - 1| $$

這樣一來 $p = 0.5$ 時得 0,$p = 0$ 或 $p = 1$ 時得 1。它也是下面 choice 公式用在是/否型 choice 上的結果,所以和 choice 置信度處在同一尺度上。

Choice

choice 把同樣的思路推廣到任意多個選項。對於一個有 $n$ 個選項的 choice,其中 $p_{\max}$ 是被選中選項的機率:

$$ \text{confidence} = \frac{p_{\max} - \frac{1}{n}}{1 - \frac{1}{n}} $$

它衡量最高機率比每個選項均分時的 $\frac{1}{n}$ 高出多少,在這個尺度上均分取 0、完全確定取 1。只有最高機率參與計算,所以 $(0.6, 0.3, 0.1)$ 和 $(0.6, 0.2, 0.2)$ 的置信度都是 0.4。

def choice_confidence(probabilities: list[float]) -> float:
    n = len(probabilities)
    return (max(probabilities) - 1 / n) / (1 - 1 / n)

choice_confidence(list(answer.probabilities.values()))

本頁頂部的探究器用的就是這個公式,配三個選項。

另有兩個更簡單的度量,同樣由 probabilities 算出,實踐中往往很有效,值得和 confidence 一起試試:

  • 最高機率,$p_{\max}$。它直接讀作「被選中的選項有多可能」,閾值因此很容易推理。它的含義取決於選項個數 —— 0.5 在兩個選項裡是弱答案,在十個選項裡卻是強答案 —— 所以要按問題分別設閾值。
  • 最高與次高之比,$p_{\max} / p_{\text{second}}$。它衡量被選中的選項比第二名明顯多少,而不管其餘部分怎麼攤開。許多真實決策最終就是在前兩名候選之間權衡,這個比值瞄準的正是這一點。

Score

score 的各檔位是有序的,所以它的公式還要計入機率離最可能檔位有多遠。對於一個有 $n$ 個檔位、編號從 $0$ 到 $n - 1$ 的 score,其中 $p_i$ 是檔位 $i$ 的機率,$m$ 是最可能的檔位:

$$ \text{confidence} = \max\left(0,\ 1 - \frac{\sum_i p_i , |i - m|}{\text{MAD}{\text{unif}}}\right) \qquad \text{MAD}{\text{unif}} = \frac{1}{n} \sum_i \left| i - \frac{n - 1}{2} \right| $$

分子裡的和,是答案與最可能檔位之間按機率加權的平均距離(以檔位計)。$\text{MAD}_{\text{unif}}$ 則是所有檔位均勻攤開時同類的平均距離,從中間檔位量起。置信度把兩者作比較,當答案至少和均勻攤開一樣散時,下限取 0。

落在相鄰檔位上的機率,讓置信度下降得比落在更遠檔位上的同樣機率少。三檔情況下,$(0, 0.5, 0.5)$ 的置信度是 0.25,因為模型在兩個相鄰檔位之間搖擺。$(0.5, 0, 0.5)$ 的置信度是 0,因為它在兩端之間搖擺。而 choice 公式會把這兩個分佈都算成 0.25。

五檔評分問題

看檔位之間的距離如何改變置信度

置信度

0.92

拖動滑塊改變某一檔的機率,其餘各檔會自動按比例分攤,總和始終是 100%。

得分
2.00
同樣機率套用 Choice 公式
0.88
這個演示是怎麼算置信度的

演示用的是 Score 公式:按機率加權,算出答案與峰值之間相隔的檔數平均值;再除以 1.2(五檔均勻分佈時同樣的平均值,從中間那一檔量起),用 1 減去它,最低到 0。落在峰值旁邊那一檔的機率,比落在遠處的機率對置信度的削弱更小 —— 這是 Choice 公式不考慮的。

def score_confidence(probabilities: list[float]) -> float:
    n = len(probabilities)
    m = probabilities.index(max(probabilities))
    spread = sum(p * abs(i - m) for i, p in enumerate(probabilities))
    even_spread = sum(abs(i - (n - 1) / 2) for i in range(n)) / n
    return max(0.0, 1 - spread / even_spread)

levels = sorted(answer.probabilities)
score_confidence([answer.probabilities[level] for level in levels])

Score 響應示例裡的 bug_severity 答案,機率是 $(0, 0.57, 0.43)$。最可能的檔位是 1,該距離為 $0.43$,而三檔的 $\text{MAD}_{\text{unif}}$ 是 $\frac{2}{3}$,所以置信度是 $1 - 0.43 / \frac{2}{3} \approx 0.35$。