
秘書很重要,小秘更需要。上一篇說素材,圖書館的事情告一段落,接下來是每天的事情:待辦、行事曆、提醒。
曾經養過六隻龍蝦當小秘。
2026年春天,一口氣開了六台虛擬機,每台裝一隻,六隻龍蝦各自有一個 Telegram bot,全部拉進同一個群組。六隻預設都走雲端的 Gemma 4 免費額度,每一台自己一把 API key,因為共用一把會被擋。它們閒著沒事的時候在一個五子棋競技場對戰,走棋靠本地的小模型,要講垃圾話才叫語言模型講。當時的想法很單純:我有虛擬機,空間記憶體夠,弄六個,可以做各式各樣的比對測試。
可是,複雜,不好用。
養了三個月,結論是複雜,不好用。複雜在設定面太寬。一個節點有六個設定位置要改,改模型要六個地方一起動,漏一個就出現說不清的行為,沒有任何提示。四月做過一次大清理:六台的排程、心跳、對話紀錄全部清空重來,因為已經分不清哪個工作用哪個模型。還有一堆小事:安裝路徑不在非互動的 PATH 裡,設定使用者要寫數字 id 不能寫帳號名,改完設定要用它自己的方式重啟。每一件都有解,但六台乘上每一件,一個人養不動。不是它不好,是它的設定,對一個人來說太麻煩:只想加一條提醒,卻得搞個老半天。
關掉。
七月底把五台移除,八月一號把最後一台也關了。關的那台待套用的安全更新有 102 個,開機 148 天沒重開。一個人的機房裡,養不起的東西要敢關,留著只會變成沒人管的門。規則是:關掉之前把當下狀態存成一份檔,磁碟留著,開得回來,但不要抱著它。
自己弄一個。
關掉之後回頭想我到底要什麼。要的東西不多:待辦、行事曆、提醒、加個發票對獎,還有用講的就能記下來,透過 Telegram 與 LINE 跟它講話。這些功能需要一個地方把它們放在一起。所以就弄一個專案,名叫 MyAIAgent。分三步:這一篇先蓋底座,一台機器、一個小秘服務、八個頁面;下一篇接 Telegram,再下一篇接 LINE。對話核心先借一個開源的 agent 框架 hermes-agent 頂著,它本來就會接 Telegram 與 LINE,不用從頭零寫聊天迴路。底座的原則只有一條:不重做已經有的東西。語言模型、文字辨識、語音辨識、語音合成都是機房裡現成的服務,小秘只拿網址來用,不再裝一份。
先開一台機器
開一台新的虛擬機,主機名 myagent.iron30.com。不必給顯示卡,因為模型不住這台,模型在本地那台語言模型機器上。這台就是一個 docker compose,四個容器:聊天核心、模型路由器、小秘服務、對外的通道。
ssh HQ,切換到 /opt/claude-working,執行 claude code:
從 ubuntu-base 範本複製一台新機器:名字 myagent,固定位址 192.168.0.40,主機名 myagent.iron30.com。
這台是我的小秘,專案名 MyAIAgent。
一、規格:4 個虛擬核心、16 GB 記憶體,系統碟放大到 60 GB。
⛔ 不要給它顯示卡。語言模型在 192.168.0.30 那台,這台只拿網址來用。
範本已經把時區、密碼登入、guest agent、IPv6 都處理好了,⛔ 不要再進去重做一次;
開機後只驗三件事:我進得去、主機名對、時間對。
二、時區 Asia/Taipei 要一路寫進容器、程式、資料庫,跟系統一致。介面一律繁體中文,程式與註解英文。
三、整台跑 docker compose,四個容器,各管一件事:
1. 聊天核心 —— 先用開源的 hermes-agent,它本來就會接 Telegram 與 LINE,這一篇先不接。
2. 模型路由器 —— 聊天核心 ⛔ 不可以直接連語言模型,一律經過路由器。
🔴 所有跟模型有關的旋鈕(時間注入、輸出上限、思考模式、溫度)只准放在路由器,
聊天核心與小秘一個都不准有。
3. 小秘服務 —— FastAPI + SQLite,REST API 給 agent 用、頁面給人用,下一段 prompt 講頁面。
4. 對外通道 —— 只開一條給訊息平台的 webhook 用,後面兩篇再接。
四、⛔ 不重做已經有的東西:語言模型、文字辨識、語音辨識、語音合成都是機房裡現成的服務,
網址寫在 .env,⛔ 不可以寫死在程式碼裡,⛔ 不可以再裝一份。
🔴 所有 token、key、密碼一律從 .env 讀;缺哪一個就停下來問我,⛔ 不可以自己編一個假的先跑。
⚠️ .env 是建容器時烘進去的,只 restart 不會重讀,改了 .env 要重建那個容器。
⚠️ 聊天核心與小秘各有一份 .env,同名變數兩份都要有;只進一份的那種錯不會報錯,只會靜默不響。
五、對外綁 myagent.iron30.com,到 NPM(192.168.0.11)加上去並取得憑證,指到這台的 8700,也就是小秘的登入頁。
⛔ 只開小秘這一頁。聊天核心、路由器、資料庫都不對外,訊息平台的 webhook 走第三點那條通道,不走 NPM。
⚠️ 外面是 https 進來、後面是 http 出去:登入的 cookie 從外面來的要帶 Secure 旗標,
但 ⛔ 不可以無條件加 —— 內網直連是 http,加了就登不進去;看 NPM 帶來的 X-Forwarded-Proto 決定。
登入連錯 5 次鎖 15 分鐘,按帳號鎖,不按來源位址。
規則:每做完一步就 commit,訊息寫「phase-N:做了什麼」;每一個 API 端點配一個測試,測試沒過不算完成。
八個頁面
小秘服務是一個 FastAPI 程式,資料存 SQLite,頁面用 HTMX,有登入。八個頁面:今日、行事曆、待辦、提醒、發票、帳號、模型、設定。介面全部是繁體中文,時區固定 Asia/Taipei,寫進容器、程式、資料庫三處,因為 agent 算時間最常錯的就是時區。每一個頁面背後都是一組 API,agent 之後就是透過這組 API 幫我記事情,頁面只是給人看跟改的地方。規則:先做給人用的頁面,再做給 agent 用的工具,因為人看得到的地方錯了才有人發現。
接著蓋小秘的頁面。做完一頁就連上去看,看到不滿意的地方截圖丟回去叫 claude 改,八頁改完是下面這樣:
小秘服務做八個頁面:今日、行事曆、待辦、提醒、發票、帳號、模型、設定。有登入,登入後上方一列分頁。
⚠️ 每一頁背後都是一組 API,頁面只是給人看跟改的地方;agent 以後用同一組 API 幫我記事情。
一、今日:今天的行程、到期的待辦、近期的提醒,三格。
⛔ 空的時候不可以留白,要寫「今天沒有安排的行程」這種句子 —— 留白分不出是沒事還是壞掉。
二、行事曆:月曆,整個月看得到,當天有記號,事件直接顯示在格子裡,上月下月可以翻。
三、待辦:標題、優先度高中低、到期日選填、標籤選填;清單可以依狀態與優先度篩。
⚠️ 日期欄位先剝掉多餘的引號再驗格式 —— agent 從對話裡抄過來的日期常常帶引號,存進去就壞。
⚠️ 到期日格式不對直接拒絕,⛔ 不可以存進去再說。
四、提醒:單次或重複。單次是一個時間點,重複是一條排程表達式,🔴 兩者只能設一個。
⛔ 過去的時間直接拒絕,不然它永遠不會響。已過期又沒響的提醒自動收掉。
排程器用 APScheduler,工作要存在磁碟上的 jobstore,服務重啟之後工作還在,⛔ 不可以重啟就掉。
發送管道主要是 LINE 推播,失敗時退回 Email,前提是 Email 有設定;沒設定就明白寫在頁面上。
清單分進行中與歷史,響過的單次提醒自己移到歷史。
五、發票:號碼是 2 碼英文字母加 8 碼數字,期別下拉選,要跟財政部公布的期別一致。
輸入時中間的空白或連字號自動去掉。🔴 同一張發票用「號碼+期別」去重,重複的直接擋。
每逢單月 26 日自動比對財政部公布的中獎號碼,中了列出獎別與金額,全部沒中也回報一句,結果推到 LINE。
⚠️ 這一頁是給沒有照片、要補建或清理紀錄用的,拍照入庫是訊息平台那邊的事,這裡先留一個入口。
六、帳號:誰能登入。新增、編輯、刪除,目前登入的那一個要標出來,⛔ 不可以刪掉自己。
七、模型:改的是聊天核心的設定檔。主要模型一組(Provider、Model ID、Base URL、key 的環境變數名),
備援模型一列,主要出錯時依序嘗試,每一筆可以設為主要或刪除。
🔴 存檔不會自動生效,頁面最上面要用警告框寫清楚:要手動重啟聊天核心,而且改完一項就重啟,
⛔ 不可以拖著繼續改下一項 —— 聊天核心執行中會把它自己記得的舊設定寫回檔案,把剛改的蓋掉。
八、設定:外觀強調色 7 種可選,淺色深色另外用右上角切換;提醒發送管道的狀態與測試發送。
⚠️ 只顯示小秘自己知道的狀態。Telegram 與 LINE 聊天的連線狀態是聊天核心容器的事,
⛔ 不可以猜著顯示綠燈,寫一句「要看那個容器的 log」就好。
規則:每一頁的表單送出後不整頁重載,用 HTMX 換那一塊;有錯誤就找原因修到正確為止。
今日
今日:今天的行程、到期的待辦、近期的提醒。

進來第一頁是今天:今天的行程、到期的待辦、近期的提醒。空的時候要明白寫「今天沒有安排的行程」,不能留白,留白分不出是沒事還是壞掉。近期提醒那一格現在掛著兩條真的在用的:每天早上 11:00 記得發文 iron30,還有 Iron30 發文檢查。之前因為漏一天,變成發文中斷。所以加這兩個提醒。
行事曆與待辦
行事曆:月曆,當天有記號,事件直接顯示在格子裡

待辦:優先度、到期日、標籤;清單依狀態與優先度

行事曆是月曆,看得到整個月,當天有記號,事件直接顯示在格子裡。待辦有優先度高中低、到期日選填、標籤選填,清單可以依狀態與優先度篩。
遇到的三個問題:
提醒
提醒:單次或重複,管道 LINE 推播、失敗退 Email;清單分進行中與歷史

提醒分單次與重複,單次是一個時間點,重複是一條排程表達式,兩者只能設一個。排程器用 APScheduler,工作存在磁碟上的 jobstore,服務重啟之後工作還在,不用重排。發送管道主要是 LINE 推播,失敗時自動退回 Email,前提是 Email 要有設定。為什麼先做推播而不是先做聊天:提醒是小秘主動找我,聊天是我找它,主動那條線先通,小秘才算存在。清單分進行中與歷史,響過的單次提醒自己移到歷史。
發票
發票:2 碼英文加 8 碼數字、選期別;單月 26 日自動對獎,結果推到 LINE

發票頁是為了統一發票對獎。一張發票是 2 碼英文字母加 8 碼數字,還要選期別,期別要跟財政部公布的一致才對得到獎。輸入的時候中間的空白或連字號自動去掉,因為手打跟辨識出來的格式都不整齊。同一張發票用號碼加期別去重複,重複的直接擋,這是 LINE 上重傳同一張照片抓到的。入庫之後每逢單月 26 日自動比對財政部公布的中獎號碼,中了列出獎別與金額,全部沒中也回報一句,結果推到 LINE。這一頁是給沒有照片或要補建清理紀錄用的,日常是在 LINE 或 Telegram 直接拍照傳,辨識號碼與期別後自動入庫,那是下兩篇的事。
帳號、模型、設定
帳號:誰能登入,目前登入的那一個標出來

模型:主要模型走路由器到本地那台語言模型,備援是雲端;上面的警告框是真的發生過的事

設定:7 種強調色、提醒管道狀態與測試發送;聊天連線狀態不在這裡

帳號頁,目前只有一個 user。模型頁改的是聊天核心的設定檔:主要模型走本地那台 Qwen3.6 語言模型,經過路由器;備援依序是雲端的 gemma-4-31b-it 與 gemini-2.5-flash,主要模型出錯才輪到。這一頁上面有一個警告框,是真的發生過的事:存檔不會自動生效,要手動重啟聊天核心;而且改完一項就要馬上重啟,不能拖著繼續改下一項,因為聊天核心執行中會把它自己記得的舊設定寫回檔案,把剛剛的改動蓋掉。設定頁只有三件事:外觀強調色 7 種可選,淺色深色另外切;提醒發送管道的狀態與測試發送,LINE 已設定、Email 未設定;Telegram 與 LINE 聊天的連線狀態不在這裡,那是聊天核心容器的事,要看它的 log。
模型的連接改成用單一路由
聊天核心不直接連語言模型,全部經過路由器。理由是 OpenClaw 那三個月學到的:模型相關的調校散在六個地方就管不動,集中在一個地方才管得動。路由器現在做的事:把時區當下時間注進提示,因為模型排提醒時曾經把時間寫成 2026-07-50 這種不存在的日期;限制單次輸出上限,因為曾經一次生成 22K token 停不下來;關掉思考模式,因為記事情不需要思考,需要的是格式對。規則:所有跟模型有關的旋鈕只准放在路由器,聊天核心與小秘一個都不准有。
這個本地模型, Qwen 3.6-35B-A3B,僅適合單一工作,不適合多重指派的任務。簡單講,一個命令一個動作,他很 ok。所以,順著這個特性 (缺點?),磨出一些經驗,放在呼叫的 prompt 裡,讓他能正確工作。
底座好了
現在這台機器上有一個小秘,八個頁面,兩條每天在響的提醒,兩張待對獎的發票。它還不會講話,也還聽不到我講話。底座的意義是:資料有地方放、時間有地方排、推播有一條線已經通了。接下來把嘴巴接上去,先接 Telegram。