Skip to content

Latest commit

 

History

21 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Tanpopo

繁體中文 · English · 日本語 · 한국어

Tanpopo 是一個以 Go 實作的本機模型服務管理器;名稱取自日語「蒲公英(たんぽぽ)」,象徵模型把生成的 Token 像種子般向外散發。管理介面提供簡單登入、模型服務管理與暫存式簡易對話;llama-server 維持跨平台與 GGUF 高相容性,Apple Silicon 另提供原生 Swift/MLX 的 mlx-server,支援文生文與多模態模型。

Tanpopo 管理介面

主要功能

  • 本機帳號密碼登入;首次啟動後應立即變更範本提供的初始登入資料,也可在系統設定經確認後關閉登入驗證,不建立使用者資料庫。
  • llama-server 與 mlx-server Runtime 由部署包自動安裝、解析與版本管理,不需設定執行檔目錄。
  • GGUF 模型目錄預設為 ~/services/models,MLX 模型目錄預設為 ~/services/mlx-models,兩者都可在系統設定調整。
  • 支援 Hugging Face 公開、gated 與 private repository 的 GGUF 單檔或完整 MLX 模型下載。
  • 模型下載頁提供 JSON 驅動的常用模型快速選單;GGUF 與 MLX 各自依 8B 級、30B 級、70B 以上分群,群內按模型名稱字母排序。選取後會自動填入 Runtime、Repository、Revision 及適用的 GGUF 檔名;清單獨立保存於 website/assets/popular-models.json,不寫死在前端程式。
  • 大型檔案在伺服器支援 Range 時以 64 MiB 區塊、最多 4 個並行工作下載;不支援時自動退回單一串流。管理畫面會顯示佇列、位元組數與進度,完成項目會自動清除;桌面 App 另可直接開啟儲存位置,瀏覽器模式會停用該按鈕。
  • 自動掃描模型目錄及其子目錄內的 .gguf 檔案與完整 MLX 模型目錄;Apple Silicon 的 mlx-server 可直接載入支援的 GGUF,不必先轉換成 safetensors。
  • **快速GGUF模式(Fast GGUF)**在 mlx-server 選擇 GGUF 時預設開啟,以模型名稱無關的 tensor 能力規則選擇 INT4、INT8、BF16 與 Group,並以永久 .fgguf 快取避免重複轉換。系統設定提供 Mode 1(均衡・預設)、Mode 2(較高精度)與 Mode 3(最快)三種策略;這套通用機制對多數可由 mlx-server 解析的 GGUF 都有幫助,但不保證每個架構、量化格式或自訂 checkpoint 都能載入、加速或維持相同精度,正式使用前仍應實測。
  • 執行狀態頁依所選 Runtime 提供按字母排序的模型下拉清單,GGUF、MLX 與 mmproj 統一以「模型名稱(目錄名稱)」顯示,但實際提交值仍為完整安全路徑。非 macOS 平台會在啟動時直接隱藏 Apple Silicon 專用的 mlx-server 選項。
  • KV Cache、MMap、DFlash 與 MTP 採全流程整合:涵蓋系統功能預設、啟動 Profile、執行開關、相容性預檢、Runtime 參數、狀態保存與錯誤回報。實際可用性仍依 Runtime 與模型能力決定;DFlash/MTP 推測解碼不可彼此並用,也與 KV Cache 量化互斥。
  • 執行狀態頁將 DFlash 與 MMap 收納於「進階設定」泡泡;兩者仍為獨立開關,不會隨功能增加而持續拉長頁面。
  • DFlash 預設關閉;不支援的 Target 會禁用開關,勾選時會即時重新掃描並檢查配對 Draft。MMap 同樣預設關閉,同時支援 llama-server 與 Apple Silicon mlx-server,啟用後可利用磁碟分頁降低載入模型時的記憶體壓力。
  • 系統設定提供服務主機目錄瀏覽器,可由 Home、檔案系統或掛載磁碟選擇 GGUF/MLX 模型目錄,不需要作業系統 Automation 權限或外部工具。
  • 可建立多組啟動參數並指定 llama-servermlx-server Runtime,執行時才與選定模型動態組合。
  • 內建 256K Context 的一般、KV Cache Q8、KV Cache Q4、強制關閉思考、MTP 與 DFlash 啟動 Profile;Apple Silicon 另有原生 MLX DFlash 1/2 與 MLX MTP Profile。
  • 可啟動、停止並查看目前模型 Runtime 的 PID、URL 與最近 128 KiB 日誌。
  • 按下「載入並啟動」會立即顯示模型載入提示,提醒大型模型可能需要轉換並耐心等候;Runtime 執行後可進行單次測試、重複 3 次測試或至少 500 個輸出 Token 的長輸出測試。重複測試會顯示平均值與中位數,所有模式都會列出 Token、生成速度、測試時間與明確失敗原因。
  • 成功啟動後會保存 Runtime、Profile、模型、mmproj、DFlash 與 MMap 選擇;關閉 Tanpopo 再開啟時,不需登入即可先自動恢復模型服務。使用者明確按下停止則不會自動恢復。
  • 簡易對話支援 Markdown 與本機數學公式渲染;模型有提供 reasoning、<think> 區段或 <|channel|> 思考通道時,會與最終回答分開顯示。思考過程在生成期間預設展開並顯示三點動畫,完成後自動收合;同時顯示輸入/輸出 Token 與每秒輸出 Token 數。
  • 管理介面支援 AUTO、繁體中文、英文、日文與韓文;選擇會保存於本機設定,AUTO 依作業系統及瀏覽器語系決定。
  • 介面提供蒲公英、晴空藍、櫻花粉與深夜紫四種配色,其中深夜紫為深色主題;切換後立即預覽並保存。
  • 視窗底部狀態列每 3 秒更新 CPU、GPU、MEMORY 與網路狀態,使用率依 50%/80% 分為低彩度綠、黃、紅三個區間。內框捲軸不與標題或狀態列重疊,停止捲動後會淡出。
  • 「系統設定 → 系統資訊」以唯讀方式顯示作業系統、Kernel、架構、主機名稱、CPU、GPU、記憶體、網路介面與目前可供其他裝置使用的管理網址;不顯示 loopback 管理網址。
  • APP 啟動時及每小時會檢查 GitHub 最新正式 Release;版本比較包含同日發布的 build 編號。Linux 可在「系統設定 → 關於」上傳正式發布 ZIP,驗證後自動更新並重新啟動服務;此功能要求管理登入驗證已開啟。
  • 原生選單與「系統設定 → 關於」會顯示 1.YY.MMDD build HHmm 版本、目前可達的管理頁面網址、可複製的模型 API /v1 URL,以及 GitHub 快速連結;本機 127.0.0.1 管理網址不列入公開資訊清單。
  • llama-server 與 mlx-server 直接監聽 Profile 指定的 Host/Port,兩個 Runtime 內部使用同一份 Tanpopo 安全策略快照驗證請求,不增加反向代理層。
  • 模型 API 可選擇不限制、只使用核發金鑰、只使用 IP 白名單,或同時使用兩種限制。
  • 系統設定提供選用的 NetPass 反向代理頁面;只有管理介面帳密驗證及模型 API Access Key 驗證都已開啟時才能建立公共網址,任一防護關閉會立即停止連線。頁面會明確警告此功能將本機暴露於公共網路,沒有確切目的不應開啟。
  • 設定保存採原子替換;Hugging Face Token 與模型 API 金鑰不會由設定 API 回傳明文。
  • macOS 圖形工作階段會以原生 AppKit/WKWebView 視窗載入管理介面,不啟動外部瀏覽器;可啟用常駐模式,在系統選單列重新顯示視窗或完整結束服務。Linux、SSH 與 headless 工作階段維持 Shell 模式。

公開測試報告

  • 模型相容性報告:整理原生 MLX、MLX 直讀 GGUF、llama.cpp GGUF、多模態投影、KV Cache 量化與推測解碼的支援範圍及相容性邊界。
  • MLX 與 GGUF 轉換的載入速度及運算精確度:以 4B、9B、27B 配對模型比較原生 MLX、llama.cpp + GGUF、MLX + Fast GGUF Mode 1/2/3,如實列出固定 100 題結果、生成速度、轉換快取及程序 RAM。

兩份 HTML 均可切換 AUTO、繁體中文與英文。報告數據是標示日期、硬體、Runtime 版本與樣本下的可重現測試快照,不代表所有模型或裝置都會得到相同結果,也不構成 Fast GGUF 的相容性、速度或精度保證。

快速啟動

開發模式需要 Go 1.25 以上、CMake 與 C/C++ 工具鏈;建立 mlx-server 另需 Swift 6/Xcode。部署包會攜帶固定版本的 llama-server 與 Apple Silicon mlx-server Runtime,不需要另外下載 llama.cpp、MLX Server 或 Python。

cd /path/to/Tanpopo
./run.command

run.command 會先呼叫 build.command --runtime 檢查目前平台的開發用 Runtime。版本相符且原始碼沒有更新時才直接沿用;缺少、版本不符或原始碼較新時,會由專案內鎖定的原始碼重新編譯 llama-server,Apple Silicon 也會一併處理 mlx-server,完成後才啟動 Go Service。Linux 不會嘗試編譯 Apple Silicon 專用的 MLX Runtime,正式安裝包則會檢查並安裝 Vulkan 建置相依套件,再建立或啟用 Vulkan Runtime。

在本機 macOS 圖形登入工作階段,服務開始監聽後會自動彈出原生管理視窗,載入目前 Session 對應的登入頁或主畫面,不會呼叫 Safari、Chrome 等外部瀏覽器。系統設定的「常駐」預設關閉;切換開關時會立即獨立保存,開啟後 Tanpopo 會出現在系統選單列,關閉視窗只會隱藏 UI,Go Service 與模型 Runtime 繼續在後台執行。可從選單列重新顯示視窗,或選擇「結束 Tanpopo」完整停止服務。常駐關閉時,關閉視窗仍會正常停止 Go Service。Linux、SSH、無圖形登入工作階段及其他未提供原生 UI 的平台,會維持現有 Shell 前景執行方式。可用環境變數明確覆寫模式:

TANPOPO_UI=shell ./run.command  # 強制 Shell
TANPOPO_UI=gui ./run.command    # 支援平台強制開啟原生視窗

Tanpopo 的 APP 版本採用 1.YY.MMDD build HHmmrun.commandrun.shbuild.commandpack.command 都會直接以 Asia/Taipei 的當日日期產生 1.YY.MMDD,並以執行時間產生 build HHmm;不讀取、不驗證,也不改寫根目錄 VERSION,跨日執行或重封裝不需要手動修改任何日期。只有要刻意重製歷史版本時才應設定 TANPOPO_VERSION,需要固定 Build 時則可設定 TANPOPO_BUILD;產出的部署包會寫入本次實際版號,GitHub Tag 使用 v1.YY.MMDD-build-HHmm。程式啟動後會立即查詢 GitHub 最新正式 Release,之後每小時重新檢查;版本與 build 都會參與比較,因此同一天的後續 Release 仍可被偵測。同一個介面工作階段對同一新版只通知一次,Draft 與 prerelease 不列入最新版。

如需強制重編兩個模型 Runtime,可執行:

TANPOPO_REBUILD_RUNTIMES=1 ./run.command

首次啟動會由 agent.sample.properties 建立 agent.properties。管理服務預設監聽 0.0.0.0:10082,本機可使用:

http://127.0.0.1:10082

區域網路內其他裝置可使用 http://<主機區網 IP>:10082 連線;實際可達範圍取決於主機防火牆與路由設定。

初始登入資料由 agent.sample.properties 提供,僅供第一次本機啟動使用;正式使用、開放區域網路或啟用反向代理前必須先變更。可在「系統設定」即時修改管理帳號與密碼;保存後會撤銷所有既有 Session,並要求使用新帳密重新登入。登入欄位會優先提示瀏覽器使用英數鍵盤,但不限制帳號密碼字元。「記住我」未勾選時使用只存在記憶體的瀏覽工作階段 Cookie;勾選後則建立以目前帳密衍生金鑰簽章的持久 Cookie,可跨 Tanpopo 服務重啟驗證,帳號或密碼一旦變更便立即失效。網站儲存空間不會保存帳號或密碼。

llama-server Runtime

本專案只管理 llama-server,不會把 llama.cpp 函式庫直接連結進 Go 程序。部署包會同時保存自訂 llama.cpp 的固定版本號、可建置原始碼,以及封裝時可取得的下列預編譯 Runtime:

  • macOS Apple Silicon(darwin/arm64,Metal)
  • Linux x64(linux/amd64,Vulkan)

封裝器會自動建立目前主機平台的預編譯 Runtime;其他平台的預編譯檔若不存在則直接略過,不會讓封裝失敗。Linux 發布包包含 build-llama-server.sh、精簡 llama.cpp 原始碼及 Vulkan 相依套件檢查器;安裝時會依發行版安裝缺少的編譯工具、Vulkan headers/shader compiler,並處理 GPU 裝置群組權限。沒有預編譯檔時會在目標主機原生建立 Vulkan Runtime。

~/services/llama.cpp/versions/<llama-server-version>/<platform>/bin/llama-server
~/services/llama.cpp/current -> versions/<llama-server-version>/<platform>

Runtime 位置不再由管理介面設定。後端會依序從部署包內的預編譯目錄、安裝後的 current 版本、開發專案的 Runtime 目錄與系統 PATH 尋找 llama-server。一般部署只需執行 install.sh,不需要手動填寫路徑。

<部署包>/llama-server/prebuilt/<platform>/bin/llama-server
~/services/llama.cpp/current/bin/llama-server
<開發專案>/llama-runtime/prebuilt/<platform>/bin/llama-server

啟動模型時,Tanpopo 會把 Profile、模型與安全策略快照路徑動態組合後,直接讓 llama-server 監聽 Profile 指定的 Host/Port。實際命令概念如下:

llama-server \
  --model /完整路徑/model.gguf \
  --mmproj /完整路徑/mmproj-model.gguf \
  --host 0.0.0.0 \
  --port 8080 \
  --ctx-size 262144 \
  --n-gpu-layers -1 \
  --openloader-access-control <安全策略快照>

對外 Runtime 直接使用 Profile 設定的 Host 與 Port;執行狀態頁會顯示並可複製 OpenAI 相容 Base URL,例如 http://<主機 IP>:8080/v1。一般 HTTP、OpenAI 相容 API 與 SSE 回應都由 llama-server 直接處理。

管理介面的「啟動參數」可保存多組參數 Profile。執行狀態頁選定 Profile 與 GGUF 後,Go 後端才會動態組合命令列並直接啟動 llama-server,不會產生或執行 .sh。Profile 的「額外參數」採每行一個 argument,例如:

--flash-attn=on
--jinja

多模態模型可在執行狀態頁另外選擇檔名含 mmproj 的 GGUF。後端會在模型目錄內安全解析檔案路徑,並於啟動時加入 --mmproj <完整路徑>;純文字模型可保留「不使用 mmproj」。詳細行為請參考 llama.cpp 多模態說明

內建 Profile 的 Context Size 均為 256K(262144)。Profile 可直接選擇 KV Cache Q8 或 Q4;執行狀態頁的獨立 Switch 決定本次啟動是否套用,關閉時維持未量化,llama-server 開啟時會轉成 --cache-type-k--cache-type-v。DFlash 與 KV Cache 量化互斥,介面與後端都會阻止兩者同時啟用。「強制關閉思考」同時設定 --reasoning off--reasoning-budget 0--jinja;MTP 使用主模型內建的 MTP heads,不需要 Draft GGUF。DFlash 預設關閉;勾選後才會把配對的 Draft 與 Target 動態組合,llama-server 會加入 --model-draft--spec-type draft-dflash。若 Draft 不存在,畫面會取消勾選並提示前往「模型下載」;啟動時後端仍會再次驗證路徑與架構。參數格式以 llama-server 選項llama.cpp speculative decoding 說明為準。

MMap 位於執行狀態頁的「進階設定」泡泡,是獨立且預設關閉的低記憶體開關,同時支援 llama-server 與 Apple Silicon 的 mlx-server。llama-server 開啟時使用 --load-mode mmap,mlx-server 則將可直接映射的 safetensors 或 GGUF 權重包裝成檔案頁面;後端會先移除 Profile 中衝突的舊參數,確保 Switch 與實際行為一致。啟動參數可選擇自動或 4、8、16、24、32、48、64、96、128 GB 的 MMap 記憶體保留目標。llama-server 會透過 --fit-target 自動配置 GPU Layers;mlx-server 會把實體記憶體扣除保留目標後的空間作為 MLX 配置目標。此數值不是 Runtime 的硬性使用上限。MMap 可讓作業系統按需從磁碟載入模型頁面,但模型大幅超過實體記憶體時,首 Token 與生成速度仍會受儲存裝置及分頁頻率影響。

mlx-server Runtime

mlx-server 是本專案內建的 Apple Silicon 專用執行檔,核心載入方式參考 MangaKitchen,直接使用 MLX Swift:

  • 文生文模型:LLMModelFactory
  • 多模態模型:VLMModelFactory
  • GGUF 模型:內建 GGUF metadata、Tokenizer 與量化權重轉換器
  • HTTP Server:SwiftNIO

整個應用不呼叫 Python、mlx_lm.server、pip 或虛擬環境;Go 管理服務與 Swift MLX Runtime 都是原生執行檔。部署主機不需要安裝 Python。

啟動時可直接使用完整 MLX 模型目錄,或從一般 GGUF 模型目錄選擇 GGUF 檔案。MLX 目錄會由 config.json 自動判斷文生文或多模態架構,再載入 safetensors、Tokenizer 與 Processor;若衍生 checkpoint 保留 Vision 設定但未提供 Processor 檔案,會退回文字模型載入。支援型別由內建 mlx-swift-lm 3.31.4 註冊表動態回報,包含原生 Gemma 4 多模態模型。GGUF 則會優先使用檔案內嵌的模型設定與 Tokenizer,並在 MLX 載入階段轉換支援的量化權重;目前 Runtime 回報的直載架構為 Gemma、Llama、Mimo、MiniCPM、Mistral、Qwen2、Qwen3、Qwen3.5 與 SmolLM3。其他掃描到的語言模型會顯示在可選取的「尚未測試」群組;啟動時會交由 mlx-server 實際載入,若不相容則回報既有的失敗原因。管理頁會以 MLXGGUF 標示來源,並以獨立路徑前綴避免兩個模型根目錄的同名項目互相覆蓋。GGUF 同目錄若有且只有一份可配對的 mmproj,mlx-server 會自動掛載;完全沒有 mmproj 時則當作純文字 LLM 載入,存在多份候選時不會猜測配對。

**快速GGUF模式(Fast GGUF)**是 mlx-server 的通用 GGUF 最佳化入口,選擇 GGUF 時預設開啟。系統設定的獨立「快速 GGUF 策略」卡片同時保存預設開關與策略選擇:

  • Mode 1(均衡・預設):K-Quant super-block 沿用來源 4-bit block,該張量固定 Group 32;其餘低位元張量使用 Group 64。
  • Mode 2(較高精度):低位元來源重新量化為 INT8/Group 64,採較保守的數值路徑。
  • Mode 3(最快):低位元來源重新量化為 INT4,策略固定 Group 32,不受手動 Group Size 參數影響。

關閉快速GGUF模式時改走 auto + group auto + recurrent off 的一般 GGUF 轉換。所有策略都只依 tensor dtype、shape、來源 block 與架構 metadata 判定,不依模型檔名寫特例;Q4_K 沿用區段的 32 元素 Group 是來源格式本身的 sub-block,不代表全域改用 Group 32。--gguf-profile quality 會使用 FP32 參考權重,只適合誤差診斷,不是一般效能模式。

Fast GGUF 的設計可套用於多數 mlx-server 能解析的 GGUF,不需要為每個模型寫特例;但它不是相容性或精度保證。模型架構、GGUF metadata、Tokenizer、tensor layout、量化方式與自訂修改都可能影響結果。DFlash 1/2 仍限定搭配 MLX safetensors Target 與相容 Draft;MTP 則支援相容的原生 MLX Target/Draft,以及包含可辨識 nextn_predict_layers 與預測層 tensor 契約的 GGUF 內嵌路徑。相容性由架構 metadata 與 shape 驗證,不依模型檔名判定。

GGUF 轉換後的永久權重快取使用 Tanpopo 內部 .fgguf 容器,並直接儲存在原始 GGUF 的同一目錄:逐 tensor 判斷是否採 LZFSE 無損壓縮,沒有足夠容量收益的 tensor 保持 raw 與 MMap 對齊。此格式不是標準 GGUF,也不供其他 Runtime 交換使用;完整位元組配置、索引、壓縮門檻與相容策略請參考 FGGUF 轉換快取格式。既有 schema 2 safetensors 快取仍可由管理介面辨識與清除。已下載模型頁可用「清除快取」只移除該 GGUF 的所有轉換設定檔,原始模型不受影響;快速模式開關與三策略位於系統設定的獨立「快速 GGUF 策略」卡片。

API 提供 OpenAI/llama-server 常用相容端點:

GET  /health
GET  /v1/health
GET  /props
GET  /models
GET  /v1/models
POST /chat/completions
POST /v1/chat/completions
POST /v1/completions
POST /completion

/v1/chat/completions 支援 OpenAI 格式的文字 content、image_url 多模態 content parts,以及原生 toolstool_choicemessage.tool_calls 與工具結果訊息。stream: true 會在生成期間逐 Token 輸出 OpenAI 相容 SSE;客戶端關閉串流或取消請求時,SwiftNIO Channel 會立即取消對應的 MLX 生成 Task,不會等待整段回答生成完畢。/models/v1/models 會回傳相同的目前載入模型,方便不同 Provider 客戶端自動取得正確 Model ID。模型 API 的金鑰與 IP 白名單由 mlx-server 自己在 SwiftNIO 請求入口執行。

內建 MLX Profile 包含一般、KV Cache Q8、KV Cache Q4、強制關閉思考、DFlash 1 Greedy 與 DFlash 2 Sampling。Profile 的量化選單決定 Q8 或 Q4,執行狀態頁的 Switch 決定本次是否啟用;開啟時 Go 後端會加入 --kv-bits--kv-group-size 64--quantized-kv-start 2048,並把 Context Size 轉成 --max-kv-size。KV Cache 量化與 DFlash 不可同時啟用。其他常用原生參數包含 --kv-scheme--prefill-step-size--thinking--no-thinking

KV Cache、MMap、DFlash 與 MTP 都是 Tanpopo 的一級功能,不是只在文件中提供的手動旗標。系統設定可保存各功能的模型預設,啟動 Profile 定義細節,執行狀態頁可針對本次載入覆寫;後端會做互斥與相容性檢查、組合正確參數、保存狀態並將失敗原因回傳介面。完整整合不代表每個模型都支援所有功能:KV Cache 格式與 MMap 行為受 Runtime 限制,推測解碼需要相容 Target/Draft 或 GGUF 內嵌預測層。

原生 MLX DFlash 1/2

MLX DFlash 是直接整合在 Swift Runtime 與專案內維護的 mlx-swift-lm 3.31.4 fork,不會呼叫 Python。Target 與 Draft 都放在可設定的 MLX 模型根目錄下;執行狀態頁會依 Target 架構啟用或禁用 DFlash 開關,勾選後才會選取與 Target 配對的 Draft。實際啟動時後端才會解析安全的相對路徑並加入:

--dflash-draft <Draft 模型完整目錄>
--dflash-block-size 5
--temperature 0

目前採用可驗證、可精確回退的實作範圍:

  • 支援文生文 Qwen3 dense,以及相容的 Qwen3.5 hybrid Target;Draft 可為 DFlashDraftModelDFlash2DraftModel。Qwen3.5 啟動時會明確使用文字模型路徑,不載入 Vision wrapper。
  • DFlash 2 實作 grouped dynamic causal convolution 與 candidate path selector;selector 只保存 top-k sparse proposal probability,避免為每個位置保留完整 vocabulary 分布。
  • Greedy 解碼使用精確 token 比對,結果與 Target Greedy 一致;Sampling 使用 exact rejection sampling,支援 temperature、top-p、top-k、min-p 與既有 penalty processor,保留 Target 條件分布。同一 seed 的 DFlash 與一般生成不保證逐 token 相同,因兩者消耗亂數的路徑不同。
  • DFlash 2 搭配 Qwen3.5/Qwen3.8 hybrid Target 且使用 Greedy 時,會自動把有效 Block Size 限制為 2,避免 Gated Delta Net 多 token 與逐 token 浮點累積順序造成 argmax 分歧;Sampling 仍使用 Profile 設定的完整 Block Size。
  • DFlash 1 Profile 的 Block Size 預設為 5,DFlash 2 Profile 預設為 8,且都不會超過 Draft checkpoint 的訓練值。
  • Draft 支援 full attention 與 sliding attention;Qwen3.5 Target 的 Gated Delta Net cache 會先還原驗證前狀態,再只重播已接受的 prefix,attention KV 則移除被拒絕的 suffix。
  • Target 僅使用可精確 trim/rollback 的一般 cache,不支援 rotating 或量化 target KV Cache。
  • DFlash Profile 雖保留全域 256K Context 選項供介面一致性使用,但啟用 Draft 時不會傳入 --max-kv-size;實際可用上下文仍受 Target 模型設定與記憶體限制。
  • 多模態 DFlash target 留待後續階段;未啟用 DFlash 時不影響既有多模態功能。

若單筆 API 請求覆寫為不支援的 Target cache 設定,mlx-server 會記錄原因並安全回退到同一 Target 的一般生成,不會用近似演算法冒充 lossless speculative decoding。生成日誌會輸出 proposed、accepted 與 acceptance rate,方便比較 DFlash 是否真的帶來效益。技術流程依據 DFlash 論文官方 MLX 參考實作

固定版本位於 mlx-server/Package.swiftmlx-swift-lm 3.31.4 以含 DFlash 擴充的專案內 fork 鎖定,其餘鎖定 mlx-swift 0.31.6swift-transformers 1.1.9swift-nio 2.101.3。部署時安裝至:

~/services/mlx-server/versions/<mlx-server-version>/darwin-arm64/bin/mlx-server
~/services/mlx-server/current -> versions/<mlx-server-version>/darwin-arm64

後端會自動從部署包、上述 current 版本或開發專案的 mlx-runtime/prebuilt/darwin-arm64 尋找執行檔,並同時驗證相鄰的 MLX Metal Library;系統設定不需要也不提供 Runtime 路徑欄位。

build.commandrun.command 會將第一次成功產生的 MLX Metal Library 保存於 mlx-runtime/metal-cache/darwin-arm64/<fingerprint>/default.metallib。指紋涵蓋平台、部署版本、Metal SDK/編譯器與全部 kernel 原始碼;相同指紋的後續建置會直接把預編譯檔注入 SwiftPM bundle,不再重編 Metal kernel。clean.command 不會刪除此快取;只有指紋改變,或明確設定 MLX_METALLIB_REBUILD=1 時才會重建。

模型 API 安全性

「系統設定」可獨立控制兩項模型 API 限制:

存取金鑰 IP 白名單 行為
關閉 關閉 不增加額外限制,維持既有 API 相容性
開啟 關閉 只驗證核發的模型 API 金鑰
關閉 開啟 只驗證實際連線來源 IP
開啟 開啟 金鑰與 IP 必須同時通過

金鑰使用密碼學安全亂數產生並加上 olk_ 前綴,明文只在核發時顯示一次;設定檔只保存 SHA-256 雜湊。客戶端可使用標準 Bearer Header:

Authorization: Bearer <核發的金鑰>

也可使用:

X-OpenLoader-Key: <核發的金鑰>

IP 白名單每行一筆,支援完整 IPv4/IPv6、CIDR 與 * 萬用字元,例如:

127.0.0.1
192.168.1.*
2001:db8:*
10.0.0.0/8

單獨使用 * 代表允許所有 IP。llama-server 與 mlx-server 都只依 TCP 連線的實際來源位址判斷,不信任客戶端提供的 X-Forwarded-For;若前方另有反向代理,白名單應設定該受信任代理的來源 IP。

NetPass 反向代理

「系統設定 → 反向代理」可由 Tanpopo 管理 NetPassClient 連線,連線成功後會顯示指向目前管理服務 Port 的 NetPass 公共網址。啟動按鈕只有在下列條件全部成立時才可使用:

  • 管理介面帳號密碼登入驗證已開啟。
  • 已核發至少一組模型 API Access Key,且金鑰驗證已開啟。
  • 已閱讀並勾選使用政策與責任說明。
  • 正式安裝包已包含目前平台的 NetPassClient 執行檔。

NetPassClient 是獨立閉源元件,其原始碼、二進位檔與正式封裝流程均不包含在本儲存庫,也不會同步至 GitHub;官方簽章安裝包只會納入與目標平台相符的受控成品。NetPass Server API Key 僅保存於本機私密設定,管理 API 只回傳是否已設定,不會回傳明文;執行期間產生的最小化暫存設定會在停止連線後移除。

NetPass 反向代理為 Tanpopo 與 Mars Semi Corp. 技術合作成果,僅供技術交流與實驗用途,目前採無償方式提供;Mars Semi Corp. 保留隨時調整使用政策的權利,相關異動將另行公告。啟用後,本機管理介面與 API 呼叫將可透過公共網路存取。使用者應自行評估需求、完成必要安全設定並承擔網路安全風險;對於因使用本服務所衍生的資安事件、資料外洩或其他損失,Mars Semi Corp. 與本軟體均不承擔責任。管理介面會以多國語言顯示此說明,使用者必須勾選已閱讀,才能開啟反向代理。

Go 管理服務只負責核發金鑰並以原子替換方式更新安全策略快照,不參與模型 API 的資料轉送。兩個 Runtime 在第一次請求載入快照,之後每 10 秒檢查一次更新;請求驗證使用 Runtime 記憶體內的快取,不會逐筆回主系統核對。啟用限制後若快照遺失、損壞或版本不相容,Runtime 會採 fail-closed 並回傳 503。策略更新與金鑰撤銷最遲在下一次重新載入週期生效,不需重新載入模型。

Hugging Face 模型下載

下載表單需要:

  • 模型格式/Runtime:GGUF 單檔或完整 MLX 模型目錄。
  • Repository:例如 bartowski/Qwen2.5-7B-Instruct-GGUF
  • GGUF 檔名:選擇 GGUF 時必填;為 repository 內的完整相對檔名,可包含子目錄。
  • Revision:預設為 main,也可使用 tag、branch、完整 commit hash 或 refs/pr/...

每個主 GGUF 會在模型根目錄下建立獨立且穩定的群組目錄,目錄名稱由 repository、主 GGUF 檔名與短識別碼組成;自動偵測的 mmproj 與 DFlash Draft 會下載到同一群組。建立工作前,服務會先讀取相同 repository/revision 的檔案清單,自動尋找 .gguf 格式的 mmproj 與 DFlash Draft;若同一 repository 沒有 Draft,則依 Hugging Face 的 base_model、DFlash 標籤、模型名稱與 Target config.json 架構搜尋其他 repository,驗證配對後自動下載最合適的 Draft GGUF。每種類型最多選擇一個;若有多個候選,會優先採用明確指向相同 Base Model、官方來源及檔名 token 最相近的檔案。附屬檔案已存在且未啟用覆寫時會直接略過,不影響主模型下載。

選擇 MLX 時不需輸入單一檔名。服務會先確認 repository 同時具有 config.json 與 safetensors,再將模型權重、Tokenizer、Processor、Chat Template 等 Runtime 檔案保留原相對路徑並下載到 ~/services/mlx-models 下的獨立目錄。Target 架構支援 DFlash 時,也會以通用的 Hugging Face metadata 搜尋獨立 Draft repository,並核對 DFlashDraftModelDFlash2DraftModel、Target layer 數、hidden size 與 vocabulary size 後,把完整 Draft repository 自動加入同一批下載。分片模型只有在 index 所列的全部 safetensors 都存在後才會出現在啟動模型清單,避免下載一半時誤啟動。

服務依照 Hugging Face 官方單檔下載說明使用以下 URL 格式:

https://huggingface.co/{owner}/{model}/resolve/{revision}/{filename}

若模型需要授權,請先在 Hugging Face 接受模型條款,再於「系統設定」保存 Access Token。Token 只會寫入權限為 0600data/settings.json,管理 API 僅回傳是否已設定。

下載先寫入同目錄的 .part-* 暫存檔,完成後才替換正式模型;同一個目的檔案同時間只允許一個下載工作。啟用覆寫時會先暫存舊檔,成功替換後再移除暫存備份。模型選擇清單會遞迴掃描模型根目錄與所有子目錄,因此新舊目錄結構中的 .gguf 都會顯示。

設定檔

agent.properties

服務進入點與本機登入資料。網路與檔案路徑設定修改後需重新啟動;管理帳密與登入開關可由系統設定即時套用:

{
  "service_name": "Tanpopo",
  "http_host": "0.0.0.0",
  "http_port": 10082,
  "web_path": "./website",
  "settings_path": "./data/settings.json",
  "startup_commands_path": "./data/startup_commands.json",
  "access_control_path": "./data/access_control.json",
  "runtime_state_path": "./data/runtime_state.json",
  "default_account": "root",
  "default_pwd": "root",
  "disable_authentication": false,
  "session_hours": 24
}

data/settings.json

由「系統設定」保存 GGUF/MLX 模型目錄與 Hugging Face 設定,可在下一次啟動模型或下載工作時直接生效。llama-server 與 mlx-server 的位置由應用程式自動解析,不寫入此設定檔。

data/startup_commands.json

由「啟動參數」頁保存多組模型 Runtime 啟動參數。每組 Profile 都可選擇 KV Cache Q8 或 Q4,以及 MMap 記憶體保留目標;是否實際套用量化由執行狀態頁的 Switch 控制。首次建立時會建立 llama-server 的一般、KV Cache Q8、KV Cache Q4、強制關閉思考、MTP、DFlash,以及 mlx-server 的一般、KV Cache Q8、KV Cache Q4、強制關閉思考、DFlash 1/2、MLX MTP Profile;Context 均預設 256K。舊版設定檔會自動遷移到目前參數格式。修改 Profile 不會影響正在執行的程序,下次啟動時才會套用。

data/access_control.json

保存模型 API 的金鑰開關、IP 白名單、金鑰名稱與 SHA-256 雜湊,檔案權限為 0600。金鑰明文不會寫入檔案,也不會由查詢 API 回傳。llama-server 與 mlx-server 只讀取這份快照,不會呼叫管理服務核對單一請求。既有安裝不需手動建立,首次啟動新版服務時會自動產生。

data/netpass.json

保存 NetPass Server URL、選用裝置名稱與 NetPass Server API Key,檔案權限為 0600,設定 API 只回傳是否已設定金鑰,不回傳明文。NetPassClient 執行期間另建立最小化暫存設定,停止連線後立即移除。

data/runtime_state.json

保存最後選定的 Runtime、模型相對名稱、啟動參數 ID、mmproj 與 DFlash 狀態,不保存本機模型根目錄、Runtime 二進位檔位置或任何金鑰。模型服務成功啟動後會標記為下次需恢復;關閉 Tanpopo 時只停止子程序並保留旗標,因此恢復流程不需要先登入管理介面。使用者在執行狀態頁按下「停止服務」時則會清除恢復旗標。若模型或啟動參數已不存在,自動恢復會停止並記錄可診斷錯誤,避免每次啟動重複失敗。

REST API

啟用管理介面登入時,除健康檢查、登入與 Session 狀態外,其餘 API 都需要已登入的 Session Cookie;關閉登入驗證時則可直接使用管理 API。

Method Path 用途
GET /api/health 服務健康檢查
POST /api/login 使用本機設定帳密登入
POST /api/logout 清除目前 Session
GET/PUT /api/admin-credentials 查詢登入狀態或更新管理帳密與登入開關;不回傳密碼明文
GET/PUT /api/settings 讀取或保存模型目錄與 Hugging Face 設定
GET/PUT /api/access-control 讀取或保存模型 API 金鑰/IP 白名單策略
POST /api/access-control/keys 核發模型 API 金鑰;明文只在此回應一次
DELETE /api/access-control/keys/{id} 撤銷模型 API 金鑰
GET /api/netpass/status 查詢 NetPassClient、公共網址與安全性前置條件狀態
PUT /api/netpass/config 保存 NetPass Server 連線設定;不回傳 API Key 明文
POST /api/netpass/start 明確確認公共網路風險後啟動反向代理
POST /api/netpass/stop 停止反向代理並清除執行期憑證檔
POST /api/system/directories 瀏覽服務主機的可用目錄
GET /api/models?runtime=... 依 Runtime 掃描 GGUF 或 MLX Target;mlx-server 會合併支援的 GGUF,並可加 role=draft 取得 MLX DFlash Draft
GET/POST /api/startup-commands 查詢或建立啟動參數 Profile
PUT/DELETE /api/startup-commands/{id} 修改或刪除啟動參數 Profile
GET/POST /api/downloads 查詢或建立下載工作
GET /api/runtime/status 查詢目前模型 Runtime 狀態
GET/DELETE /api/runtime/logs 查詢或清除目前 Runtime 日誌
POST /api/runtime/start 依 Profile 載入模型並啟動 Runtime
POST /api/runtime/stop 停止目前模型 Runtime

專案結構

src/cmd/llamaloader/  服務進入點與關閉流程
src/api/              HTTP 路由與網站入口
src/appversion/       APP 版本與更新來源建置資訊
src/updatecheck/      GitHub Release 定時檢查與版本比較
src/config/           本機 JSON 設定讀寫與驗證
src/accesscontrol/    模型 API 金鑰與 IP 白名單策略快照管理
src/startupcommand/   llama-server 啟動參數 Profile 保存
src/session/          最小化的記憶體登入 Session
src/download/         Hugging Face 背景下載與進度
src/llamacpp/         模型掃描與 llama-server/mlx-server 程序管理
src/domain/           共用資料型別
src/directorybrowser/ 服務主機目錄瀏覽資料
src/desktopui/        GUI 工作階段偵測與原生視窗程序管理
src/netpass/          NetPassClient 子程序、私密設定與公開網址狀態管理
desktop-ui/           macOS AppKit/WKWebView 原生 UI 原始碼
scripts/              llama-server/mlx-server/原生 UI 建置工具
llama-server/         鎖定版本、只供建置 llama-server 的精簡 llama.cpp 原始碼
llama-runtime/        預編譯 Runtime 暫存與封裝規格
mlx-server/            Swift/MLX 相容 API Server 與鎖定的 mlx-swift-lm fork
mlx-runtime/           Apple Silicon 預編譯 Runtime 與持久化 Metal Library 快取
website/              登入、管理介面與常用模型 JSON 清單

授權

Tanpopo 中由專案著作權人擁有的原創程式碼採雙軌授權,適用範圍見 LICENSE-NOTICE.md

  • 開放原始碼:GNU General Public License v3.0 or later(GPL-3.0-or-later),完整條款見 LICENSE
  • 商業授權:不適合採用 GPL 的使用情境,可另行洽談書面商業授權,詳見 COMMERCIAL-LICENSE.md

第三方程式碼與相依套件維持各自的授權條款,詳見 THIRD_PARTY_NOTICES.md。安全性與私密回報方式見 SECURITY.md

建置

專案內的 llama-server/ 是預設且已鎖定版本的原始碼。執行 build.command 時,如果目前主機缺少相同版本的 llama-server Runtime,封裝器會自動原生編譯並保存至 llama-runtime/prebuilt/<platform>。例如也可以手動執行:

./scripts/build-llama-server-runtime.sh \
  ./llama-server \
  ./llama-runtime/prebuilt/darwin-arm64 \
  custom-4e97ac86ebe2-openloader.3

Linux x64 使用相同命令,但輸出位置改為 ./llama-runtime/prebuilt/linux-amd64。已有預編譯檔時,其 VERSION 必須與內建原始碼版本一致。若封裝主機沒有其他平台的預編譯檔,該平台不會造成封裝失敗;部署包仍會攜帶完整精簡原始碼,並在安裝到該平台時原生編譯。封裝時也可以指定自訂原始碼與鎖定版本:

Apple Silicon 的 mlx-server 可獨立建立;build.sh 找不到正確版本的預編譯檔時,也會在 Apple Silicon 封裝主機自動執行此步驟:

./scripts/build-mlx-server-runtime.sh
LLAMA_CPP_SOURCE_DIR=/path/to/our-llama.cpp \
LLAMA_SERVER_VERSION=b12345-custom.1 \
./build.sh

./bin/Tanpopo

build.sh 只會建置及收集 llama-server target,不會執行 Git 或更新 llama.cpp。內建快照目前鎖定官方 commit 4e97ac86ebe2c4cb8212d98d2641ad6768810896,包含 qwen35qwen35moe 架構支援。封裝內容會排除 .git、文件、測試、範例、既有 build 目錄等開發檔案,但保留建置 llama-server 所需的 ggmlcommontools/servertools/mtmd、UI 載入器、CMake 與相依原始碼。依先前約定,部署 ZIP 由維護者需要時自行執行 build.command 產生。

未指定 LLAMA_CPP_SOURCE_DIR 時,封裝器會直接優先使用專案內的 llama-server/;只有該目錄不存在時,才依序檢查專案內的 llama.cpp~/services/llama.cpp~/llama.cpp,最後在 ~/Codes 內尋找唯一的外部原始碼。內建原始碼的版本鎖定位於 llama-runtime/SOURCE_VERSION;外部來源可使用 LLAMA_SERVER_VERSIONLLAMA_SERVER_VERSION_FILE 或來源目錄的 LLAMA_SERVER_VERSION 指定,否則會讀取 cmake/build-info.cmake 或原始碼 commit 中繼資料。版本檔不可命名為 VERSION 放在 llama.cpp 原始碼根目錄,避免 macOS 不分大小寫的檔案系統攔截 C++ 標準標頭 <version>

可先執行 ./build.command --check,只檢查實際採用的原始碼、版本及 Runtime 策略,不會開始編譯或建立 ZIP。輸出會明確標示哪些平台會在封裝時編譯,以及哪些平台改由部署時原生編譯。

執行檔仍需能讀取工作目錄下的 agent.sample.propertieswebsite/。如由其他目錄啟動,可使用參數指定設定範本:

./bin/Tanpopo \
  -config /path/to/agent.properties \
  -sample-config /path/to/agent.sample.properties

About

Local model service manager for llama-server and Apple Silicon MLX Server

Resources

Security policy

Stars

2 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages