你以為自架 AI 助理最難的是模型。不是。

模型換六次就好了。真正會讓你卡住的,是 nginx 回傳 400、瀏覽器無限 redirect、還有人設怎麼寫都不生效這種鬼問題。NousResearch 的 Hermes Agent v0.13.0 是一套開源 AI 代理框架,可以接各種 LLM 後端,自帶 Dashboard 跟多平台 Gateway。我在公司的 Ubuntu 26.04 VM 上把它跑起來,串上 LINE 聊天機器人,中間踩的坑比安裝步驟還多。

這篇文章是 Notion 開發筆記的整理,保留原始的踩坑順序。不是教學文,比較像驗屍報告。


先畫一張圖

整體架構其實不複雜,用一句話講完:外面的流量進來先經過 nginx 做 SSL 終止,然後根據路徑決定往哪送。

1
2
3
4
5
Internet → TP-Link Router (port 80+443)
→ VM 235: nginx 中央閘道 (SSL 終止)
├── / → VM 199:80 (CoolApps 管理系統)
├── /hermes/ → localhost:9119 (Hermes Dashboard)
└── /line/webhook → localhost:8646 (Hermes LINE Gateway)

VM 規格是 16 核 7.2GB RAM、40GB 硬碟,跑 VMware。Hermes 本身不吃什麼資源,因為推論全丟給外部 API——它是代理框架,不是推論引擎。這個區分很重要:你不需要 GPU,你需要的是穩定的 API key。


六次模型切換:一部免費仔的血淚史

如果用餐廳來比喻:你不是在挑哪間好吃,你是在試哪間還沒倒閉、還沒漲價、而且不會上錯菜。

第一次:google/gemma-3-27b-it:free

OpenRouter 上面看到免費就選了。結果 404,模型已經下架。連門都沒開。

第二次:google/gemma-4-31b-it:free

同一個平台換一個新的。能動了,對話品質也還行,但大概聊了二十幾輪就開始噴 429——免費額度見底。OpenRouter 的 free tier 大方是大方,但你不會想拿它當生產環境。

第三次:gemini-2.5-flash(Google 直連)

繞過 OpenRouter,直接接 Google API。可以用,但回應速度有夠慢,體感大概 8-10 秒才開始吐字。LINE 聊天機器人等這麼久,使用者早就關掉了。

第四次:gemini-2.0-flash(Google 直連)

換同系列的舊版,速度快很多。但免費配額的消耗速度超乎預期,幾個人測試一下午就快撞天花板了。

第五次:llama-3.3-70b-versatile(Groq)

Groq 的推論速度是真的猛,回應幾乎是瞬間。但長對話到後面會開始亂碼——中文字亂跳、句子斷在奇怪的地方。短對話用起來真香,長對話直接炸了。

六次。換了六次模型。

第六次(最終):deepseek/deepseek-v4-flash:free(OpenRouter)

DeepSeek V4 Flash 的免費版。1M context window、中文品質好、回應穩定、沒有亂碼。這個組合跑了兩週,零問題。有時候最後才找到的那個選項,反而是從一開始就該試的。


nginx 的三個坑

模型搞定之後以為可以收工了。結果 nginx 又給了三堂課。

坑一:Dashboard 400 Invalid Host header

Hermes Dashboard 跑在 localhost:9119,nginx 做反向代理。設定看起來沒問題,但打開瀏覽器就是 400。

原因是 Dashboard 的 dev server 會驗 Host header,而 nginx 預設把外部的 domain 直接轉過去,Dashboard 不認。解法很直接:

1
2
3
4
location /hermes/ {
proxy_pass http://127.0.0.1:9119/;
proxy_set_header Host 127.0.0.1:9119;
}

把 Host 硬寫成 localhost 就過了。這種問題文件不會告訴你,因為大部分人不會把 Dashboard 塞在子路徑後面。

坑二:ERR_TOO_MANY_REDIRECTS

VM 235 的 nginx 收到 / 的請求,代理到 VM 199 的 port 80。但 199 上面也有一個 nginx,它的規則是「HTTP 一律 301 到 HTTPS」。問題來了:235 已經做了 SSL 終止,送過去的是 HTTP——199 收到 HTTP 就 redirect 回 HTTPS——235 再送一次 HTTP——無限迴圈。

瀏覽器直接 ERR_TOO_MANY_REDIRECTS。

解法是讓 199 知道「這個請求其實已經走過 HTTPS 了」:

1
2
3
4
5
6
7
# VM 235 的設定
proxy_set_header X-Forwarded-Proto $scheme;

# VM 199 的判斷
if ($http_x_forwarded_proto != "https") {
return 301 https://$host$request_uri;
}

這個 redirect 迴圈在多層代理的架構裡幾乎是必踩的坑。只要你的 SSL 終止點和應用伺服器不在同一台機器,就要想到 X-Forwarded-Proto

坑三:Dashboard 安全

Dashboard 直接暴露在公網上是不行的。加了兩層防護:nginx 的 auth_basic 做基本驗證,再配 fail2ban 擋暴力破解。不是什麼高深的做法,但至少別人不能直接打開你的 AI 助理後台亂設定。


SOUL.md 人設不生效

Hermes Agent 有個設計叫 SOUL.md——你把 AI 助理的人格設定寫在這個檔案裡,理論上 Agent 就會照著演。

理論上。

實際上透過 LINE Gateway 進來的對話,SOUL.md 完全不生效。AI 助理還是用預設的口吻回答,你寫的「草總」草泥馬人設完全被忽略。查了一輪之後發現這是 Gateway 的已知 Bug(#6731),Gateway 在處理訊息時根本沒有讀 SOUL.md。

繞路的方式是用環境變數把人設直接注入:

1
export HERMES_EPHEMERAL_SYSTEM_PROMPT="你是「草總」,一隻草泥馬 AI 助理。說話輕鬆幽默,用台灣繁體中文回答。"

環境變數的優先順序比 SOUL.md 高,Gateway 繞不過去。不優雅,但能用。

另一個相關的問題:免費模型偶爾會亂碼輸出,尤其是回應太長的時候。解法是在 SOUL.md(或環境變數)裡加上嚴格指令:「回答控制在 500 字以內,不要產生亂碼」,再搭配 max_tokens 限制。治標,但夠用。


最終的模型分工

一個有趣的發現:與其找一個萬能模型,不如讓不同模型各做各的事。最後的配置是三個模型各司其職:

用途 模型 來源 為什麼
主力對話 deepseek-v4-flash:free OpenRouter 穩定、中文好、1M context
上下文壓縮 llama-3.3-70b-versatile Groq 極快,壓縮不需要長對話
圖片辨識 gemini-2.0-flash Google 多模態能力強

Groq 的 Llama 長對話會亂碼,但拿來做上下文壓縮——把長對話摘要成短的——剛好避開它的弱點,同時發揮它的速度優勢。這比「找到一個完美模型」務實得多。


部署這件事教了我什麼

整個過程花了大概三天,其中寫 code 的時間不到半天。剩下的時間都在除錯——不是程式的 bug,是架構的 bug。nginx 設定少一行 header、模型 API 突然改 policy、開源專案的已知問題還沒修。

自架 AI 助理的門檻不在「會不會寫程式」。它在另一個地方:你願不願意在第五次失敗之後,還是冷靜地看 log、查 issue、換一條路試。

這不是智力問題,是耐心問題。

而且說實話,DeepSeek V4 Flash 免費版的品質,放在兩年前大概要花不少錢才能買到。開源生態走到今天,16 核 7.2GB RAM 的 VM 就能跑一個有模有樣的 AI 助理,不需要 GPU、不需要付月費。門檻在降低,但要真的把它跑起來、跑穩,你還是得親手摸過每一層。

沒有捷徑。但至少坑我都幫你踩過了。