- 我提到 Hermes Agent 的 LINE adapter PR
- 這次我最在意的不是「我寫了多少程式」,而是過去踩過的 LINE reply token 問題,真的能轉成開源專案裡的工程設計。
- 我平常主要在 Claude Code 裡工作,這次也是一樣:我做領域判斷、架構決策和驗證,Claude Code 把它們整理成可運行的 Python。
- 對我來說,這次經驗比較像是在確認一件事:被 maintainer 採納的,不是 code volume,而是設計品質。
我和 Claude Code 一起寫的 LINE adapter,被 NousResearch 的 Hermes Agent 採用了
vibe coding 也能有貢獻價值——只要架構設計得當
先說結論
上個月我往 NousResearch 的 Hermes Agent 提了一個 LINE adapter 的 PR。Hermes Agent 是個很大的開源專案,我那時看到 repo 已經是 142k+ stars,第一反應其實不是興奮,而是有點緊張。
最後我的 PR #18153 沒有直接 merge;但 maintainer 後來把七個社群 LINE PR 合成成另一個正式 merged 的 PR #23197,並且明確寫出從我這邊拉進去的幾個設計。
老實說,那個一千多行的 LINE adapter 並不是我一行一行寫出來的。整段過程比較接近我自己會叫的 vibe coding:我做架構設計、驗證和修正,Claude Code 幫我把它變成可運行的 Python。這篇想記下來的,不是「我多會寫程式」,而是:一個沒被其他 PR 處理好的 LINE 邊界條件,怎麼變成可被 maintainer 採納的工程設計。
先從一個 LINE RAG bot 開始
這個故事其實不是從 Hermes 開始,而是從半年前一個比較小的案子開始。
那時我在幫朋友做一個 LINE RAG bot。真正卡住我的,不是 RAG 本身,而是 LINE。
LINE webhook 在收到訊息後,會給 bot 一個 reply token,可以把它想成一次性的免費回覆憑證。問題是 LINE 官方文件沒有把它寫成一個很死的秒數;但不管是社群經驗,還是平台本身的 loading animation 設計,大家大致都會把它當成大約一分鐘內要用掉的東西。只要 RAG 沒找到、需要再 fallback 去做 web search,整個等待時間就會很容易把這個 token 拖過期。
這裡就出現了一個我一直記得的兩難:如果堅持用 reply token,就得想辦法在很短的時間內把答案送回去;但如果直接改成 push message,成本又會突然變得很不友善。那時我就已經開始摸索,怎麼在 LINE 的限制裡塞下一個比較像樣的 fallback 流程。
後來那個 bot 沒有繼續往前推,但 reply token、慢回應和成本這幾個坑,留在我腦子裡很久。這也變成我後來看到 Hermes 沒有 LINE support 時,第一個想到的差異點。
為什麼會看 Hermes 的 LINE 支援
最近我重新看 Hermes Agent 的平台支援時,發現它已經有 Telegram、Discord、Signal、Matrix 這些整合,但偏偏沒有 LINE。
這件事對我來說很微妙,因為我自己其實不太會用通訊軟體跟 agent 長時間互動。我還是比較偏好 Claude Code 這種 TUI 介面,因為每一次工具呼叫、每一次搜尋、每一次 retrieve 都會顯示得很清楚。
但我自己的偏好是一回事,台灣多數使用者的習慣又是另一回事。你如果真的想把 agent 帶到更多日常工作情境裡,LINE 幾乎是一個很難跳過的入口。
我一直有一個很直接的念頭:我很想讓身邊的人也感受到 AI 真的有用,只是 Claude Code 那種終端機畫面,常常第一眼就先把人嚇跑。Hermes 加上 LINE,對我來說剛好像是一個更接近日常入口的可能性。
所以我看到 Hermes 沒有 LINE,腦中第一個想法不是「太好了我自己要用」,而是「這塊應該還是要有人補上」。
撞 PR 的慌張時刻
於是我就開始做,然後把 PR #18153 送了出去。
結果沒多久,下面就有人留言提醒我:已經有另一個 LINE PR 了。
我那時真的有點嚇到。不是因為覺得自己白做了,而是我第一時間以為自己是不是踩到某種 OSS 禮儀:沒有先搜尋清楚,就直接衝去做了一個別人已經在做的東西。那種感覺很像在很大的公開場合講錯話,會先想把自己縮起來。
所以我做了一件現在回頭看很有我風格的事:我先慌張地把自己的 PR 關掉了。
過了一晚之後,我才比較冷靜下來,重新去 GitHub 翻整個脈絡。結果越翻越意外,因為不是一個、也不是兩個,而是當時已經有六個 LINE PR,後來甚至變成七個。大家其實都看見了同一個缺口,也都熱心地想把它補上。
但我再仔細往下看時,發現了一個我很在意的點:雖然大家都在做 LINE support,可是沒有人真的在解那個最麻煩的地方,也就是 reply token 大約 60 秒的限制。
我真正補上的那一塊
我後來把 PR 又重新打開,然後把心態調整得很單純:不是去跟別人比誰做得比較大,而是只做我真的知道怎麼解、而且也剛好沒人處理好的那一塊。
那一塊就是:怎麼讓 LINE 在 agent 工作流下,盡可能無感地維持免費。
我最後採用的做法其實不複雜。當 Hermes 的回應時間快要逼近 reply token 的安全邊界時,不要硬等到它失效,而是在比較保守的門檻先把原本那顆 token 用掉,送出一個按鈕訊息和一句「回覆中,請稍後」。
如果使用者之後點那顆按鈕,LINE 會再送回一個新的 webhook event,也就等於給 Hermes 一顆新的 reply token。這時候 adapter 就可以用那顆新的 token,把已經排隊完成的答案送回去。對使用者來說,它比較像是多點一下「拿答案」;對系統來說,卻是在既有規則裡重新換到一次免費回覆的機會。
Hermes 後來在官方 LINE 文件裡,也把這個流程寫成預設的慢回應機制:LINE_SLOW_RESPONSE_THRESHOLD 預設是 45 秒,理由就是在大約 60 秒的 reply token 視窗裡,先留一段緩衝。
為什麼我最後改用 Template Buttons
不過這個設計一開始也不是一次就對。
我第一版用的是 Quick Reply,那種貼在訊息下方、看起來很方便點的小按鈕。剛做出來時我其實滿開心的,因為它很輕,看起來像是最自然的互動方式。
但我一拿去實際測,就撞到一個很現實的問題:如果使用者還在等答案時,又順手傳了一句新的訊息進來,Quick Reply 會直接被新的訊息洗掉。也就是說,那顆原本拿來「補回一顆新 reply token」的按鈕,反而會在真實聊天場景裡最容易消失。
所以我後來把它改成 Template Buttons 訊息。它沒有 Quick Reply 那麼輕巧,但它會留在聊天紀錄裡,使用者就算隔一段時間再滑回去,也還是可以點。
這個取捨後來也真的被保留進 merged 的 adapter.py。官方註解甚至直接把那個理由寫得很白:
Template Buttons stay tappable from chat history, unlike Quick Reply chips which are dismissed the moment any new message arrives in the chat.
對我來說,這段話很有趣,因為它不是什麼高深的演算法,而是一個很小、但真的只有跑過 round trip 才會在意的聊天介面判斷。

Vibe coding 裡,哪些事還是得由人負責
如果只看最後進 merged PR 的 plugins/platforms/line/adapter.py,你會看到它是一個一千多行的 adapter。就我自己的實際體感來說,裡面真正由我親手敲進去的 code,可能連 50 行都不到。
整個 PR 基本上就是 vibe coding。Claude Code 寫,我做架構與驗證。
但我也因為這次經驗,更清楚地分出兩件事:哪些部分我確實交給了 Claude Code,哪些部分其實還是只能由我自己負責。
我做的,主要是這五件事:
- 領域知識:我不是從零開始碰 LINE。前面幫朋友做 LINE RAG bot 時,reply token、push 成本、慢回應這些坑我已經踩過一次。
- 架構決策:到底要不要做 postback、什麼時候該 fallback Push、reply token 要怎麼接回排隊中的答案,這些不是模型自己長出來的,而是我先決定方向。
- 真實驗證:我有真的在 LINE Official Account 上跑過 round trip,而不是只看測試過了就算。
- 邊角案例:像 Quick Reply 會被新訊息洗掉、busy-ack 訊息會被吞掉,這些比較像聊天情境裡的真實摩擦,不太像只看規格文件就會自然想到的事。
- 設計取捨:45 秒閾值、Template Buttons 優先於 Quick Reply、postback 的狀態流要怎麼走,這些本質上都是設計選擇。
Claude Code 做的,則是把這些決定轉成可運行的 Python,還有把測試補齊。當方向夠清楚時,它可以很快把很多原本會很耗時的機械工作做完。
對我來說,這也是 vibe coding 比較有意思、也最容易被誤解的地方。它確實可以大幅加速程式碼的產出,但實際的架構、設計和驗證,還是得靠人下去處理。它不是把思考外包掉,而是把「把想法翻成大量可執行 code」這件事加速。前面那個 framing、取捨、驗證,還是得有人負責。
被 maintainer 採用的那一刻
大概兩週後,我收到 GitHub 通知,看到 Teknium 在 PR 上的回應。
那一刻我其實先愣了一下,因為我原本以為最可能的結局,就是這個 PR 靜靜地被關掉,或者只留一句「我們已經有別的實作在處理了」。結果不是。

他不是只說一句謝謝,而是很具體地寫了這次合成的做法,也很具體地點出從我這裡拉進去的部分:
From your PR specifically we pulled in the Template Buttons postback cache state machine, Markdown URL preservation, three-allowlist gating, and system-message bypass.
如果用中文簡單講,就是:這次他們把七個社群 PR 合成成一個正式的 LINE plugin,而從我的 PR 裡,拉進去了四個具體設計。
前面已經講過最核心的 Template Buttons postback cache state machine。另外三個我自己也很有感。
Markdown URL preservation 其實不是什麼很大的功能,單純比較像我自己看了會想修掉的那種細節。LINE 不吃一般 Markdown,如果直接原樣送出,粗體、code fence、標題符號都會變成字面上的雜訊。我那時做的處理,比較像是把 LINE 不懂的標記拿掉,但盡量保留 URL 的可點性,讓訊息至少維持可讀。
Three-allowlist gating 則跟我一開始想像的使用場景有關。我那時設計 LINE bot,不是只想像一對一聊天,而是也會想到一起出遊的群組,所以權限控制不該只有 user,還要把 group 和 room 都當成一等公民來處理。這件事放在 LINE 上特別實際,因為它本來就不只是單聊工具。
System-message bypass 我後來回頭看,覺得它很能代表「只有真的跑過才會在意」的那種小地方。因為前面為了處理慢回應,我做了 postback cache 的等待流程;但像 Queued、Interrupting 這類系統訊息,或一些忙碌中的提示,不應該被一起吞進等待中的快取裡,不然使用者會以為 bot 沒反應。它們應該直接作為可見的訊息泡泡送出去,讓人知道系統現在到底在做什麼。
我後來又回去看 merged 的 adapter.py,那種感覺很奇妙。不是抽象地覺得「好像有被用到」,而是真的可以在正式合併後的程式碼裡,看到多處明確標注 PR #18153 (leepoweii)。
有些地方甚至連註解都幾乎是直接沿用我的設計理由。像我前面提到的 Template Buttons / Quick Reply 差異,就被寫成這樣:
Template Buttons stay tappable from chat history, unlike Quick Reply chips which are dismissed the moment any new message arrives in the chat.
這句話我很喜歡,因為它不是在炫技,而是很忠實地描述一個真實聊天介面的行為差異。

除了程式碼本身,合成 PR 也保留了 Co-authored-by,甚至加進了 release note attribution 的對應表。這些細節對我來說都很有重量,因為它們不是那種模糊的「有參與到」,而是很正式地承認:這些設計確實是從這裡來的。

我回去看到自己的名字真的被放進備註、被寫進正式合併後的脈絡裡時,那個感覺很直接:原來這次做的東西,真的不是只停在自己的 branch 裡,而是會跟著 Hermes 一起被更多人用到。這也是我第一次很具體地感覺到:原來有一個設計,真的會跟著這個專案一起被世界使用。以後如果朋友剛好用了 Hermes Agent,我甚至可以很直接地說,那裡面有一小段設計,是我貢獻進去的。
而最有意思的地方是,Teknium 其實不知道我是 vibe coding。
他看到的不是「這個人是不是傳統工程師」,也不是「這段 code 是不是逐行手打出來的」。他看到的只有一個 PR,和裡面幾個他認為值得採用的設計。這反而讓我很有感,因為最後被看見的,不是我用什麼姿勢寫 code,而是我提出來的設計到底有沒有價值。
被採用的不是 code volume,而是設計品質
這次經驗讓我最想留下來的一句話,大概就是:
即使 vibe coding,只要架構設計得當,也是可以有貢獻的。
我能補上的,其實不是「比別人更會寫 Python」,而是另一組東西:對 LINE 限制的記憶、對產品摩擦的敏感、對使用成本的判斷、對真實聊天情境的驗證,還有把這些東西整理成一個比較穩定工作流的能力。
Claude Code 補上的,則是把這些判斷快速 mapping 成可運行的 Python、測試和 PR 形式。兩邊剛好互補。
所以如果要說這次讓我確認了什麼,我會說:vibe coding 真正有沒有價值,不在於你能不能一句 prompt 生出很多 code,而在於你有沒有足夠清楚的問題意識,能不能做出像樣的設計判斷,還有願不願意把那些判斷放回真實場景裡驗證。程式碼產出可以被加速,但架構、設計和驗證,並不會因此自動發生。
這也是為什麼我不太把這次看成「AI 幫我完成了一個 adapter」,而比較像是:我用 AI 工具,把一段原本停留在經驗裡的領域知識,放大成一個真的能被開源專案採用的設計。
寫在最後
Teknium 最後那句 please keep contributing,我應該會記很久。不是因為它聽起來很勵志,而是因為它讓這整次經驗變得很具體:原來這條路是走得通的。就算我不是傳統工程背景出身,就算整個過程大量依賴 Claude Code,只要問題抓得夠準、設計做得夠清楚、驗證做得夠老實,還是有可能補上真正有用的東西。
如果你剛好也在做 agent、工具整合,或只是對這類實驗有興趣,歡迎來信:me@pwlee.xyz,或在 GitHub 上找我:leepoweii。
迫不及待要去找下一個貢獻機會了。
常見問題
這篇是在說 PR 被 merge 了嗎?
#18153 沒有直接 merged;maintainer 後來在合成 PR #23197 時,把我其中幾個設計拉進正式版本,並保留 Co-authored-by 署名。