Jev 在 25 行 Python 中——一個極簡本地分類器如何運作

快速重點

一個 25 行的 Python 腳本可以透過載入 GGUF 格式的 LLM、提供帶有標籤選項的提示,並把模型最後一個 token 的 logits 轉換為機率,模擬 Jev 的核心功能——一個快速且本地的決策模型。


腳本的功能

它載入 GGUF 模型,格式化帶有標籤選項的提示,執行前向傳播,提取對應選項 token 的最後一個 token logits,並歸一化為機率。

# /// script
# requires-python = ">=3.12"
# dependencies = ["huggingface-hub", "llama-cpp-python", "numpy"]
# ///

import numpy
from llama_cpp import Llama

model = Llama.from_pretrained(
    repo_id="Qwen/Qwen3-0.6B-GGUF",
    filename="Qwen3-0.6B-Q8_0.gguf",
    n_ctx=512,
    logits_all=True,
    verbose=False,
)

labels = ["A", "B", "C"]
choices = ["合法", "垃圾郵件", "釣魚"]
email = "薪資部門要求你在非公司登入頁面輸入密碼。"
options = "\n".join(
    f"{l}. {c}" for l, c in zip(labels, choices, strict=True)
)
prompt = f"""\n<|im_start|>system
選擇一個選項。
\n<|im_start|>user
郵件:{email}\n\n{options}\n<|im_start|>assistant
\n\n"""
model.eval(tokens=model.tokenize(text=prompt.encode(), add_bos=False, special=True))

logits = model.scores[model.n_tokens - 1]
token_ids = [model.tokenize(text=l.encode(), add_bos=False)[0] for l in labels]
choice_logits = numpy.asarray([logits[t] for t in token_ids])
logprobs = choice_logits - numpy.logaddexp.reduce(choice_logits)
probabilities = numpy.exp(logprobs)

for name, scores in (
    ("Logits", choice_logits),
    ("對數機率", logprobs),
    ("機率", probabilities),
):
    values = numpy.round(scores.astype(float), 3).tolist()
    print(f"{name}:", dict(zip(choices, values, strict=True)))

該腳本會輸出三個字典,例如:

Logits: {"合法": 26.254, "垃圾郵件": 27.262, "釣魚": 29.614}
對數機率: {"合法": -3.482, "垃圾郵件": -2.474, "釣魚": -0.122}
機率: {"合法": 0.031, "垃圾郵件": 0.084, "釣魚": 0.885}

為何這很重要

它顯示 Jev 的核心行為——將自然語言提示與離散選項轉換為校準機率——並不需要專有 API、合成資料或基於強化學習的後訓練。 整個流程可在本地運行,不會產生網路延遲,並可使用任何 GGUF 兼容模型重現。

社群見解

對數機率的注意事項

"直接使用 logprobs 在以聊天模型為基礎時總是令人不安,因為它們是訓練來產生散文式輸出的。……你應該加入明確的系統指示或使用結構化輸出,以避免模型偏離主題。" – sigmoid10

此評論警告,若模型在選項 token 前產生額外的散文,則 token 級別的機率可能被扭曲。加入明確的系統提示或限制助理輸出格式可降低此風險。

提示順序的影響

"由於遮罩注意力機制,如果你把選項放在內容之前,變換器已經知道它需要尋找什麼,並能為該任務分配更多 token。" – antirez

將選項清單放在提示的較早位置,可提升模型對分類任務的專注度。

結構化輸出的替代方案

"不要讓模型只產生 "A", "B", 或 "C",然後查看機率,而是讓它直接產生 "合法", "垃圾郵件" 或 "釣魚"……你也可以讓它以文字或數字形式直接賦予機率。" – sigmoid10

使用 JSON 或純文字架構作為助理的回應,可簡化後續解析,並減少對 token 級別 logits 的依賴。

機率校準的疑慮

"機率並不總是正確的;校準決策通常需要基於強化學習的微調(RLCD)。" – 原始貼文

許多回應者指出,原始 logits 無法保證良好的校準性。溫度縮放、Brier 損失微調或後處理校準曲線等技術可提升可靠性。

速度與準確率的權衡

"為什麼你不希望分類器有『推理』?速度和成本是明顯的原因,但這不就是一種權衡嗎?" – brap

此腳本為了降低延遲而放棄了任何鏈式思考推理。對於高風險決策,具備明確推理的較慢模型可能帶來更高的準確率。

實際考量

模型選擇

範例使用 Qwen/Qwen3-0.6B-Q8_0.gguf,這是一個 0.6B 參數的模型,可在普通硬體上運行。使用量化或更小的模型可提升推論速度,但不同領域的準確率可能有所差異。

延遲測量

本文未提供基準數據。社群成員要求具體的延遲與錯誤率數字(例如:「45 個問題低於 200 毫秒」)。在將此方法投入生產前,於目標硬體上測量端到端時間至關重要。

錯誤處理

若模型產生預期外的 token,解析可能失敗。加入嚴格的輸出架構(例如帶有 choice 欄位的 JSON)與重試邏輯,可減少錯誤回應。

可擴展性

相同模式適用於任何多類別分類任務:將 labels、choices 和 email 替換為適當的領域資料,並調整提示以反映新情境。

替代方案與開源實作

  • OpenJev – 更完整的開源參考實作。
  • openjev-sglang – 整合至 sglang 執行環境,以提升吞吐量。
  • OpenJev on DiffusionGemma – 展示此方法在不同主幹模型上的應用。
  • Laya – 一個明確針對 System-One 風格決策優化的開源權重模型(見 SylonZero 的評論)。

總結

這段 25 行的腳本證明,Jev 的核心概念——以提示為基礎的分類並提取機率——可透過通用 LLM、無需專有訓練與極少程式碼重現。然而,實務工作者應意識到校準限制、提示設計細節,以及在生產環境中依賴此輕量級流程前,需具備穩健的輸出解析機制。

Sources

相關

  • Dispatch
  • 專案
  • 專案
  • Dispatch
  • 專案