先說結論
最近社群吵得很熱的 Jev,被一篇諷刺文用 25 行 Python「重現」了:把選項編成 A、B、C,讓模型只算下一個字,再讀出這三個字的機率。這篇帶你一行一行走過那段程式,看懂「用 logits 做分類」到底在做什麼,也順便看清楚:這個簡化版漏掉了哪些真正困難的部分。
它想解決的問題:讓 LLM 給出「一個答案加一個信心」
很多實務工作只需要模型做選擇:這封信是正常、垃圾還是釣魚?用聊天方式問,模型會回一段話,你還得解析,也拿不到「它有多確定」。原文作者的主張是:Jev 說穿了就是拿到一個有選項的 prompt,輸出每個選項的機率,而這件事用本地的小模型就能做到——快、在本機跑、資料不用送去別的地方。
動手走一遍:一封可疑的薪資信
第一步:載入一顆小模型
原文用 llama-cpp-python 載入 Qwen3-0.6B 的 GGUF 量化版,作者註明任何 GGUF 模型都可以。
關鍵參數是 logits_all=True:要求程式保留每個位置的 logits。logits 是模型在「選下一個字」之前,對詞彙表裡每個 token 打的原始分數,還沒轉成機率。
第二步:把問題寫成選擇題
labels = ["A", "B", "C"]
choices = ["Legitimate", "Spam", "Phishing"]
email = "Payroll asks for your password on a non-company sign-in page."
範例信件是「薪資部門要你在非公司的登入頁面輸入密碼」。prompt 用 Qwen 的對話格式組成,system 只說 Choose one option.。
細節是:assistant 開頭預先塞了一組空的 <think></think>。Qwen3 會先「思考」再回答,這等於告訴它思考已結束,下一個字直接就是答案。
第三步:只跑一次前向計算
model.eval(...) 把 prompt 丟進模型,不生成文字,只取最後位置的 logits,也就是「接下來最想說什麼」的分數表。
第四步:從幾萬個分數裡,只挑三個出來
token_ids = [model.tokenize(text=label.encode(), add_bos=False)[0] for label in labels]
choice_logits = numpy.asarray([logits[token_id] for token_id in token_ids])
logprobs = choice_logits - numpy.logaddexp.reduce(choice_logits)
probabilities = numpy.exp(logprobs)
查出 A、B、C 的 token 編號,只取這三格分數,再做 softmax(轉成加總為 1 的機率)。
原文的輸出:
| 選項 | logit | 機率 |
|---|---|---|
| Legitimate | 26.254 | 0.031 |
| Spam | 27.262 | 0.084 |
| Phishing | 29.614 | 0.885 |
模型以 88.5% 判定這是釣魚信。我自己驗算了一下:三個 logit 之間只差 1 到 3 分,但指數放大後,差距就變成約 3% 對 88%。這也提醒我們,logit 的小差距會被 softmax 大幅放大。
簡化版漏掉的東西
原文自己也承認這是諷刺文。它刻意列出「我們沒做的事」:沒叫它 System One decision model、沒呼叫 API、沒造合成資料、也沒用 RLCD(Reinforcement Learning for Calibrated Decisions,針對校準決策的強化學習)去訓練。文末還附上了更完整的開源實作 OpenJev 等連結。
HN 討論剛好補上了這些差距:
- 第一個 token 不等於答案:
sigmoid10指出,聊天模型被訓練成寫句子,它可能其實想說「A phishing attempt seems likely…」,這時第一個字A反而拿到最高分。他建議改用結構化輸出,直接限制模型只能生成Legitimate、Spam、Phishing這幾個完整的詞。 - 選項該放前面:
antirez提到,LLM 的注意力是單向遮罩的,前面的字看不到後面。把選項放在信件之前,模型讀信時就已經知道要找什麼;另一個技巧是把題目和標籤重複一次。 - 沒有比較數據:有留言指出文中沒有延遲、運算量和錯誤率的比較。
換句話說,這 25 行抓到的是骨架;真正難的是讓 88.5% 名副其實——說 88% 時真的約有 88% 會對。這就是「校準」,也是原文點名卻沒做的部分。
適合與不適合的場景
適合:標籤固定、數量少的分類;資料不能送到外部 API 的場景;需要分數當門檻,低於某個機率就轉人工。
不適合:需要先推理才答得出來的題目,因為這裡把思考關掉了;也不適合把機率直接當可靠信心——沒校準的小模型,數字好看不代表準。
延伸思考
- 諷刺文反而是好教材:它把被包裝成「新典範」的東西拆回零件,讓人看清哪些是通用技巧、哪些才是附加價值。
- 價值在校準,不在管線:讀 logits 誰都會,評估這類產品時該先問校準怎麼驗證。
- 提示設計仍左右結果:選項順序、重複題目、第一個 token 是否被污染,都會改變那個看似精確的機率。
- 留意「我也做了一個」的熱潮:HN 上已有人抱怨許多號稱重現 Jev 的示範經不起細看。
參考來源
- Jev in 25 lines of Python(Duarte O.Carmo,NobodyWho)
回應
還沒有回應,成為第一個留言的人吧。