本機與混合推論
並非每個提示都需要動用位於他人資料中心裡的前沿模型。Bromure Agentic Coding 可以透過 Apple 的 MLX 框架,直接在你的 Mac GPU 上執行開放權重的程式設計模型——不需要往返雲端、沒有按權杖計費,程式碼也不會離開機器。工作區可以完全在裝置端執行、在使用雲端的同時保有裝置端安全網,或者逐一為每個代理程式混搭這兩種方式。
本機推論是每個工作區各自的選擇,與 Fusion 彼此獨立:Fusion 決定有多少個模型回答提示,而路由決定哪個後端來回答。本章說明推論在何處執行、模型目錄與下載如何運作、三種路由模式與混合政策引擎、如何將個別代理程式指向本機模型,以及如何觀察引擎的行為。此窗格逐欄位的設定參考,收錄在本機模型設定中。
附註: 此處的一切都在 Mac 主機上執行,而非在 VM 內部。Virtualization.framework 不會給予 Linux 客體任何 GPU、Metal 或 MLX 存取權,因此裝置端推論必須在 macOS 上進行,並由客體跨越傳輸邊界來連接。需要 Apple Silicon(M1 或更新版本)——與應用程式本身的需求相同。
推論在何處執行
引擎內建於應用程式中;沒有東西需要安裝,不需要 Python 環境,也不需要指向任何外部伺服器,例如 Ollama、LM Studio 或自架的 vLLM 執行個體。當工作階段需要裝置端推論時,應用程式會啟動一個私有的 MLX 引擎,並將客體代理程式接上它。
引擎子行程
MLX 引擎是以應用程式自身二進位檔的受監督子行程(bromure-cli model _mlx-engine)形式執行,而非在應用程式內部。這是刻意為之的隔離:載入一個對 Mac 記憶體而言過大的模型,只會終止引擎子行程,絕不會影響應用程式或其執行中的 VM。父行程會自動重新啟動當掉的引擎,最多三次;此後便會放棄,並記錄下 engine child crashed repeatedly — giving up (a model likely OOMs this Mac) 這行日誌。應用程式結束時會終止子行程,而硬當機遺留的任何孤兒行程,會在下次啟動時被回收。
單一引擎服務於每個開啟的工作區。它會在 127.0.0.1 上綁定一個由核心指派的回送埠——絕不是 0.0.0.0,也絕不是慣用的 11434(該埠會保留空著,讓另外安裝的 Ollama 或 LM Studio 能繼續運作)。它會在一個記憶體預算下平行載入數個模型,該預算為主機統一記憶體減去 16 GB(下限為 8 GB),並在首次使用時延遲載入每個模型,當預算吃緊時淘汰最久未使用的模型。開啟或關閉工作區,會透過管理端點即時重新設定執行中的引擎——無需重新啟動。
當引擎正在暖機時,工作階段視窗會顯示一個狀態小標籤,內容為 正在啟動本機引擎…,並在引擎回應就緒探測後清除。
客體如何連接引擎
VM 內的代理程式從不直接與引擎對話。它們指向合成主機 https://bromure.llm——一個沒有真實 DNS 的名稱——而主機端的 MITM 代理伺服器會攔截它,套用它對雲端流量所套用的相同提示注入掃描與追蹤記錄擷取,然後將請求轉發到主機端引擎。因此本機推論絕不是盲點:它跨越相同的傳輸邊界,並落入與呼叫 Anthropic 相同的稽核軌跡中。
代理程式被釘選在哨兵模型名稱 bromure-local 上,主機會將其重新對應到工作區目前作用中的模型。切換作用中模型是一次主機端重新對應,代理程式無需重新啟動——代理程式持續要求 bromure-local,只是背後換上了不同的模型。
附註: 若某模型的架構是 MLX 引擎尚未支援的,會以一個清楚而永久的錯誤失敗——「its architecture … isn't supported by the on-device engine yet — pick a different model」——並以用戶端錯誤形式回傳,讓代理程式不會反覆重試。
模型目錄
目錄是一份精選的預轉換 MLX 模型清單,每個都針對在代理式程式設計中最要緊的一件事經過審核:量化模型經常破壞工具呼叫,因此每個目錄項目都帶有一個工具呼叫驗證徽章。項目也會記錄下載大小與最低統一記憶體需求,窗格會將其轉化為一道 RAM 適配關卡。
應用程式內建了一份基準目錄,讓窗格在第一天就能離線運作。啟動時,應用程式會從 https://dl.bromure.io/mlx/catalog.json 擷取一份重新整理後的目錄;較新的資訊清單會完全取代基準目錄(並非合併)。從已發布目錄中移除的模型會從清單消失——除非你已經安裝了它,在這種情況下它會以已安裝的額外項目形式保留下來。
隨基準內建的模型
內建目錄是一組橫跨各記憶體層級的 Qwen3 程式設計模型。四者全部通過工具呼叫驗證:
| 模型 | 磁碟佔用 | 最低統一記憶體 | 建議 |
|---|---|---|---|
| Qwen3 8B (4-bit DWQ MLX) | 4.3 GB | 16 GB | 是 |
| Qwen3-Coder 30B-A3B (4-bit DWQ MLX) | 17 GB | 32 GB | 是 |
| Qwen3-Coder-Next 80B-A3B (mxfp4 MLX) | 42 GB | 96 GB | 是 |
| Qwen3-Coder 480B-A35B (4-bit MLX) | 270 GB | 512 GB | 否 |
80 億參數的模型可在任何受支援的 Mac 上執行;4800 億參數的專家混合(mixture-of-experts)模型需要一台 512 GB 的機器(M3 Ultra),也正因如此未被標為建議。重新整理後的目錄可能會在不更新應用程式的情況下加入更新或更大的版本。
徽章與 RAM 適配關卡
窗格中的每一列(以及 bromure-cli model catalog 的每一行)都帶有兩個徽章:
- 一個大小層級——需要 16 GB 或以下的模型為 S,最高 32 GB 為 M,最高 64 GB 為 L,超過則為 XL。
- 對照你的 Mac 統一記憶體的一個適配判定:可容納、吃緊或無法容納。「可容納」要求模型的最低需求再加上 16 GB 空間給作業系統與其他一切;「吃緊」表示它能載入但幾乎沒有餘裕;「無法容納」表示模型的最低需求超過你的記憶體。無法容納的列會呈灰色,無法被選取或下載。
舉例來說,Qwen3 8B 模型(最低 16 GB)在 16 GB 的 Mac 上讀作吃緊,在 32 GB 或以上讀作可容納;Qwen3-Coder 30B-A3B(最低 32 GB)從 48 GB 起讀作可容納。
使用目錄以外的模型
目錄是一份精選菜單,而非一道圍籬。任何已為 MLX 格式的 Hugging Face 儲存庫,都能從命令列以其 org/repo 名稱拉取(見命令列參考);這類模型會被視為未經測試——它不帶工具呼叫保證,也沒有 RAM 適配保證。GGUF 格式的儲存庫會被直接拒絕,因為 GGUF 是 Ollama 與 llama.cpp 的路線,而非 MLX:
That's a GGUF (Ollama/llama.cpp) model — Bromure serves MLX weights only.
下載與儲存模型
權重由一個內建的純 Swift 下載器直接從 huggingface.co 拉取——沒有 Python、沒有 mlx_lm.convert、沒有任何形式的轉換。下載器會從 Hugging Face API 讀取儲存庫的檔案清單,將每個權重檔串流至一個 .partial 暫存檔,並原子性地將其改名歸位;儲存庫中的文件、圖片與任何 GGUF 檔案都會被略過。開始之前,會有一道磁碟空間預檢,寧可快速失敗也不會塞爆你的磁碟:
Not enough disk space: 40 GB free, but about 270 GB is needed.
模型的存放位置
下載的權重會落入你的 Application Support 目錄下,一個扁平的、以儲存庫為單位的配置中:
~/Library/Application Support/BromureAC/models/<org>--<name>/
每個目錄都存放著模型的 config.json、其 .safetensors 分片,以及其分詞器。下載是一項全域副作用,由每個工作區共享——拉取一個模型一次,就讓所有工作區都能使用它。其他工具先前快取在 ~/.cache/huggingface/hub 中的模型,會透過硬連結一次性遷移到此目錄,因此不會重複下載任何東西。
窗格中的下載狀態
每個模型列上的動作控制項,會反映其狀態:
| 狀態 | 控制項 | 意義 |
|---|---|---|
| 未安裝 | 下載按鈕 | 準備拉取(若模型無法容納則停用)。 |
| 下載中 | 進度條 + 位元組標籤 + 停止(✕) | 一個由磁碟上真實位元組驅動的確定式進度條;✕ 會取消並刪除部分檔案。 |
| 已中斷 | 已中斷 + 繼續 / 捨棄(垃圾桶) | 應用程式因當掉或被終止而未完成的拉取。繼續會從停止之處接續;捨棄會刪除部分檔案。 |
| 失敗 | 重試按鈕 | 下載發生錯誤;將游標懸停以查看原因。 |
| 已安裝 | 已安裝,並帶有一個移除選單項目 | 已完整下載並準備好服務。 |
由於下載器可在檔案粒度上續傳,被中斷的拉取永遠不必從頭來過,而部分下載也絕不會被誤認為可運作的安裝——在最後一個位元組落地之前,會有一個進行中的哨兵檔案標記它。
提示: 你下載的第一個模型會自動被設為工作區的作用中模型,因此全新的工作區只需一次點擊,就能從「沒有本機模型」變成「準備好服務」。
為工作區啟用本機模型
在工作區瀏覽器中開啟工作區,點擊編輯工作區,並選取本機模型窗格(薄荷綠的 CPU 圖示)。此窗格一開始只是單一開關;模式選擇器與模型清單只會在本機推論開啟後才出現。
- 開啟啟用本機模型(「在這台 Mac 上執行程式設計模型,而非使用雲端。」)。這會將工作區的路由從 Cloud 移開;再次關閉它則會還原為 Cloud。
- 挑選一個模式:
- Local — 一律裝置端會將每個請求都保留在這台 Mac 上。如同窗格所指出的,回覆是私密的但較慢,並受限於你能塞進記憶體的模型。
- Hybrid — 雲端,回退至本機會照常將請求送往雲端,只有在雲端無法連接時才回退至裝置端模型——雲端的速度與品質,加上本機安全網。
- 在模型清單中——其標題為 模型 · N GB 統一記憶體,其中 N 是你 Mac 的記憶體——下載一個模型,然後以其左側的圓點選取它為作用中。呈灰色的列所需的記憶體超過你 Mac 所擁有的。
- 點擊儲存。
路由模式與作用中模型的選取會在你儲存時保存;下載由於是全域性的,無論你是否儲存都會立即發生。若你選取的模型加起來所需的記憶體接近或超過你 Mac 的記憶體——引擎會平行服務它們,因此其記憶體會累加——窗格會顯示警告,並要求你捨棄其中一個或改選較小的模型。
完整的欄位清單與預設值在本機模型設定中。
路由:Cloud、Local 與 Hybrid
路由是頂層、每個工作區各自的選擇,決定哪個後端服務代理程式的 LLM 流量。它有三個值:
| 模式 | 行為 |
|---|---|
| Cloud | 預設值。請求會直通至真實供應商(可選擇加上主機端憑證替換;見憑證)。 |
| Local | 每個 LLM 請求都在裝置端服務。 |
| Hybrid | 預設使用雲端,並依政策驅動回退至本機模型。 |
選取 Local 或 Hybrid 會自動啟用 MITM 攔截路徑——你永遠不必為此另外切換一個開關。每個獲得回答的回合,都會在追蹤記錄中以一個服務來源標記標註,記錄下是哪個後端回答的:cloud 或 local-<model>。你可以在追蹤檢視器中閱讀它,逐回合確認混合工作階段實際去了哪裡。
路由是在窗格中設定的每個工作區預設值,但也可以透過命令列以 bromure-cli vm routing 在執行中的 VM 上變更(見命令列參考)。
附註: 本機路由會將代理程式送往 Anthropic 與 OpenAI 主機(以及
bromure.llm哨兵)的流量重新路由到引擎。它不會劫持一個本身已釘選在真實雲端憑證上的代理程式——舉例來說,一個共用工作區的訂閱制 Claude 代理程式,仍保有其真實的雲端流量。若要強制某個特定代理程式無論工作區路由為何都走本機,請使用它自己的本機模型驗證模式,如下所述。
混合回退政策
Hybrid 並非單一開關,而是一個小型政策引擎,經過調校以絕不透過中途換模型來打斷一段程式設計軌跡。每個決定都在工作階段邊界做出,而後便是黏著的——一旦一段對話被路由到某個後端,它在該工作階段的餘下時間都會停留在那裡(連貫性防護)。
什麼會觸發回退至本機
對於一段新的工作階段,第一條符合的規則獲勝,順序如下:一段已釘選的黏著工作階段、一份耗盡的雲端權杖預算、一個不健康的雲端(健康關卡)、一項分流比例指派,否則便是雲端。在一個已經在飛往雲端途中的請求期間,有兩件事會強制立即在本機模型上重播,並將該工作階段釘選為本機直至其生命週期結束:
- 硬錯誤——被拒絕或逾時的連線,或來自供應商的 HTTP
429、529或5xx。 - 錯過的軟性期限——在 TTFT 預算內(預設為 5 秒)未收到第一個權杖。
底層是一道保守的健康關卡:雲端在最近約十個請求中至少失敗三次後,或當 TTFT 的指數加權移動平均攀升超過 8 秒時,會被標記為不健康,而它只有在三次乾淨、快速的探測後才會復原。當雲端不健康時,新的工作階段會直接走本機,無需各自先付出軟性逾時的代價。兩個後端絕不會彼此競速——沒有推測式對沖,也沒有雙重花費;回退只有在真正的觸發條件之後才會啟動。
可調旋鈕
有三個旋鈕被開放出來,且僅能透過命令列對執行中的 VM 操作(見命令列參考)。它們會依工作區保存,但除非路由為 Hybrid,否則會被忽略:
| 旋鈕 | 命令 | 預設值 | 效果 |
|---|---|---|---|
| 雲端權杖預算 | bromure-cli vm hybrid budget <tokens> <vm> | 0(無限制) | 每個滾動 24 小時視窗內雲端服務權杖的上限;一旦超過,新的工作階段便走本機,直到視窗滑回上限之下。 |
| 軟性 TTFT 逾時 | bromure-cli vm hybrid ttft <seconds> <vm> | 5 | 未收到第一個權杖前的秒數,之後請求會被取消並在本機重播。 |
| 本機分流 | bromure-cli vm hybrid split <0-100> <vm> | 0 | 即使雲端健康時,仍主動釘選至本機的新工作階段百分比,以調合成本、延遲與隱私。 |
健康關卡的內部運作(8 秒的 EWMA 門檻、失敗視窗與復原探測次數)是固定的,不可由使用者調整。
本機模型作為代理程式後端
路由是工作區層級的軸線,但你也可以將單一代理程式指向本機引擎,讓工作區的其餘部分留在雲端。在工作區的代理程式分頁中,每個代理程式——Claude Code、Codex 或 Grok——都有一個驗證模式選擇器,其選項包含本機模型。選擇它、挑選一個已安裝的模型,該代理程式就會完全對著裝置端引擎執行,並使用引擎會忽略的虛設雲端金鑰;MITM 會套用與對雲端流量相同的防護。
這讓混合工作區成為可能——例如,訂閱制的 Claude Code 與本機模型上的 Codex 並存。整個設定檔範圍的 Local 路由絕不會劫持雲端代理程式的真實流量,而每個代理程式各自的 Local 模式也絕不會外溢到其他代理程式。當你在本機模型窗格中切換本機推論開或關時,應用程式會自動讓每個代理程式的驗證模式保持同步。
Fusion 中的本機模型
本機模型也是 Fusion(多模型合成功能)中的有效參與者,而且它在其中可以扮演兩種角色之一:
- 作為一條腿。 在 要融合的模型 下勾選本機模型並挑選一個已安裝的模型;它的草稿答案會與 Claude、Codex 和 Grok 一同加入面板。由於它在你的 Mac 上執行,它是一條零邊際成本的稱職額外腿。
- 作為評審。 選擇 Local 作為 Fusion 評審供應商,讓分析與合成階段完全在裝置端執行,使整個評審步驟遠離雲端。
這兩種角色都需要至少一個已下載的本機模型;在此之前,Fusion 窗格中對應的列會呈灰色,並附有提示要你先在此處下載一個。完整的面板工作流程請見 Fusion。
工具呼叫修復
量化模型在代理式使用中最主要的失敗模式,是將工具呼叫以純文字形式發出,而非發出代理程式可以執行的結構化呼叫。一個修復代理伺服器位於引擎前方——客體與 MITM 本機路由都指向它,而非指向裸引擎——並透明地挽救這些情況。
對於每個回應,它會緩衝輸出並重新解析模型可能洩漏呼叫的許多臨時形態,包括:
<function name="write_file" arguments='{…}'>
<tool_call>{…}</tool_call>
[{"name": "…", "parameters": {…}}]
以及 Qwen3-Coder 原生的 <function=Name><parameter=k>v</parameter></function> 格式與 Gemma 的通道格式。它會從所找到的任何東西合成出正確的工具使用區塊,並以代理程式原生傳輸形態、協定正確的 SSE 重新發出訊息。它也會偵測卡住的前言——模型陳述了一個動作(「Now I'll create the file:」),然後在從未呼叫工具的情況下結束回合——並重新提示至多兩次以挽回缺失的呼叫。每當宣告了工具時,系統提示都會附加一則工具格式提醒。
修復在本機推論中始終開啟,無需任何設定。引擎問題會被轉換為傳輸原生的錯誤主體,因此代理程式會顯示真正的原因,而非一個通用的失敗,例如:
Local inference engine unreachable (starting up, reloading a model, or stopped) — retry in a moment.
監控引擎
視窗選單下有兩個視窗,讓你不必開啟 Console.app 就能觀察裝置端推論。
推論指標
視窗 → **推論指標…**會開啟一個即時遙測面板(視窗標題為 Inference Metrics),標題列有 Local inference 標籤與引擎的回送位址。它會將引擎的 Prometheus 指標解析成卡片——Decode tok/s、Prefill tok/s、Running、Waiting、In flight、Avg latency、Cache hit、Metal mem、Gen tokens 與 Prompt tokens——外加一個 Loaded models 清單,以及一個帶有原始表格的 All metrics 展開項。
此視窗每 5 秒輪詢一次,且僅在它開啟時輪詢。解碼與預填率依設計為終身累計比率,因此它們讀起來是穩定的平均值,而非跳動的每秒差值。當引擎停止時,面板會顯示 engine not reachable,而在一次漫長的生成期間,它可能會短暫顯示 engine busy (timed out)。
推論引擎日誌
視窗 → **推論引擎日誌…**會開啟引擎子行程輸出加上父行程生命週期事件的即時追蹤(視窗標題為 Inference Engine Log)——模型載入、「serving」、每個請求的統計,以及任何 OOM、當機、重新啟動或載入錯誤。各行以顏色標示(紅色表失敗、綠色表健康事件、橘色表警告、藍色表進行中的工作)。工具列提供一個 Filter… 欄位、一個 Auto-scroll 核取方塊、Copy 與 Clear;當尚未發生任何事情時,它讀作 No inference-engine activity yet。此緩衝區是一個上限為 5,000 行的記憶體內環形緩衝,而每一行也會被鏡像到應用程式的 stderr,因此從終端機啟動 bromure-cli 會給你一份持久的副本。
命令列參考
模型與路由命令會與執行中應用程式的控制 API 對話,因此應用程式(或其代理程式)必須正在執行。作用於特定 VM 的命令會取一個結尾的 <vm> 引數,它是一個 VM id 或工作區名稱。持久的每個工作區預設值是在上文所述的 GUI 窗格中編輯的;這些命令作用於一段即時的工作階段。周邊的命令集請見自動化與 CLI。
模型管理:
bromure-cli model catalog [--all] [--offline]
bromure-cli model pull <catalog-id | org/repo>
bromure-cli model ls
bromure-cli model use <catalog-id | org/repo> <vm>
bromure-cli model rm <catalog-id | org/repo>
| 命令 | 作用 |
|---|---|
model catalog | 列出精選模型及其適配與工具呼叫徽章和一個已安裝勾號,並印出你 Mac 的統一記憶體。它會先重新整理即時目錄(若失敗不致命)。--all 會納入無法容納於這台 Mac 的模型;--offline 會略過重新整理,僅使用內建與快取的目錄。 |
model pull | 依目錄 id 或任何 Hugging Face MLX 儲存庫下載模型。它會驗證儲存庫為 MLX(拒絕 GGUF)、預檢磁碟空間,然後顯示一個由磁碟上真實位元組驅動的進度條。 |
model ls | 列出已安裝的模型及其磁碟用量與儲存庫。 |
model use | 為一個執行中 VM 的工作區設定作用中本機模型——一次主機端對 bromure-local 哨兵的重新對應,代理程式無需重新啟動。 |
model rm | 從磁碟移除一個已安裝模型的權重。 |
執行中 VM 的路由與混合政策:
bromure-cli vm routing cloud|local|hybrid <vm>
bromure-cli vm hybrid budget <tokens> <vm>
bromure-cli vm hybrid ttft <seconds> <vm>
bromure-cli vm hybrid split <0-100> <vm>
bromure-cli vm fusion enable|disable <vm>
vm routing 設定後端模式;三個 vm hybrid 旋鈕調校回退政策(且只有在路由為 Hybrid 時才生效)。vm fusion 會啟用彼此獨立的多模型面板,並在 Fusion 中說明。
內部診斷命令
這些隱藏子命令是為了開發與疑難排解而存在,並非日常工作流程的一部分。引擎子行程本身是由應用程式以 bromure-cli model _mlx-engine --config <path> 生成的。
| 命令 | 用途 |
|---|---|
bromure-cli model _mlx-serve <repo> | 為一個模型啟動行程內 MLX 伺服器並封鎖,印出其埠與金鑰以供 curl 測試。 |
bromure-cli model _mlx-selftest <repo> | 載入一個模型、生成一次,並印出 TTFT 與 decode tok/s。 |
bromure-cli model _repair-serve --engine-port <port> | 對一個執行中的引擎獨立執行工具呼叫修復代理伺服器。 |
bromure-cli model _tc-test <path> | 對一個已儲存的文字檔執行工具呼叫挽救,以檢查洩漏呼叫的擷取。 |
bromure-cli model _spec-bench <main-repo> --draft <draft-repo> | 為一對模型基準測試推測式解碼關閉與開啟的表現。 |
效能預期
裝置端推論以速度換取隱私與成本,而這筆交易是真實的——請據此設定期望:
- 吞吐量隨模型與晶片而異。 像 Qwen3 8B 這樣的小模型在任何受支援的 Mac 上都很俐落;大型的專家混合版本較慢且需要多得多的記憶體。推論指標視窗會顯示你的硬體上實際的解碼與預填率——那是可據以規劃的誠實數字。
- 第一個請求要付出模型載入的代價。 一個冷引擎在暖機時會顯示 正在啟動本機引擎…;大型權重要花上實實在在的時間才能載入記憶體,然後第一個權杖才會出現。後續請求則會略過此步驟。
- 多回合的代理程式迴圈在第一回合後會變得更便宜。 引擎會保留每段對話的前綴 KV 快取(每個模型最多四個工作階段槽位),因此每個代理程式回合只會預填新的權杖,而非整份逐字稿——而且旁鏈不會淘汰主對話的快取。
- 生成是序列化的。 引擎一次執行一個生成,因此數個忙碌的工作階段是共享 GPU,而非真正平行執行。
- 推理模型會默默思考。 對於發出
<think>區塊的模型,該區塊在答案抵達代理程式之前總是會被剝除——你得到品質,卻沒有逐字稿的膨脹。
提示: 若某個本機模型感覺很慢或卡住了,請先開啟推論引擎日誌視窗:模型載入、淘汰、OOM 重新啟動與不支援架構的錯誤,全都會以純文字浮現在那裡,這比從代理程式那一側猜測要快。