跳至主要內容

里程碑

我的 LINE 智慧時間助理「Sukima(すきま)」

Oooubliele @oooubliele發布於 已編輯

@…
先附上官方帳號連結
點這裡!(在新分頁開啟)

  • 1.簡介

明明手頭有一大堆待辦事項,卻總是拖延症發作,看著空白的行事曆發呆不知從何排起;或者因為缺乏事前規劃,白白浪費了課堂與零星活動之間的空檔,最後只能在死線前熬夜趕工。
為了消除「手動排程」的心理負擔與操作摩擦力,我利用 n8n 串接 LINE Messaging API、Google Gemini 與 n8n Data Tables,打造了一個以自然語言驅動的時間排程助理——「Sukima(すきま)」。

  • 2.動機跟為啥叫這個名字

一開始跟著課程就有完成一個很簡單的日文解析+拆解翻譯之類的
但想試著多做一點,所以想到開幕典禮設計網站的主題是安排代辦事項的東東
當初有這個想法是因為我真的太會拖了!(所以我現在才發里程碑)
知道有很多事情要做但就是懶得排進行事曆
一直在明知道「該做正事的時間點」,只是因為沒先安排好代辦事項,就拖延症爆發開始浪費時間🤞🏻
最後快到死線才開始拼命趕(same 我前天才開始看課程),所以就想說如果可以發訊息一樣,把待辦事項跟可以做事的時段發出去,就自動幫我安排好一週內的活動就太棒ㄌ!

然後Sukima這個名字也是gemini幫我想的!
「すきま」是縫隙的意思
象徵著日常生活中的「縫隙與零碎間隙」
「使用者完全不需要手動填寫複雜的日曆表格,只要像平常傳訊息聊天一樣,把空閒時段與待辦事項丟給系統,AI 就會自動幫你把事情妥善安嵌在最適合的時間縫隙」
這樣的說法我蠻喜歡的!

想解決的問題
多數人排程失敗的關鍵,往往不在於「缺乏時間」,而在於維護行事曆的成本過高:

  1. 輸入摩擦力過大:每次要安排事項,都要打開 App、手動選擇年月日、拉動起訖時間滑桿。
  2. 零碎時間無法利用:例如下午兩點到四點有空,但手頭有「跑步 45 分鐘」和「背日文單字」,一般工具很難自動把零碎時間切分、分段嵌入,並標記剩下的空檔。
  3. 取消排程時斷裂:當某項任務臨時取消,原本被切割開的時間往往就此閒置,缺乏智慧「時段縫合」的機制。

因此,我希望 Sukima 具備真正的動態時間運算邏輯:不僅能聽懂口語,更能動態維護使用者每一天的「可用時間池」。

  • 3.目前的功能

目前Sukima 的設計有三個互動模式:

  1. 空閒時間登記: 使用者只需輸入自然口語(如「我禮拜三下午 13:00 到 16:00 有空」),系統會自動解析基準時間與時區,轉換成標準的 YYYY-MM-DD 與 24 小時制時間區間,並透過日期防重機制精準寫入資料庫。
  2. 多待辦動態嵌入: 支援一句話排入多個任務(如「我要跑步半小時跟背日文單字」)。AI 能精準提煉動名詞作為乾淨的任務名稱,未指定時間的事項自動套用預設時長(60 分鐘),並依序在空閒區間中「切分時間」。排完任務後,若該時段仍有餘裕,系統會自動切出一筆新的 available 時段供未來使用。
  3. 取消與相鄰時段縫合: 當使用者取消某項排程(如「取消明天的重訓」),系統不只是將該任務還原為空閒,還會自動比對當天前後是否有相鄰的可用時段。若有相鄰空檔,會智慧執行「一伸長、一刪除」的演算法,將破碎的時間重新縫合為一段完整的自由大空檔。
  • 4.製作過程

前面先按照課程的東西建立好基本架構跟想要的功能switch分流之後就開始全力跟Gemini溝通了
Java什麼的我完全看不懂。

主要使用 n8n 建立全自動化工作流程,並使用 Data Tables 作為使用者的個人排程資料庫(包含 userid, date, starttime, endtime, stautus, task_name 等欄位)。

  1. 接收與意圖分流: 透過 Webhook 接收 LINE 訊息後,利用 Switch 節點判定使用者的意圖(登記時間、安排任務、取消任務、或查詢)。
  2. AI 時間運算與語意解析: 串接 Google Gemini Chat Model。在排程時,前端先從資料庫撈取當前用戶的所有可用時段,讓 AI 在記憶體中直接推導多任務的連續排程運算,輸出乾淨的資料庫操作指令陣列(包含 update 原時段、insert 新增任務或切分出的剩餘可用時段)。
  3. 並行資料庫處理與防斷流架構: 透過自訂的 JavaScript Code 節點(Prepare Update)整理 AI 輸出的操作指令,並採用平行分流架構: If (Success) 判定後,一側並行執行 Split Updates \rightarrow Update row(s) 與 Split Inserts \rightarrow Insert row(s),另一側直接觸發 HTTP Request 發送 LINE 成功訊息。這樣即使遇到不需要新增資料(純更新)的情境,工作流也不會因為空陣列而中斷。
  • 5.過程的挑戰

完全法科。
高中是三類組 大學算是社會科學方面的,對程式設計什麼的完全是一竅不通、、、
會接觸到的只有統計軟體,所以就算有ai幫忙在實際操作的時候頭還是超痛的。
但總歸來說最後還是生出一個成品,gemini有幫我整理一些做的過程出現的問題
有興趣的可以看看...

  1. 多任務的語意偏誤: 測試時發現,當輸入「我要跑步半小時跟背日文單字」時,AI 會將「半小時」同時綁定給前後兩件事。後來在 System Prompt 中加入了嚴格的「反繼承禁令(Anti-inheritance Rule)」,明定每一項待辦的時長必須單獨評估,未緊鄰時長詞的事項強制套用 60 分鐘預設值,才徹底解決了語意牽連問題。
  2. 切分時間後的狀態謬誤: 在任務排入後切出剩餘時間時,AI 或資料庫節點容易誤把沒有任務的剩餘時段也標記為 booked。為此,除了在 Prompt 中強化範例約束,我也在 Code 節點內加入了程式碼層級的防禦邏輯:凡是沒有 task_name 的時段,強制將 stautus 校正為 available,形成雙保險。
  3. 資料庫更新對象錯置(相鄰合併 Bug): 在開發取消待辦的「縫合機制」時,曾遇到合併後相鄰時段莫名消失的狀況。仔細比對 Data Tables 與節點輸入輸出才發現,系統把伸長後的新時間寫入了即將被刪除的節點 ID,接著後方的 Delete 節點又把該 ID 刪除,導致兩段時間一起被蒸發。排查出這個索引對應錯誤後,修正了 Filter Condition,讓演算法能精準保留正確的主時段。
  4. n8n 空陣列斷流機制: n8n 的預設機制是當 Code 節點輸出空陣列時,後續節點會直接停止執行。原本將 LINE 回覆接在資料庫寫入後方,導致只要當次排程不需要 Insert 新時段,用戶就永遠收不到 LINE 通知。改為平行分流拓撲後,徹底解耦了資料庫副作用與使用者訊息通知。
  • 6.目前的限制

只能說是理想很豐腴現實很骨感...
之前想內容的時候想了一堆想要的功能但我根本沒時間想也沒辦法做!
像是想要像多鄰國那樣在要做事的時候情勒你、紀錄連勝什麼的
但目前的形式還是需要用戶先傳訊息官方帳號才會給出反應
主動傳訊息需要花錢又沒研究怎麼操作,所以整個功能上就弱化很多ㄌ
還有一些自己測試的問題,像是ai想太久用戶(我本人)會等到不耐煩,還有雖然說他應該會「智能」安排進合適的時間,但測試下來他目前應該還是按照順序往下排
只能說真的非常兩光。
畢竟是只花了6個小時生出來的東西,沒辦法和板上的其他大神比...
但剛做完的時候還是很有成就感的!
一樣以下是gemini幫我整理的一些限制,有興趣的可以看看~

  1. 跨日與超長任務排程:目前邏輯專注於單日內可用空檔的切分與安排,對於跨午夜的時段或超過單次空檔上限的超長專案,尚未實作自動跨天拆解。
  2. 動態優先級權衡:目前由 AI 依照時段長度由前往後依序挑選最合適的空間塞入,未來若能引入待辦事項的緊急程度或使用者的個人習慣(如上午偏好深思、傍晚偏好運動),排程會更加人性化。
  • 7.心得

其實做完突然有一陣小空虛,不確定自己花了這些時間是否真的有獲得什麼,自己好像也不是真的那麼的有興趣,好像也沒辦法像交流版上的夥伴一樣這麼的有熱忱去改良、發想甚至不確定自己打下的這些文字是不是真的會被看見。
但現在決定先忘記這種情緒!
畢竟我還是真實的投入了時間,看了課程還實際操作了 這些都是我之前沒有接觸過的東西,那總會學到一些什麼吧
而且這幾天的充實還有最後完成的成就感不會騙人(雖然完全是死線戰士)
還是期待未來會有什麼任務~希望自己繼續加油喔!

附上加入代辦事項AI Agent 的 System Prompt
(其實不知道為什麼挑這個放但感覺放了比較強)

程式碼
你是一位精準的時間排程秘書。你的任務是:
1. 分析用戶輸入中包含的所有待辦事項(可能為一項或多項,例如「跑步半小時跟背日文單字」)。
2. 為「每項待辦」獨立確定所需時長。
3. 從【可用時段清單】中依序安排進入符合長度的時段。排入後若該時段有剩餘時間,後續的待辦事項可優先接續排入該剩餘時間區間。

【待辦時長獨立判定規則(極高優先級,嚴格執行)】:
- 每一項待辦事項的時長必須「單獨、分開計算」,嚴禁共享或繼承其他事項的時長!
- 只有直接緊鄰、明確修飾該事項的時長詞才算數。
- 若某個事項本身「沒有緊接著說明時長」,一律強制預設為 60 分鐘,絕對不准套用前面或後面事項出現過的時間!

【待辦名稱提煉規則】:
task_name 必須是乾淨的核心動名詞,嚴格剔除所有主詞、口語助詞與時長數字!
- 「我要跑步半小時」 ──> task_name: "跑步"
- 「背日文單字」 ──> task_name: "背日文單字"

【剩餘時間狀態嚴格規則】:
- 任何排完任務後「切分出來的剩餘時間」,其 stautus 必須強制為 "available",task_name 為空字串 ""!

【資料庫異動邏輯】:
對於被使用的第一個原空閒時段(具有原始 ID):
- 第 1 個排入的任務:將該原始時段做「update」,更新為 booked,時間縮小至該任務長度。
- 若有第 2 個、第 3 個任務接續排入同一個時段:產生「insert_task」,新增為 booked。
- 全部任務排完後,若該時段最後仍有剩餘時間:產生「insert_available」,新增為 available(名稱為空)。
若時段完全足夠或完全不夠,如實記錄在 reply_message。

請嚴格輸出純 JSON,嚴禁包含 Markdown 標記(不要輸出 ```json 或 ```):

標準輸出格式:
{
  "success": true,
  "reply_message": "已為您依序安排:\n1. 「跑步」:10月28日 14:00-14:30 (30分鐘)\n2. 「背日文單字」:10月28日 14:30-15:30 (預設60分鐘)\n該時段剩餘 15:30-18:00 仍可使用!",
  "operations": [
    {
      "action": "update",
      "id": 1,
      "date": "2026-10-28",
      "start_time": "14:00",
      "end_time": "14:30",
      "stautus": "booked",
      "task_name": "跑步"
    },
    {
      "action": "insert",
      "id": null,
      "date": "2026-10-28",
      "start_time": "14:30",
      "end_time": "15:30",
      "stautus": "booked",
      "task_name": "背日文單字"
    },
    {
      "action": "insert",
      "id": null,
      "date": "2026-10-28",
      "start_time": "15:30",
      "end_time": "18:00",
      "stautus": "available",
      "task_name": ""
    }
  ]
}

若時長完全不夠或無可用時段:
{
  "success": false,
  "reply_message": "目前可用空閒時間不足以安排您所列出的待辦事項,請先擴增可用時段!",
  "operations": []
}

0 個愛心0 則留言

登入並驗證手機後就能留言。登入