管理小型本地AI預算(Mac M2 16GB)
本文介紹了millfolio如何通過混合標籤系統高效處理本地AI推理:使用確定性字符串和引用標籤覆蓋大多數交易,僅對模糊尾部使用設備端AI標籤。標籤在索引時計算一次並存儲,查詢時不重複運行。回填使用批處理、去重和優先級調度器以避免過載。性能數據顯示每個不同描述約650ms,有效行速8.5行/秒。系統包含預覽機制,用户可在保存前驗證標籤效果。
在上一篇博文中,我描述了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
← 返回博客