AI News HubLIVE
站內改寫4 分鐘閱讀

管理小型本地AI預算(Mac M2 16GB)

本文介紹了millfolio如何透過混合標籤系統高效處理本地AI推理:使用確定性字串和引用標籤覆蓋大多數交易,僅對模糊尾部使用裝置端AI標籤。標籤在索引時計算一次並儲存,查詢時不重複執行。回填使用批處理、去重和優先順序排程器以避免過載。效能資料顯示每個不同描述約650ms,有效行速8.5行/秒。系統包含預覽機制,使用者可在儲存前驗證標籤效果。

來源Hacker News AI作者: winding

在上一篇博文中,我描述了millfolio的分層設計:前沿模型在別名化模式上編寫小程式,而本地模型在裝置上讀取您的實際檔案。最後我承諾會寫一篇關於執行本地模型的無聊部分——以批處理模式執行,並設定優先順序,以便您的筆記型電腦保持可用。這就是那篇博文。

問題:模型無法隨記錄擴充套件

數年的銀行和信用卡對賬單涉及數千筆交易。本地模型擅長閱讀其中一筆——“這是訂閱嗎?”正是它擅長的針對性問題。但它無法做到的是,在使用者提問時,在筆記型電腦GPU上對數千筆交易重複回答這個問題。即使每筆記錄只需幾分之一秒,像“去年我在訂閱上花了多少錢?”這樣的問題也會變成數分鐘的推理——而下個問題又會重複所有工作。

因此,設計規則變成:模型的判斷是一種計算一次並儲存的東西,而不是在提問時執行的東西。

答案:三種標籤

每筆交易在索引時獲得標籤,標籤來自一個純文本規則檔案,您可以開啟並編輯(categories.txt——每行一條規則,該檔案是事實來源)。三種標籤按成本排序:

字串標籤——便宜且常見。標籤是大小寫不敏感的子關鍵詞列表,帶有可選的排除項以否決匹配:

phone = verizon, at&t, t-mobile, mint mobile groceries = whole foods, trader joe, safeway, costco

純字串匹配,幾乎零成本,覆蓋了大部分真實消費歷史——商戶字串具有重複性。

引用標籤——由其他標籤構建的標籤。規則可以引用@標籤名而不是關鍵詞,因此您可以組合組而不重複任何人的關鍵詞列表:

food = @groceries, @restaurant

仍然是確定性的且免費——當引用標籤已存在於行上時,引用標籤觸發。引用迴圈是無害的(標籤只會新增,因此評估收斂),引用可以指向AI標籤,這使第三種標籤也是可組合的。

AI標籤——沒有關鍵詞列表能捕獲的模糊尾部。規則是一個是/否問題,裝置端模型是判斷者:

subscriptions : 這是週期性訂閱費用嗎?

這是唯一需要推理的型別——這正是它作為儲存標籤而不是查詢時呼叫的原因。

在提問時,所有三種標籤看起來相同:生成的程式過濾.tags,對數千條記錄的答案是字串比較,而不是模型呼叫。還有一個隱私紅利:前沿模型被告知標籤名稱和作用範圍說明(因此它編寫過濾它們的程式),但從未接觸關鍵詞——您的實際商戶字串留在裝置上。

批處理,以及何時休眠

AI標籤仍然需要計算一次,“一次”意味著對現有每條記錄進行回填,加上之後到達的記錄。這項工作透過一個單一的裝置端工作編排器執行:一個磁碟支援的佇列,重啟後持續存在,一次處理一個作業——索引和AI標籤回填永遠不會爭搶引擎,並且兩者都向互動式問題讓步。

在回填作業內部,分類是批處理並去重的:

多個描述在一個提示中傳送給模型,它回答1:是, 2:否, …——一次推理呼叫分類整個切片。

在模型看到之前,精確重複的描述被摺疊:每月出現24次的費用被分類一次,結果擴散出去。在真實對賬單上,這節省了大部分工作(統計頁面保持記錄分類數與覆蓋數的執行計數)。

一個小賬本記錄每個規則已實現的程度,以單調插入代鍵——因此完成的標籤永遠不會對舊記錄重新執行;新記錄增量處理。

在切片之間,回填器休眠——休眠長度就是優先順序設定:高是100ms呼吸,中是1.2秒,低是5秒。這一個旋鈕決定了機器是“快速完成”還是“我在工作,整晚都行”。您也可以無限期暫停後臺處理。

速度如何?

以下統計資料透過執行mill run https://raw.githubusercontent.com/millfolio/vault/5915bf52f17b9baf2c4fe71695dae03e05a9ee16/privacy-box/eval/local_classifier_eval.mojo 在Mac M2 16GB上生成。(程式只列印聚合資料——沒有商戶字串或金額——並可在任何millfolio安裝上執行;它流式傳輸的即時進度行需要millfolio ≥ 0.4.49。)

原始輸出如下:

模型:Qwen/Qwen2.5-3B-Instruct 問題:“對於每個片段:如果它是雜貨店或超市購買(食品購物),回答‘是’;對於所有其他情況(外出就餐、餐廳、咖啡店以及任何非雜貨費用),回答‘否’。每個答案必須恰好是‘是’或‘否’——絕不能是‘無’,也絕不能是其他。”對比關鍵詞標籤‘groceries’作為參考。

資料:2930筆交易行,988個不同描述(3.0倍去重);分類了400個(平衡:29個標記+371個未標記)覆蓋2228行

ML(行級別,模型對比關鍵詞規則): 一致性70.6% 精確率39.0% 召回率100.0% F1 56.2% 混淆矩陣:TP 419 FP 654 FN 0 TN 1155 基準率18.8% (關鍵詞標籤是不完美的真實——不一致是模型與規則之間的,不是經過認證的模型錯誤;樣本是平衡的,因此基準率和一致性反映樣本,而不是完整資料) 答案分佈:111是·25否·264無·0其他

操作: 400個描述在大約40次模型呼叫中(批處理約10個/呼叫),總計260.9秒 1.5個不同描述/秒·8.5行/秒有效(去重擴散後)·每個不同描述約652ms

(關於答案分佈行的說明:‘無’是批處理協議的‘不適用’出口——模型將其用作大多數行的否定。它被幹淨地解析並計為‘否’。)

‘groceries’關鍵詞標籤——一個精心挑選的超市品牌列表——是參考標籤,Qwen2.5-3B-Instruct對相同記錄回答等效的是/否問題。樣本是故意平衡的(每個標記的描述,用未標記的填充),分類是每次模型呼叫批處理10個描述,重複費用像真實標籤回填那樣去重:2930筆交易行摺疊成988個不同描述,在模型看到之前節省了3倍。

結果,在覆蓋2228行的400個不同描述上:針對關鍵詞規則的召回率100%,精確率39%(F1 56%)。召回率數字顯示模型捕捉到了關鍵詞列表標記為雜貨的419行中的每一行,從未看到列表。精確率數字比看起來更有趣:654個“假陽性”是模型說雜貨而我的十幾個品牌關鍵詞列表說無的行——這混合了真正的模型錯誤和我的列表不知道的雜貨商。這種不對稱是整個混合設計的關鍵論點:確定性規則給您精確、可審計的頭部;模型給您尾部覆蓋;預覽UI存在是因為兩者都不應盲目信任。

操作上:每個不同描述約650ms,每秒1.5個不同描述,去重後每個判決傳播出去,有效每秒8.5行——因此一個2900行的資料在幾分鐘的後臺時間內獲得完整的AI處理,這正是回填排程器設計的預算。

信任,但要預覽

標籤系統只有在您對規則有信心時才有效,因此UI絕不要求您盲目儲存。當您建立或編輯標籤時,在持久化之前會進行模擬執行:

對於字串或引用標籤,編輯後的規則在儲存的交易上評估,您會看到匹配計數以及匹配的描述示例——以及未匹配的示例——因此過於貪婪的關鍵詞會立即顯現。

對於AI標籤,問題在時間限制的樣本(約5秒的裝置端模型)上執行,您會看到“約N條記錄會匹配”,並排顯示正面和負面示例。

看到兩側都很重要。假陽性從匹配列表中明顯可見;假陰性只有在UI也顯示規則之外的內容時才顯現。直到您儲存才寫入任何內容。程式碼生成模型與您合作管理分類法——當生成程式必須內聯分類某些內容時,它可以將問題作為可重用的AI標籤提回,這樣下次就是儲存的標籤過濾器,而不是新的推理。

總結

這些都不足為奇——這是每個資料系統最終都會發展出的批處理與線上分離。本地化的扭曲在於昂貴的資源不是雲賬單,而是您的GPU和前臺工作,因此排程器的工作既是禮貌也是吞吐量。一次計算判斷,將其儲存為標籤,僅將AI預算用於模糊尾部,並始終在規則執行前向使用者展示其效果。

演示:demo.millfolio.app

工作原理:millfolio.app

程式碼:github.com/millfolio

← 返回部落格