はじめに
前回の記事では、TypeSafe AIの判断特化モデル Jev を取り上げ、
型安全と、判断が正しいことは別ではないか
という観点から考えました。
Jevは文章を生成するLLMとは違い、プログラムがそのまま扱いやすい構造化された値を返します。
これは業務システムに組み込むうえで大きな利点です。
しかし、公式ドキュメントをさらに読み進めていて、もう一つ気になる点が出てきました。
Jevはさまざまな場面で、0.7や0.97といった数字を返します。
ところが、この数字はすべて同じ意味ではありません。
たとえば、
probability = 0.7
confidence = 0.7
score = 0.7
noul = 0.7
は、見た目こそ同じ0.7ですが、意味も使い方も異なります。
さらに公式ドキュメントには、
refund = 0.72
not_refund = 0.47
という、一見すると「0.72 + 0.47 = 1.19?」と首をかしげたくなる例まで掲載されています。
今回は、Jevが返す数字をどう読むべきなのか、公式ドキュメントをもとに整理します。
Jevには3種類の質問がある
TypeSafeでは、System Oneに対する質問を大きく3種類に分けています。
| Primitive | 何を聞くか | 主な戻り値 |
|---|---|---|
| Choice | 候補の中ではどれか | choice / probabilities / confidence |
| Score | 段階のどこに位置するか | score / probabilities / confidence |
| Noul | この命題は真か | noul |
Choiceは分類です。
たとえば、
billing
technical
sales
の中から、問い合わせ内容に最も適したものを選ぶ。
Scoreは、たとえば、
calm
frustrated
very angry
のような順序のある段階上で、どこに位置するかを判断します。
Noulは、
この問い合わせは返金を求めているか?
のようなYes / No型の判断です。
ここまでは分かりやすい。
問題は、ここから返ってくる「数字」を全部同じ感覚で読んでしまうことです。
probabilityは「候補への確率」
ChoiceやScoreでは、各候補に対するprobabilitiesが返ります。
Choiceなら、たとえば、
{
"billing": 0.70,
"technical": 0.20,
"sales": 0.10
}
のような形です。
Choiceの場合、これらの確率の合計は1になります。
TypeSafeはJevをRLCD(Reinforcement Learning for Calibrated Decisions)で学習し、生成文章ではなく、判断と較正された確率を返すことを目指しています。
公式のAI primerでは、較正について次のように説明されています。
- 0.2を付けた予測群では、対象事象がおよそ20%発生する
- 0.8ならおよそ80%
- 1.0なら100%
ただし、ここには重要な但し書きがあります。
These rates describe groups of predictions, not a guarantee about any single answer.
(これらの割合は、予測の集団全体についての傾向を示すものであり、個々の回答が正しいことを保証するものではありません。)
つまり、
probability = 0.8
だから、
この1件が80%の確率で正しい
と保証しているわけではありません。
0.8という値を付けた予測を多数集めたとき、そのグループ全体としておよそ80%正しい状態を目指す
という話です。
言い換えれば、1件だけを見て「この判断は80%正しい」と読むのは強すぎる読み方で、「同じ条件で100件処理したら、およそ80件正解しているはず」という運用時の期待値の話です。
ここはかなり重要な違いです。
confidenceはprobabilityではない
さらに紛らわしいのがconfidenceです。
公式ドキュメントでは、ChoiceとScoreのconfidenceは、probabilitiesの分布の形を1つの数値に要約したものと説明されています。
1つの候補に確率が集中していればconfidenceは高くなり、複数の候補に広がっていれば低くなります。
たとえば、
A = 0.98
B = 0.01
C = 0.01
なら、かなり一つに集中しています。
一方、
A = 0.36
B = 0.34
C = 0.30
なら、かなり迷っています。
confidenceは、この「分布がどれくらい尖っているか」を扱いやすい1つの数字にしたものです。
つまり、
confidence = 0.97
は、
97%正しい
という意味ではありません。
モデルの答えが、どれだけ一つの候補へ集中しているか
を表しています。
公式も、confidenceは絶対的な定義として固定されたものではなく、用途によって別の指標を使ってもよいため、元のprobabilitiesも返している、としています。
confidence 1.0 でも「正解」の保証ではない
ここで、公式ドキュメントが Score の章で明示している重要な注意点があります。
Score のレベル分布として、たとえば次のような結果が返ることがあります。
{
"score": 0.0,
"confidence": 1.0,
"probabilities": {
"0": 1.0,
"1": 0.0,
"2": 0.0
}
}
confidence が 1.0 になっているので、一見「モデルは100%自信を持っている」と読みたくなります。
しかし公式はこう明記しています。
confidence 1.0 means the returned distribution puts all its probability on one level. This describes the model's answer, not a guarantee that the answer is correct.
(confidence 1.0 は「モデルが1つの判断に確率を100%寄せた」という意味であり、「その判断が100%正しい」という意味ではありません。)
つまり confidence = 1.0 は、
「モデルの答えが1つのレベルに完全に集中している」
と言っているだけであって、
「その答えが正しい」
ことは保証していません。
これは confidence を業務システムの自動処理条件に使うときに、そのまま「正解率の代理指標」として扱えないことを意味します。
入力に十分な情報があるか
と、
与えられた候補の中で分布が集中したか
は、別問題です。
confidenceが高いということは、後者が起きているというだけの話です。
Noulの0.7はまた別物
Noulには独立したconfidenceがありません。
Noulが返すのは、
この命題がYesである確率
です。
たとえば、
refund_requested = 0.7
なら、
「この顧客は返金を求めている」という命題に対するYes側の確率
です。
ここで面白い公式例があります。
同じ問い合わせ、
I'm not happy with the fit. What are my options here?
(フィット感がイマイチなのですが、どんな対応ができますか?)
に対して、「返金を求めているか」をNoulとして聞くと、
noul = 0.22
一方、Yes / NoのChoiceとして聞くと、
yes = 0.01
no = 0.99
confidence = 0.97
となります。
同じような内容を聞いているのに、
Noul → 0.22
Choice → no 0.99
です。
一見すると矛盾しているように見えます。
しかし公式は、ChoiceとNoulはそもそも異なる問いだと説明しています。
Choiceは、
候補の中ならどれか
という相対判断。
Noulは、
この命題そのものは真か
という絶対判断です。
だから、数値をそのまま横に並べて比較してはいけません。
0.72 + 0.47 = 1.19?
さらに強烈なのが、公式のこの例です。
問い合わせは、
I was charged twice for the same order. Can someone look into this?
(同じ注文に対して二重に請求されています。確認してもらえますか?)
これに対して、別々のNoulで、
返金を求めているか?
と、
返金以外のことを求めているか?
を聞きます。
すると、
refund = 0.72
not_refund = 0.47
となります。
合計すると、
1.19
です。
普通の確率の感覚なら、
P(refund) + P(not refund) = 1
になってほしくなります。
しかし公式は、別々の質問について算術的な恒等関係を期待してはいけないと明記しています。
さらに、
Noulで調整した閾値をChoiceへ持ち込むな
とも書いています。
理由は単純です。
System Oneでは、それぞれの質問が独立して評価されます。
一つの質問の結果が、別の質問へ隠れた前提として渡されるわけではありません。
つまり、
Noul("refund?")
と、
Noul("not refund?")
は、人間が考える
P(A)
P(not A)
という一つの確率空間の表裏として処理されているわけではない。
独立した2つの意味判断です。
ここを普通の確率変数のように扱うと、システム側で意味のない計算をしてしまいます。
Scoreはさらにややこしい
Scoreもまた、数字だからといって単純な「点数」ではありません。
Scoreでは、各レベルに確率が割り当てられ、その確率分布からscoreが計算されます。
たとえばレベルが、
0 = calm
1 = frustrated
2 = very angry
で、
0: 0.00
1: 0.70
2: 0.30
なら、
score
= 0 × 0.00
+ 1 × 0.70
+ 2 × 0.30
= 1.30
となります。
ここで重要なのは、異なる確率分布から同じscoreが出ることがある点です。
たとえば、
level 1 = 100%
でもscoreは1.0。
しかし、
level 0 = 50%
level 2 = 50%
でもscoreは1.0になります。
数字だけ見ると同じです。
でも意味は全く違います。
前者は、
ほぼ確実にレベル1
後者は、
両極端に割れている
です。
だからscoreだけを見ると、元の確率分布にあった情報が失われます。
公式もこの点をはっきり書いています。
Higher confidence does not establish which answer is correct.
(confidence が高いことは、その回答が正しいことの証明にはなりません。)
confidenceが高いことは、モデルの答えが正しいことを立証しません。
数字が同じだから意味も同じ、confidenceが高いから答えも正しい、といった単純な読み替えができないのがJevの数字です。
同じ0.7でも意味が違う
ここまでをまとめると、同じ0.7でもこうなります。
Choice probability = 0.7
→ その選択肢に割り当てられた確率
confidence = 0.7
→ 確率分布がどれくらい一つに集中しているか
Score = 0.7
→ レベル番号を確率加重した値
Noul = 0.7
→ その命題がYesである確率
見た目は全部0〜1の数字です。
しかし、
- 数式が違う
- 意味が違う
- 比較方法が違う
- 閾値の決め方が違う
- 他の数字との演算可能性も違う
わけです。
ここを理解せず、
if value > 0.8:
auto_execute()
のように数字だけ見て処理すると、コードとしては正常に動きます。
型エラーも出ません。
例外も発生しません。
しかし、意味としては間違っている可能性があります。
これは前回の記事で書いた「静かに間違う」問題の、さらに一段深い形です。
だからTypeSafeは「コードを主役」にしている
公式の「How to build with TypeSafe」を読むと、この問題に対するTypeSafe側の考え方はかなり明確です。
System Oneはエージェントではありません。
自分で次の行動を決めるものでもありません。
公式は、
build a normal software workflow and insert System One only where AI is needed.
(基本は通常のソフトウェアでワークフローを構築し、従来のロジックでは判断しにくい箇所にだけSystem Oneを組み込みます。)
という設計を推奨しています。
決定論的な処理や制御フローはコード側。
AIには、コードでは書きにくい意味判断だけを任せる。
さらに公式は、
Ask the most explicit, narrow, specific, atomic questions you can.
(質問はできるだけ明確かつ具体的にし、一度に1つの判断だけを求めるようにします。)
とし、複雑な判断を小さな質問へ分解することを、このガイドで「おそらく最も重要な概念」とまで書いています。
そのうえで、複数の判断結果はコード側で重み付けして合成します。
confidenceを使った自動処理・人間確認・上位モデルへのエスカレーションも、コード側で制御します。
これはかなり重要な設計思想だと思います。
confidenceの閾値も固定値ではない
たとえば、
if confidence >= 0.8:
auto_execute()
と書けば簡単です。
しかし、「0.8以上なら安全」という普遍的なルールがあるわけではありません。
TypeSafe自身も、
The correct threshold values depend on your domain and the performance of the model for your use case.
(どの閾値が適切かは、対象業務と、そのユースケースにおけるモデルの実際の性能をもとに決める必要があります。)
としています。
つまり、閾値は、
- 間違ったときの損失
- 人間確認のコスト
- 自分たちのデータ上での精度
- その処理が読み取りなのか、破壊的操作なのか
などによって変えるべきです。
公式の実装例でも、低リスク処理と高リスク処理ではconfidenceの扱いを変えています。
つまり、
数字を返すところまでがモデルの仕事。
その数字をどう使うかは、システム設計の仕事。
ということです。
では、Jevは何に使うのか
ここまで読むと、
こんなに数字の扱いに神経を使うなら、そもそもJev使わなくてよくないか?
と思うかもしれません。
しかし公式ドキュメントを読むと、Jevが「気持ちよく」使える領域はかなり明確です。
if文では書きにくいが、人間なら一瞬で判断できる意味判断
を、コードの部品として大量・高速に処理する。ここが本命です。
たとえば、
- 問い合わせ内容の分類
- 文章の緊急度判定
- ログの異常っぽさの判定
- ポリシー違反の検知
- LLM出力の品質チェック
- 人間確認へエスカレーションすべきかの判定
こういった、
if "返金" in text:
...
では拾えないが、
「二重請求されてるんだけど、確認してもらえます?」
を「返金要求」として意味レベルで判定できる部分にJevを置く。
そして、判定結果を受けた後の、
担当部署へ送る
confidenceが低ければ人へ回す
高額案件なら必ず人間確認
はコード側。
公式もこの設計を明示しています。
code owns control flow ... while TypeSafe handles the semantic decisions and language understanding.
(処理の流れ(制御フロー)はコード側で管理し、意味的な判断や自然言語の理解が必要な部分だけをTypeSafeに任せます。)
さらに公式は、Jevを「AIそのものの監視役」として使う Universal Verification という用途も挙げています。
LLMのプロンプト、出力、tool call、citationなどを、安価・高速にチェックする。
高価な生成AIに毎回「この出力正しい?」と別の生成AIを呼ぶのはコストも遅延も大きい。そこにJevを軽量な意味センサーとして挟む、という発想です。
つまりJevは、
AIというより、ソフトウェアに埋め込める意味センサー
と考えると位置づけがはっきりします。
センサーは値を返すだけ。
その値を受けて業務を止めるか、流すか、人に回すかを決めるのはコードです。
これが、ここまで数字の意味を丁寧に整理してきた理由でもあります。
センサーの値を正しく読めなければ、センサーを置いた意味がなくなるからです。
公式が挙げる9つの失敗モード
なお、公式のjev-1.13向けjaggednessページには、今回取り上げた「数字の解釈」以外にも、Jevが苦手とする9つの失敗モードが列挙されています。
具体的には、指示を文字通りに読んでしまう「Literal reading」、計算や日付比較の弱さ、間接参照の弱さ、無関係な情報を含む大きなstateでの精度低下、プロンプトインジェクション耐性の弱さ、そして今回中心に扱った「構造的不変量が保証されない」問題などです。
いずれも「コード側で処理すべきことをコード側に残す」「AIには狭い意味判断だけを任せる」という設計方針の裏返しです。
詳しくは公式ドキュメントを参照してください。
第一弾より、もう一段深い問題
前回の記事では、
型が正しい
≠
判断が正しい
と書きました。
今回、さらにその内側を見ると、
数字が返っている
≠
数字の意味を正しく理解している
という問題があります。
さらに言えば、
型が正しい
≠
判断が正しい
≠
数字の解釈が正しい
≠
業務判断として正しい
です。
Jevが仕様通りに動いていても、
開発者がconfidenceを正解率として扱えば間違える。
Noul同士を補数だと思って計算しても間違える。
Scoreだけを見て元の分布を無視しても、重要な情報を失う。
どれもプログラムとしては普通に動きます。
だから見つけにくい。
おわりに
Jevは、AIの判断をソフトウェアで扱いやすい値として返します。
これは非常に強力です。
ただし、値が構造化されていることと、その値の意味が単純であることは別です。
probability
confidence
score
noul
はいずれも数字ですが、同じ数字ではありません。
そして、その違いを理解せず業務ロジックへ接続すると、
型は正しい。値も返っている。処理も正常終了している。それでもシステム全体としては間違っている。
ということが起こり得ます。
前回の記事では、
必要なのは、モデルの外側にある評価設計です。
と書きました。
今回公式ドキュメントを読み進めて、その中身が少し具体的になりました。
評価設計とは、単に「AIの精度を測る」ことだけではありません。
モデルが返す値が何を意味し、その値をどの条件で、どこまで業務判断に使うのかを設計すること。
そこまで含めて、AIをシステムに組み込むということなのだと思います。
参考資料
-
TypeSafe AI Documentation
https://docs.typesafe.ai/introduction -
Primitives
https://docs.typesafe.ai/primitives -
Advanced primitives
https://docs.typesafe.ai/primitives/advanced -
AI primer
https://docs.typesafe.ai/introduction/machine-learning-primer -
Confidence
https://docs.typesafe.ai/confidence -
How to build with System One
https://docs.typesafe.ai/concepts/how-to-build-with-system-one -
Example use cases
https://docs.typesafe.ai/concepts/use-case-map -
Jev 1.13 jaggedness
https://docs.typesafe.ai/model-jaggedness/jev-1.13