Skip to content

用 llama.cpp 串起本地 AI Agent:Hermes、OpenHands、n8n 與 SearXNG

Billy

需求

之前參考零度博客的文章,成功能在 llama UI 使用本地模型,但我想要的不只是聊天,而是一套可以長時間工作的本地 AI:能執行指令、修改程式、搜尋網路,也能從 Discord 接收任務。

最後採用的組合是:

這篇主要分享它們怎麼接在一起,不會逐條展開所有安裝選項。只要先理解每個服務負責什麼,實際設定就沒有看起來那麼複雜。

myAI 本地 AI 服務啟動完成畫面
一個指令依序啟動 llama.cpp、Docker 服務與 Hermes Agent。

整體架構

這套架構的核心只有一個:所有 Agent 共用同一個 llama.cpp 模型 API

                     ┌─ SearXNG(網路搜尋)
Discord ─ Hermes ────┤
             │       └─ Docker 工具環境

             ├───────── llama.cpp ─ Qwen 本地模型

OpenHands ────┘

n8n ── 排程 / Webhook / HTTP API ── llama.cpp、Hermes 或其他服務

我的電腦是 Windows,llama.cpp 與 Hermes Agent 直接執行在 Windows;OpenHands、SearXNG、n8n 和 PostgreSQL 則放在 Docker Desktop。

這樣做的好處是 llama.cpp 可以直接使用顯示卡,不必在容器裡另外處理 CUDA;需要隔離環境的 OpenHands 與自動化服務則交給 Docker 管理。

1. 用 llama.cpp 提供共用模型 API

模型使用 Qwen3.6-35B-A3B 的 IQ2_M GGUF 量化版本,由 llama-server 啟動:

llama-server.exe `
  -m .\models\Qwen3.6-35B-A3B-IQ2_M.gguf `
  --alias qwen3.6-35b-a3b-iq2 `
  -ngl 999 `
  -c 65536 `
  -np 1 `
  -ctk q4_0 `
  -ctv q4_0 `
  --flash-attn on `
  --api-key YOUR_API_KEY `
  --host 0.0.0.0 `
  --port 8080

啟動後就會得到一個 OpenAI 相容 API:

http://127.0.0.1:8080/v1

-c 65536 是 64K context;-np 1 代表只保留一個完整的推論 slot。因為這台電腦只有一張顯示卡,與其同時跑多個縮水的工作,不如讓 Hermes、OpenHands 和 n8n 排隊共用完整 context。

我也把 KV cache 設成 Q4,降低長 context 佔用的顯示記憶體。這組設定在 RTX 5070 Ti 16GB 上大約使用 13.8GB VRAM,實際能接受的 context 還是要依模型、量化和顯示卡調整。

2. 串接 OpenHands

OpenHands 放在 Docker 裡,設定重點是讓容器找到 Windows 上的 llama.cpp:

environment:
  LLM_MODEL: openai/qwen3.6-35b-a3b-iq2
  LLM_BASE_URL: http://host.docker.internal:8080/v1
  LLM_API_KEY: ${LLAMA_API_KEY}
  LLM_MAX_INPUT_TOKENS: 61440
  LLM_MAX_OUTPUT_TOKENS: 4096

這裡不能填 127.0.0.1:8080,因為對 Docker 容器來說,127.0.0.1 是容器自己;要用 host.docker.internal 才能連回 Windows 主機。

模型有 65,536 tokens,但 OpenHands 的輸入上限設成 61,440,預留一部分給模型輸出和通訊格式,避免工作做到最後才因 context 滿掉而失敗。

OpenHands 可以執行指令與修改檔案,所以我只掛載一個專用資料夾:

environment:
  SANDBOX_VOLUMES: /run/desktop/mnt/host/c/projects/myAI/workspace:/workspace/project:rw

不要直接掛載整個系統碟或使用者目錄。需要 AI 處理的專案先放進 workspace,權限範圍比較清楚,也不容易誤改其他檔案。

3. 用 SearXNG 提供網路搜尋

本地模型本身不知道即時資訊,llama.cpp 也不會憑空多出搜尋能力,所以另外架一個 SearXNG。

SearXNG 是聚合搜尋引擎,可以查詢多個公開搜尋來源,並用 JSON 回傳結果。Docker 啟動後,我把它限制在本機的 8888 port:

services:
  searxng:
    image: searxng/searxng:latest
    ports:
      - "127.0.0.1:8888:8080"

測試網址如下:

http://127.0.0.1:8888/search?q=test&format=json

在 SearXNG 的 settings.yml 還要開放 JSON 格式:

search:
  formats:
    - html
    - json

我一開始使用 DDGS,偶爾會遇到空結果或搜尋錯誤。改成自架 SearXNG 後,Open WebUI 與 Hermes 都共用同一個搜尋後端,狀況穩定許多,也不需要另外申請搜尋 API key。

4. 串接 Hermes Agent

Hermes 是這套系統的主要入口。它負責維持工作階段、呼叫工具、壓縮長對話,還能透過 Discord 接收訊息。

模型設定指向 llama.cpp:

model:
  default: qwen3.6-35b-a3b-iq2
  provider: custom:local-llama
  context_length: 65536

providers:
  local-llama:
    api: http://127.0.0.1:8080/v1
    key_env: LLAMA_API_KEY
    transport: chat_completions

Hermes 執行在 Windows 上,所以這裡使用 127.0.0.1。搜尋則指向剛才建立的 SearXNG:

web:
  search_backend: searxng
SEARXNG_URL=http://127.0.0.1:8888

長時間工作很容易用滿 context,因此我也開啟 Hermes 的對話壓縮:

compression:
  enabled: true
  threshold: 0.55
  target_ratio: 0.20
  protect_last_n: 16

當內容累積到一定程度,Hermes 會把較舊的內容整理成摘要,同時保留最近的訊息。這不能保證任務永遠不會失去細節,但比單純等到 context 爆掉可靠很多。

Hermes 的終端工具同樣放進 Docker,並限制在同一個 workspace。即使 Discord Bot 收到不適當的指令,能碰到的檔案範圍仍然有限。

例如我把 Apple Health 匯出的資料放進 workspace,再從 Discord 請 Hermes 檢查資料夾。它能先辨識大型 XML 與其他資料,再分段執行後續分析,不需要直接把整個檔案塞進一次對話。

從 Discord 請 Hermes 檢查 workspace 裡的 Apple Health 匯出資料
Hermes 從 Discord 接收任務,並讀取限定 workspace 裡的檔案。

需要即時資料時,Hermes 會呼叫 SearXNG 搜尋。例如請它查看部落格現有文章,搜尋與整理結果都會直接回傳到 Discord。

Hermes 從 Discord 搜尋 SimpleStacks 網站並整理文章
透過 Discord 呼叫 Hermes 搜尋網路並整理結果。

5. n8n 負責排程與自動化

Hermes 適合接收自然語言任務,n8n 則適合處理固定流程,例如:

n8n 可以用 HTTP Request 節點呼叫 llama.cpp:

POST http://host.docker.internal:8080/v1/chat/completions
Authorization: Bearer YOUR_API_KEY

如果要從 n8n 搜尋網路,因為它和 SearXNG 在同一個 Docker network,可以直接使用服務名稱:

GET http://searxng:8080/search?q={{ $json.keyword }}&format=json

n8n 的資料不要只放在容器裡。我使用 PostgreSQL 保存設定與執行資料,並替 n8n 的 volume、資料庫和加密金鑰做備份,這樣容器更新或重建後,工作流程不會一起消失。

6. 最容易弄錯的連線位置

這次串接花最多時間的地方,其實不是模型,而是分清楚「誰正在呼叫誰」。

呼叫端目標使用的網址
Windows 上的 Hermesllama.cpphttp://127.0.0.1:8080/v1
Docker 裡的 OpenHands / n8nllama.cpphttp://host.docker.internal:8080/v1
Windows 上的 HermesSearXNGhttp://127.0.0.1:8888
Docker 裡的 n8nSearXNGhttp://searxng:8080

同樣一個服務,從 Windows 和 Docker 連線時可能要使用不同網址。先畫清楚服務的位置,通常就能解決大部分的「明明有啟動,卻連不上」問題。

啟動與停止

服務變多後,我沒有再逐個手動啟動,而是做成三個指令:

start-myAI.bat
status-myAI.bat
stop-myAI.bat

啟動順序是:

  1. 先啟動 llama.cpp,等待模型 API 可以連線
  2. 啟動 SearXNG、n8n、PostgreSQL 與 OpenHands
  3. 確認 llama.cpp 的 context 至少有 64K,再啟動 Hermes

停止時除了關閉 Docker 容器,也要結束 llama-server。只執行 docker compose down 不會卸載 Windows 上的模型,VRAM 當然還是會被佔用。

使用上的限制

這套架構目前使用一個 llama.cpp slot,所以不適合同時讓多個 Agent 大量輸出。Hermes、OpenHands 和 n8n 可以一起開著,但最好一次只讓一個主要任務生成,其他請求會排隊等待。

另外,我只把一般操作介面綁定在 127.0.0.1。Hermes API 具有終端和檔案工具,不要直接把 port 開到公網。若要從外部使用,可以透過 Discord,或另外使用有身分驗證的 VPN。

結果

完成後,這台電腦上的同一個 Qwen 模型可以:

這套組合不是把五個服務硬塞在一起,而是把工作分清楚:llama.cpp 專心推論、SearXNG 提供搜尋、Hermes 負責互動、OpenHands 負責程式工作、n8n 負責固定流程。理解這個分工後,後續更換模型或增加新的工具也比較容易。

下列的
THREEjs 局部網格細分