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
- 專案