iT邦幫忙

2026 iThome 鐵人賽

DAY 6
0
ChatGPT & Codex

這隻 LINE Bot 不是我寫的:30 天讓 Codex 從零幫我做到上線系列 第 6

Day 6 - 我想替 LINE Bot 加「換一批」按鈕,結果先碰到一個問題:它怎麼記得上一輪?

  • 分享至 

  • xImage
  •  

上一個系列裡,我和 Codex 從零做出了一個會看地圖的 LINE Bot。使用者分享位置後,Bot 會透過 Vertex AI Google Maps Grounding 找附近咖啡廳,再送回繁中摘要與可以直接打開的 Maps 來源卡片。

做到這裡,Bot 已經會「找店」了,但互動還是一次性的。推薦看完之後,如果使用者不喜歡這一批,或想找更適合帶筆電工作的地方,只能重新傳位置、重新開始。

所以這次,我想讓 Bot 不只是回答一次就結束,而是能接著上一輪搜尋繼續互動。

最先想到的是兩個很直覺的功能:

  • 換一批咖啡廳
  • 找更適合工作的店

一開始我以為,這應該只是多放兩顆按鈕。真的和 Codex 討論後才發現,畫面上的按鈕反而是最簡單的部分。

比較麻煩的是:使用者按下「換一批」時,Bot 要怎麼知道上一次在哪裡搜尋,又推薦過哪些店?

這篇先從這個問題開始,聊聊為什麼我選了 LINE Postback,以及 Bot 怎麼替一次搜尋保留短暫的記憶。

https://ithelp.ithome.com.tw/upload/images/20260817/201835560XF4uG0QSN.png


不是每顆按鈕都適合用 Postback

Postback 可以把使用者的點擊送回後端,讓程式決定下一步。聽起來很方便,但不是所有按鈕都需要繞回伺服器。

我們最後把三種操作分開:

  • 打開 Google Maps:使用 URI action
  • 重新分享位置:使用 LINE 原生 location action
  • 沿用上一輪搜尋:使用 Postback action

所以只有「換一批」和「更適合工作」使用 Postback。它們都需要後端拿出上一輪資料,再做一次新的搜尋。

這個選擇看起來很小,卻讓我避開一個常見的陷阱:不是因為想用某個 API,就把所有按鈕都改成同一種 action。先看使用者想做什麼,再決定工具,通常簡單很多。


按鈕只說「想做什麼」,不要把所有資料都塞進去

使用者按下 Postback 後,LINE 會把一段 data 傳回來。

最直覺的做法,是把經緯度、搜尋偏好和上一批店名全部放進這段資料。但這樣不只很長,也會讓後端收到一包難以驗證的外部輸入。

最後我們只留下三件事:

v=1&a=reroll&s=abc123
  • v:資料格式版本
  • a:這次按了什麼,例如 reroll
  • s:搜尋 session ID

「更適合工作」也使用同一個格式,只把 action 改成 work_friendly

這樣按鈕只需要表達「我想做什麼」,真正的位置、偏好與店家名單則由後端保存。

我也很喜歡 displayTextdata 分開這個設計。使用者看到的可以是自然的「🔄 換一批咖啡廳」,程式收到的仍然是穩定、簡短的指令。以後就算改了按鈕文案,也不用跟著改後端流程。

至於 v=1,是為了處理聊天室裡的舊按鈕。LINE 訊息可能留很久,未來資料格式改版時,後端至少能知道這是哪一版,而不是猜一段舊字串代表什麼。


Postback 會通知後端,但不會幫 Bot 記住上一輪

Postback event 只會說「有人按了按鈕」,不會自動帶回上一輪搜尋的完整內容。

要讓「換一批」成立,Bot 至少要記得:

  • 上次搜尋的位置
  • 現在使用哪種偏好
  • 前一批推薦過哪些店

這些資料放在 Cloud Run 記憶體並不可靠,因為服務可能重啟,也可能同時有多個 instance。第一次搜尋和下一次點擊,不一定會落在同一台機器上。

另一個做法是每次都請使用者重新傳位置,但那樣「換一批」就失去意義了。

所以我們選擇 Firestore,替每次搜尋建立一份有效 30 分鐘的 session。它不是永久會員資料,只是讓 Bot 暫時記得這一輪對話。

Session 大致保存:

搜尋位置
搜尋偏好
上一批店名
建立者與所在對話
到期時間

完整的 Gemini 回答、整張 Flex Message 或所有 Maps metadata 都不需要存,因為下一輪搜尋用不到。

這裡的原則很簡單:不是記得越多越好,而是只記住下一步真的需要的東西。


一顆留在聊天室裡的舊按鈕,也要有使用期限

搜尋 session 會綁定原本的 LINE 使用者和對話。就算有人拿到 session ID,也不能在另一個群組或用另一個帳號操作它。

30 分鐘後再點,程式會請使用者重新分享位置。Firestore 的 TTL 之後再負責刪除過期資料。

這兩件事分工不太一樣:

  • 程式判斷現在還能不能用
  • TTL 負責稍後把舊資料清掉

Codex 當時用一句很好記的說法整理:程式負責守門,TTL 負責打掃。


實戰小結

我原本只想加兩顆按鈕,最後先做的卻是把按鈕與記憶分開:

  • Postback 只用在需要後端繼續處理的操作
  • 按鈕只帶 action 和短 session ID
  • 搜尋狀態另外放在 Firestore
  • Session 只保存必要資料,而且會過期
  • 使用者和對話都要對得上才能操作

這些東西不會直接出現在畫面上,卻決定「換一批」之後會不會變成難以維護的功能。

下一篇會接著把這份記憶用起來:怎麼真的避開上一批店家、保留工作偏好,以及使用者連點時,如何避免重複呼叫模型。


本篇完整程式碼

https://github.com/zonawang/codex-postback-action


上一篇
Day 5 - LINE Bot 查地圖要等 30 秒:Loading Animation 背後,還藏著 Webhook 200 的陷阱
下一篇
Day 7 - 「換一批」怎麼真的換?從搜尋 Session 到 LINE Postback Handler
系列文
這隻 LINE Bot 不是我寫的:30 天讓 Codex 從零幫我做到上線7
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言