← Writing
AI 工作流 · · 5 min read · Read in English

Wingman 怎麼做的?用 Jev 判斷、LLM 寫字,做一個回訊息小幫手

讓 Jev 先決定怎麼回,再請 LLM 寫成三則草稿,填進輸入框但不送出

每天在 Slack、LINE、Discord 之間切來切去,應該都有過這種經驗:訊息一則一則跳出來,有的要立刻回,有的只要回一個「收到」,光是判斷「這則到底要不要回、該怎麼回」,就已經花掉不少力氣。

九月底我做了一個叫 Wingman 的 macOS 選單列小工具,想幫自己省下這一步。有人傳訊息來,它會在輸入框上方浮出「✦ 3 則建議」,按 ⌥Space 展開三則草稿,最適合的那則標上 ★。按 Enter,它把那一則打進輸入框就停手,真正送出的 Enter 永遠由我自己按。

這篇文章想跟大家分享 Wingman 是怎麼做出來的:Jev 跟 LLM 各自負責什麼、七個聊天 App 怎麼讀、寫草稿的模型怎麼挑,以及公司的對話會經過誰的主機。

一則訊息進來,⌥Space 展開三則建議,★ 是最推薦的,Enter 把它打進輸入框

先說這個專案的核心想法,只有一句話:Jev 負責判斷,LLM 只負責寫字。

Jev 是 TypeSafe 的 System One 決策模型,它不會寫句子,只回答「選項固定的問題」,而且每個答案都附一個機率,例如這則訊息想要什麼、需不需要回、多急。一次判斷約 0.3 秒。LLM 拿到這些判斷之後才開始寫,所以一次建議等 2 到 4 秒,費用約 0.0002 美元。

目前支援 Slack、Discord、Messenger、Instagram、Threads、LINE、Telegram,原始碼在 GitHub,MIT 授權。

一次建議是怎麼跑的#

一次建議的六個步驟:讀聊天、Jev 問 6 題、程式決定、LLM 各寫一句、Jev 挑最好的、填入不送出

我們順著上面這張圖,看一次建議從訊息進來到你按下 Enter,中間發生了什麼事。

新訊息進來、畫面停住 1 秒之後,Wingman 開始讀聊天,只取最近 20 則,交給 Jev 一次問六題:意圖、要不要回、多急、哪幾種回法最能推進對話、氣氛多緊張、有沒有話中有話,每題都附機率。

接著由程式決定。「要不要回」低於 0.5 就停在這裡,不叫 LLM;否則取機率最高的三種回法,請 LLM 照三種回法各寫一則,寫好一則先顯示一則。三則都寫好之後,再把它們當成同一題的選項問 Jev 一次,機率最高的標上 ★。最後按 Enter 或 1 到 3,文字進輸入框,其餘就由你自己來。

這樣分工是因為價差。判斷一次大約 1,000 到 1,800 個 input token,不到 0.0001 美元,寫一則草稿則是它的 2 到 3 倍。先讓便宜的 Jev 決定值不值得寫,閒聊跟公告底下就不會白叫一次 LLM,輸入框上方也不會多浮一顆打擾人的提示。

Jev 問的六題#

先看一個實際的例子。下面這張圖是 Jev 判斷一則訊息的樣子:對方問「今天下班前能不能發版?」,它回答對方想催進度、需要回、最適合的回法是給進度和時間,每個答案都附一個機率。LLM 寫好三則草稿之後,Jev 會再被叫一次,把三則草稿當成同一題的三個選項來排名。對方只說了一句「感恩 :)」的時候,三則草稿拿到 99%、0%、1%,它挑中「不客氣,有需要再跟我說!」,換我也會選這則。

Jev 判斷一則訊息:對方想要什麼 94%、需不需要回 91%、怎麼回最好 94%

每次建議實際問的是下面六題。選項是我自己列的,Jev 只負責從裡面挑,並告訴我們它有多確定:

  • 對方想要什麼 → 問資訊、請求或交辦、催進度、確認或同意、告知、閒聊、抱怨、感謝,共八種
  • 需要回嗎 → 是或否,附機率
  • 多急 → 0 到 3 分,從「幾天內」到「馬上」
  • 怎麼回最能推進對話 → 直接答應、答應但附條件、給進度和時間、先問清楚、婉拒或延後、表達感謝、簡短回應,共七種
  • 氣氛多緊張 → 平和、留意、緊張、快吵架、翻臉,共五級
  • 有沒有話中有話 → 是或否,附機率

後面兩題是這個專案後來加的。氣氛偏緊張的時候,三則草稿會先把事情講開,不急著附和。另外,如果機率最高的三種回法全都是「答應」,第三則會換成「婉拒或延後」,因為三則都答應的話,做不到的人就沒有一則可以選了。

整體架構#

資料走到哪裡:聊天 App 和 Wingman 都在你的 Mac 上,只有問 Jev、請 LLM 寫字兩種請求會離開

圖中虛線框是你的 Mac,裡面有聊天 App 和 Wingman 本身,框外是 Mac 之外。只有兩種請求會離開你的電腦,一種是問 Jev,一種是請 LLM 寫字。讀訊息、判斷要不要繼續、顯示面板、把文字填進輸入框,全部都在你的 Mac 上完成。

再往裡面看一層,就是程式的核心。Brain 是唯一同時跟 Jev 和 LLM 講話的模組:先問 Jev 六題,程式根據答案挑出三種回法,LLM 照著各寫一句,最後再讓 Jev 替三句排名、標上 ★。讀取器、流程、面板、填入器都只做自己那件事,不碰模型。

技術核心:讀取器把訊息交給流程,Brain 串起 Jev 和 LLM,再經建議面板和填入器進到聊天輸入框

每個聊天 App 怎麼讀#

做這個專案的第一步,是用 macOS 的 Accessibility API 把每個 App 都探一遍,因為它們的差別非常大。

Slack 一個畫面 362 個節點有 193 個帶文字,LINE 700 多列訊息 0 個有文字,Telegram 0 個可讀元素

探出來的結果在上面這張圖。Slack 和 Discord 都是 Electron 做的,輔助使用樹整棵 DOM 都讀得到,只需要「輔助使用」權限。Messenger、Instagram、Threads 的網頁版也是讀輔助使用樹,而且只在確切的網址上讀。

LINE 就不一樣了,聊天室名稱和輸入框還讀得到,訊息本身卻是空的。Telegram 更徹底,輔助使用樹整個是空的。這兩個 App 拿不到訊息文字,所以要再加上「螢幕錄影」權限,改用 Apple Vision 在本機做 OCR,截圖不會上傳。中文辨識相當準,誰說的話則用泡泡的 x 座標來分:對方的從左邊約 12% 開始,自己的在約 93% 結束。

Slack、Discord、Messenger、Instagram、Threads 我已經在真實聊天上用過,LINE 和 Telegram 因為走 OCR,目前用得比較少。

網頁版還有一個額外的限制:瀏覽器裡只讀這三個網站的訊息頁。Instagram 和 Threads 貼文底下的留言,只會讀游標所在輸入框的那一則貼文,單純滑動動態牆不會讀任何東西。回在貼文底下的是公開留言,面板上也會特別標明。

寫草稿的模型:最便宜的不一定划算#

寫草稿的模型,我用 scripts/bench-writers.py 拿四段假的 Slack 對話、同一份 prompt 逐一測試,再用 OpenCC 數有幾處不是台灣用語。以下是 9/27 在台灣量到的結果,圖中節錄四個,六個的完整結果在圖下面的文字版:

寫草稿模型節錄四個:DeepSeek V4.1 Flash 不編造內容,最便宜的兩個編出了時間和行程

文字版的結果如下:

  • DeepSeek V4.1 Flash → 平均 1.7 秒、每次 0.00015 美元,台灣用語最乾淨(0 處),不知道的時間會留 [時間]
  • DeepSeek V4 Flash → 3.5 秒、0.00004 美元,編出時間:「三點半前能過」「明天早上給你修正版」
  • Qwen 3.7 Flash → 2.4 秒、0.00003 美元,編出行程:「下午兩點後」「今天排滿會議」
  • 另外三個(Qwen 3.8 Flash、Gemini 3.1 Flash-Lite、Claude Haiku 4.5)每次 0.0001 到 0.00155 美元,沒有編造內容,只是混進了「还」「數據」「項目」這類不是台灣用語的字

最出乎我意料的是,最便宜的那兩個模型,會替我寫出對話裡一個字都沒提過的時間和行程。這種草稿讀起來最順,一不注意就按下 Enter,等於替我答應了一件事。DeepSeek V4.1 Flash 雖然貴了好幾倍,一次也才 0.00015 美元,換來的是我不用逐字檢查它有沒有亂承諾,所以我選它當預設。

另外有兩個地方也跟大家分享:

  • OpenCC 的數字只能拿來篩掉明顯不行的模型,它連「權限」都會改成「許可權」,所以草稿還是得一則一則讀
  • 回覆的語言由程式先判斷再告訴寫手,因為只在規則裡寫「用對方的語言回」,對方用英文道謝時,多數模型還是回中文

公司的對話會經過誰的主機#

Slack 裡的對話是公司資料,所以資料的去向,我在跑 bench 之前就先決定好了:

  • 沒有 Wingman 的伺服器,每個人用自己的 API key,我不會收到 key,也不會收到任何對話
  • 只送最近 20 則,加上聊天室名稱、發言人名字和你的顯示名稱,判斷送給 TypeSafe,寫字走 OpenRouter
  • 只走零資料保留、不蒐集資料的供應商,並且排除 DeepSeek、StreamLake、Alibaba、SiliconFlow、Baidu 這幾家中國的主機,排除之後 DeepSeek V4.1 Flash 的 1.7 秒變成通常 2 到 4 秒,偶爾 8 到 10 秒
  • 聊天內容預設不存檔,想讓它記得更久可以打開「記住聊天」,每個聊天室最近 300 則會加密保存,金鑰只存在這台 Mac 的鑰匙圈,放著不開 90 天就刪
  • 日誌只記時間、次數和費用,不記訊息文字,設定裡還有一顆按鈕可以全部清掉

費用方面,一次完整的建議大約 0.0002 美元,一天 20 次,一個月約 0.1 美元。這些都是按量計費的 API key,ChatGPT 和 Claude 的訂閱沒辦法給第三方 App 使用。

我也試過 macOS 26 的 Apple 端側模型(FoundationModels)。它支援 zh-Hant-TW、免費、資料不出電腦,拿來處理公司對話最讓人放心。不過第一則回覆就等了 18.6 秒,對話問的是今天,它卻寫「明天上午發版」,連誰該回客戶都搞錯,所以沒有當預設。

為什麼只填、不送#

Wingman 對其他 App 唯一做的事,就是把你選的草稿打進輸入框。下面是 LINE 社群裡的真實畫面(成員名字已經遮蔽):右下角冒出提示、按 ⌘Space 看三則建議、選一則之後字出現在輸入框,送出的那下還是你按。注意第一則建議寫的是「預計 [時間] 前」,它不知道時間,就留空格給我填。

實際用起來的三個畫面:出現圖示、看三則建議、填進輸入框

它還有幾道保護:

  • 它不按 Enter,連草稿裡可能被當成 Enter 的字元都會先拿掉,因為在 Slack 裡換行就等於送出
  • 打字之前會先確認聊天室還是原本那個、輸入框有焦點,只要有一項不符,就改成把草稿放進剪貼簿
  • 別人傳來的訊息會以純文字交給模型,惡意的訊息可以試著帶偏草稿,所以送出前一定要讀過一遍,不過模型沒有任何工具和金鑰,也碰不到其他聊天室

面板上我也刻意不顯示百分比。Jev 的機率很容易衝到兩端,一則合理的草稿旁邊寫著 0%,第一眼會讀成「這則寫錯了」,所以我改用「★ 最推薦」跟「也不錯」兩種標籤,數字收進 tooltip。

自己裝來用#

需求是 macOS 14 以上、Xcode 16 以上,以及 brew install opencc,接著執行:

git clone https://github.com/chyiiiiiiiiiiii/jev-wingman.git
cd jev-wingman
./scripts/install.sh

第一次開啟會帶我們走三步:授權、填 key、設定顯示名稱。key 的部分,OpenRouter 一定要填,TypeSafe 選填,有填的話判斷會快上好幾秒。

總結#

這篇文章分享了 Wingman 的做法:讓 Jev 判斷要不要回、怎麼回,讓 LLM 負責寫,再讓 Jev 幫草稿排名。如果大家也想做類似的工具,我自己的經驗有三點。

  • 先探每個 App 的輔助使用樹再決定架構,因為 Slack 和 LINE 看起來差不多,讀法卻完全不同
  • 挑寫手模型要用自己的對話一則一則讀,重點看它會不會替你答應事情
  • Enter 一定要留給使用者自己按

接下來我想繼續優化 LINE 和 Telegram 的 OCR,也想用日誌看看 ★ 那一則實際被選中的比例有多高。有興趣的朋友歡迎留言跟我分享你的想法。

延伸閱讀#

參考與相關資源#