iT邦幫忙

2026 iThome 鐵人賽

DAY 15
0
AI 自動化

用 LINE Bot 和 Agent Skill 自動化整理筆記與 IG 發文系列 第 15 篇

Day 15|指令用規則、內容用 AI:用 LINE 搜尋、刪除、註記、標待辦

  • 分享至 

  • xImage
  •  

昨天講完重複網址怎麼查重,最後提到 LINE 上那些搜尋、刪除、註記、標待辦的指令,今天就來看這幾個指令是怎麼分工的。先講結論:這一整塊,我一行 AI 都沒用。

既然存筆記都靠 AI 分類,搜尋和下指令也可以丟給模型,讓我直接用講的,像「幫我把那篇 Cloudflare 的刪掉」。我沒有這樣做,理由很實際:這些操作的意圖都很單純,而且做錯的代價比分類錯高。分類下歪了我可以事後改,但誤刪或誤標,我不想承擔「模型這次可能理解錯」的風險。

所以入口 handleTextMessage 的判斷順序是純規則:

const command = parseCommand(text);
if (command) {
  await handleCommand(env, replyToken, command);
  return;
}

const match = text.match(/https?:\/\/[^\s]+/);

// 沒有網址 → 當作搜尋關鍵字
if (!match) {
  await handleSearch(env, replyToken, text);
  return;
}
// 有網址(且不是指令)→ 才走抓內文、AI 分類、寫進 Notion

一則訊息進來,先看是不是「指令關鍵字 + 網址」,不是的話看有沒有網址,沒有網址就當搜尋,都不是才走存筆記。AI 只出現在最後那條路,前面兩條完全沒碰。

指令的比對靠一張對照表:

const COMMANDS = [
  { keys: ['取消待辦', '取消待办', 'untodo'], action: 'untodo' },
  { keys: ['待辦', '待办', 'todo'], action: 'todo' },
  { keys: ['刪除', '删除', 'delete'], action: 'delete' },
  { keys: ['註記', '注记', '備註', '备注', 'note'], action: 'note' },
  { keys: ['分類', '分类', 'category'], action: 'category' },
];

parseCommand 用 startsWith 一個一個比,所以「取消待辦」一定要排在「待辦」前面,不然「取消待辦」會先被當成「待辦」吃掉,意思整個反過來。每組關鍵字除了繁體中文,還多放了簡體和英文的寫法。

比到關鍵字之後,還要在後面抓得到網址才算指令,沒有網址就 continue,讓訊息繼續往下掉到搜尋。這是刻意的:「待辦」單獨傳,會列出待辦清單;「待辦 https://...」才是把那篇標成待辦。關鍵字一樣,有沒有網址決定它是哪一種意思。網址後面剩下的文字則當作 extra,註記的內容和新的分類名稱都從這裡來。

有一個小細節要留意:parseCommand 的比對沒有轉小寫,所以「todo <網址>」可以,「Todo <網址>」不行。手機輸入法如果自動把句首字母大寫,這則訊息會因為帶網址、又沒被認成指令,直接被當成新網址存進去。搜尋那邊的關鍵字有做 toLowerCase(),兩邊處理不一致,這是目前留著的小缺口。

指令要對哪一篇筆記動手,靠 resolvePageId 找出 page ID,這個函式昨天講過了,可以貼 Notion 頁面連結,也可以貼原始文章網址。找到之後,四個動作各自很短:

case 'delete':
  await archiveNotionPage(env, pageId);   // PATCH { archived: true }
case 'note':
  await appendNote(env, pageId, command.extra);
case 'todo':
  await setTodo(env, pageId, true);       // 勾選「待辦」checkbox
case 'category':
  await setCategory(env, pageId, command.extra);

刪除不是真的刪。archiveNotionPage 只是對頁面送 { archived: true },等於丟進 Notion 垃圾桶,30 天內還撈得回來,回覆訊息裡我也有寫明這件事。刪除是這四個動作裡最危險的一個,用封存而不是真的移除,操作失誤還有救。

註記則是疊加,跟 Day 14 講的邏輯一樣,appendNote 在頁面內容底下補一段,前面帶著台北時間的時間戳,可以一直加,不會蓋掉舊的。

分類就不設限。setCategory 直接把我打的字寫進去,不用管是不是在 CATEGORIES 那七個裡面,Notion 遇到沒看過的名稱會自動建立新選項。AI 分類時我把它限制在固定清單裡,是為了讓資料整齊;但我自己手動改的時候,有想法就是有想法,不需要再被清單管。

沒有網址的訊息進到 handleSearch,裡面也是一串 if:

  • 「說明」「help」:回使用說明
  • 「最近存的」:列最新 5 筆
  • 「待辦清單」:列所有勾了待辦的
  • 「依分類搜尋」:跳出 Quick Reply 按鈕,列出全部分類
  • 其他任何字:丟進 searchNotion

最後那個才是一般搜尋。搜尋照理說可以用 Notion 的 API filter 去篩,但這裡有個雷:分類是 select、標籤是 multi_select,篩選時給的值如果不是資料庫裡已經存在的選項,API 直接回 400,包在 or 裡也一樣。搜尋的關鍵字很常不是既有選項,這條路走不通。

所以 searchNotion 改成先抓最近 100 筆回來,自己在 JS 裡把標題、分類、標籤串成一個字串,用 includes 比對關鍵字,最後只回前 5 筆。

const haystack = [item.title, item.category, ...item.tags].join(' ').toLowerCase();
return haystack.includes(needle);

這種做法很土,而且有明顯的限制:只搜得到最近 100 筆,也只能比對標題、分類、標籤,不會搜摘要或內文。但對我的用法夠了,搜尋的詞多半是分類或標籤裡看得到的字,部分符合就找得到。這也是為什麼標籤一致這麼重要,Day 11 花力氣讓 AI 重複用同一個詞,在這裡派上用場:標籤越統一,單純的字串比對就越準。

回頭看這一整塊,我覺得可以用一個標準來切:使用者要的東西是不是有明確答案。

存筆記要判斷「這篇屬於哪個分類、值得記哪幾個重點」,沒有標準答案,才需要 AI。刪除、標待辦、改分類、加註記這些,我要的就是照字面執行,一個字都不想被詮釋。搜尋也是,我要的是「標題有這個詞的都給我」,不是「模型覺得相關的給我」。

用規則還有兩個附帶好處。一個是不吃模型額度,也不怕免費模型掛掉,Day 12 講的 fallback 在這條路上根本用不到,指令永遠反應得出來。另一個是行為可預測,出問題我看程式碼就知道為什麼,不用猜模型當下在想什麼。

代價就是我得記住指令格式,打錯字就不會觸發。這也是明天要講的事:用圖文選單、Quick Reply 這些介面,把「要記住格式」這個負擔再降低一點。

明天來看 LINE 上的體驗細節:輸入中動畫、Quick Reply、圖文選單,以及為什麼這個 Bot 只服務我一個人。


上一篇
Day 14|同一個網址不重複存:先查再決定新增或更新
下一篇
Day 16|體驗細節:輸入中動畫、Quick Reply、圖文選單、只服務自己
系列文
用 LINE Bot 和 Agent Skill 自動化整理筆記與 IG 發文 共 17 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言