Ollama 封面圖:在自己的電腦執行開源語言模型

Ollama 教學:本機執行開源模型,實測串接 Open WebUI、OfficeCLI 與資安設定

內容概述

Ollama 是 MIT 授權的開源模型執行工具,讓您在自己的 macOS、Windows 或 Linux 電腦上下載並執行 Qwen、Gemma、Llama、gpt-oss 等開放模型,並提供命令列工具(CLI)、本機 REST API,以及與 OpenAI API 相容的介面。在本機執行時,提示詞與資料不會離開您的電腦,軟體本身免費,成本主要落在硬體。

這次強哥在一台沒有 GPU 的 Linux 實驗主機上,用 Docker 實測了一條完整的路線:Ollama 0.40.13 執行 qwen3.5:0.8b 小模型,前面接 Open WebUI v0.12.5 聊天介面,再透過 mcpo 0.0.20 把 OfficeCLI v1.0.160 的 MCP 工具接進來,讓模型「用聊天產生 Word 會議記錄」。先講結論:架設和資安設定都能做得很穩,但 0.8b 小模型在 42 次文件產生測試中,沒有一次產出完全正確的檔案,還會在檔案缺內容時回報「已成功」。官方文件的安裝方式、API 用法與資安建議,本文也一併整理(標明為查核,未實機測試)。

讀完本文,您可以:

  • 用 Docker 安全地跑起 Ollama:只綁 127.0.0.1、限制記憶體、關掉雲端模型,並知道 0.8b/2b 小模型在 CPU 上的實際速度與記憶體用量。
  • 把 MCP 工具接到 Open WebUI:用 mcpo 把 OfficeCLI 轉成有金鑰驗證的 OpenAPI 工具伺服器,並看懂 Native、Legacy、技能(Skills)三種呼叫方式的實測差異。
  • 避開自架 AI 工具的資安與維運陷阱:包含金鑰明文存放、CORS、撤銷權限後殘留的舊金鑰、逾時後伺服器端仍繼續執行,以及容器記憶體不足(OOM)。

成本與風險摘要

先看這裡:

動手前先了解要花多少資源、風險在哪裡:

  • 適用對象與規模:個人開發者、想在本機試用開源模型的工程師,以及幾個人共用一台主機的小團隊。要讓小模型「自動產生正式文件」目前不可靠:本次 0.8b 在 48 次測試(含 10/31 重測 6 次)中 0 次完全正確,產出一定要有人檢查。
  • 成本(硬體、訂閱、授權):Ollama(MIT)、mcpo(MIT)、OfficeCLI(Apache-2.0)免費;Open WebUI 採自訂的 Open WebUI License(不是 OSI 認證的開源授權),超過 50 位使用者時不能移除品牌標示。本次三個容器的記憶體上限合計約 5 GB(Ollama 3g、Open WebUI 1.5g、mcpo 512m),映像檔約 9.7 GB、模型約 4 GB。
  • 維護時間:mcpo 最新版 0.0.20(2026-02-28 發布)和新版 mcp 套件不相容,要鎖定相依套件版本才裝得起來;OfficeCLI 版本更新很快(v1.0.160 在 2026-10-30 發布),建議關閉自動更新、手動驗證後再升級。
  • 資安注意事項:Ollama 本機 API 沒有驗證,所有連接埠請只綁 127.0.0.1;工具伺服器的 Bearer 金鑰會以明文存在 Open WebUI 資料庫,管理員看得到;Open WebUI 預設 CORS 是 *,要自己收緊。
  • 常見誤區:以為模型說「驗證通過」檔案就是對的(實測有內容缺一半仍宣稱成功的情況);以為使用者能在聊天裡下載產生的 Word 檔(其實檔案只寫在工具容器的 /out 資料夾);以為 Docker 的 -p 11434:11434 只開給本機。
  • 不建議使用的情況:需要一般使用者自助產生、下載文件的服務;記憶體小於 8 GB 又沒有獨立顯示卡,卻想跑工具呼叫這類長流程;需要帳號權限、稽核紀錄的正式服務卻不打算加驗證閘道。
  • 測試日期與版本號:實測日期 2026-10-30,2026-10-31 另重測技能範本 6 次(台北時間):Ollama 0.40.13、Open WebUI v0.12.5(slim 映像)、mcpo 0.0.20、OfficeCLI v1.0.160、模型 qwen3.5:0.8b 與 qwen3.5:2b,Linux(Debian 13)+Docker 29.9.2、無 GPU。資料查核日期 2026-10-30:macOS/Windows 安裝、Modelfile、REST API、程式庫與雲端方案等內容依官方文件整理,未實機測試。

第一部分:適不適合您

先看 Ollama 能做什麼、這次串接的架構長什麼樣子,以及您的硬體與需求適不適合。

應用場景

Ollama 適合「想用大型語言模型,但不想把資料交給雲端服務」的情境,例如:

  • 處理機密文件:合約、內部文件或客戶資料的摘要與改寫。官方 FAQ 寫明「We don’t see your prompts or data when you run locally」。
  • 自架 AI 應用的模型後端:讓 Open WebUI、Dify、ChatOllama 這類工具透過 API 呼叫本機模型。
  • 讓模型呼叫工具:本次實測的情境:在 Open WebUI 聊天中,讓模型透過 OfficeCLI 建立 Word 檔。架構可行,但小模型的可靠度不夠,詳見「實測結果」。
  • 程式開發輔助:用 ollama launch 把模型接到 Claude Code、Codex、OpenCode 等程式助手(官方 README 列出的整合,未實測)。
  • 知識庫與 RAG:用 nomic-embed-text、embeddinggemma 等嵌入模型產生向量,搭配向量資料庫做文件檢索(未實測)。

技術特點與整合

示意圖:CLI、Python/JavaScript 函式庫、OpenAI 相容 SDK 與 Open WebUI 等用戶端,都連到預設只聽 127.0.0.1:11434 的 Ollama 伺服器,再由 llama.cpp 或 MLX 執行引擎使用 GPU 或 CPU,模型檔存在 ~/.ollama/models
圖:Ollama 的運作方式(原創示意圖,依官方文件繪製)
  • 一個指令下載並執行模型:ollama run gemma4 會自動下載模型並進入對話;模型清單在 ollama.com/library。
  • 本機 REST API:預設在 http://localhost:11434/api,提供 chat、generate、embeddings 與模型管理等端點。
  • OpenAI 與 Anthropic 相容介面:/v1 支援部分 OpenAI API,也有 Anthropic 相容的 /v1/messages,現有程式通常只要改 base_url。
  • 工具呼叫(tool calling):支援工具的模型(例如本次的 qwen3.5)可以回傳結構化的工具呼叫。實測 0.8b 與 2b 在單純的工具呼叫測試(查天氣、建立文件各 3 次)都是 3/3 正確,但變成多步驟的 Word 產生流程就失敗了。
  • 多種硬體加速:NVIDIA(CUDA)、AMD(ROCm v7)、Apple Silicon 與 Vulkan;沒有 GPU 時用 CPU 執行(本次實測就是 CPU)。
  • 選用的雲端模型:登入後可用雲端模型;不需要時可以用 OLLAMA_NO_CLOUD=1 整個關閉(本次實測有關閉)。

這次串接的另外三個元件:

  • Open WebUI:自架的聊天介面,提供帳號、模型權限、工具伺服器與技能(Skills)設定。
  • OfficeCLI:用指令建立與編輯 Word、Excel、PowerPoint 檔的工具,內建 MCP 伺服器(officecli mcp,以 stdio 溝通)。
  • mcpo:Open WebUI 團隊的轉接工具,把 stdio 的 MCP 伺服器包成有 API 金鑰的 OpenAPI 伺服器,Open WebUI 才能當成「工具伺服器」使用。

近期版本重點

以下整理自 GitHub Releases(2026-10-30 查核):

版本重點
v0.40.13LFM3 模型可在 Linux 與 Windows 上執行(本次實測版本)
v0.40.12新增 LFM3 系列與 d1 decision 模型;Apple Silicon 上的提示詞處理加快
v0.40.11macOS 支援語音輸出(/v1/audio/speech)
v0.40.0Apple Silicon 上支援的模型預設使用 MLX

適用規模與不適合的情況

長條圖:ollama.com 模型庫標示的下載大小,llama3.2:1b 1.3 GB、llama3.2:3b 2.0 GB、qwen3.5:4b 3.3 到 4.0 GB、deepseek-r1:8b 5.2 GB、gemma4:e2b 4.6 到 7.5 GB、qwen3.5:9b 6.6 到 7.6 GB、gemma4:e4b 6.6 到 9.5 GB、gpt-oss:20b 14 GB、gemma4:31b 19 到 20 GB、deepseek-r1:70b 43 GB、gpt-oss:120b 65 GB
圖:常見模型的下載大小(原創圖表,資料來源:ollama.com/library,2026-10-30 查核)

模型檔大小大致等於需要的記憶體下限,再加上上下文所需的空間。本次實測的兩個小模型,在 CPU 上的數字如下(上下文長度 8192):

項目qwen3.5:0.8bqwen3.5:2b
模型檔大小(ollama list)1.3 GB2.7 GB
關閉 thinking 後的輸出速度約 51~64 tok/s(另需關閉草稿模型,見踩坑紀錄)約 30~31 tok/s
基本測試時容器記憶體峰值2.806 GiB(上限 3g)4.218 GiB(上限 4.5g)
工具呼叫長流程在 3g 上限下 OOM 7 次未測(需要 4.5g 以上)

官方建議的記憶體對應(未實測):gemma4:e2b 下載約 7.2 GB,官方建議 8 GB 可用 VRAM 或 Mac 統一記憶體;VRAM 不夠時會改用系統 RAM,回應會變慢。

自架與 ollama.com 雲端怎麼選:

  • 本機執行:軟體免費,資料不離開電腦;成本是硬體、電費與您的維護時間。適合資料敏感、使用量穩定的情境。
  • ollama.com 雲端方案(Pricing 頁面,2026-10-30 查核):免費方案可在本機執行模型;Pro 每月 US$20(或每年 US$200);Max 每月 US$100;Team 每月 US$500。官方 FAQ 說明雲端模型會處理您的提示詞與回應,但不儲存、不記錄,也不拿來訓練;機密資料仍建議只用本機模型。

不適合的情況:

  • 要小模型自動產生正式文件:本次 0.8b 在 48 次 Word 產生測試(含 10/31 重測 6 次)中 0 次完全正確,最好的一次也只做出 6 項內容中的 3 項。
  • 要讓一般使用者自己下載產出的檔案:這個架構的檔案只寫在工具容器的資料夾,聊天介面不會出現下載連結。
  • 多人正式服務卻沒有驗證閘道:Ollama 本身沒有帳號系統,也預設一次處理有限的請求(OLLAMA_NUM_PARALLEL 預設 1),要服務大量使用者應另外評估推論伺服器。

第二部分:動手實測

這一部分照實際執行的順序,從測試環境、安裝、串接工具到實測結果,每一步都附上實際輸出。

測試環境

項目本次實測
主機Linux 實驗主機(Debian 13、8 vCPU、約 15 GiB 記憶體、無 GPU),Docker 29.9.2
OllamaDocker 映像 ollama/ollama:0.40.13,記憶體上限 3g,只綁 127.0.0.1:11434
Open WebUIghcr.io/open-webui/open-webui:v0.12.5-slim,上限 1.5g,只綁 127.0.0.1:18010
mcpo+OfficeCLI自建映像(mcpo 0.0.20+OfficeCLI v1.0.160),上限 512m,只綁 127.0.0.1:18012
模型qwen3.5:0.8b(主測)、qwen3.5:2b(只做基本測試),上下文長度 8192
網路三個容器在同一個 Docker 網路 jslab-owui-net,彼此用容器名稱連線

以下指令都是本次實際執行過的指令(只省略實驗用的標籤參數),金鑰與密碼都改成 <...> 代號。

安裝步驟

步驟 1:了解官方安裝方式(查核,未實測)

Ollama 官方支援 macOS(Sonoma 14 以上)、Windows 10 22H2 以上與 Linux(x86_64、ARM64)。以下指令來自官方 README 與 docs.ollama.com(2026-10-30 查核),本次只實測 Docker 方式:

curl -fsSL https://ollama.com/install.sh | sh
curl -fsSL https://ollama.com/install.sh | OLLAMA_VERSION=0.40.13 sh

第二行是固定版本的寫法。Windows 可在 PowerShell 執行 irm https://ollama.com/install.ps1 | iex,或下載 OllamaSetup.exe。

注意:執行安裝腳本前先看內容

「下載後直接交給 sh 執行」等於讓腳本用您的權限做任何事。在正式主機上,建議先用 curl -fsSL https://ollama.com/install.sh -o install.sh 存檔、看過內容再執行。

Linux 手動安裝與 systemd 服務(官方範例)

官方文件的手動安裝與開機自動啟動指令如下,完整步驟(建立專用 ollama 使用者、服務檔內容)請見 Linux 文件:

curl -fsSL https://ollama.com/download/ollama-linux-amd64.tar.zst \
    | sudo tar x -C /usr
sudo systemctl daemon-reload
sudo systemctl enable ollama
sudo systemctl start ollama
journalctl -e -u ollama

AMD 顯示卡請改下載 ollama-linux-amd64-rocm.tar.zst,ARM64 請下載 ollama-linux-arm64.tar.zst。

步驟 2:用 Docker 執行 Ollama,只綁本機並關閉雲端(實測)

先建立三個容器共用的 Docker 網路,再啟動 Ollama。重點有三個:-p 127.0.0.1:11434:11434 只開給本機、--memory 3g 限制記憶體、OLLAMA_NO_CLOUD=1 關閉雲端模型:

sudo docker network create jslab-owui-net
sudo docker run -d --name jslab-ollama --network jslab-owui-net \
  --memory 3g --memory-swap 3g \
  -p 127.0.0.1:11434:11434 -v jslab-ollama:/root/.ollama \
  -e OLLAMA_CONTEXT_LENGTH=8192 -e OLLAMA_NO_CLOUD=1 \
  ollama/ollama:0.40.13
curl -s http://127.0.0.1:11434/api/version
ss -ltn | grep 11434

成功時您會看到(實測輸出節錄):

{"version":"0.40.13"}
LISTEN 0      4096       127.0.0.1:11434      0.0.0.0:*
msg="Ollama cloud disabled: true"

Ollama cloud disabled: true 出現在容器記錄(sudo docker logs jslab-ollama),代表雲端模型已關閉。

危險:Docker 的 -p 預設開在所有網路介面

Docker 官方文件寫明「Publishing container ports is insecure by default」:官方範例的 -p 11434:11434 會綁在主機的 0.0.0.0,同網路的其他電腦都能呼叫沒有驗證的 Ollama API。只在本機使用時,請一律寫成 -p 127.0.0.1:11434:11434。

示意圖:A 為預設 127.0.0.1:11434,只有本機連得到;B 為 OLLAMA_HOST=0.0.0.0:11434,同網路任何人都能呼叫沒有帳號密碼的 API;C 為需要給別人用時,維持只聽 127.0.0.1,前面放有驗證的反向代理或 VPN,再以防火牆限制來源
圖:11434 連接埠的三種開放方式(原創示意圖,依官方文件繪製)

步驟 3:下載模型並關閉 thinking 與草稿模型(實測)

一般情況下用 ollama pull 下載模型:

sudo docker exec jslab-ollama ollama pull qwen3.5:0.8b
sudo docker exec jslab-ollama ollama pull qwen3.5:2b
sudo docker exec jslab-ollama ollama list

成功時您會看到(實測輸出節錄):

NAME            ID              SIZE      MODIFIED
qwen3.5:2b      0689d44085e0    2.7 GB    55 minutes ago
qwen3.5:0.8b    de63045f2975    1.3 GB    About an hour ago

本次實驗主機的網路環境特殊,ollama pull 被 Ollama 的安全檢查擋下,改用手動下載並逐一驗證 sha256(見「踩坑紀錄」與【進階】章節)。一般讀者的環境通常不會遇到。

qwen3.5 預設開啟 thinking(先思考再回答)。實測 0.8b 用 ollama run 問一個簡單問題,花了 12 分 18 秒、產生 5485 個 token,最後回答還是簡體中文。用 API 呼叫時加上 "think": false 關閉,回答就只要幾秒:

curl -s http://127.0.0.1:11434/api/chat -d '{
  "model": "qwen3.5:0.8b",
  "messages": [{"role": "user", "content": "<您的問題>"}],
  "think": false,
  "stream": false
}'

0.8b 還內建一個加速用的草稿模型(MTP draft),但在 CPU 上反而讓速度慢了大約 10 倍,要用 draft_num_predict=0 關閉(數據見「踩坑紀錄」)。

步驟 4:安裝 Open WebUI 並收緊預設值(實測)

Open WebUI 用 slim 映像,透過 Docker 網路以容器名稱連 Ollama。WEBUI_SECRET_KEY 放在權限 600 的 env 檔,不寫在指令列;同時關閉版本檢查、OpenAI 連線,並把 CORS 限定在自己的網址:

sudo docker run -d --name jslab-openwebui --network jslab-owui-net \
  --memory 1.5g --memory-swap 1.5g \
  -p 127.0.0.1:18010:8080 -v jslab-openwebui:/app/backend/data \
  --env-file <env 檔路徑> \
  -e OLLAMA_BASE_URL=http://jslab-ollama:11434 \
  -e ENABLE_VERSION_UPDATE_CHECK=false -e ENABLE_OPENAI_API=false \
  -e CORS_ALLOW_ORIGIN=http://127.0.0.1:18010 \
  ghcr.io/open-webui/open-webui:v0.12.5-slim

啟動後第一個註冊的帳號會成為管理員,之後的註冊預設會被拒絕。強哥用 curl 檢查了 CORS、第二次註冊與未登入存取:

成功時您會看到(實測輸出節錄):

health_after=18s
access-control-allow-origin: http://127.0.0.1:18010
== second signup (should be refused)
{"detail":"You do not have permission to access this resource. Please contact your administrator for assistance."} HTTP 403
== no-token models
HTTP 401

從其他來源(測試用的 evil.example)送出的請求,回應裡不會有 access-control-allow-origin。

注意:CORS 預設是 *

沒有設定 CORS_ALLOW_ORIGIN 時,Open WebUI 的啟動記錄會出現 CORS_ALLOW_ORIGIN IS SET TO '*' 的警告。設定成自己的網址並重建容器後,這個警告就消失了(資料 volume 保留即可)。

另外兩個建議設定:

  • 在模型設定關閉 thinking 與草稿模型:在工作區(Workspace)→ 模型的 Advanced Params 設定 think=false,並加自訂參數 draft_num_predict=0(本次用 API 設定)。Open WebUI 會把不認得的自訂參數直接傳給 Ollama。
  • 關閉背景任務:Open WebUI 預設會用同一個模型在背景產生對話標題、後續建議與標籤,每則訊息都會多跑幾次推論。本次在管理員設定 → 介面把 title、follow-up、tags、autocomplete 等背景任務全部關閉。

授權提醒

Open WebUI 採用自訂的 Open WebUI License,不是 OSI 認證的開源授權。依授權第 4 條,除非 30 天內的使用者不超過 50 人、取得書面同意或購買企業授權,否則不能修改或移除 Open WebUI 的品牌標示。

步驟 5:用 mcpo 把 OfficeCLI MCP 轉成 OpenAPI 工具伺服器(實測)

OfficeCLI 的 MCP 伺服器(officecli mcp)用 stdio 溝通,Open WebUI 的工具伺服器則要 OpenAPI。mcpo 負責轉接,並加上 API 金鑰驗證。強哥自建了一個映像,重點是:

  • 基底映像用 digest 固定:python:3.13-slim@sha256:2d4473…。
  • 安裝 ICU 函式庫:OfficeCLI 是 .NET 程式,缺少 libicu76 時會直接中止。
  • 相依套件鎖版本並驗證雜湊:用 mcpo v0.0.20 官方 uv.lock 匯出的清單,pip install --require-hashes(原因見踩坑紀錄)。
  • OfficeCLI 執行檔驗證 sha256:和 Release 頁面的 SHA256SUMS 比對。
  • 以非 root 執行:USER 1000:1000,並關閉 OfficeCLI 自動更新。

Dockerfile 的關鍵段落:

FROM python:3.13-slim@sha256:2d44738ebf4ce5f63b9d9ea871e9c7cfdc0426f7b0c97cac915fd88ded1d86bb
RUN apt-get update \
 && apt-get install -y --no-install-recommends libicu76 \
 && rm -rf /var/lib/apt/lists/*
COPY requirements.lock.txt /tmp/req.txt
RUN pip install --no-cache-dir --require-hashes --no-deps -r /tmp/req.txt && pip check
COPY --chmod=755 officecli /usr/local/bin/officecli
COPY --chmod=644 launch.py /app/launch.py
RUN echo "baa084b64ec634bd9d41a0592db3ed85f11658b358bab898679537ea7f3e73a9  /usr/local/bin/officecli" | sha256sum -c - \
 && useradd -u 1000 -m -d /home/app app && mkdir -p /out && chown 1000:1000 /out
ENV OFFICECLI_SKIP_UPDATE=1 OFFICECLI_NO_AUTO_INSTALL=1 HOME=/home/app
USER 1000:1000
WORKDIR /out
CMD ["python", "/app/launch.py"]

launch.py 從唯讀掛載的檔案讀出金鑰,再啟動 mcpo,這樣金鑰不會出現在 ps 看得到的指令列,也不會出現在 docker inspect 的環境變數裡:

import sys
from pathlib import Path

key = Path("/run/secrets/mcpo.key").read_text().strip()
if len(key) < 32:
    sys.exit("mcpo.key missing or too short")
sys.argv = [
    "mcpo", "--host", "0.0.0.0", "--port", "8000",
    "--api-key", key, "--strict-auth",
    "--cors-allow-origins", "http://127.0.0.1:18010",
    "--name", "OfficeCLI",
    "--", "officecli", "mcp",
]
from mcpo import app
app()

啟動容器時把根目錄設成唯讀、移除所有 Linux capabilities,只把 /out 掛成可寫的輸出資料夾:

sudo docker run -d --name jslab-mcpo --network jslab-owui-net \
  --memory 512m --memory-swap 512m --pids-limit 256 \
  --user 1000:1000 --read-only --tmpfs /tmp --tmpfs /home/app:uid=1000,gid=1000 \
  --cap-drop ALL --security-opt no-new-privileges \
  -e HOME=/home/app -e OFFICECLI_SKIP_UPDATE=1 -e OFFICECLI_NO_AUTO_INSTALL=1 \
  -v <金鑰檔路徑>:/run/secrets/mcpo.key:ro -v <輸出資料夾>:/out \
  -p 127.0.0.1:18012:8000 jslab/mcpo-officecli:0.0.20-1.0.160

成功時您會看到(實測輸出節錄):

Starting MCP OpenAPI Proxy on 0.0.0.0:8000 with command: officecli mcp
Up 8 seconds 127.0.0.1:18012->8000/tcp

接著檢查驗證與 CORS。沒帶金鑰一律 401、金鑰錯誤 403、從其他來源的 CORS 預檢被拒絕,三個連接埠都只聽 127.0.0.1:

成功時您會看到(實測輸出節錄):

no key   GET /docs -> 401
no key   POST /officecli -> 401
bad key  POST /officecli -> 403
good key GET /openapi.json -> 200
CORS preflight from 18010:
HTTP/1.1 200 OK
CORS preflight from evil.example:
HTTP/1.1 400 Bad Request
LISTEN 0      4096       127.0.0.1:18012      0.0.0.0:*
LISTEN 0      4096       127.0.0.1:18010      0.0.0.0:*
LISTEN 0      4096       127.0.0.1:11434      0.0.0.0:*
from LAN IP (172.30.0.2):18012 -> 000
實測截圖:mcpo 產生的 OpenAPI 文件頁,標題為 officecli 1.0.160,紅框標出唯一的端點 POST /officecli 與右上角的 Authorize 按鈕
實測截圖:OfficeCLI 的 MCP 經 mcpo 轉接後只有一個 POST /officecli 端點(紅框為重點標註;強哥的實驗環境)

用金鑰直接呼叫,確認 OfficeCLI 能建立 Word 檔。command 可以是字串,也可以是 JSON 陣列:

curl -s http://127.0.0.1:18012/officecli \
  -H "Authorization: Bearer <mcpo 金鑰>" -H 'Content-Type: application/json' \
  -d '{"command":["add","/out/t14.docx","/body","--type","paragraph","--prop","style=Heading1","--prop","text=mcpo 測試標題"]}'

成功時您會看到(實測輸出節錄):

--- POST {"command":"--version"}
"1.0.160"
--- POST {"command":"create /out/t14.docx"}
"Created: /out/t14.docx"
--- POST {"command":["add","/out/t14.docx","/body","--type","paragraph","--prop","style=Heading1","--prop","text=mcpo 測試標題"]}
"Added paragraph at /body/p[@paraId=00100000]\nWARNING: style 'Heading1' was not defined in the styles part; added Word's built-in definition ('heading 1')"
--- POST {"command":"add /out/t14.docx /body --type table --prop rows=3 --prop cols=3"}
"Added table at /body/tbl[1]"
--- POST {"command":"validate /out/t14.docx"}
"Validation passed: no errors found."
--- POST {"command":"create /etc/x.docx"}
"500: {'message': \"Error: Read-only file system : '/etc/x.docx'\"}"

最後一行是刻意測試:容器根目錄唯讀,寫到 /etc 會失敗。

步驟 6:在 Open WebUI 註冊工具伺服器與技能(實測)

管理員到管理員設定 → Integrations → External Tool Servers 新增連線。網址填容器名稱 http://jslab-mcpo:8000(Open WebUI 從伺服器端連線),Auth 選 Bearer 並貼上 mcpo 金鑰,再用 Access Control 只授權給需要的使用者:

實測截圖:Open WebUI 管理員的 Edit Connection 視窗,紅框標出 URL http://jslab-mcpo:8000、Bearer 金鑰欄位(已遮罩)與 Access Control 按鈕
實測截圖:在管理員設定註冊 OfficeCLI 工具伺服器,金鑰欄位為遮罩顯示(紅框為重點標註;強哥的實驗環境)

接著在工作區建立技能(Skills),把 OfficeCLI 的正確指令寫成範本,再建立模型預設(preset),綁定工具與技能。以下是技能內容的節錄,代號 <檔案路徑> 是強哥改過的寫法(原因與 10/31 重測結果見踩坑紀錄):

每次呼叫 tool_officecli_post 只做一件事。command 用 JSON 字串陣列,
第一個元素是子指令,第二個是檔案路徑 <檔案路徑>。
`create` 只建立空白檔,不接受標題或內容參數。內容一律用 `add`,表格儲存格用 `set`。

1. 建立空白檔:["create","<檔案路徑>"]
2. 大標題:["add","<檔案路徑>","/body","--type","paragraph","--prop","style=Heading1","--prop","text=標題文字"]
7. 表格:["add","<檔案路徑>","/body","--type","table","--prop","rows=4","--prop","cols=3"]
8. 填儲存格:["set","<檔案路徑>","/body/tbl[1]/tr[1]/tc[1]","--prop","text=項目"]
9. 檢查:["validate","<檔案路徑>"]

- 只用使用者提供的內容,不要自己加。
- 全部 add/set 做完後執行 validate;validate 通過才回報完成,並告訴使用者檔案路徑。
實測截圖:Open WebUI 模型預設 jslab-oc-skill 的編輯頁,紅框標出 Base Model 為 qwen3.5:0.8b,以及 Tools 為 OfficeCLI (mcpo)、Skills 為 officecli-minutes、Builtin Tools 只開 Skills
實測截圖:模型預設綁定 OfficeCLI 工具與 officecli-minutes 技能(紅框為重點標註;強哥的實驗環境)

注意:一般使用者要另外授權 base model

非管理員使用模型預設時,除了預設本身,還要有底層 base model(這裡是 qwen3.5:0.8b)的讀取權限,否則 API 只會回「Model not found」,記錄裡才看得到 base_model_read_denied。另外,用模型更新 API 修改時不會改到存取權限,要另外呼叫存取權限的更新 API。

常用指令與 API(依官方文件)

以下整理自官方 CLI 文件與 API 文件(2026-10-30 查核)。用 Docker 執行時,在指令前加 sudo docker exec -it jslab-ollama:

指令用途
ollama run gemma4執行模型並進入對話(本機沒有時會先下載)
ollama pull gemma4只下載模型(或更新到最新版)
ollama ls列出已下載的模型
ollama ps查看目前載入記憶體的模型,以及用 GPU 還是 CPU
ollama stop gemma4把模型從記憶體卸載
ollama rm gemma4刪除模型檔,釋放磁碟空間
ollama create <名稱> -f Modelfile用 Modelfile 建立自訂模型
ollama show --modelfile llama3.2查看模型的 Modelfile

用 Modelfile 自訂模型

Modelfile 是設定模型行為的文字檔,可以固定系統提示詞與參數。以下是官方文件的範例:

FROM llama3.2
PARAMETER temperature 1
PARAMETER num_ctx 4096
SYSTEM You are Mario from super mario bros, acting as an assistant.

存檔後用 ollama create <名稱> -f ./Modelfile 建立,再用 ollama run <名稱> 執行。

用 REST API 與 OpenAI SDK 呼叫

官方 README 的 chat 範例,"stream": false 會一次回傳完整結果:

curl http://localhost:11434/api/chat -d '{
  "model": "gemma4",
  "messages": [{"role": "user", "content": "Why is the sky blue?"}],
  "stream": false
}'

已經用 OpenAI SDK 寫好的程式,把 base_url 指到本機的 /v1 即可。官方文件說明 API 金鑰欄位「required but ignored」:

from openai import OpenAI

client = OpenAI(base_url='http://localhost:11434/v1/', api_key='ollama')
chat_completion = client.chat.completions.create(
    messages=[{'role': 'user', 'content': 'Say this is a test'}],
    model='gpt-oss:20b',
)

官方也有 ollama-python(pip install ollama)與 ollama-js(npm i ollama)函式庫。Ollama 只支援 OpenAI API 的一個子集,用到進階功能前請先對照 OpenAI 相容性文件。

上下文長度越長需要的記憶體越多。依官方文件,預設值會依 VRAM 自動決定,可以用環境變數 OLLAMA_CONTEXT_LENGTH 或 Modelfile 的 PARAMETER num_ctx 調整;本次實測固定為 8192。

實測結果:0.8b 能不能可靠地產生 Word

強哥準備了 5 個難度遞增的提示詞(P1 標題+段落、P2 編號議程、P3 待辦表格、P4 完整會議記錄、P5 修改既有檔案),每次開新對話,用一般使用者帳號執行,再用 OfficeCLI 的 validate 與內容比對評分。P4 的提示詞如下:

請用 officecli 工具產生一份 Word 會議記錄,存成 {path},完成後執行 validate 並 close。
內容:
- 會議名稱:JSLab 十一月內容規劃會議
- 日期:2026-11-03(星期二)14:00–15:00,線上
- 出席者:強哥(主持)、小美(編輯)、阿凱(技術)
- 議程:1. 十月文章成效回顧 2. 十一月主題排程 3. 實驗環境資源分配
- 決議:Ollama 文章加入 OfficeCLI 章節,11/10 前發佈;kind 文章不再更新
- 待辦:阿凱 11/05 前完成 MCPO 截圖;小美 11/07 前完成校稿;強哥 11/09 前確認發佈

三種模式的成功率

Open WebUI 有兩種函式呼叫模式:Native(用模型原生的工具呼叫)與 Legacy(用提示詞引導),強哥另外測了「Native+綁定技能」:

模式次數完全正確有呼叫工具產生有效 docxmcpo 回應 200/500平均延遲
Native150121(空白檔)26/13753.5 秒
Legacy150300/1139.0 秒
Native+技能6065(內容不完整)36/2434.3 秒
Direct 工具伺服器+技能606未逐一統計26/9491.0 秒
Native+技能(10/31 重測,範本改用 <檔案路徑>)6066(內容不完整)54/3852.0 秒

10/30 的 42 次全部失敗,10/31 重測的 6 次也全部失敗。各模式的失敗原因:

  • Native:會呼叫工具,但參數幾乎都錯,例如在 create 塞入 --title、--text 等不存在的參數,對 Word 檔用簡報的路徑 /slide[1],甚至建立了一個 deck.pptx,然後在錯誤裡反覆重試 36~60 次。
  • Legacy:0.8b 幾乎不會用提示詞式的工具呼叫,12 次直接寫出 PowerShell、Python 程式或 Markdown 叫使用者自己執行。
  • Native+技能:語法正確率大幅提升(mcpo 回應 200 的比例從 16% 升到 60%),6 次中有 5 次產生通過 validate、有標題和段落的檔案,也沒有假裝成功;但每次都在中途停下來,沒有一次建立表格。10/31 重測的結果見下方「重測」一節。
實測截圖:Native 模式的工具呼叫紀錄,紅框 1 是模型對 create 帶入不存在參數的呼叫,OUTPUT 為 500 錯誤;紅框 2 是之後連續 14 次呼叫
實測截圖:Native 模式一開始就用錯 create 的參數,之後在錯誤中反覆重試(紅框為重點標註;強哥的實驗環境)

技能幫最多,但還是做不完

最好的一次是 P4 的技能模式第 2 次:9 次工具呼叫(6 次成功、3 次失敗),檔案通過 validate,6 項內容做出 3 項。下圖左邊是模型實際產出的檔案,右邊是強哥用正確指令手動做出的參考檔,右邊不是模型產出:

實測截圖:技能模式第 2 次的工具呼叫紀錄,共 9 次呼叫,其中 6 次成功、3 次失敗,輸入框旁可以看到工具與技能圖示
實測截圖:綁定技能後,模型照範本逐步呼叫 OfficeCLI(紅框為重點標註;強哥的實驗環境)
實測截圖:左邊是模型產出的 Word 檔,只有標題、出席者與 1 個議程項目;右邊是用正確指令做出的參考檔,有完整的議程、決議事項與待辦表格
實測截圖:左為 0.8b 實際產出,右為手動製作的參考檔(不是模型產出)(紅框為重點標註;強哥的實驗環境)

技能為什麼有效:沒有技能時,模型只能從 OfficeCLI 的工具說明猜指令。實測這份工具說明有 4002 個字元,光是掛上工具,每次請求的提示詞就從 13 個 token 增加到 1602 個 token;0.8b 讀了說明還是常用錯。技能直接給出逐步的指令範本,模型照抄的成功率就高很多。

重測:技能範本改用 <檔案路徑> 之後

10/30 的測試中,0.8b 曾把技能範本裡的代號 F 當成真的檔案路徑送出去。強哥在 2026-10-31(台北時間)把範本裡的 F 全部改成 <檔案路徑>,並加上一句「一定要換成使用者給的完整路徑」,其他設定不變,也就是同一個 Native+技能預設、同樣的 P3(待辦表格)與 P4(完整會議記錄)提示詞,各跑 3 次。唯一的差別是 Ollama 容器記憶體從 3 GB 提高到 4 GB。結果:

  • 路徑問題解決了:6 次共 92 次工具呼叫,每一次都用了提示詞給的完整路徑,沒有一次把 <檔案路徑> 或 F 原樣送出。
  • 整體成功率沒有改善:6 次都是 0 次完全正確。6 個檔案都存在而且通過 validate,但內容不完整(P3 三次都是 0/1,P4 分別是 3/6、2/6、3/6)。mcpo 回應 54 次 200、38 次 500,平均 52.0 秒。
  • 新的錯誤:500 錯誤大多是表格路徑猜錯(例如 /body/tbl[1]/colspan[3]),或把 command 送成引號壞掉的 JSON 字串。這次有 3 次建立了表格(10/30 是 0 次),但儲存格內容都放錯或是空白。
  • 又出現過度宣稱:P3 第 2 次的 17 次呼叫全部回應 200,模型回覆「檔案檔 p3-skill-r2.docx 已成功生成並儲存」,但表格的標題列不是「項目/負責人/期限」,資料也重複錯置。另外 5 次在呼叫完工具後沒有最終文字回覆。
  • 4 GB 記憶體夠用:重測期間沒有發生記憶體不足(OOM),Ollama 容器的峰值約 3,613 MiB。
實測截圖:左邊是 10/31 重測 P3 第 2 次的對話,17 次工具呼叫後模型回覆檔案已成功生成並儲存;右邊是這個檔案轉成圖片,表格內容重複錯置,標題列也不對
實測截圖:範本改用 <檔案路徑> 後路徑都正確,但表格內容仍然錯置,模型卻宣稱成功(紅框為重點標註;強哥的實驗環境)

結論:把代號改成 <檔案路徑> 值得做,它解決的是「路徑寫錯」這一個問題;但 0.8b 組不出完整文件的根本原因是模型能力,換範本寫法救不回來。

小心「假裝成功」

這是本次最需要注意的發現:模型的最後回覆不能當作結果。Native 模式有 5 次在檔案沒做好時宣稱「已成功建立」,其中一次的檔案通過 validate,但裡面 0 個段落。Direct 工具伺服器的 P4 第 2 次也一樣,檔案 6 項內容只有 3 項,模型卻回覆「會議記錄已成功生成並保存,檔案路徑為:/out/s5/p4-direct-r2.docx」,還列出「驗證通過:✓」:

實測截圖:Direct 工具伺服器模式的對話畫面,模型經過 10 次工具呼叫後,回覆會議記錄已成功生成並保存、驗證通過,但檔案缺少議程、決議與待辦
實測截圖:validate 確實通過,但內容缺一半,模型仍宣稱成功(紅框為重點標註;強哥的實驗環境)

validate 只檢查檔案格式是否合法,不檢查內容是否完整。如果要把這類流程交給同事使用,請一定用 view <檔案路徑> outline 或打開檔案檢查內容。

Direct 工具伺服器:改由瀏覽器呼叫工具

Open WebUI 還有另一種接法:使用者在自己的設定裡註冊工具伺服器,工具由瀏覽器直接呼叫,不經過 Open WebUI 伺服器。強哥暫時開啟這個功能,用測試帳號註冊 http://127.0.0.1:18012,驗證後出現「Connection successful」:

實測截圖:一般使用者在設定的 External Tool Servers 註冊工具伺服器,網址為 http://127.0.0.1:18012,Bearer 金鑰已遮罩,畫面顯示 Connection successful
實測截圖:使用者自行註冊 Direct 工具伺服器,金鑰為遮罩顯示(紅框為重點標註;強哥的實驗環境)

結果 6 次也是 0 次成功(平均 91.0 秒、最長 147.6 秒),和伺服器端呼叫是同一個層級,瓶頸仍是 0.8b 的參數品質,不是傳輸路徑。強哥從 mcpo 記錄確認,所有請求都來自主機上的瀏覽器,沒有經過 Open WebUI 容器。

這種接法的資安取捨:

  • 好處:工具伺服器可以只在使用者自己的電腦上(127.0.0.1),Open WebUI 伺服器碰不到。
  • 金鑰在瀏覽器裡:瀏覽器直接把金鑰送到工具伺服器,任何能在該瀏覽器執行 JavaScript 的東西都碰得到;金鑰也以明文存在使用者設定(資料庫),管理員看得到。
  • 工具伺服器必須開 CORS:要允許 Open WebUI 的網址(這裡只允許 http://127.0.0.1:18010)。
  • 每個使用者要自己管理:自己註冊、自己保管金鑰;依設計,工具只在瀏覽器分頁開著時才能執行(本次未實測關分頁的情況)。

記憶體與 OOM

即使是 1.3 GB 的 0.8b,在 3g 記憶體上限下,Ollama 一共被系統 OOM 終止 7 次(dmesg 顯示 CONSTRAINT_MEMCG,llama-server 約 3.12 GB)。工具呼叫越多次,上下文越長,記憶體就越吃緊;被終止時,Open WebUI 會收到 HTTP 500「model runner has unexpectedly stopped」。

各容器的實測峰值:Ollama 3,068 MiB(上限 3g)、Open WebUI 410 MiB、mcpo 174 MiB。建議給 0.8b 至少 3.5~4g,或限制工具呼叫的次數;2b 在基本測試時峰值就到 4.218 GiB,要給 4.5g 以上。

產出的檔案在哪裡

OfficeCLI 的檔案只會寫到 mcpo 容器的 /out(掛載到主機的資料夾)。Open WebUI 的聊天裡不會出現附件或下載連結,使用者要有主機檔案系統的權限才拿得到檔案。這個架構比較適合「伺服器端產出、到共享資料夾取檔」,不適合讓一般使用者自助下載。

踩坑紀錄

點選每個症狀可以展開原因與解法:

ollama pull 失敗:redirect target not allowed … resolves to non-public 198.18.0.1

原因:實驗主機的 DNS 會把所有網址解析到 198.18.0.1 這個假 IP(網路通道的設計),而 Ollama 0.40.13 會拒絕轉址到非公開 IP 的下載,這是它的安全檢查。

解法:不要用 --insecure(會把 registry 降級成 http),也不要改 Ollama 的安全檢查。強哥改在主機上手動下載模型檔,逐一驗證 sha256 後再複製進容器(見下方【進階】)。一般網路環境通常不會遇到這個問題。

0.8b 回答一個簡單問題花了 12 分鐘,還用簡體中文

原因:qwen3.5 預設開啟 thinking。實測 ollama run 產生了 5485 個 token(12 分 18 秒),最後的回答是簡體中文,還有事實錯誤。用 API 設 "think": true 且限制 1024 個 token 時,token 全部用在思考,沒有產生答案。

解法:API 呼叫加 "think": false;Open WebUI 在模型的 Advanced Params 設定 think=false。要繁體中文時,請在提示詞明確要求。

0.8b 關閉 thinking 後仍然只有每秒約 5 個 token

原因:0.8b 模型內建 MTP 草稿模型(draft_num_predict=2),在 CPU 上反而拖慢速度。固定 seed 各跑 3 次:草稿開啟時 5.7/4.8/5.4 tok/s,關閉後 51.4/64.1/61.4 tok/s,差了大約 10 倍。把記憶體上限調到 4.5g 速度也一樣,不是記憶體問題。

解法:在 Open WebUI 模型設定加自訂參數 draft_num_predict=0。關閉後工具呼叫測試仍是 3/3 正確。

mcpo 啟動失敗:ImportError: cannot import name ‘streamablehttp_client’

原因:直接 pip install mcpo==0.0.20 會裝到 mcp 2.3.0,但 mcpo 0.0.20 需要的匯入在 2.x 已經不存在;mcpo 的 pyproject 只寫了 mcp>=1.17.0,沒有限制上限。

解法:從 mcpo v0.0.20 的 uv.lock 匯出完整相依清單(含 mcp==1.17.0),用 pip install --require-hashes --no-deps -r requirements.lock.txt 安裝,再跑 pip check。

OfficeCLI 在容器裡一執行就中止

原因:OfficeCLI 是 .NET 程式,python:3.13-slim 映像沒有 ICU 函式庫,初始化語系(CultureInfo)時直接中止。

解法:在 Dockerfile 用 apt-get install -y --no-install-recommends libicu76 安裝。(本次實驗主機的 apt 另外需要 -o Acquire::EnableSrvRecords=false,這是主機網路環境的特例,一般環境不需要。)

OfficeCLI 截圖指令回傳 500:No headless browser available

原因:view <檔案路徑> screenshot 需要 Chrome、Edge、Chromium 或 Firefox,精簡的工具容器裡沒有。

解法:加裝 Chromium 會讓映像大約多 300 MB。強哥選擇不裝,讓模型改用 validate、view <檔案路徑> issues、view <檔案路徑> text 檢查,截圖由主機端另外處理。

模型把技能範本裡的「F」當成真的檔案路徑

原因:本次實測的技能用 F 代表檔案路徑(例如 ["create","F"]),0.8b 有時會原封不動地把 F 當成路徑送出去。

解法:範本裡的代號改用明顯不像真實值的寫法,例如 <檔案路徑>,並在提示詞給出完整路徑。強哥在 10/31 用這個改法重測 6 次,92 次工具呼叫全部用了正確的完整路徑,沒有再出現代號被原樣送出的情況;不過 6 次的內容仍然不完整,詳見上方「重測」一節。

用戶端逾時了,工具卻還在一直執行

原因:工具呼叫的迴圈在 Open WebUI 伺服器端執行。實測一次 300 秒後用戶端逾時,伺服器端仍繼續呼叫到第 60 次;呼叫 /api/tasks/chat/{id}/stop 也沒有停下來。

解法:限制模型的工具呼叫次數、給工具伺服器設定記憶體與程序數上限(本次 mcpo 用 --memory 512m、--pids-limit 256)。批次測試時,逾時後要等伺服器端真的結束,再跑下一個,否則記錄會互相汙染。

撤銷 Direct 工具伺服器權限後,使用者的舊金鑰還留在資料庫

原因:Open WebUI v0.12.5 的使用者設定是「欄位補丁」:沒有 Direct 工具伺服器權限時,刪除工具伺服器的請求會被直接丟掉。先撤權限的話,使用者就刪不掉已註冊的伺服器,金鑰留在資料庫。

解法:順序要反過來:權限還開著時,先清除使用者的工具伺服器設定,再關閉權限與功能。強哥第一次先關權限,清除沒有生效,重新開啟、清除、再關閉後才還原成功。

管理員帳號用技能時,模型試圖建立或覆寫技能

原因:在 Native 模式下,內建工具的 Skills 類別會對管理員(或有技能寫入權限的使用者)提供 create_skill、update_skill_files 這類寫入工具。實測 0.8b 曾 7 次嘗試建立或覆寫技能,都因參數錯誤或 ID 重複而失敗,技能沒有被改動。

解法:讓工具與技能只給沒有技能寫入權限的一般帳號使用;管理員帳號只用來設定,不用來做日常對話。

【進階】手動下載 Ollama 模型並驗證 sha256

【進階】手動下載模型檔並逐一驗證 sha256(點選展開)

只有在 ollama pull 因網路環境無法使用時才需要。腳本從 registry.ollama.ai 下載 manifest 與每個 blob,比對 sha256 與 manifest 裡的 digest,全部相符才複製進容器:

#!/usr/bin/env bash
set -euo pipefail
MODEL=$1 TAG=$2 STAGE=$3
REG=https://registry.ollama.ai/v2/library/$MODEL
ACC='Accept: application/vnd.docker.distribution.manifest.v2+json'
mkdir -p "$STAGE"
curl -fsS "$REG/manifests/$TAG" -H "$ACC" -o "$STAGE/manifest-$MODEL-$TAG.json"
for d in $(jq -r '.config.digest, .layers[].digest' "$STAGE/manifest-$MODEL-$TAG.json"); do
  f="$STAGE/${d/:/-}"
  [ -f "$f" ] || curl -fsSL "$REG/blobs/$d" -o "$f"
  got=sha256:$(sha256sum "$f"|cut -d' ' -f1); [ "$got" = "$d" ] && echo "sha256 OK $d" || { echo "SHA MISMATCH $d"; exit 2; }
done
sudo docker exec jslab-ollama mkdir -p /root/.ollama/models/blobs /root/.ollama/models/manifests/registry.ollama.ai/library/$MODEL
for d in $(jq -r '.config.digest, .layers[].digest' "$STAGE/manifest-$MODEL-$TAG.json"); do
  sudo docker cp "$STAGE/${d/:/-}" jslab-ollama:/root/.ollama/models/blobs/${d/:/-}
done
sudo docker cp "$STAGE/manifest-$MODEL-$TAG.json" jslab-ollama:/root/.ollama/models/manifests/registry.ollama.ai/library/$MODEL/$TAG

實測 0.8b(1.32 GB)下載 23 秒、2b(2.68 GB)約 80 秒,每個 blob 都顯示 sha256 OK。用法:./fetch-ollama-model.sh qwen3.5 0.8b <暫存資料夾>。

安全檢查清單與清理

官方 FAQ 寫明「Ollama binds 127.0.0.1 port 11434 by default」,驗證文件也寫明本機 API 不需要驗證。架設完成後,請逐項確認:

  • 所有連接埠只綁 127.0.0.1:用 ss -ltn 確認 11434、18010、18012 都是 127.0.0.1;實測從區網 IP 連 18012 無法連線。不要設 OLLAMA_HOST=0.0.0.0,真的要給別人用,請在前面加有驗證的反向代理或 VPN。
  • 工具伺服器一定要有金鑰:mcpo 加 --api-key 與 --strict-auth,金鑰用唯讀檔案掛載,不放指令列或環境變數。
  • 記得金鑰是明文存放:Open WebUI 會把工具伺服器的 Bearer 金鑰以明文存在資料庫,管理員看得到;請用專用的金鑰,定期更換。
  • 收緊 CORS:Open WebUI 設 CORS_ALLOW_ORIGIN,mcpo 設 --cors-allow-origins,都只允許自己的網址。
  • 撤銷權限前先清金鑰:要關掉 Direct 工具伺服器時,先清除使用者已註冊的伺服器,再關權限。
  • 工具只授權給一般帳號:用 Access Control 只授權需要的使用者;一般使用者沒有技能寫入權限。
  • 限制工具容器:唯讀根目錄、--cap-drop ALL、no-new-privileges、非 root、記憶體與程序數上限,只開放一個輸出資料夾。
  • 關閉不需要的對外連線:OLLAMA_NO_CLOUD=1、ENABLE_VERSION_UPDATE_CHECK=false、ENABLE_OPENAI_API=false、OFFICECLI_SKIP_UPDATE=1。
  • 固定版本並驗證雜湊:映像檔用固定版本或 digest,套件用 --require-hashes,執行檔用 sha256sum -c。

測試結束後,依序刪除模型、容器、volume、網路與映像檔(強哥實際的清理指令):

sudo docker exec jslab-ollama ollama rm qwen3.5:2b qwen3.5:0.8b
sudo docker stop jslab-openwebui jslab-mcpo jslab-ollama
sudo docker rm jslab-openwebui jslab-mcpo jslab-ollama
sudo docker volume rm jslab-openwebui jslab-ollama
sudo docker network rm jslab-owui-net
sudo docker image rm ghcr.io/open-webui/open-webui:v0.12.5-slim jslab/mcpo-officecli:0.0.20-1.0.160 ollama/ollama:0.40.13 python:3.13-slim
sudo docker builder prune -f

docker volume rm 會刪掉 Open WebUI 的帳號、對話與設定,執行前請先匯出需要保留的資料。金鑰與密碼檔請用 shred -u 刪除。

第三部分:評價與延伸

最後整理這次實測的優缺點、綜合評價,以及接下來可以怎麼做。

優缺點

優點:

  • 架設與資安設定很穩:三個容器都能只綁 127.0.0.1、限制記憶體、以非 root 與唯讀方式執行,驗證與 CORS 檢查全部符合預期。
  • 資料不離開主機:模型、聊天與產出的檔案都在自己的主機上,雲端模型可以整個關閉。
  • 工具串接可行:mcpo 讓 stdio 的 MCP 伺服器變成有金鑰的 OpenAPI,Open WebUI 可以用權限控制誰能用。
  • 技能明顯改善小模型:綁定技能後,工具呼叫的成功比例從 16% 升到 60%,10/30 Native+技能的 6 次也沒有假裝成功(但 Direct 模式+技能,以及 10/31 重測各有 1 次過度宣稱)。

缺點:

  • 小模型不可靠:0.8b 在 48 次測試(含重測)中 0 次完全正確,還會在檔案缺內容時宣稱成功。
  • 記憶體比想像中多:0.8b 在 3g 上限下仍 OOM 7 次。
  • 相依套件要自己顧:mcpo 0.0.20 要鎖定 mcp 1.x 才能執行。
  • 取檔不方便:產出的檔案只在工具容器的資料夾,聊天裡沒有下載連結。
  • 金鑰明文存放:Open WebUI 資料庫裡的工具伺服器金鑰,管理員看得到。

綜合評價

以下是強哥依本次實測給的評分(5 分滿分):

  • 安裝難易度:3.5 分。Ollama 與 Open WebUI 用 Docker 很快就能跑起來,但 mcpo+OfficeCLI 要自建映像、鎖相依套件、補 ICU 函式庫。
  • 安全預設與可收緊程度:4 分。Ollama 預設只綁本機,三個元件都能收緊到只綁 127.0.0.1、有金鑰、限 CORS;扣分在 Open WebUI 預設 CORS 是 *,以及金鑰明文存放。
  • 小模型的工具可靠度:1 分。0.8b 在 48 次測試(含重測)中 0 次完全正確,還會假裝成功。
  • 資源成本:3.5 分。軟體免費、不需要 GPU 就能跑,但 0.8b 跑工具流程也要 3.5~4g 記憶體。
  • 維護負擔:3 分。mcpo 最新版停在 2026-02-28,要自己鎖版本;OfficeCLI 更新頻繁,要手動驗證後再升級。

總結:這套組合適合想在自己主機上試驗「AI+工具」流程、又重視資料不外流的個人與小團隊。架構與資安面都沒問題,真正的瓶頸是模型能力:0.8b 只適合用來驗證流程,要真的產出可用的文件,請換更大的模型並重新測試,而且產出一定要有人檢查。

小技巧

  • 先用 curl 直接測工具:在接上模型前,先用金鑰呼叫 POST /officecli 確認指令正確,出問題時才分得清是工具還是模型的錯。
  • 技能範本用 <檔案路徑> 這類代號:不要用 F、X 這種模型可能當真的單一字母(10/31 重測後,92 次呼叫的路徑全部正確)。
  • 檢查內容,不只檢查格式:validate 通過不代表內容完整,用 view <檔案路徑> outline 看標題與段落數。
  • 用 ollama ps 確認有沒有用到 GPU:PROCESSOR 欄位出現 CPU 比例,代表模型放不進 VRAM,換小一號的模型通常比調參數有效。
  • 小模型記得關 thinking 與草稿模型:think=false、draft_num_predict=0,速度差很多。
  • 給 Ollama 容器留餘裕:0.8b 跑工具流程至少 3.5~4g,2b 至少 4.5g。

結語與下一步

這次實測證明,Ollama+Open WebUI+mcpo+OfficeCLI 的架構可以在沒有 GPU 的主機上安全地跑起來,但 0.8b 這種小模型還不能可靠地產生 Word 文件。建議先用小模型確認流程與資安設定,再換更大的模型重新測試成功率;不論用哪個模型,產出的文件都要有人檢查。

下一步,您可以:

參考連結

本文僅供學習參考,請在您自己的環境自行評估風險,詳見免責與揭露聲明。

本文寫作方式:本文的實測部分由強哥在自己的實驗環境執行(2026-10-30,技能範本於 2026-10-31 重測,台北時間),文中的指令、輸出、數字與截圖都來自實測紀錄;macOS/Windows 安裝、Modelfile、REST API、程式庫與雲端方案等內容依官方文件整理(2026-10-30 查核),未實機測試。文章架構、實測規劃與審稿由強哥負責,資料整理與初稿由 AI 助理協作完成。封面與示意圖為原創繪製(未使用 AI 生成圖片),截圖為實測畫面。

返回頂端