部落格

不定期分享最新資訊文章

  • article-Instagram Graph API 打造 IG 自動發文系統 (結合 Cloudinary) | (EP11) n8n 自動化 API 串接教學

    2026/4/18

    AI自動化 n8n API串接 社群行銷
    Instagram Graph API 打造 IG 自動發文系統 (結合 Cloudinary) | (EP11) n8n 自動化 API 串接教學
    在上一篇教學中,我們介紹了 如何透過 Facebook Graph API 自動發布多圖貼文。今天,我們將進一步把自動化版圖擴展到 Instagram (IG)。 透過 n8n、Instagram Graph API,並結合 Cloudinary 作為圖片的公開圖床,我們可以打造一套「一鍵自動多平台發文」的系統。這篇文章將帶你拆解整個 n8n 工作流程,並一步步完成必要的 API 權限申請。 系統運作流程解析:IG 自動發文的底層邏輯在正式動手之前,我們先理解 n8n 節點的運作邏輯。要透過 API 發布 IG 貼文,流程如下: 表單提交 (Form Submission): 接收要發布的文字內容與圖片檔案。 圖片檢查與圖床轉換: IG API 嚴格規定,圖片必須是一個「公開可存取的網址 (Public URL)」。因此,我們必須先將圖片上傳至 Cloudinary 以取得公開網址。 建立 Instagram 容器 (Create Container): 根據 Meta 官方內容發佈文件,我們需要先用圖片網址與貼文內容建立一個 Media Container。 等待緩衝 (Wait): 設定約 30 秒的緩衝時間,避免 Meta 伺服器處理過慢導致後續請求失敗。 正式發佈 (Publish): 獲取 Container ID 後,執行最終的發佈動作。 延伸閱讀: 更詳細的 n8n IG API 串接原理,可參考 n8n Instagram API 實戰指南。 步驟一:如何設定 Meta 開發者應用程式與取得 IG 權杖?要讓系統代為發文,我們必須先在 Meta 開發者平台申請專屬的應用程式與存取權杖 (Access Token)。 1. 建立 Meta 應用程式前往 Meta 開發者應用程式介面 (Apps): 點擊「建立應用程式」,選擇「其他」>「企業商家」。 填寫應用程式名稱(例如:n8n-ig-auto-post)與聯絡信箱。 2. 設定隱私權政策網址為了讓應用程式能順利上線,Meta 要求提供隱私權政策網址: 可利用免費工具 PrivacyPolicies.com 快速生成一份基本的隱私權條款。 將生成的專屬網址複製,貼回到 Meta 應用程式的「基本資料 > 隱私權政策網址」中並儲存。 將應用程式狀態切換為 「上線 (Live)」。 3. 新增 Instagram 測試人員與轉換專業帳號由於應用程式尚未經過繁瑣的官方審查,我們需要將自己的 IG 帳號加入「測試人員」: 在 Meta 後台左側選單進入「應用程式角色 > 角色」。 新增「Instagram 測試人員」,輸入你的 IG 帳號。 重要提醒: 你的 IG 帳號必須切換為 「專業帳號 (商業或創作者)」,否則無法透過 API 發文! 打開手機 IG App,進入「設定 > 網站權限 > 應用程式和網站 > 測試人員邀請」,點擊「接受」。 4. 取得 Access Token 與 IG ID 回到 Meta 開發者後台,設定「Instagram 圖形 API」。 使用「圖形 API 測試工具 (Graph API Explorer)」。 勾選所有與 instagram_manage_* 及 instagram_content_publish 相關的權限。 點擊「Generate Access Token (產生存取權杖)」,並將這串落長的 Token 複製保存。 同時記下你的 Instagram ID,這兩個值將會填入 n8n 的設定中。(註:測試用的 Token 預設有效限期約為 2 個月,過期需重新產生。) 步驟二:為什麼需要 Cloudinary?如何設定免憑證上傳?如前所述,IG Graph API 不接受直接傳送本機圖片,只接受公開網址。我們使用 Cloudinary 來做自動化圖床。 1. 取得 Cloud Name登入 Cloudinary 控制台,在 Dashboard (儀表板) 找到你的 Cloud Name,這會是 n8n API 呼叫的基礎路徑。 2. 設定 Unsigned Upload Preset (無簽章上傳預設)在設定自動化時,為了安全性與便利性,我們 不使用 API Key 與 API Secret,而是改用 Upload Preset Name。 進入 Cloudinary 的「Settings > API Keys > Upload」。 點擊「Add Upload Preset」。 將 Signing mode 設定為 Unsigned。 設定一個你專屬的 Upload preset name (例如:n8n-try-2026),並設定要存放的資料夾名稱 (Folder)。 儲存後,將這個 Preset Name 複製下來。 為什麼不直接使用 API Key?將 API Secret 寫死在前端或簡單的工作流中存在資安風險。Unsigned Upload Preset 允許你在不暴露核心密鑰的情況下,讓系統把檔案上傳到指定資料夾,是自動化流程中最推薦的簡化做法。詳情可參考這篇探討:為何 n8n 教學愛用 Cloudinary Upload Preset?安全與便利的平衡。 步驟三:整合 n8n 節點並執行測試最後,我們回到 n8n 介面,將剛剛取得的參數填入對應的資料表或節點中: Cloudinary 節點設定: 將 Cloud Name 與 Upload Preset Name 填入。 Instagram 節點設定: 將 IG ID 與 Access Token 填入 Authorization 欄位。 觸發流程: 打開 n8n 的表單提交 (Form Trigger),上傳一張圖片並輸入測試文字。 驗證結果: 執行流程後,打開你的 Instagram 頁面,就可以看到圖片已經成功透過 n8n 自動發布了! 常見問答 (FAQ)Q:為什麼流程執行成功,但 IG 上卻沒有出現貼文,或出現權限錯誤?A:這通常是最常見的設定問題,建議依序檢查以下幾項: 你的 IG 帳號是否已切換為 專業帳號(創作者或商業)。 該 IG 帳號是否已正確加入 Meta App 的 Instagram 測試人員,並且已在手機上接受邀請。 產生 Access Token 時,是否有勾選 instagram_content_publish、instagram_basic 等必要權限。 你的 IG 是否有正確綁定對應的 Facebook Page。許多 Meta API 權限是透過粉專與商業資產關聯來驗證的。 如果以上都確認無誤,建議回頭檢查 n8n 的 HTTP Request 回傳內容,Meta 通常會在錯誤訊息中直接指出是權限不足、帳號資格不符,還是參數格式有問題。 Q:為什麼圖片已經上傳到 Cloudinary,但 Instagram API 還是說 image_url 無效?A:因為「有網址」不等於「符合 IG API 可讀取的公開網址」。你需要確認: 該圖片網址可以在 無痕模式 直接開啟,不需要登入、不會跳轉、也不會出現權限限制。 網址指向的是 實際圖片檔,而不是預覽頁、下載頁或帶驗證機制的暫時連結。 圖片格式為常見可支援格式,例如 jpg 或 png。 圖片尺寸與比例不要過於極端,避免 Meta 在建立容器時失敗。 最穩定的做法,就是使用 Cloudinary 上傳後取得的 secure_url 當作 image_url,不要自行拼接其他可能會失效的連結。 Q:為什麼流程中要加 Wait 節點?可以直接建立容器後馬上 Publish 嗎?A:理論上可以連續呼叫,但實務上不建議。因為 Meta 在建立 Media Container 後,還需要一點時間處理圖片內容;若你太快發送 Publish 請求,就可能出現容器尚未就緒、發文失敗,或偶發性的 API 錯誤。 因此在 n8n 中加入約 20 到 30 秒的 Wait,是一種很常見也很實用的穩定化做法。如果你想再更精準一些,也可以改成輪詢 Container 狀態,確認處理完成後再執行 Publish。 Q:這套流程可以直接發 Reels、限時動態或多張輪播貼文嗎?A:這篇教學的流程主要針對 單張圖片貼文。若你要發: 輪播貼文:通常需要建立多個媒體項目,再組成 Carousel Container,流程會比單張圖複雜。 Reels:需要改用影片上傳與對應的發佈流程,參數與等待時間也不同。 限時動態:支援情況與發佈方式需依 Meta API 當前規範確認,不能直接套用一般貼文邏輯。 也就是說,這篇文章適合作為「IG 自動發文入門版」,如果你後續要延伸到更多貼文型態,建議再額外拆成不同 workflow 來做。 Q:Cloudinary 的 Unsigned Upload 安全嗎?會不會被別人亂傳圖片?A:Unsigned Upload 本質上是只要知道 Preset Name 就能上傳,因此有一定風險。但你可以透過 Cloudinary 後台針對該 Preset 設定「檔案格式限制」、「檔案大小限制」甚至是「上傳後轉檔規則」,來避免遭惡意濫用。對於個人自動化用途而言,比起洩漏 API Secret,這是相對安全且輕量的做法。 如果你是要提供給團隊或正式商業場景使用,建議再往前一步: 將上傳來源限制在特定流程或後端。 規劃專用資料夾,方便管理與清理。 定期輪替 Upload Preset,避免長期暴露固定入口。 監控 Cloudinary 使用量,避免異常流量造成額外成本。 Q:我的自動發文系統突然失效了,發生了什麼事?A:最可能的原因是 Meta Access Token 過期。透過 Graph API 測試工具生成的 Token 通常只有 60 天左右的效期。若要長期自動化,建議在到期前透過 API 延長權杖效期,或是定期手動重新生成一次並更新至 n8n 中。 除了 Token 之外,也建議同步檢查: Meta App 是否仍維持上線狀態。 測試帳號是否仍保有測試人員身分。 Cloudinary Preset 是否被修改、停用或刪除。 n8n 中的節點參數是否被其他人誤改。 Q:這套流程適合正式營運使用嗎?還是只適合測試?A:可以用於正式營運,但前提是你要把它從「可跑」升級成「可維護」: 權杖更新機制要制度化,不能等過期才手動補救。 n8n 流程要加上錯誤通知,例如失敗時寄 Email、發 Slack 或 LINE Notify。 圖片、文案、發文時間最好有資料表或資料庫可追蹤。 若有多人使用,建議加入審核機制,避免錯發或重複發文。 如果你只是個人品牌、小型工作室,這篇教學已足夠作為第一版;但若你是企業團隊,後續應把監控、權限管理與例外處理一併補上。 Q:如果我想把這個流程擴充成「一鍵同步發 Facebook + Instagram」,要怎麼做?A:這正是 n8n 很適合發揮的地方。你可以把「表單輸入」或「內容資料表」當成單一來源,接著分流到不同平台節點: 一條流程處理 Cloudinary 圖片上傳。 一條分支送往 Facebook Graph API。 另一條分支送往 Instagram Graph API。 最後把各平台回傳結果寫回 Google Sheets、Airtable 或 Notion。 這樣你就能把原本重複操作的社群發文,整理成一套真正可複用的多平台內容發布系統。

  • article-AI 工具名詞全解析:一次搞懂 MCP、Skill 與 CLI 的差異與應用場景

    2026/4/13

    AI工具 AI自動化 AI Agent
    AI 工具名詞全解析:一次搞懂 MCP、Skill 與 CLI 的差異與應用場景
    最近如果你常接觸 AI 開發、AI Agent 或開發者工具,應該很容易出現一種感覺:「怎麼每個東西一下叫 MCP,一下叫 Skill,一下又冒出 CLI?」明明都像是在「讓 AI 幫我做事」,為什麼名詞越來越多? 很多開發者一開始也常看得霧煞煞。例如明明已經知道某個工具有 Skill,結果又看到它推出 CLI,心裡就會冒出一個問號:所以我到底是要用哪一個?還是兩個都要用? 這不是大家故意把事情搞複雜,反而是因為 AI 協作時代真的來了,工具開始分層,於是名詞也跟著變多了。本篇文章將帶你深度解析這三者的定位,幫你建立清晰的 AI 工具觀念地圖。 核心觀念:釐清 CLI、Skill 與 MCP 的階層關係最簡單的理解方式是:這三個名詞不是互斥的競品,而是不同層級的入口。 CLI:給人類或 AI 直接操作的命令列入口。 Skill:給 AI 使用的能力封裝。 MCP:讓 AI 可以用標準方式接上外部工具和資源的協定。 如果要更白話一點: CLI 像是「工具的操作面板」 Skill 像是「AI 已經學會怎麼用的一招」 MCP 像是「AI 與工具之間的通用插座」 它們常常是在同一個生態系裡扮演不同角色,讓同一個能力能夠被不同使用者(人類或 AI)順利呼叫。 為什麼開發工具越來越重視 CLI 介面?因為 AI 很會處理文字,而 CLI 剛好就是純文字介面。 過去我們覺得 GUI(圖形化介面)很直覺,按鈕、選單對人類最友善。但對 AI 來說,GUI 的操作成本極高,它需要理解畫面、找按鈕、判斷狀態。相反地,CLI 非常單純:輸入是文字、輸出是文字、參數明確且結果結構化。 例如當你叫 AI 幫你部署專案、初始化設定或跑測試,如果背後有 CLI,AI 幾乎就能很自然地組出命令來執行。AI 操作 CLI 的成本極低、成功率高,且極易整合,這也是為什麼越來越多工具開始強化 CLI 支援。 時代演進:從「人機協作」到「AI Agent 獨立操作」以前的工具通常只有網站、後台與按鈕,由「人」手動操作。現在的工具則必須兼顧多重入口,包含 API、SDK、CLI、Skill 甚至 MCP Server。 這是因為現在的操作者不再只有人類,AI Agent 也要能操作工具。當一個工具想要同時服務一般使用者、開發者、自動化流程與 AI Agent 時,它自然就會長出不同層級的入口。 生活化比喻:用「餐廳點餐」秒懂工具分工假設你開了一家餐廳,同樣都是「點餐」,可以有很多入口: 客人現場看菜單點餐 打電話訂餐 外送平台下單 自動接單系統接 API 這些管道互不衝突,本質上都是同一個餐廳的能力。放到 AI 工具也是一樣: CLI:像打電話直接下明確的指令。 Skill:像店員已經會某套流程,知道怎麼幫你把事情處理好。 MCP:像統一的接單規格,外部平台都可以照這個標準格式接進來。 CLI 是什麼?為何它是 AI 最愛的溝通介面?CLI (Command Line Interface) 即命令列介面,讓你用文字指令直接操作工具。例如: 1234npm installgit commit -m "update"playwright testvercel deploy CLI 的核心優勢: 指令明確:一條指令做一件事,輸入輸出極度清晰。 容易自動化:非常適合 Shell Script、CI/CD 與批次流程。 易於被 AI 生成:AI 極度擅長根據需求組出合理的命令。 無須 GUI 依賴:對一次性任務與開發流程特別方便。 Skill 是什麼?如何讓 AI 具備專業技能?Skill 可以想像成「AI 已經包裝好的能力單元」。 它通常不只是某個工具本身,而是「AI 如何使用這個工具」的抽象化過程。當你請 AI「幫我用瀏覽器點開登入頁並檢查流程」時,如果 AI 具備對應的 Skill,它就會知道:該用哪個工具、先做什麼、後做什麼、以及如何處理回傳結果。 Skill 的重點在於:AI 是否已經具備這項能力,並知道怎麼把它用起來。 MCP 是什麼?解密 AI 串接外部資源的通用協定MCP (Model Context Protocol) 是一個讓 AI 能用標準方式接上外部工具的協定。 過去每個工具都要各自開發整合方法,對 AI 系統來說維護成本極高。有了 MCP 之後,工具只要照著標準規格暴露能力,AI 就能輕鬆理解這個工具提供哪些功能、參數該怎麼傳遞、結果如何取得。MCP 更像是「規格」或「接口標準」,而不是某個單一的執行功能。 觀念統整:建立你的 AI 工具腦中地圖怕混淆的話,請記住這個最簡單的框架: CLI 解決:「怎麼操作工具?」 Skill 解決:「AI 會不會用這個工具?」 MCP 解決:「外部能力怎麼標準化接進來?」 業界案例分享:Playwright、GitHub 與 Vercel 的應用案例一:Playwright 自動化測試 CLI:你自己下達 npx playwright test 指令跑測試或錄製腳本。 Skill:你對 AI 說「幫我測試登入流程」,AI 透過內建的 Skill 幫你操作 Playwright。 MCP:AI 系統需要用標準方式接入瀏覽器自動化能力時,將 Playwright 暴露成可呼叫工具。 案例二:GitHub 專案管理 CLI:你使用 gh pr create 來建立 Pull Request。 Skill:AI 自動幫你看 PR 差異、整理 Issue 並產生 Commit 訊息。 MCP:讓 AI Agent 可以標準化地接進 GitHub API,執行完整的 Repo 管理。 案例三:Vercel 雲端部署 CLI:手動輸入 vercel deploy 發布專案。 Skill:AI 幫你檢查部署設定、排查 Build Error 或修正環境變數。 MCP:把專案狀態查詢與部署能力標準化,提供給 AI Agent 隨時呼叫。 實用評估指南:如何判斷當下該使用哪一層級?當你看到一個新工具時,可以問自己三個問題: 操作對象是誰?自己操作先看 CLI;讓 AI 幫你操作先看 Skill。 任務性質為何?一次性任務用 CLI 通常最快;長期且複雜的系統整合則需要 API 或 MCP。 你的角色是什麼?如果你只是「使用者」,Skill + CLI 就足夠;如果你在「建立 AI 工具鏈」,就必須深入理解 MCP。 總結:打破競品迷思,擁抱 AI 工具新生態很多開發者一看到新名詞,就會擔憂「是不是舊工具要被取代了?」。但實際上,CLI、Skill 與 MCP 常常是分工關係,而非競爭關係。 同一個能力同時存在這三種入口,反而代表這個工具正在邁向成熟,能同時滿足人類開發者、AI 輔助與系統整合的需求。記住一句話:CLI 是操作入口,Skill 是 AI 能力,MCP 是整合標準。看懂了這個生態拼圖,你就能在 AI 時代輕鬆駕馭各種新興工具! 常見問答 (FAQ)Q:我只是個普通的終端開發者,沒有在開發 AI Agent,還需要了解 MCP 嗎?A:現階段你不一定要「開發」MCP,但了解 MCP 的概念非常有幫助。因為未來會有越來越多好用的開發工具採用 MCP 協定,當你懂 MCP,你就能輕易將各種外部資料庫或工具無縫接入你日常使用的 AI 編輯器(如 Cursor)中,大幅提升開發效率。 Q:既然 AI 已經可以透過 Skill 幫我做事,我是不是不用再學 CLI 語法了?A:兩者並不衝突,甚至相輔相成。雖然 AI 可以代勞,但當你需要進行本機精細除錯、手動重現問題、或者將腳本整合進無 AI 環境的 CI/CD 流程時,CLI 仍然是不可或缺的基石。Skill 幫你省去學習複雜語法的認知負擔,但 CLI 確保了你對系統的絕對掌控權。 Q:為什麼同一個工具會有 CLI 也有 Skill?這樣不會多此一舉嗎?A:不會。CLI 解決的是「可操作性」(讓機器或人可以透過文字執行),而 Skill 解決的是「好協作性」(讓 AI 知道流程與邏輯)。就算 AI 有了 Skill 去幫你執行任務,底層往往還是透過呼叫 CLI 或 API 來完成。提供多重入口是為了服務不同情境與不同角色。 Q:MCP 跟一般 API 有什麼差別?A:API 是開發者直接呼叫的介面,通常需要知道參數與程式流程;MCP 則是為 AI 設計的「通用語境協定」,它不只暴露能力,還描述用途、參數、回傳格式和行為限制,讓 AI 平台可以用一致方式理解、選擇與串接工具。簡單來說,MCP 是 API 的「AI 標準化版本」。 Q:我有一個任務,該先用 CLI、Skill,還是直接找 MCP?A:先看任務性質。 想要自己操作、確認每一步,或寫成 shell script:選 CLI。 想要讓 AI 直接用自然語言完成複雜流程:選 Skill。 想要把能力標準化、跨工具串接、讓多種 AI 都能呼叫:選 MCP。實際上,最常見的路徑是「先有 CLI,再包成 Skill,最後用 MCP 做標準化整合」。 Q:如果我現在只會用 CLI,未來是否還需要補上 Skill/MCP 的知識?A:是的。CLI 是基礎,但當你想讓 AI 幫你自動執行日常工作、把工具能力交給 AI 使用,Skill 能讓你更快實現;如果你要在企業內部整合多個系統,MCP 就能幫你避免「每個工具都要重新整合一次」的問題。這三者累積起來,才是真正的 AI 工具鏈能力。 Q:Skill 和 MCP 哪個更適合企業導入?A:兩者各有定位。 Skill 適合讓 AI 用自然語言執行特定任務,例如客服流程、內容生成、測試引導。 MCP 適合企業級資源整合,例如跨系統資料查詢、內部資源呼叫、AI Agent 需要訪問特定資料源。最理想的情況是:把穩定核心能力做成 MCP 工具,再在此基礎上為 AI 提供 Skill 層,實現既穩定又易用的自動化體驗。

  • article-如何使用 Spokenly 提升 4 倍寫作速度?Mac 必備 AI 語音轉文字工具教學

    2026/4/12

    AI工具 AI自動化
    如何使用 Spokenly 提升 4 倍寫作速度?Mac 必備 AI 語音轉文字工具教學
    為什麼你需要 Spokenly?開口就能寫的 4 倍速體驗在快節奏的工作環境中,打字速度往往跟不上大腦思考的速度。今天要為大家介紹一款極具潛力的 Mac 平台小工具——Spokenly。它的核心理念非常直觀:「開口說,就能寫」,透過強大的 AI 語音辨識技術,官方宣稱能幫助使用者將寫作速度大幅提升 4 倍。 Spokenly 能夠在背景隨時待命,只要按下快捷鍵,就能即時將你的語音轉化為精準的文字,不僅支援多種語言,還能完美整合到你日常使用的各種應用程式中。 Spokenly 方案解析:免費本地模型與付費進階功能目前 Spokenly 提供了 macOS 版本,並在網路上獲得了包括知名開發者保哥(Will 保哥)在內的多位專家好評。在費用與方案上,主要分為以下幾種模式: 完全免費(本地模型): 只要你的 Mac 效能許可,下載並使用本地端的語音辨識模型(如 Apple 內建語音分析器)是完全免費的,這也是多數使用者的首選。 自備 API 金鑰 (BYOK): 允許進階使用者串接自己的 API(如 OpenAI、Google Gemini 等),依使用量自行計費。 Spokenly Pro 訂閱制: 若不想自己處理複雜的 API 設定,也可以直接付費升級 Pro 版本,享受更進階的雲端辨識服務。 如何挑選並測試語音辨識模型?安裝完 Spokenly 後,你會發現系統內建了多種模型供你選擇,例如 Apple 自家的語音分析器、NVIDIA 的模型,以及開源的 Qwen(千問)模型。 實測 Apple 內建語音分析器經過實際測試,在一般環境下,Apple 的模型已經具備極高的準確度。然而,在背景噪音較大或是中英夾雜的情況下,仍可能出現以下小瑕疵: 同音字誤判: 例如將人工智慧的「AI」聽成中文的「哀」。 特殊符號與格式遺失: 像是唸出電子郵件地址「test123@example.com」時,可能會被辨識成零碎的英文字母與單字拼湊(如 test123 小老鼠 example dot com)。 若遇到純英文的模型(如部分 NVIDIA 模型),則無法處理中文語音。綜合評估下來,對於 Mac 使用者,Apple 內建的語音分析器是目前兼顧速度與準確度的最佳本地選擇。 1今天下午三點半,我在台北 101 附近開會,順便測試一個新的語音辨識模型。這個 model 的準確率大概是 92.5%,但在背景有點吵的情況下,還是會把「AI」聽成「哀」。另外,我剛剛說的 email 是 [email protected],記得幫我記下來。最後一件事,下週一(4 月 15 號)上午 10 點,再提醒我確認專案進度,OK 嗎? 突破辨識極限!如何串接 Gemini API 進行 AI 自動校正?Spokenly 最強大的「殺手級功能」,在於它允許你搭配 AI 提示詞(Prompt)進行文字後處理。這意味著,你可以先用本地模型快速將語音轉成逐字稿,再交由強大的 LLM(大型語言模型)自動幫你抓錯字、排版並加上標點符號。 步驟一:取得 Google Gemini API Key以網路上公認 CP 值極高的 Gemini 3.1 Flash Lite Preview 為例,非常適合用來做快速的文字修正: 前往 Google AI Studio。 點擊左側選單的 Get API key 並建立一把新的金鑰。 複製該金鑰。 步驟二:在 Spokenly 中設定 AI 後處理 打開 Spokenly 的「AI 提示」設定。 在「進階設定」的 AI 提供商中,選擇新增並填寫名稱、貼上剛剛複製的 API Key。 指定模型名稱為 gemini-3.1-flash-lite-preview。 步驟三:設定超強 AI 提示詞 (Prompt)設定完成後,請在 Spokenly 的「提示詞」區塊輸入以下設定。當你錄音結束後,Spokenly 就會自動套用這個 Prompt,將凌亂的逐字稿瞬間變成可直接發送的專業文本! 123456修正為自然繁體中文,保留原意與口語感。修正錯字、標點、分段。英文與技術名詞保留原樣(如 API、React、Node.js)。只輸出結果。{{text}} 總結:用語音解放雙手,迎接 AI 高效時代在 AI 時代,學會利用工具來加速資訊輸出是提升競爭力的關鍵。Spokenly 不僅僅是一個簡單的錄音軟體,它結合了「本地免費辨識」與「雲端 AI 智慧校正」的雙重優勢。無論你是要回覆 Email、撰寫企劃案,還是與 AI 助理(如 ChatGPT)進行深度對話,Spokenly 都能為你省下大量的打字時間。 🔗 相關資源連結 Spokenly 官方網站 (繁體中文) Google AI Studio (取得 Gemini API 金鑰) 常見問答 (FAQ)Q:Spokenly 是完全免費的嗎?需要連網才能使用嗎?A:Spokenly 支援「本地模型」模式(如 Mac 內建的 Apple 語音分析器),這種模式是完全免費且不需要連上網路即可使用的,非常適合重視隱私與離線工作環境的使用者。 Q:如果語音辨識出現同音錯字或中英夾雜辨識不良怎麼辦?A:這正是 Spokenly 的強項。你可以透過內建的「AI 提示」功能,串接 Google Gemini 或 OpenAI 的 API,並設定專屬的提示詞(Prompt),讓 AI 在語音轉化為文字後,自動幫你修正錯字、還原英文專有名詞並進行排版。 Q:Spokenly 可以在 Windows 電腦上使用嗎?A:目前 Spokenly 主要提供針對 Apple 生態系優化的 macOS 版本(以及支援 iPhone)。若你是 Windows 使用者,可能需要尋找其他支援跨平台的語音辨識替代方案。

  • article-使用 Facebook Graph API 自動發布多圖貼文 | (EP10) n8n 自動化 API 串接教學

    2026/4/4

    AI自動化 n8n API串接 社群行銷
    使用 Facebook Graph API 自動發布多圖貼文 | (EP10) n8n 自動化 API 串接教學
    如果你正在找「n8n Facebook 多圖貼文教學」、「Facebook attached_media 怎麼設定」或「n8n 如何一次發布多張圖片到 Facebook」,這篇就是針對這些問題整理的實戰版本。 先前我們分享過如何透過 n8n 模板自動發布「單圖加單文」到 Facebook。今天這篇文章,我們將進一步把流程升級成一次發布多張圖片的 Facebook 貼文,並直接拆解多數人最常卡住的 attached_media、/photos 與 binary 判斷問題。 如果你還沒完成 Page ID、長期 Page Access Token 或單圖發文設定,建議先閱讀上一篇:n8n 串接 Facebook 自動發文教學:Meta API、Page ID、長期 Token 完整指南。 這篇文章可以把它理解成上一篇的進階版:前一篇解決「先發得出去」,這一篇解決「如何穩定改成多圖發文」。 如何在 n8n 表單中開啟多檔案上傳功能?在原本的預設模板中,表單 (Form) 節點僅支援單張圖片與一篇文章。若要實現多圖上傳,我們必須先從觸發器 (Trigger) 著手修改。 請進入 n8n 的 Form Trigger 節點,找到設定並勾選 Multiple Files 功能。開啟此選項後,表單就能一次接收多張圖片的輸入。為了確認功能正常運作,建議先進行測試,例如輸入標題「test 0403 多圖」並同時上傳三張圖片,藉此確認資料是否成功進入後續的工作流中。 破解 API 迷思:為什麼 Facebook Graph API 其實不吃 JSON?這是在串接 Facebook Graph API 時最容易踩到的坑!許多人在查閱 Meta 官方文件時,會看到官方範例給的都是 JSON 格式。然而,當你實際在 n8n 中將 Content-Type 設為 JSON 時,常常會遇到發文失敗或行為異常的狀況。 經過測試與 AI 的輔助分析,我們得出了一個重要結論:Facebook Graph API 預設其實是接收 url-encoded 與 form-data 格式,而非 JSON。 在 n8n 的 HTTP Request 節點中,最佳的實踐方式是: 主體內容 (Body): 使用 form-urlencoded 模式,將 Token、Message 與整理好的 attached_media 傳送出去,這樣不僅容易發送,穩定度也最高。 圖片上傳 (Photo Upload): 使用 form-data 的方式來傳送二進位 (Binary) 的圖片檔案。 請果斷放棄使用 JSON 格式來修改多圖貼文,直接採用 form-urlencoded 與 form-data,能幫你省下大量的除錯時間。 實戰解析:多圖貼文真正要改的是什麼?很多人第一次改 Facebook 多圖貼文時,會以為只要把 attached_media[0] 改成 attached_media[1]、attached_media[2] 就好。實際上不是這樣。 多圖貼文的核心不是「多加幾個欄位」,而是整個流程要改成先上傳圖片、再集中發文。 正確流程如下: 表單允許一次上傳多個檔案 把每張圖拆成獨立 item 每張圖各自呼叫 POST /photos,並設定為未發佈 收集每張圖回傳的 photo id 最後只呼叫一次 POST /feed,把所有 media_fbid 一起送進 attached_media 換句話說,你不是直接把多張圖片塞進同一次照片上傳請求,而是先把每張圖變成 temporary photo,最後再用一篇貼文把它們組起來。 最短版修改清單如果你手上已經有上一篇的單圖工作流,要改成多圖版,實務上先完成這 5 件事就夠了: Form Trigger 把 Multiple Files 改成 true 原本的「如果圖片不存在」條件,改成檢查 Object.keys($binary ?? {}).length === 0 新增一個 Code 節點,把多張圖片展開成多個 item 新增一個 Code 節點,把所有 photo id 整理成 attached_media 最後發文的節點,把 attached_media[0] 改成整個 attached_media 陣列 如果你是用既有模板直接改,這 5 項通常就是變更範圍的 80%。剩下的問題,多半都是權限、Graph API 版本,或請求格式設定錯誤。 多圖上傳的資料處理與判斷邏輯1. 先展開圖片,再逐張上傳表單收到多張圖片後,n8n 內部通常不會直接變成多筆獨立資料,而是先包在同一個輸入裡。這時要先新增一個節點,把圖片展開成一張圖一個 item,後面的 Facebook 上傳節點才能逐張處理。 這一步的重點不是「看起來有三張圖」,而是流程裡真的要變成三個可迭代的 item。只有這樣,後面的 POST /photos 才能對每張圖各自拿到一個 photo id。 2. 每張圖都先走 POST /photosFacebook 多圖貼文不是直接把多張 binary 一次送到 /feed。正確做法是每張圖先打一次 /{page_id}/photos,並設定為不立即發佈,讓 Facebook 先建立暫存照片。 等每張圖都成功回傳 ID 之後,才進到最後一個發文節點。這也是很多人一直測不通的原因,因為他們跳過了「先建立 temporary photo」這一步。 3. 最後一次把所有 media_fbid 組回 attached_media當你拿到多張圖的 photo id 後,接下來不是再一張一張發貼文,而是把所有 ID 整理成 Facebook 要的格式,例如: 12345[ { "media_fbid": "photo_id_1" }, { "media_fbid": "photo_id_2" }, { "media_fbid": "photo_id_3" }] 最後只呼叫一次 POST /feed,並把整包 attached_media 傳出去,這樣 Facebook 才會把它視為同一篇多圖貼文。 4. 「是否有圖片」的判斷邏輯也要一起改單圖流程常見的寫法,通常是假設只有一個固定欄位,例如 binary.data 或某個指定圖片名稱。但多圖流程下,這種判斷很容易失準,因為二進位檔案不再只有單一鍵值。 比較穩的做法,是直接檢查目前是否真的存在任何 binary 檔案: 12345if (Object.keys($binary ?? {}).length === 0) { // 沒有圖片,走純文字貼文流程} else { // 有圖片,走圖片上傳與多圖發文流程} 這段寫法的好處是,不需要綁死某個圖片欄位名稱,對單張圖、多張圖、甚至沒有圖片的情境都比較穩。 可直接參考的 Code Node 範例如果你想更快落地,下面這兩段可以作為 Code 節點的參考起點。實際欄位名稱還是要依你的工作流資料結構微調,但核心思路就是這樣。 範例 1:展開多張圖片這個節點的目的是把同一筆輸入裡的多張 binary 圖片,拆成多個 item,讓後面的 POST /photos 可以逐張執行。 1234567891011121314const binaryEntries = Object.entries($binary ?? {});return binaryEntries.map(([key, file]) => { return { json: { ...$json, binaryKey: key, fileName: file.fileName ?? key, }, binary: { [key]: file, }, };}); 這段的重點是: 先用 Object.entries($binary ?? {}) 取出所有圖片 每張圖各自回傳成一個 item 保留原本的 $json,避免後面發文文案或其他欄位不見 範例 2:整理成 attached_media當每張圖片都上傳到 POST /photos 後,Facebook 會回傳各自的 id。接下來就要把這些 id 整理成最後發文節點要吃的格式。 12345678910111213const attached_media = $input.all().map((item) => { return { media_fbid: item.json.id, };});return [ { json: { attached_media, }, },]; 如果你的最後一個發文節點還需要貼文文字、Page ID 或其他欄位,就記得在這裡一起帶回去,不要只剩 attached_media。 最後發文節點要注意什麼?整理完之後,最後一個 POST /feed 節點要送的,不再是單一的 attached_media[0],而是整包 attached_media。也就是說,這一步的重點不只是欄位名稱改掉,而是前面的資料形狀已經從單張圖邏輯,變成多張圖陣列邏輯。 跨平台自動發文的策略與考量在學會了 Facebook 多圖發文後,你可能會想:「我能不能把這個多圖工作流直接套用到 Instagram、Threads、X (Twitter) 或 LinkedIn 上?」 這裡要特別提醒,每個社群平台的 API 設計與支援度皆不相同。Facebook 接受的 attached_media 多圖陣列格式,放到其他平台可能會導致報錯。如果你追求的是「一鍵同時發布到所有平台」,那麼維持「一圖一文」會是最安全、兼容性最高的方式。 然而,如果你是為了深入學習 API 串接與自動化邏輯,強烈建議你親手實作一次專屬於 Facebook 的多圖發文流程。這能幫助你透徹理解 API 格式的差異、陣列資料的轉換,大幅提升你的 n8n 實戰能力! 常見問答 (FAQ)Q:多圖貼文是不是只要多加幾個 attached_media[1]、attached_media[2] 就可以?A:不行。這是最常見的誤解。Facebook 多圖貼文的重點不是多塞幾個欄位,而是要先讓每張圖各自上傳成未發佈照片,再把所有 photo id 組成 attached_media 後一次送進 POST /feed。如果你只是在原本單圖節點上多加幾個欄位,通常流程會不穩,或根本不會被 Facebook 正確識別成同一篇多圖貼文。 Q:在 n8n 裡,正確的多圖發文順序是什麼?A:最穩的順序是這樣: 表單開啟多檔上傳 將多張圖展開成多個 item 每張圖各自呼叫 POST /photos 收集所有回傳的 photo id 最後呼叫一次 POST /feed,把所有 media_fbid 傳進 attached_media 如果你的流程不是這個順序,通常就是之後會卡住的地方。 Q:為什麼我照著官方文件用 JSON 傳多圖,還是一直失敗?A:因為官方文件的範例格式,不代表在 n8n 裡就是最穩的做法。實務上,Facebook Graph API 在這類發文情境下,通常用 application/x-www-form-urlencoded 與 multipart/form-data 會更穩。簡單說: 圖片上傳用 form-data 最後發文用 form-urlencoded 如果你整段流程都硬用 JSON,常見結果就是欄位格式對了,但請求仍然失敗,或 Facebook 不照你預期解析。 Q:為什麼「是否有圖片」這個判斷在多圖版容易壞掉?A:因為單圖流程通常只檢查某一個固定欄位,例如 binary.data。但多圖上傳時,binary 的結構不一定只會有單一鍵值,所以原本那種寫死欄位名稱的判斷方式常常會失準。比較穩的寫法是: 1Object.keys($binary ?? {}).length === 0 這樣你判斷的是「現在到底有沒有任何圖片檔」,而不是賭某個欄位名稱剛好存在。 Q:表單已經開了 Multiple Files,為什麼還是不能直接發多圖?A:因為 Multiple Files 只解決「前端可以一次上傳多張圖」,沒有幫你完成後面的資料整理。你還是得自己把圖片展開、逐張上傳、收集 ID、再整理成 attached_media。也就是說,表單只是入口,多圖貼文能不能成功,關鍵仍然在後面的工作流設計。 Q:多圖流程測試時,最少要驗證哪些情境?A:至少要測這 3 種: 沒有圖片,只發純文字 只有 1 張圖片 一次上傳多張圖片 如果這三種都能正常執行,代表你的條件分流、binary 判斷、圖片上傳與最後發文邏輯大致是穩的。只測「三張圖剛好成功一次」其實不夠,因為很多錯誤都發生在無圖或單圖情境切換時。 Q:如果我要沿用上一篇單圖模板,最少要改哪些地方?A:最小修改範圍就是本文前面那 5 項: Form Trigger 開啟 Multiple Files 調整「是否有圖片」判斷 新增圖片展開節點 新增 attached_media 整理節點 把最後發文欄位從單一 attached_media[0] 改成整個 attached_media 你可以把它理解成:前面多了一段「圖片預處理」,最後一段則從「單圖發文」改成「多圖組裝後發文」。 Q:如果發文節點一直報權限錯誤,是多圖流程寫錯了嗎?A:不一定。多圖流程錯誤與權限錯誤是兩件事。如果你看到的是 OAuth、permission、scope 相關訊息,通常先檢查的不是 attached_media,而是: 你現在用的是不是正確的 Page Token 權限是否包含 pages_manage_posts Page ID 是否對應到同一個粉專 這類問題比較接近授權設定,而不是多圖組裝本身。需要的話可以回頭對照上一篇的 Token 教學一起排查。 Q:這篇流程可以直接套到 Instagram 或其他平台嗎?A:不建議直接照搬。這篇的重點是 Facebook Page 的多圖貼文流程,而 attached_media 這種組法本身就帶有平台特性。若你是做跨平台自動發文,最穩的策略通常還是先維持「一圖一文」,再依各平台 API 能力逐一擴充,而不是假設 Facebook 的多圖格式能通用。 參考資料 Meta Developers:Page Posts 上一篇:n8n 串接 Facebook 自動發文教學

  • article-n8n 串接 Facebook 自動發文:從 Meta API 到取得長期 Token 完全指南 | (EP.9) n8n 自動化 API 串接教學

    2026/4/3

    AI自動化 n8n API串接 社群行銷
    n8n 串接 Facebook 自動發文:從 Meta API 到取得長期 Token 完全指南 | (EP.9) n8n 自動化 API 串接教學
    如果你正在找「n8n 串接 Facebook 自動發文教學」、「Facebook Page ID 怎麼找」或「Meta 長期 Token 怎麼拿」,這篇就是針對這些問題整理的實戰指南。 在這篇教學中,我們將探討如何利用 n8n 工作流自動化工具,串接 Facebook Graph API,實現粉絲專頁的一鍵自動發文功能。 如果你不想從零開始刻節點,本篇教學將會使用由(Darks)開源提供的多平台自動發文模板進行示範,並專注解決串接過程中最容易卡關的 Meta 應用程式建立與 長期 Access Token 獲取。 你可以把這篇文章理解成一份實戰排雷手冊:不是只告訴你「理論上可以串接」,而是直接處理多數人在實作時最常遇到的三個問題: Token 很快失效,導致昨天能發、今天不能發 Meta 權限沒有勾完整,n8n 執行後直接報錯 模板本身可用,但一到自己的帳號與粉專環境就卡住 只要你把 Page ID、長期 Page Access Token、HTTP 節點版本 這三件事設定正確,Facebook 自動發文流程通常就能穩定跑起來。 n8n 串接 Facebook 自動發文前,你需要先準備什麼?在開始設定之前,你至少要先備好以下 4 個元素: 一個可正常登入的 n8n 環境 一個你有管理權限的 Facebook 粉絲專頁 一個 Meta for Developers 應用程式 可用於發文的 Facebook Page ID 與長期 Page Access Token 如果這四個條件都具備,後面的設定會順很多;如果少其中任何一項,通常就會卡在權限、授權或 endpoint 錯誤。 如何快速導入 n8n 自動發文模板?1. 取得並匯入工作流模板你可以前往 n8n 官方 Templates 庫 或創作者 Darks 的 Portaly 頁面 獲取一鍵自動發文模板。 作法: 複製模板內容後,直接在你的 n8n 畫布上按下 Ctrl+V (或 Cmd+V) 即可貼上完整的工作流。 2. 設定社群金鑰 (Data tables)在新版的 n8n 中,我們可以使用 Data tables 來集中管理各個社群平台的 API 金鑰,取代過去分散在各個節點填寫的麻煩。 在 n8n 左側選單點擊 Data tables,選擇 Create data table。 將表格命名為 社群金鑰(若使用模板,請務必與模板預設名稱完全一致)。 新增所需欄位(例如:main_scope、attribute、value)。 針對 Facebook 發文,我們至少需要準備並填入兩項核心資料: Facebook Page ID Facebook Access Token 接下來,我們將進入 Meta 開發者後台,去獲取這兩項關鍵資料。 如何建立 Meta 開發者應用程式,讓 n8n 可以串接 Facebook?要透過 API 發文到 Facebook 粉絲專頁,你必須先在 Meta 建立一支應用程式來取得權限。 1. 新增應用程式 前往 Meta for Developers。 點擊右上角的 建立應用程式。 應用程式類型請選擇 「商家 (Business)」 或 「其他 → 商家」。 輸入易於辨識的名稱(例如:n8n-fb-autopost),並填寫聯絡電子郵件。 2. 解決「隱私權政策」網址要求建立應用程式後,前往 應用程式設定 → 基本資料。系統會要求填寫「隱私權政策網址 (Privacy Policy URL)」才能將應用程式狀態切換為「上線」。 專家建議: 如果你沒有個人網站的隱私權頁面,可以使用免費的 Privacy Policy Generator 生成一份公版隱私權條款,獲取連結後貼回 Meta 後台即可過關。 3. 將應用程式切換為「上線」模式在基本資料設定完成並儲存後,務必將應用程式頂部的狀態由「開發中」切換為 「上線」,這樣 n8n 才能順利調用 API。 如何取得 Facebook 長期 Access Token 與 Page Token?這是整個流程中最容易出錯的環節。預設取得的 Token 通常只有 1 小時的壽命,我們必須將其轉換為「粉絲專頁專用的長期 Token」。 第一步:取得短期 User Token 在 Meta 開發者後台,點擊頂部選單的 「工具」→「圖形 API 測試工具 (Graph API Explorer)」。 右側面板設定: Meta 應用程式:選擇你剛建立的 App。 用戶或粉絲專頁:選擇 「取得粉絲專頁存取權杖」,並授權勾選你的粉絲專頁。 新增權限 (Permissions): 這是發文成功的關鍵,請務必加入以下 5 個權限: pages_show_list pages_read_engagement pages_read_user_content pages_manage_posts pages_manage_engagement 點擊 Generate Access Token(產生存取權杖),並複製這串短效期金鑰。 第二步:轉換為長效期 Token 在「圖形 API 測試工具」中,點擊上方的 「存取權杖偵錯工具」 或點擊權杖旁的「i」圖示展開詳情。 點擊底部的 「延伸存取權杖 (Extend Access Token)」,取得約 2-3 個月效期的長期 User Token。 關鍵轉換: 我們需要將 User Token 換成 Page Token。回到圖形 API 測試工具,在 GET 請求欄位輸入以下端點(請替換為你的粉絲專頁 ID):1/{你的粉絲專頁編號}?fields=access_token&access_token={剛剛取得的長效_User_Token} 點擊提交,返回的 JSON 數據中,access_token 欄位的值就是你最終需要的 長期粉絲專頁發文金鑰! 將這個 Token 與你的 Page ID 填回 n8n 的 Data tables 中,前置作業就大功告成了。 如果你想先驗證 Token 是否真的可用,建議在 n8n 正式執行前,先用 Graph API Explorer 或 HTTP Request 測一次最小請求。只要能成功打到粉絲專頁資料,後續發文流程通常就不會差太遠。 補充:Facebook Page ID 怎麼找最快?如果你手上還沒有 Page ID,最穩的方式不是直接猜名稱,而是透過 Meta 工具或 Graph API 查詢實際 ID。因為在 n8n 串接 Facebook 發文時,真正用來指定目標粉專的是 Page ID,不是粉專顯示名稱。 你可以把這個觀念記住: 粉專名稱是給人看的 Page ID 是給 API 用的 只要這裡填錯,後面就算 Token 正確,發文也可能失敗或打到錯的目標。 n8n Facebook 自動發文失敗怎麼排查?常見報錯修復整理如果你在執行 n8n 工作流時遇到錯誤,通常是以下兩個原因: 1. Graph API 版本過舊Meta API 更新頻繁,模板中預設的 API 版本可能是 v23.0。若報錯,請進入 n8n 的 HTTP Request 節點(負責發布貼文的節點),將 URL 中的版本號手動更改為最新版,例如 v25.0: 1https://graph.facebook.com/v25.0/{{ $json.facebook_id }}/feed 2. If 節點 (判斷圖片是否存在) 報錯舊版的 n8n If 節點在讀取空值時容易發生中斷錯誤。若你的流程在判斷「是否上傳圖片」時卡住,建議將該原有的 If 節點刪除,重新拖曳一個新的 If 節點,並重新設定判斷條件(如判斷 binary.data 是否存在),即可解決錯亂問題。 3. 發文成功回傳 200,但粉專上看不到貼文這種情況通常不是 n8n 沒有送出,而是你打到的目標不是預期中的粉絲專頁、權限對錯頁、或貼文被發到不同類型的內容區塊。建議依序檢查: Data table 裡的 Facebook Page ID 是否填成正確粉專,而不是個人帳號 ID。 Access Token 是否真的是該粉專對應的 Page Token。 HTTP Request 節點送出的 endpoint 是否為 /{page_id}/feed,而不是其他物件路徑。 粉專角色是否足夠,且授權帳號仍然是該粉專的管理者或具備可發文權限的人員。 4. 明明有 Token,卻跳出權限不足或 OAuth 相關錯誤這通常代表問題不在「有沒有 Token」,而在於 Token 綁定的權限範圍不夠。最常見的修法是重新生成權杖,並重新勾選 pages_manage_posts、pages_read_engagement 等必要權限,再重新做一次長效與 Page Token 轉換。只換節點設定、不重拿權杖,很多時候是修不好的。 實務建議:讓 Facebook 自動發文流程更穩定的 4 個做法如果你是要把這個流程真的用在營運,而不只是測試一次,建議多做以下幾件事: 把 Token 到期日記錄下來長期 Token 不是永久有效。建議在 Notion、行事曆或任務系統中記錄建立日期與預估到期時間,避免某天排程突然中斷才回頭找原因。 先做最小發文測試一開始不要直接串完整的 AI 文案、自動抓圖、自動排程。先測最簡單的純文字貼文,確認 Page ID、Token 與 endpoint 都正確,再逐步加功能。 把錯誤訊息完整保留n8n 的執行紀錄、HTTP status code、Meta 回傳的錯誤訊息都很重要。很多 Facebook API 問題不是節點壞掉,而是錯誤訊息裡早就明講是版本、權限或參數不符。 避免把憑證硬寫在節點裡如果你未來還要串接 Instagram、Threads 或其他平台,建議持續用 Data tables 或統一憑證管理方式來控管金鑰,後續維護會簡單很多。 如果你接下來要改成 Facebook 多圖貼文這篇文章處理的是「先把 Facebook 自動發文打通」,也就是 Page ID、長期 Token、基本發文與常見權限問題。如果你已經能穩定發單圖或純文字,下一步通常就是改成多圖貼文。 但這一步不是只把欄位多複製幾份而已。Facebook 多圖貼文的正確做法,會需要: 表單支援多檔上傳 每張圖各自呼叫 POST /photos 收集所有 photo id 最後用 attached_media 一次組回 POST /feed 完整做法我另外拆成一篇:使用 Facebook Graph API 自動發布多圖貼文。如果你現在已經跑通這篇的單圖流程,建議直接接著看下一篇。 n8n 串接 Facebook 自動發文 FAQ以下這一段我特別整理成「真的會遇到的卡點」,如果你不是要理解原理,而是要把流程跑起來,這些問題通常最值得先看。 Q:為什麼我的 Facebook 發文權限一小時就失效了?A:因為你一開始拿到的通常不是最終可用的 Page Token,而是「短效期用戶權杖 (Short-lived User Token)」。這種 Token 常常只有約 1 小時效期,適合測試,不適合正式排程。 正確流程應該是: 先取得短期 User Token 再延長成長期 User Token 最後透過 API 轉換成對應粉專的 Page Token 只有完成第三步,你放進 n8n 裡的憑證才比較適合長期自動發文。很多人以為「已經拿到 Token」就可以了,結果其實只是停在第一步。 Q:建立 Meta 應用程式時,強制要求填寫「隱私權政策網址」該如何解決?A:Meta 為了合規性,要求上線的 API 應用程式必須具備隱私權政策。若你沒有自己的官網,最簡單的做法就是先用 Privacy Policy Generator 產生一份可公開存取的頁面,再把該 URL 貼回 Meta 後台。 實務上要注意兩件事: 這個網址必須能從外部正常開啟,不能是內網或尚未發布的頁面。 就算你現在只是自己測試,Meta 仍然常要求基本資料填完整,否則某些功能或狀態切換會卡住。 Q:執行 n8n 流程時出現 Graph API 版本錯誤怎麼辦?A:Meta 會定期淘汰舊版的 Graph API,所以你拿到的工作流模板就算之前能跑,過一陣子也可能因為版本過期而失效。最直接的做法,就是打開 n8n 中負責發文的 HTTP Request 節點,把 URL 裡的版本號更新成目前支援的版本,例如 v25.0。 如果你更新版本後還是報錯,不要只看版本本身,也要同步檢查: endpoint 路徑有沒有寫錯 權限是否完整 請求方法是否為 POST 送出的欄位名稱是否符合該 endpoint 要求 Q:Page ID 要去哪裡找?可以直接用粉專名稱代替嗎?A:不建議用粉專名稱硬猜,最穩的方式還是直接拿 Facebook Page ID。你可以在 Meta 的工具或相關 API 查到 Page ID,之後固定填進 n8n 的 Data table。因為實際發文 endpoint 是依照 ID 指向目標粉專,不是依名稱辨識。 如果你填錯 Page ID,常見結果有兩種: 直接報錯,表示找不到對應資源 成功執行,但其實打到錯的粉專或錯的頁面物件 Q:我明明是粉專管理員,為什麼還是無法發文?A:因為「你是管理員」不一定等於「這次授權出來的 Token 具備正確發文權限」。Facebook API 的世界裡,是否能發文不是只看帳號身份,還要看這次產生 Token 時到底勾了哪些 scopes。 換句話說,常見問題不是角色不夠,而是: 你勾漏了 pages_manage_posts 你拿的是 User Token,不是 Page Token 你授權的是 A 粉專,但實際要發的是 B 粉專 Q:n8n 裡建議用 Credentials 還是 Data tables 管理 Token?A:如果你現在是跟著模板快速實作,而且這份工作流本身就是用 Data tables 設計,那直接沿用 Data tables 會最快,也比較符合這篇教學的流程。它的優點是你可以把多個平台的憑證集中管理,後續替換比較方便。 但如果你的團隊之後會把這套流程做得更正式、更模組化,也可以評估改成 n8n Credentials 或其他集中式密鑰管理方案。重點不在工具名稱,而在於你要避免把 Token 分散寫死在不同節點裡,否則未來更新憑證會很痛苦。 Q:可以用這種方式排程每天自動發文嗎?A:可以,這正是 n8n 很適合的場景之一。你可以在前面接 Schedule Trigger,固定每天、每週或特定時段執行,再把產生好的文案送到 Facebook 發文節點。 不過正式排程前,建議先確認三件事: Token 已經換成長期可用的 Page Token 貼文內容來源是穩定的,不會臨時產出空值 流程裡有做基本錯誤處理,避免發文失敗卻沒人知道 Q:Facebook 自動發文可以順便帶圖片嗎?A:可以,但比起純文字貼文,圖片流程通常更容易出錯,因為你還要額外確認圖片檔案來源、格式、欄位名稱,以及 n8n 裡對 binary 資料的處理是否正常。這也是為什麼很多人在模板裡會卡在 If 節點或圖片判斷邏輯。 建議的做法不是一開始就硬上圖片版,而是: 先測純文字貼文 再測單張圖片貼文 最後才整合 AI 文案、圖片生成與排程 這樣你比較容易知道問題到底出在 Facebook API、n8n 節點,還是圖片資料本身。 Q:為什麼 n8n 測試時能發,排程時卻失敗?A:這種情況非常常見,因為手動測試與排程執行的上下文不一定完全一樣。最常見的原因包括: 測試時用的是手動輸入資料,排程時來源欄位其實是空的 Token 到排程執行時已失效 前面某個節點在排程模式下沒有成功輸出資料,導致發文節點吃到空值 所以你不能只看「手動跑一次有成功」,還要回頭檢查排程當下的 input/output 與 execution log。 Q:如果未來 Access Token 過期了,要整套重做嗎?A:通常不用整套重做,但你至少要重新完成「拿新 Token」這一段,並把新的值更新回 n8n 使用的地方。只要 App、粉專、流程本身都還在,通常不需要整套模板重建。 比較務實的做法是: 把 Token 更新流程寫成你自己的內部 SOP 記錄 Page ID、App 名稱、授權帳號 每次更換 Token 後立刻做一次最小發文測試 這樣下次出問題時,你不會又從零開始排查。 Q:這套流程適合哪些人先導入?A:最適合的是有固定社群內容產出需求的人,例如個人品牌經營者、顧問、行銷團隊、接案工作者,或本來就已經在用 n8n 串內容工作流的人。尤其如果你已經有固定的文案來源,例如 AI 產文、Notion 選題、Google Sheets 排程表,Facebook 自動發文會很容易接進去。 反過來說,如果你現在連貼文策略、審稿流程、內容節奏都還沒建立好,那先把 API 串起來不一定會立刻帶來效益。自動化放大的前提,是你原本的內容流程已經有基本穩定度。

  • article-如何使用 Claude Cowork 自動生成專業AI PPT 簡報

    2026/4/2

    AI工具 AI自動化 Claude
    如何使用 Claude Cowork 自動生成專業AI PPT 簡報
    今天的主題非常特別,我們將深入探討如何利用 Claude 的協作功能(Co-work / Workspace)來完成一項許多上班族的痛點任務——自動製作 PPT 簡報。透過這套 AI 自動化流程,你只需要準備好大綱與空白模板,剩下的排版與生成工作通通交給 AI,最快 10 到 15 分鐘就能拿到一份完整的簡報成品! 準備步驟:如何建立專屬的 AI 簡報工作區?要讓 Claude 幫你精準產出簡報,前期的資料準備非常關鍵。請跟著以下步驟建立你的專案環境: 建立專屬資料夾:在桌面上開啟一個新的資料夾,作為這次簡報生成的工作區。 匯入品牌模板:將你平常使用的「空白簡報模板」放入資料夾中。這一步非常重要,這能確保 AI 產出的簡報符合你的品牌風格(例如:保留你的首頁設計與結尾感謝頁)。 準備內容大綱:預先準備好你要製作的簡報文字內容或企劃大綱。 實戰核心:如何下達 Prompt 讓 Claude 批量生成?準備好素材後,我們就可以請 AI 開始工作了。你可以先透過其他的 AI 工具(如 ChatGPT)根據你的主題生成大綱,接著將這些大綱餵給 Claude,並下達明確的指令。 你可以參考以下這段 Prompt 架構: 123456789101112請根據我提供的空白簡報模板([你的模板名稱.pptx]),以及以下的大綱內容,幫我製作一份完整的 PPT 簡報。簡報主題:AI 內容工廠 - 一鍵生成 100 支短影片腳本大綱架構:1. 開場金句(直接套用:大多數人不是不會做短影片,是撐不久...)2. 痛點放大(約 10 分鐘:為什麼 99% 的人做不起來?)3. 實作核心(約 45 分鐘:輸入 1 主題,產出 100 個腳本)...(貼上完整大綱)...要求:- 必須保留模板的第一頁(封面)與最後一頁(封底)。- 中間內容請依照大綱邏輯,自動進行排版與視覺化。 送出指令後,Claude 就會開始執行簡報的編譯與視覺化 QA(品質檢驗)。根據測試,大約只需要 10 到 15 分鐘,AI 就能從無到有產出一份包含 15 頁內容的完整簡報檔。 成果優化:如何精修排版與品牌視覺?當 Claude 產出簡報後(例如下載為 PPTX 格式),你可以打開檔案進行對照與微調。你會發現: 首尾一致性:AI 會完美沿用你提供的第一頁(封面)與最後一頁(QR Code 或感謝頁)的設計。 中間頁面排版:AI 會根據你提供的大綱自動填入文字,並進行初步排版。 進階優化技巧:如果生成的排版風格不如預期(例如顏色不對、字體大小不統一),不用擔心。你可以在後續的對話中,加入更明確的「品牌風格指令」。例如: 1請確保所有標題使用 [字型名稱]、大小為 [XX],並使用 [色號代碼] 作為強調色。你可以參考我過去簡報的視覺風格來進行排版。 只要給予足夠的分析資料與指令,Claude 就能更貼近你的專屬簡報風格,徹底擺脫過去手動一頁一頁調整格式的痛苦! 想讓 AI 生成的簡報更穩,關鍵不是模型,而是輸入品質很多人第一次用 AI 做簡報時,最容易誤會的一點是:以為只要模型夠強,簡報就會自動變得專業。實際上,真正決定成果品質的,通常不是模型名稱,而是你提供給 Claude 的素材是否夠完整。 如果你只丟一段主題給 AI,例如「幫我做一份 AI 行銷簡報」,那它大多只能產出一份泛用型內容;但如果你能同時提供以下資訊,結果通常會穩很多: 明確的大綱結構:每一段要講什麼、順序怎麼排、哪裡要當重點頁。 既有模板檔案:包含封面、配色、字體風格、頁首頁尾等品牌元素。 講者情境:這份簡報是對客戶提案、內部報告、課程教學,還是銷售簡報? 頁數與節奏要求:例如希望控制在 12 到 15 頁,每頁不要過滿。 視覺偏好指令:例如偏商務、偏極簡、偏高對比,或要保留特定 icon 與圖表風格。 換句話說,Claude 更像是一位執行能力很強的簡報協作助手,而不是會自動讀心的設計總監。你給它的上下文越完整,它輸出的內容就越接近可直接上台使用的版本。 給新手的實務建議:第一次不要追求一次到位如果你是第一次測試這種 AI 簡報工作流,建議不要一開始就丟最重要的提案簡報。比較穩的方式,是先拿一份你已經熟悉主題、而且結構清楚的內容做測試,目的是先驗證三件事: 模板有沒有被正確沿用:封面、封底、色系與版型是否保留下來。 內容切頁有沒有合理:AI 有沒有把一整段文字硬塞進同一頁。 後續修改成本高不高:你拿到成品後,是小修即可,還是幾乎要重做。 當你第一次跑完流程後,建議把不滿意的地方整理成明確規則,例如: 標題最多 14 字 每頁列點不超過 5 點 遇到流程說明優先改成圖解型版面 結論頁一定要包含 CTA 與聯絡方式 這些規則一旦整理好,之後就能變成你的固定 Prompt 模板。未來每次只要換主題,不用再從零開始調整,整體產出速度會快很多。 常見問答 (FAQ)Q:使用 Claude 生成簡報,會不會失去原本的品牌風格?A:不會的。核心秘訣在於「提供空白模板」。只要你在上傳需求時,一併附上帶有你品牌識別(Logo、特定配色、首尾頁設計)的 PPT 模板,Claude 就會在該框架下生成內容,確保品牌視覺的一致性。 Q:AI 生成出來的簡報可以後續手動修改嗎?A:當然可以。Claude 最終產出的是標準的簡報格式檔案。你可以直接用 PowerPoint 或 Keynote 打開,針對裡面的文字、圖片或排版進行自由微調,你依然擁有 100% 的修改控制權。 Q:如果覺得 AI 排版出來的樣式很陽春,該怎麼辦?A:這通常是因為指令不夠具體。建議你先請 Claude 讀取並分析你過去做過、覺得好看的簡報檔案,然後在 Prompt 中明確指定「字體大小、標題顏色、列點方式」,讓 AI 掌握你的排版邏輯,下一次生成的品質就會大幅提升。 Q:用 Claude 做簡報,真的能取代 PowerPoint 手動排版嗎?A:比較精準的說法是「大幅減少手動排版時間」,但通常還不會完全取代人工。Claude 很適合先完成 70% 到 90% 的初稿,包括頁面拆分、標題整理、內容填入與基本版型延用;但如果是高層提案、投資人簡報或重要課程教材,最後仍建議人工做一次視覺與訊息密度校正。 Q:我應該先準備完整逐字稿,還是只給大綱就夠了?A:兩種都可以,但用途不同。如果你要的是「快速出初稿」,給大綱就夠;如果你要的是「內容精準、邏輯完整、接近可直接上台講」,那最好提供逐字稿、重點段落或你原本的企劃內容。大綱適合做架構,逐字稿則更能幫助 AI 抓到你真正想表達的語氣與細節。 Q:Claude 生成簡報通常適合哪些類型的內容?A:最適合的是結構清楚、重點明確的簡報,例如課程簡報、內部教育訓練、顧問提案、服務介紹、產品說明、工作坊教材與內容行銷型簡報。相對來說,如果是高度依賴精細動畫、複雜圖表、互動效果或極高設計要求的發表會簡報,AI 可以先做底稿,但後段仍需要設計師細修。 Q:如果 Claude 把內容切頁切得很怪,問題通常出在哪裡?A:大多不是模型失常,而是原始內容沒有明確段落層級。當一份大綱沒有標示「章節、子題、重點、案例、結論」時,AI 很容易把資訊切得過碎,或反過來把太多內容塞進同一頁。比較好的做法是先把大綱整理成一層一層的結構,再清楚標記哪些段落要獨立成頁。 Q:我可以直接丟一份 Word、Notion 或純文字內容給 Claude 嗎?A:可以,但建議先整理過再丟。因為原始文件常常包含很多不適合直接上投影片的內容,例如過長段落、重複描述、備註型文字或講者腦中才懂的提示。先把內容整理成「標題 + 重點列點 + 案例補充」的格式,AI 轉成簡報時會準很多。 Q:如果我的簡報需要圖表、流程圖或案例頁,Claude 也能一起處理嗎?A:可以先幫你建立頁面結構與內容建議,但圖表與流程圖的精緻程度,通常還是取決於模板、素材與你給的指令清不清楚。若你希望某頁一定要做成流程圖、比較表或三欄式案例頁,最好直接在 Prompt 中說明,不要只寫「請幫我排版得好看一點」。 Q:為什麼有時候 AI 生成的簡報文字很多,看起來像把文章貼上去?A:這是 AI 做簡報很常見的問題,本質上是「把文件摘要」和「做投影片」混在一起。投影片不是文章頁面,而是輔助口說的視覺媒介,所以一頁通常只需要保留最核心的資訊。你可以在指令中明確要求:每頁只保留 3 到 5 個重點、每點一句話、必要時改成圖解或流程式表達,這樣會明顯改善。 Q:第一次使用這種 AI 簡報流程,最推薦怎麼測試?A:建議先挑一份你已經做過、而且很熟悉的舊簡報主題來測。這樣你最容易判斷 AI 是真的幫你省時間,還是只是換一種方式增加修改成本。第一次測試不要追求完美,而是先看它能不能穩定保留模板、正確切頁,並讓你在 15 到 30 分鐘內完成最後微調。 Q:這種做法最適合哪些人導入?A:最適合的是有固定產出簡報需求的人,例如顧問、講師、業務、行銷企劃、知識型創作者、內訓講師與中小企業老闆。只要你常常在做「把同一套邏輯換主題重做簡報」這件事,就很適合把大綱整理、初稿排版與版型套用交給 Claude 先完成。

  • article-社群發布自動化指南:使用 n8n 與 Notion 打造零失誤半自動工作流 | (EP.8) n8n 自動化 API 串接教學

    2026/4/1

    AI自動化 n8n API串接 社群行銷
    社群發布自動化指南:使用 n8n 與 Notion 打造零失誤半自動工作流 | (EP.8) n8n 自動化 API 串接教學
    為什麼社群自動化不能只追求「全自動」?許多人一接觸 AI 與自動化,第一個念頭就是:「能不能讓 AI 寫完文之後,直接自動發到 Facebook、Instagram、X、Threads?」 答案是技術上可以,但商業上通常不值得冒這個風險。 社群內容不是單純的文字搬運,而是品牌對外發聲。只要 AI 生成的資訊有誤、語氣偏掉、格式跑版,或誤用了不合時宜的字詞,就可能造成客服壓力、品牌信任受損,甚至引發公關危機。對大多數企業、自媒體團隊與接案行銷人員來說,更穩健的做法不是「全自動」,而是 半自動化(Human-in-the-loop)。 半自動化的核心精神很簡單: AI 負責加速產出:先生成貼文草稿、平台文案、標籤與 CTA。 人類負責最後把關:檢查事實、語氣、素材與排程是否正確。 系統負責穩定執行:核准後再由 n8n 自動分發到指定平台。 這種流程的優勢在於,你把最耗時的「重複性工作」交給系統,卻把最關鍵的「品牌判斷」留在人手上。效率有提升,風險也不會失控。 一套真正可落地的社群工作流長什麼樣?如果你想建立的是可以每天穩定運作,而不是只示範一次的流程,建議把整體架構拆成四層: 內容生成層:用 OpenAI 或其他模型產出各平台草稿。 內容管理層:用 Notion 當內容資料庫,集中管理文案、素材、狀態與排程。 流程執行層:用 n8n 根據狀態與時間條件執行發布邏輯。 結果回寫層:將發布結果、錯誤訊息、發布時間與平台連結回寫到 Notion。 這樣的設計有一個很大的好處:當流程某一段需要調整時,你只要修改那一層,不需要整套重做。例如你今天先發 Facebook,未來要擴充 LinkedIn 或 Threads,也只要增加分流與對應 API 邏輯即可。 內容資料庫該放哪裡?為什麼我更推薦 Notion在人工審核階段,你需要一個所有人都看得懂、也方便協作的內容資料庫。常見做法有兩種:Google Sheets 與 Notion。 Google Sheets 的優點是簡單、直觀、容易大量編修;但如果你的需求不只是存資料,而是希望團隊成員能更舒服地檢查文案、管理狀態、切換檢視與長期維護,那麼 Notion 會更適合作為內容中台。 原因很實際: 版面更適合內容審稿:不只是表格,而是可以用資料庫、看板、日曆等方式檢視。 欄位可讀性更高:小編、主管、客戶比較容易理解目前每篇文章卡在哪個階段。 更像內容管理系統(CMS):未來要擴充 SOP、素材區、發文規範、提示詞模板,也能都留在同一個工作空間。 如果你想做的是長期能交接、能維護、能多人使用的流程,Notion 通常比單純的試算表更穩。 建議建立的 Notion 欄位為了讓 n8n 能穩定讀取與判斷,至少準備以下欄位: 文章標題(Title):內部辨識用,不一定會直接對外發布。 主文內容(Content):長文或主敘述內容。 平台文案(Caption):針對社群平台的短文案,可依平台拆欄位。 發布平台(Platform):多選欄位,例如 FB、IG、X、Threads、LinkedIn。 審核狀態(Status):例如 Draft、Reviewing、Ready、Published、Failed。 立即發布(Publish Now):勾選後可讓 n8n 優先處理。 預約發布時間(Scheduled Time):做排程發布時會用到。 素材連結(Asset URL):圖片或影片 URL,特別是 IG 幾乎一定會用到。 發布結果(Post URL):成功後回寫平台貼文網址。 錯誤紀錄(Error Log):方便追蹤 API 錯誤與人工補救。 如果你預計經營多平台,建議一開始就把「平台文案」與「素材」拆開,不要把所有東西都塞在同一個欄位中,否則後期擴充會很痛苦。 狀態管理才是自動化成功的關鍵很多人以為自動化的核心在 API 串接,但實務上,真正決定流程穩不穩的,通常是 狀態管理設計得好不好。 建議在 Notion 中至少規劃以下 5 種狀態: Draft(草稿):AI 剛產出,尚未人工確認。 Reviewing(審核中):編輯、主管或客戶正在修改內容。 Ready(準備發布):內容、素材、平台都已確認,可交由系統處理。 Published(已發布):已成功送出到指定平台。 Failed(發布失敗):流程有執行,但 API 回傳錯誤或資料不完整。 多了 Failed 這個狀態很重要,因為真實世界的流程不可能永遠一次成功。當貼文因為字數超限、素材格式錯誤、Token 過期或 API 配額不足而失敗時,你需要明確知道它不是還沒發,而是「發送失敗,等待處理」。 n8n 要怎麼知道你準備好了?當文章在 Notion 中被標記為 Ready 後,n8n 需要一個觸發機制來接手。常見有兩種方式: 做法 A:排程巡檢(Schedule Trigger)這是最適合新手上手的方法。你可以設定 n8n 每隔 1 到 5 分鐘讀取一次 Notion,找出符合條件的資料。 優點: 設定簡單 不需要額外開發前端按鈕 容易除錯與觀察流程 缺點: 不是即時發布 如果排程太密,會增加不必要的 API 呼叫 做法 B:Webhook 即時觸發當你希望按下按鈕就立刻發文,或要從其他系統觸發 n8n,就可以用 Webhook。 優點: 幾乎即時執行 比較適合做人工核准後立即送出 缺點: 權限與安全性要處理好 建置成本比排程高一些 實務建議: 先用排程把流程跑穩,再考慮升級成 Webhook。多數團隊真正卡住的不是「延遲 3 分鐘」,而是資料格式與狀態管理不夠嚴謹。 一條穩定的 n8n 發布流程,至少要包含哪些節點?當 n8n 開始執行後,建議的基本邏輯如下: Schedule Trigger / Webhook:啟動流程。 Notion 查詢節點:讀取資料庫中符合條件的貼文。 IF / Filter:確認狀態為 Ready,且已達預約時間。 資料清理 / 格式化:處理文案長度、日期格式、平台欄位與素材欄位。 Loop / Split In Batches:逐筆處理,避免多篇一起失敗難以追蹤。 平台分流:依據平台呼叫不同 API,例如 Meta Graph API、X API、LinkedIn API。 成功回寫 Notion:更新狀態為 Published,記錄發布時間與貼文連結。 失敗回寫 Notion:更新狀態為 Failed,寫入錯誤訊息,方便人工補救。 如果你再往前走一步,還可以加入: 重試機制:暫時性 API 錯誤時自動重送。 Slack / Email 通知:發布成功或失敗時提醒相關人員。 審核紀錄:寫回最後編輯者與核准時間,讓流程更可追溯。 真正會踩雷的,不是 API,而是內容格式很多新手第一次做社群自動化,最容易忽略的是:不同平台根本不是把同一段文字複製貼上就能發。 例如: X(Twitter):字數限制嚴格,太長就直接失敗。 Instagram:通常需要搭配圖片或影片,純文字流程很容易卡住。 Facebook / LinkedIn:可接受較長文,但語氣與換行邏輯仍需要調整。 Threads:文案節奏與互動感通常要比部落格摘要更口語。 所以,部落格長文、電子報內容與社群貼文應該視為三種不同內容型態,而不是同一份文案的不同輸出位置。 比較好的做法在 AI 生成階段,就直接要求模型輸出: 部落格摘要版 Facebook / LinkedIn 版 X 短文版 Instagram Caption 版 Hashtags CTA 這樣做的好處是,你的資料庫會從一開始就長得像「可發布資料」,而不是一團等待人工重寫的草稿。自動化流程要穩,前面的資料結構就不能含糊。 給新手的落地建議:先做小,再做快如果你現在正準備開始做這套系統,建議先用最小可行版本(MVP)上線: 先只做 單一平台,例如先串 Facebook。 先只做 排程發布,不要一開始就追求即時按鈕。 先只處理 單張圖片 + 單段文案,避免一開始就挑戰輪播、影片或多素材邏輯。 先把 成功回寫與失敗紀錄 做好,再談擴充。 只要這四件事能穩定運作,你就已經打下很強的基礎。之後再加入更多平台、更多模板、更多審核流程,整體成本會低很多。 常見問答(FAQ)Q:我可以把整套流程做到全自動,完全不人工審核嗎?A:可以,但不建議作為日常商業流程的預設模式。AI 生成內容仍可能出現事實錯誤、語氣失準、錯別字、敏感用語或品牌不一致的問題。對企業與品牌來說,省下幾分鐘審稿時間,通常不值得拿品牌風險去交換。比較務實的做法是保留人工核准,只把重複性工作交給系統。 Q:我不會寫程式,也能做出這套 n8n + Notion 工作流嗎?A:可以。這套流程本質上屬於低程式碼(Low-code)範圍,大部分邏輯都能透過 n8n 節點與 Notion 資料庫完成。真正需要花時間的不是寫程式,而是把欄位、狀態、平台規則與錯誤處理想清楚。只要流程設計正確,新手也能先做出可用版本。 Q:為什麼我在 X 或 Instagram 發文時常常失敗?A:最常見原因不是 n8n 壞掉,而是資料不符合平台規則。X 常見問題是字數超限;Instagram 常見問題是缺少必要素材、圖片格式不符,或 API 權限未設定完整。建議把不同平台的文案與素材拆欄位管理,並在發送前加入資料檢查節點,先擋掉不合法資料。 Q:Google Sheets 跟 Notion,我到底該選哪一個?A:如果你只是想快速驗證概念、資料欄位也很單純,Google Sheets 會更快上手;但如果你希望流程能長期維護、多人審稿、清楚管理狀態與內容,Notion 會更適合。簡單說,Sheets 比較像暫時資料表,Notion 比較像內容中台。 Q:我應該先做排程發布,還是直接做 Webhook 即時發布?A:建議先做排程。因為新手最需要先驗證的是資料結構、狀態流程與平台發布是否穩定,而不是「有沒有即時」。等到排程模式穩定之後,再把同樣邏輯改成 Webhook 觸發,風險會低很多。 Q:如果同一篇內容要發到 Facebook、Instagram、X,需要共用同一份文案嗎?A:不建議。你可以共用同一個主題與核心訊息,但每個平台最好有自己的 Caption。不同平台的字數限制、閱讀節奏、Hashtag 使用方式與 CTA 風格都不同。若硬要共用同一段文案,失敗率與成效不佳的機率都會提高。 Q:預約發布該怎麼設計比較安全?A:最穩的做法是同時判斷兩個條件:Status = Ready 且 Scheduled Time <= 現在時間。此外,成功發送後要立刻把狀態改成 Published,避免下一次排程重複發文。若流程可能重跑,也可以額外加入「已發送平台 ID」或「發布鎖」欄位做保護。 Q:如果 API 發布失敗,應該怎麼補救?A:不要只讓流程報錯結束,最好把錯誤寫回 Notion。建議至少回寫 Failed 狀態、錯誤訊息、失敗時間,必要時再發 Slack 或 Email 通知。這樣團隊成員能快速知道是哪一篇、哪個平台失敗,以及該補哪一段資料。 Q:這套流程適合哪些人先導入?A:最適合的是有固定內容產出節奏的人或團隊,例如自媒體經營者、內容行銷團隊、接案代操、顧問型品牌、課程講師與中小企業。只要你每週都在重複做「整理文案、人工貼上、切平台、確認格式」這些事,就很適合先從半自動化開始。

  • article-如何用 n8n 打造 AI Agent 專屬記憶庫?Logging 實戰 | (EP.7) n8n 自動化 API 串接教學

    2026/3/31

    AI自動化 n8n API串接
    如何用 n8n 打造 AI Agent 專屬記憶庫?Logging 實戰 | (EP.7) n8n 自動化 API 串接教學
    為什麼 AI 需要 Logging?告別「金魚腦」的專屬黑盒子當我們將 LINE 等通訊軟體與 AI 結合時,常常會遇到一個災難現場:AI 沒有記憶。它無法記住上一秒的對話,導致每次回覆都像初次見面,甚至引發錯誤(Error)。 Logging 的本質,就是系統的專屬「黑盒子」。一句話講完:Logging 就是為了讓你在事後「看得懂發生過什麼事」。 在 n8n 或任何自動化流程中,Log 不僅僅是無聊的資料,它是拯救開發者的五大超能力: 除錯 (Debug): 沒紀錄只能瞎猜,有紀錄就能精準抓蟲。 重現 (Reproduce): 還原當下觸發錯誤的 Prompt。 監控 (Monitor): 追蹤系統的成功率與 API 呼叫狀況。 優化 (Optimize): 作為未來訓練 AI 的精華資料。 稽核 (Audit): 有紀錄才有證據,知道哪個環節出錯。 記憶的進化:從「給人看」到「給 AI 看」Logging 的應用可以分為兩個階段: 階段一:只做 Logging(給人看)為了事後查看、稽核執行結果。我們開始把資料寫入 Google Sheets,方便我們進行 Debug 與狀態確認。 階段二:Logging + 給 AI 查(AI 也要看)當 AI 需要記得前文、參考歷史紀錄,或是做進階的資料檢索(RAG)時,Log 就直接升級成了 AI 的 Context(上下文)。這能讓 AI 瞬間恢復記憶,甚至做到個人化預測與專屬知識庫的搭建。 踩雷警告!為什麼讓 AI 自動撈資料(Tool Calling)是一場災難?很多新手會有一個致命誘惑:「既然 AI 這麼聰明,不要在 Workflow 查了,直接寫個 Tool 讓 AI 自己去 Google Sheet 撈資料(Tool Calling)不是更簡單?」 想法很完美,但對於新手與固定規則的任務來說,這是一個巨大的陷阱! 失控的可控性: AI 可能亂查太多的資料、查錯條件,甚至決定「不查了」,看它心情做事。 成本超級高: 先讓 LLM 判斷 → 呼叫工具 → 再回傳 LLM,速度極慢且狂燒 Token。 除錯大地獄: 出錯時你根本不知道是 Prompt 寫壞、工具沒寫好,還是 AI 邏輯當機。 架構大 PK:Workflow 先查 vs. AI Agent 自己撈 比較項目 Workflow 先查 (Pre-fetch / 固定 Context) AI Agent 自己撈 (Tool Calling / 動態查詢) 適用情境 固定規則(例:每次都查最新 3 筆對話) 動態條件(例:查閱特定主題的歷史紀錄) 穩定度 極高 (100% 執行) 較低(看 AI 心情決定是否呼叫) 除錯難度 簡單清晰 複雜地獄 花費成本 低 高 專家建議: 在進入 AI 節點前,先由 Workflow 流程預先整理好必要資訊(固定 Context),確保 AI 每次都有穩定、可控的上下文。只有在遇到「不確定需求」或「延伸問題」時,才交由 Agent 進行動態查詢。 完整 Workflow 架構解析本次實作的完整流程共分為 三大區段,以下逐一拆解。 區段一:接收與解析 LINE 訊息1Webhook1 → Edit Fields1 Webhook1 接收 LINE Messaging API 傳入的 POST 請求(路徑:line-0324)。 Edit Fields1 負責從 LINE 事件結構中提取三個關鍵欄位: 欄位 來源路徑 說明 input_text body.events[0].message.text 使用者輸入的訊息 userId body.events[0].source.userId 識別使用者身份 replyToken body.events[0].replyToken LINE 回覆用的一次性 Token 區段二:建立固定 Context(Pre-fetch 記憶)1Get User History → Build History Context → Debug History Preview 這是整個架構的靈魂——在 AI 介入前,由 Workflow 自行整理好歷史記憶。 Get User History:從 Google Sheets 的 logging 工作表中讀取所有紀錄。 Build History Context:透過 Code 節點對資料進行篩選與格式化: const current = $('Edit Fields1').first().json; const currentUserId = current.userId || ''; const rows = $input.all().map(item => item.json); // 只取同一位使用者、狀態為 success 的最近 3 筆紀錄 const filtered = rows .filter(row => row.userId === currentUserId && row.status === 'success') .sort((a, b) => { const ta = new Date(a.timestamp || 0).getTime(); const tb = new Date(b.timestamp || 0).getTime(); return tb - ta; }) .slice(0, 3); const historyContext = filtered.length ? filtered.map((row, idx) => { return `${idx + 1}.\n時間:${row.timestamp || ''}\n輸入:${row.input_text || ''}\n摘要:${row.summary || ''}\n分類:${row.category || ''}\n關鍵字:${row.keywords || ''}`; }).join('\n\n') : '無歷史紀錄'; return [ { json: { ...current, history_context: historyContext, history_count: filtered.length } } ]; 核心邏輯: 過濾條件為「userId 相同」且 status === 'success',排除失敗紀錄後,取最新 3 筆,確保注入 AI 的都是可靠的高品質記憶。 Debug History Preview:在此節點新增 debug_ 前綴欄位(debug_userId、debug_history_count、debug_history_context 等),讓你在 n8n 執行面板中可以直接確認「AI 即將收到的歷史資料長什麼樣子」,是開發初期排查問題的透明窗口。 區段三:AI 分析、回覆 LINE 與寫入 Log1AI Agent1 → HTTP Request1 → Prepare Log1 → Google Sheets Log1 AI Agent1(搭配 Google Gemini)接收完整的 Context 後進行分析。 Prompt 設計如下: 請讀取以下內容,輸出摘要、主題分類、3 個關鍵字。 本次使用者輸入:{{$json.input_text}} 以下是此使用者最近的互動紀錄,僅供理解上下文與延續語意。 若與本次輸入無關,請以本次輸入為主: {{$json.history_context}} System Message 明確規範 AI 行為,防止幻覺與格式失控: 你是資料整理助手。 規則: 1. 使用繁體中文。 2. 不要捏造未提供的資訊。 3. 請只輸出 JSON。 4. 欄位必須包含 summary、category、language、keywords。 5. 若有歷史互動紀錄,僅可用來補足上下文,不可把過去內容誤當成這次輸入內容。 6. 若本次輸入與歷史紀錄無明顯關聯,請忽略歷史紀錄。 7. 若資訊不足,也必須輸出合法 JSON。 Structured Output Parser 確保 AI 輸出符合以下 JSON Schema,強制欄位驗證,防止格式亂跑: { "type": "object", "properties": { "summary": { "type": "string" }, "category": { "type": "string", "enum": ["AI工具", "程式開發", "商業", "教育", "其他"] }, "keywords": { "type": "array", "items": { "type": "string" } }, "language": { "type": "string" } }, "required": ["summary", "category", "keywords", "language"], "additionalProperties": false } HTTP Request1 呼叫 LINE Reply API,將 AI 分析結果回傳給使用者。 Prepare Log1 + Google Sheets Log1 將本次執行的完整資料寫回 Google Sheets,包含以下欄位: 欄位 說明 timestamp 執行時間($now) workflow Workflow 名稱 status 執行狀態(success) executionId n8n 執行 ID userId / replyToken 使用者識別資訊 input_text 本次輸入 summary / category / language / keywords AI 分析結果 history_count 本次帶入的歷史筆數 history_context 實際注入 AI 的歷史文字 設計亮點: 記錄 history_count 與 history_context 讓你未來可以回溯「AI 當時看到的是什麼」,是除錯 Hallucination 的關鍵利器。 🎁 附錄:完整 n8n Workflow JSON 腳本你可以直接複製以下 JSON 程式碼,並匯入至你的 n8n 專案中進行測試。匯入後請記得將 Google Sheets 文件 ID 替換為你自己的試算表 ID,並重新設定 Google Sheets 與 LINE Bearer Token 的憑證(Credentials)。 { "nodes": [ { "parameters": { "httpMethod": "POST", "path": "line-0324", "options": {} }, "type": "n8n-nodes-base.webhook", "typeVersion": 2.1, "position": [-1392, -288], "id": "07a2efae-2d4c-4b63-ab6d-38366b22f782", "name": "Webhook1", "webhookId": "a6ff766a-b5f5-4d36-9066-963fc0e4407f" }, { "parameters": { "assignments": { "assignments": [ { "id": "820ce329-eb3e-46b7-8264-c13e6bab20e1", "name": "input_text", "value": "={{ $json.body.events[0].message.text }}", "type": "string" }, { "id": "b9d8194d-1c76-4ad3-a2ab-95fc0db6a001", "name": "userId", "value": "={{ $json.body.events[0].source.userId || '' }}", "type": "string" }, { "id": "6fbbf8c4-4044-41a6-9721-4f11ec8b0001", "name": "replyToken", "value": "={{ $json.body.events[0].replyToken || '' }}", "type": "string" } ] }, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [-1152, -288], "id": "d03c1de9-2b49-4ed0-98a3-d79d0cf0bb96", "name": "Edit Fields1" }, { "parameters": { "documentId": { "__rl": true, "value": "YOUR_GOOGLE_SHEET_ID", "mode": "list", "cachedResultName": "google sheet logging" }, "sheetName": { "__rl": true, "value": "gid=0", "mode": "list", "cachedResultName": "logging" }, "options": {} }, "type": "n8n-nodes-base.googleSheets", "typeVersion": 4, "position": [-912, -288], "id": "0ff96efd-5db8-45c3-a43e-0b1db98e31b3", "name": "Get User History" }, { "parameters": { "jsCode": "const current = $('Edit Fields1').first().json;\nconst currentUserId = current.userId || '';\n\nconst rows = $input.all().map(item => item.json);\n\nconst filtered = rows\n .filter(row => row.userId === currentUserId && row.status === 'success')\n .sort((a, b) => {\n const ta = new Date(a.timestamp || 0).getTime();\n const tb = new Date(b.timestamp || 0).getTime();\n return tb - ta;\n })\n .slice(0, 3);\n\nconst historyContext = filtered.length\n ? filtered.map((row, idx) => {\n return `${idx + 1}.\\n時間:${row.timestamp || ''}\\n輸入:${row.input_text || ''}\\n摘要:${row.summary || ''}\\n分類:${row.category || ''}\\n關鍵字:${row.keywords || ''}`;\n }).join('\\n\\n')\n : '無歷史紀錄';\n\nreturn [\n {\n json: {\n ...current,\n history_context: historyContext,\n history_count: filtered.length\n }\n }\n];" }, "type": "n8n-nodes-base.code", "typeVersion": 2, "position": [-672, -288], "id": "fe67f1ce-515a-471c-8fda-cdabfe30b00b", "name": "Build History Context" }, { "parameters": { "assignments": { "assignments": [ { "name": "debug_userId", "value": "={{ $json.userId }}", "type": "string" }, { "name": "debug_input_text", "value": "={{ $json.input_text }}", "type": "string" }, { "name": "debug_history_count", "value": "={{ $json.history_count }}", "type": "string" }, { "name": "debug_history_context", "value": "={{ $json.history_context }}", "type": "string" } ] }, "includeOtherFields": true, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [-432, -288], "id": "61c5f27f-f9e9-4eb1-93eb-3f18ea2b586f", "name": "Debug History Preview" }, { "parameters": { "promptType": "define", "text": "=請讀取以下內容,輸出摘要、主題分類、3 個關鍵字。\n\n本次使用者輸入:{{$json.input_text}}\n\n以下是此使用者最近的互動紀錄,僅供理解上下文與延續語意。若與本次輸入無關,請以本次輸入為主:\n{{$json.history_context}}", "hasOutputParser": true, "options": { "systemMessage": "=你是資料整理助手。\n\n規則:\n1. 使用繁體中文。\n2. 不要捏造未提供的資訊。\n3. 請只輸出 JSON。\n4. 欄位必須包含 summary、category、language、keywords。\n5. 若有歷史互動紀錄,僅可用來補足上下文,不可把過去內容誤當成這次輸入內容。\n6. 若本次輸入與歷史紀錄無明顯關聯,請忽略歷史紀錄。\n7. 若資訊不足,也必須輸出合法 JSON。" } }, "type": "@n8n/n8n-nodes-langchain.agent", "typeVersion": 3.1, "position": [-176, -288], "id": "e969d51a-4654-4d55-85ae-4c8efe0c3fa0", "name": "AI Agent1" }, { "parameters": { "options": {} }, "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini", "typeVersion": 1, "position": [-224, -64], "id": "8454dd71-055e-43b5-b445-5289f37fc7f8", "name": "Google Gemini Chat Model1" }, { "parameters": { "schemaType": "manual", "inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"summary\": { \"type\": \"string\" },\n \"category\": {\n \"type\": \"string\",\n \"enum\": [\"AI工具\", \"程式開發\", \"商業\", \"教育\", \"其他\"]\n },\n \"keywords\": {\n \"type\": \"array\",\n \"items\": { \"type\": \"string\" }\n },\n \"language\": { \"type\": \"string\" }\n },\n \"required\": [\"summary\", \"category\", \"keywords\", \"language\"],\n \"additionalProperties\": false\n}" }, "type": "@n8n/n8n-nodes-langchain.outputParserStructured", "typeVersion": 1.3, "position": [16, -64], "id": "b9638a0d-bfc5-4af6-8dbc-91f225223b3a", "name": "Structured Output Parser1" }, { "parameters": { "method": "POST", "url": "https://api.line.me/v2/bot/message/reply", "authentication": "genericCredentialType", "genericAuthType": "httpBearerAuth", "sendHeaders": true, "headerParameters": { "parameters": [{ "name": "Content-Type", "value": "application/json" }] }, "sendBody": true, "specifyBody": "json", "jsonBody": "={\n \"replyToken\":\"{{ $('Webhook1').item.json.body.events[0].replyToken }}\",\n \"messages\":[\n {\n \"type\": \"text\",\n \"text\": \"【summary】{{ $json.output.summary }} \\n【category】{{ $json.output.category }} \\n【language】{{ $json.output.language }} \\n【關鍵字】{{ $json.output.keywords.join('、') }}\"\n }\n ]\n}", "options": {} }, "type": "n8n-nodes-base.httpRequest", "typeVersion": 4.4, "position": [208, -288], "id": "371bad55-6ecb-4cc0-8ef2-3a8a0d9ffdc7", "name": "HTTP Request1" }, { "parameters": { "assignments": { "assignments": [ { "name": "timestamp", "value": "={{ $now }}", "type": "string" }, { "name": "workflow", "value": "={{ $workflow.name }}", "type": "string" }, { "name": "status", "value": "success", "type": "string" }, { "name": "executionId", "value": "={{ $execution.id }}", "type": "string" }, { "name": "userId", "value": "={{ $('Webhook1').item.json.body.events[0].source.userId || '' }}", "type": "string" }, { "name": "replyToken", "value": "={{ $('Webhook1').item.json.body.events[0].replyToken || '' }}", "type": "string" }, { "name": "input_text", "value": "={{ $('Edit Fields1').item.json.input_text || '' }}", "type": "string" }, { "name": "summary", "value": "={{ $('AI Agent1').item.json.output.summary || '' }}", "type": "string" }, { "name": "category", "value": "={{ $('AI Agent1').item.json.output.category || '' }}", "type": "string" }, { "name": "language", "value": "={{ $('AI Agent1').item.json.output.language || '' }}", "type": "string" }, { "name": "keywords", "value": "={{ $('AI Agent1').item.json.output.keywords ? $('AI Agent1').item.json.output.keywords.join('、') : '' }}", "type": "string" }, { "name": "history_count", "value": "={{ $('Debug History Preview').item.json.history_count || 0 }}", "type": "string" }, { "name": "history_context", "value": "={{ $('Debug History Preview').item.json.history_context || '' }}", "type": "string" } ] }, "options": {} }, "type": "n8n-nodes-base.set", "typeVersion": 3.4, "position": [448, -288], "id": "920dbd89-1a14-47ce-85f2-cf2bd86b93ba", "name": "Prepare Log1" }, { "parameters": { "operation": "append", "documentId": { "__rl": true, "value": "YOUR_GOOGLE_SHEET_ID", "mode": "list", "cachedResultName": "google sheet logging" }, "sheetName": { "__rl": true, "value": "gid=0", "mode": "list", "cachedResultName": "logging" }, "columns": { "mappingMode": "defineBelow", "value": { "timestamp": "={{ $json.timestamp }}", "workflow": "={{ $json.workflow }}", "status": "={{ $json.status }}", "executionId": "={{ $json.executionId }}", "userId": "={{ $json.userId }}", "replyToken": "={{ $json.replyToken }}", "input_text": "={{ $json.input_text }}", "summary": "={{ $json.summary }}", "category": "={{ $json.category }}", "language": "={{ $json.language }}", "keywords": "={{ $json.keywords }}", "history_count": "={{ $json.history_count }}", "history_context": "={{ $json.history_context }}" } }, "options": {} }, "type": "n8n-nodes-base.googleSheets", "typeVersion": 4, "position": [704, -288], "id": "89ea098f-51c3-4aa2-8632-8c0114eb5b92", "name": "Google Sheets Log1" } ], "connections": { "Webhook1": { "main": [[{ "node": "Edit Fields1", "type": "main", "index": 0 }]] }, "Edit Fields1": { "main": [[{ "node": "Get User History", "type": "main", "index": 0 }]] }, "Get User History": { "main": [[{ "node": "Build History Context", "type": "main", "index": 0 }]] }, "Build History Context": { "main": [[{ "node": "Debug History Preview", "type": "main", "index": 0 }]] }, "Debug History Preview": { "main": [[{ "node": "AI Agent1", "type": "main", "index": 0 }]] }, "AI Agent1": { "main": [[{ "node": "HTTP Request1", "type": "main", "index": 0 }]] }, "Google Gemini Chat Model1": { "ai_languageModel": [[{ "node": "AI Agent1", "type": "ai_languageModel", "index": 0 }]] }, "Structured Output Parser1": { "ai_outputParser": [[{ "node": "AI Agent1", "type": "ai_outputParser", "index": 0 }]] }, "HTTP Request1": { "main": [[{ "node": "Prepare Log1", "type": "main", "index": 0 }]] }, "Prepare Log1": { "main": [[{ "node": "Google Sheets Log1", "type": "main", "index": 0 }]] } } } 常見問答 (FAQ)Q:為什麼不直接使用 OpenAI 或 Gemini 內建的 Memory 功能?A:雖然部分 LLM 提供內建對話記憶,但對於自動化流程開發者來說,那就像一個無法受控的「黑盒子」。將 Memory 獨立存放在 Google Sheets 或資料庫中,能讓你隨時監控、修改、除錯(Debug),並確保 AI 不會產生難以追蹤的幻覺(Hallucination)。 Q:Google Sheets 適合拿來當作長期的大型資料庫嗎?A:對於新手測試、輕量級專案或概念驗證(PoC),Google Sheets 是完美且直觀的工具,因為它「視覺化且易懂」。但當你的系統上線且流量增大時,建議將 Logging 系統轉移至 PostgreSQL、MySQL 或 Supabase 等正規關聯式資料庫,以確保效能與穩定性。 Q:什麼時候才真正需要用到 Tool Calling(動態查詢)?A:當用戶的需求不確定或需要跨時間區間搜尋時。例如,當用戶問:「幫我整理『上個月』關於『商業策略』的所有新聞」,這種條件不固定的問題,Workflow 先查(固定 Context)無法預測,此時才適合讓 AI 透過 Tool Calling 自行下達條件去資料庫撈取資料。 Q:為什麼過濾歷史紀錄時要加上 status === 'success' 的條件?A:這是防止「垃圾記憶污染」的關鍵設計。如果 AI 曾因為網路錯誤、格式異常或 Token 不足而失敗,那筆紀錄的 input_text 或 summary 可能是空的或不完整的。把這些「失敗記憶」注入 AI,反而會讓 AI 困惑或輸出錯誤的摘要。只保留 success 的紀錄才能確保記憶品質。 Q:Debug History Preview 節點有什麼用?正式上線後可以刪掉嗎?A:Debug History Preview 是一個「透明窗口」節點,讓你在 n8n 執行面板中可以直接看到「AI 即將收到的歷史資料長什麼樣子」,在開發初期排查問題時非常有價值。正式上線後可保留(幾乎沒有效能開銷),作為日後維護時的快速診斷工具。若確定不再需要除錯,可刪除以精簡流程。 Q:Structured Output Parser 是什麼?為什麼要用它?A:Structured Output Parser 的作用是強制 AI 必須按照你定義的 JSON Schema 格式輸出,而不是隨意回傳文字。如果 AI 輸出不符合格式(例如缺少 summary 欄位),n8n 會自動觸發重試。這對於後續的 keywords.join('、') 等欄位操作至關重要——若格式不穩定,後面的節點就會直接報錯。 Q:category 欄位為什麼要用 enum 限制固定選項?A:這是維持資料一致性的核心手段。如果不加 enum,AI 可能今天回傳「AI 工具」、明天回傳「人工智慧工具」、後天回傳「AI Tools」,同一個意思三種寫法,導致你在 Google Sheets 篩選或後續統計時出現資料亂象。使用 enum: ["AI工具", "程式開發", "商業", "教育", "其他"] 強制統一格式,是設計健壯資料管線的基本功。 Q:為什麼要在 Log 中記錄 history_count 和 history_context?A:這是為了讓未來的你能「重現 AI 當時的視角」。假設某次 AI 回傳了奇怪的摘要,你打開 Log 可以直接看到:「當時 AI 帶了幾筆記憶(history_count)」以及「那些記憶的完整內容是什麼(history_context)」。沒有這兩個欄位,你只能看到輸出結果,完全無法判斷問題出在 Prompt、歷史資料,還是 AI 本身。 Q:Prompt 中說「若與本次輸入無關,請以本次輸入為主」,這樣真的有效嗎?A:這條規則能降低 AI 誤用歷史資料的機率,但不能完全保證。因此 System Message 中同時加入了「不可把過去內容誤當成這次輸入內容」的明確規則,雙重防護。若主題相近偶爾仍可能混淆,此時可考慮在 Prompt 中加入更明確的分隔標記(如 ---歷史紀錄開始---)來強化區隔。 Q:replyToken 是什麼?為什麼要記錄在 Log 裡?A:LINE 的 replyToken 是一個一次性、有時效的 Token(約 30 秒有效),用來對應「這次訊息的回覆權限」。HTTP Request 節點使用它呼叫 LINE Reply API 回傳訊息給使用者。記錄在 Log 中,是為了當回覆失敗時,你可以確認 Token 是否正確傳遞(雖然過了時效無法重新使用,但至少能確認資料流程正確)。 Q:如果使用者是第一次傳訊息(沒有任何歷史紀錄),流程會出錯嗎?A:不會。Build History Context 節點在 filtered.length 為 0 時,會將 history_context 設為 '無歷史紀錄' 字串,並將此值傳給 AI Prompt。AI 收到這個明確的提示後,會直接以本次輸入為唯一依據進行分析,完全不受影響。

  • article-n8n 串接 Gemini API:從基礎節點到 AI Agent 結構化輸出 | (EP.6) n8n 自動化 API 串接教學

    2026/3/30

    AI自動化 Gemini n8n API串接
    n8n 串接 Gemini API:從基礎節點到 AI Agent 結構化輸出 | (EP.6) n8n 自動化 API 串接教學
    在 n8n 的自動化工作流中,許多人習慣使用 ChatGPT 的 AI 模型。然而,隨著 Google Gemini 系列模型的強勢崛起(尤其是具備免費額度的優勢),越來越多開發者與行銷人開始轉向使用 Gemini 來節省成本並維持高效的運算能力。 本文將帶您手把手實戰,從申請 Gemini API 密鑰開始,完整解析在 n8n 中串接 Gemini 的兩種核心做法:基礎節點搭配 JavaScript 解析,以及免寫程式的 AI Agent 結構化輸出。 如何快速取得 Google Gemini API 密鑰?要讓 n8n 成功呼叫 Gemini,我們首先需要前往開發者後台申請 API Key。 進入開發者平台:前往 Google AI Studio。 尋找申請入口:在左側選單點擊 Get API key。 建立密鑰:點選 Create API key,系統會要求您選擇或建立一個 Google Cloud 專案(Project)。如果您之前尚未建立過,可以點擊 Create project 來創建一個新專案。 選擇計費方案: 若您有綁定信用卡並啟用了付費帳單,系統可能會預設給予 Tier 1 (Postpay) 權限,這在需要呼叫「生成圖片」等進階模型時非常有用。 若您想完全免費使用,請確保專案的計費狀態設定為 Free tier,這對於一般的文本處理與自動化任務已經非常夠用。 複製密鑰:成功生成後,將這串 API Key 複製下來,準備貼到 n8n 的憑證(Credentials)設定中。 實戰方法一:透過「Message a Model」節點與 JS 解析 JSON在 n8n 中,最直覺的呼叫方式是使用原生的 Google Gemini 節點(Message a Model 操作)。但在實際應用場景中,我們通常會要求 AI 輸出特定的 JSON 格式(例如:分類、摘要、關鍵字),以便後續串接 LINE Bot 或寫入資料庫。 步驟與痛點解析 建立 Credentials:在 Message a Model 節點中,新增 Google Gemini(PaLM) API account,將剛剛複製的 API Key 貼入並儲存。 設定 Prompt 與 System Message:在 Node 設定中,您可以要求它輸出 JSON,並開啟 Output Content as JSON 選項。 痛點(為何需要 Code 節點):即使勾選了輸出 JSON,Gemini 原生節點回傳的資料結構往往被包裝在一大包 JSON 陣列內(無法像 ChatGPT 節點那樣直接完美對應輸出規格)。 JavaScript 解析解法:為了解決這個問題,我們必須在後面加上一個 Code 節點,透過 JavaScript 將純文字轉換並萃取出我們需要的欄位。 Code 節點解析範例: 12345678910111213141516const raw = $json.content?.parts?.[0]?.text ?? '';let parsed;try { parsed = JSON.parse(raw);} catch (error) { parsed = { summary: '', category: '其他', keywords:[], language: 'zh-TW' };}return [{ json: parsed }]; 透過上述程式碼,我們才能確保後續的 HTTP Request 節點(例如推播 LINE 訊息)能正確讀取到 summary、category 與 keywords 等變數。這對於不熟悉程式碼的用戶來說,門檻相對較高。 實戰方法二:使用 AI Agent 輕鬆達成結構化輸出(專家推薦)為了避開繁瑣的程式碼解析,強烈建議使用 n8n 的 AI Agent 架構。透過「Agent + Model + Output Parser」的黃金三角,您可以讓系統自動將 Gemini 的輸出鎖定在嚴格的 JSON 規格內。 完美輸出的配置步驟: 加入 AI Agent 節點:在畫布中新增 AI Agent,並將輸入源連接至前置節點。 **連接語言模型 (Language Model)**:在 Agent 的 Model 輸入端,掛載 Google Gemini Chat Model 節點,並選定模型(如 gemini-2.5-flash)。 **強制結構化輸出 (Output Parser)**: 開啟 Agent 節點內的 Require Specific Output Format。 在 Parser 輸入端掛載 Structured Output Parser 節點。 在 Parser 內直接定義您期待的 JSON Schema(如下方範例)。 JSON Schema 定義範例: 1234567891011121314151617{ "type": "object", "properties": { "summary": { "type": "string" }, "category": { "type": "string", "enum":["AI工具", "程式開發", "商業", "教育", "其他"] }, "keywords": { "type": "array", "items": { "type": "string" } }, "language": { "type": "string" } }, "required":["summary", "category", "keywords", "language"], "additionalProperties": false} 使用 AI Agent 搭配 Structured Output Parser 的最大優勢在於:完全免寫任何一行解析用的 JavaScript 程式碼!系統會嚴格逼迫 Gemini 依照您提供的 Schema 回傳乾淨、格式化好的 JSON,極大地提升了工作流的穩定性與開發效率。 附錄:完整 n8n 工作流 JSON您可以直接複製以下 JSON 匯入您的 n8n 畫布中進行測試: { "nodes":[ { "parameters": { "promptType": "define", "text": "=請讀取以下內容,輸出摘要、主題分類、3 個關鍵字。\n\n內容:\n{{$json.input_text}}", "hasOutputParser": true, "options": { "systemMessage": "你是資料整理助手。\n\n規則:\n1. 使用繁體中文。\n2. 不要捏造未提供的資訊。\n3. 請只輸出 JSON。\n4. 欄位必須包含 summary、category、language。\n5. 若資訊不足,也必須輸出合法 JSON。" } }, "type": "@n8n/n8n-nodes-langchain.agent", "typeVersion": 3.1, "position":[352, -352], "name": "AI Agent" }, { "parameters": { "options": {} }, "type": "@n8n/n8n-nodes-langchain.lmChatGoogleGemini", "typeVersion": 1, "position":[288, -144], "name": "Google Gemini Chat Model" }, { "parameters": { "schemaType": "manual", "inputSchema": "{\n \"type\": \"object\",\n \"properties\": {\n \"summary\": { \"type\": \"string\" },\n \"category\": {\n \"type\": \"string\",\n \"enum\":[\"AI工具\", \"程式開發\", \"商業\", \"教育\", \"其他\"]\n },\n \"keywords\": {\n \"type\": \"array\",\n \"items\": { \"type\": \"string\" }\n },\n \"language\": { \"type\": \"string\" }\n },\n \"required\":[\"summary\", \"category\", \"keywords\", \"language\"],\n \"additionalProperties\": false\n}" }, "type": "@n8n/n8n-nodes-langchain.outputParserStructured", "typeVersion": 1.3, "position":[544, -128], "name": "Structured Output Parser" } ], "connections": { "Google Gemini Chat Model": { "ai_languageModel": [[{"node": "AI Agent","type": "ai_languageModel","index": 0}]] }, "Structured Output Parser": { "ai_outputParser": [[{"node": "AI Agent","type": "ai_outputParser","index": 0}]] } } } 常見問答 (FAQ)Q:為何在 n8n 中選擇使用 Gemini 而不用 ChatGPT?A:主要優勢在於成本與免費額度。Google AI Studio 提供了非常慷慨的 Free tier(免費層),對於剛開始建置自動化工作流、或需求量在中小型範圍的用戶來說,可以大幅降低 API 的呼叫成本,同時 Gemini 2.5 Flash 處理速度極快,非常適合自動化場景。 Q:為什麼使用基礎的「Message a Model」節點還需要額外寫程式碼?A:因為基礎的 LLM 節點雖然能設定輸出 JSON,但往往會包裝在複雜的結構層級中,無法直接無縫對接下一個節點的變數欄位。透過加入 JavaScript Code 節點進行 JSON.parse() 解析,才能精準拆解出所需的鍵值(Keys),讓後續推播或寫入資料庫的動作不出錯。 Q:如果不擅長寫程式,有什麼替代方案嗎?A:強烈建議採用本文示範的 AI Agent + Structured Output Parser 方法。這種架構屬於「宣告式」操作,您只需要在介面上填寫 JSON 格式規範(Schema),n8n 與 AI 就會自動溝通並轉換出完美對應的資料格式,徹底免除撰寫解析程式碼的困擾。 Q:Google Gemini 的免費額度真的夠做 n8n 自動化嗎?A:對大多數入門情境來說,通常夠用。若您的工作流主要是做摘要、分類、標籤整理、客服訊息初步回覆,Free tier 往往已足以支撐測試與小量正式使用。不過如果您開始大量處理長文本、頻繁排程,或同時有多個工作流共用同一組 API Key,就需要留意速率限制與用量上限。最穩健的做法是先用免費層把流程跑通,再依實際流量決定是否升級付費方案。 Q:什麼情況下該用「Message a Model」,什麼情況下該直接改用 AI Agent?A:如果您的任務只是單純的一進一出,例如摘要、翻譯、分類、改寫,且後面只要接一個 Code 節點就能順利整理資料,那麼 Message a Model 通常更簡單、成本也更低。但如果您已經明確知道後面要依賴固定欄位,例如 summary、category、keywords 去串接 LINE、Email、Sheets 或資料庫,那麼直接使用 AI Agent + Structured Output Parser 會更穩定,後續維護也更省力。 Q:為什麼我明明要求 Gemini 輸出 JSON,結果還是會多出說明文字或格式錯誤?A:因為單靠 Prompt 約束,模型仍可能在某些情況下額外補充說明,尤其當輸入內容較長、規則較複雜,或模型判斷需要「解釋」時更容易發生。這也是本文會把兩種方法拆開講的原因:如果您走基礎節點路線,就要準備用 Code 節點做容錯解析;如果您要的是更高穩定性,就應直接改走 Structured Output Parser,把格式控制交給系統,而不是只靠文字要求。 Q:匯入本文附錄的工作流 JSON 後,還需要手動修改哪些地方?A:需要,因為附錄的 JSON 是示範骨架,不是可直接上線的最終版本。至少要檢查三個地方:第一,Google Gemini Chat Model 是否已綁定您的 Gemini API Credential;第二,前置節點是否真的有提供 input_text 這個欄位;第三,後續節點若要讀取 Agent 的結果,是否使用正確路徑,例如 output.summary、output.category、output.keywords。如果其中任何一個欄位名稱對不上,流程就很容易出現空值或報錯。 Q:如果我的 JSON Schema 定義得太嚴格,會不會反而讓模型常常失敗?A:會有這種可能,尤其當您同時要求太多欄位、限制太多列舉值,或輸入內容本身資訊不足時。實務上建議 Schema 先維持「夠用就好」:只保留後續流程真正會用到的欄位,避免一開始就設計過多可有可無的結構。對自動化工作流來說,穩定輸出 4 個必要欄位,通常比一次追求 10 個欄位更有價值。 Q:如果後面我要把 Gemini 的結果寫進 Google Sheets、Notion 或資料庫,最重要的注意事項是什麼?A:最重要的是欄位名稱與值域要先標準化。不要讓模型今天輸出 AI工具、明天輸出 AI 工具、後天又輸出 AI Tool。一旦分類名稱不一致,後面做搜尋、篩選、儀表板統計都會變得很麻煩。因此像本文示範的 enum 設計就非常重要,它不是為了形式好看,而是為了確保資料落地後仍然可被穩定使用。

  • article-如何使用 n8n 串接 Gmail?Google OAuth2 授權設定全攻略 | (EP.5) n8n 自動化 API 串接教學

    2026/3/28

    AI自動化 n8n API串接 Google
    如何使用 n8n 串接 Gmail?Google OAuth2 授權設定全攻略 | (EP.5) n8n 自動化 API 串接教學
    為什麼這篇設定很重要?在 n8n 的自動化流程中,Gmail 常常不是單獨存在,而是扮演「最後通知出口」的角色。你可能會先從 LINE、表單、Webhook 或資料庫拿到資料,再交給 AI 做整理,最後自動寄出摘要通知。這也是很多人卡關的地方:流程節點都接好了,結果 Gmail 節點始終無法授權。 Google 已經不建議用帳號密碼直接讓第三方服務寄信,因此在 n8n 中要使用 Gmail,標準做法就是透過 Google Cloud Console 建立 OAuth2 授權,再把 Client ID 與 Client Secret 填回 n8n。 這個設定一旦完成,未來你不只可以用在 Gmail,也能延伸到 Google Calendar、Google Drive、Google Sheets 等常見 Google 服務。更重要的是,當你做 AI 自動化工作流時,這組憑證就是能不能穩定落地的關鍵一步。 實用資源連結: Google Cloud Platform Google Cloud Console 這篇文章會完成什麼?本文會帶你完成兩件事: 在 Google Cloud 建立可供 n8n 使用的 Gmail OAuth2 憑證。 把這組憑證套用到一個實戰工作流:LINE Webhook -> AI Agent -> LINE Reply + Gmail 通知 根據你提供的工作流 JSON,這條流程的核心邏輯如下: Webhook:接收 LINE Bot 傳入的 webhook 事件。 If:確認收到的是文字訊息,而不是貼圖、圖片或其他事件。 Edit Fields:把 body.events[0].message.text 整理成 input_text。 AI Agent:交給 OpenAI 模型做摘要、分類、關鍵字萃取。 Structured Output Parser:限制輸出格式必須是固定 JSON。 HTTP Request:呼叫 LINE Reply API,把摘要結果回傳給使用者。 Gmail:再寄一封 Email,把摘要結果與原始文字同步通知給自己或團隊。 也就是說,Gmail OAuth2 不是孤立設定,而是整條 AI 通知流程的一部分。 第一步:如何在 Google Cloud Console 建立專案與啟用 API?要讓 n8n 可以代表你操作 Gmail,第一件事就是在 Google Cloud 建立專案,並啟用對應 API。 登入平台: 前往Google Cloud Console 並使用你的 Google 帳號登入。(建議預先綁定實體信用卡以利通過身分驗證,避免使用易遭拒絕的簽帳金融卡)。 建立新專案: 點擊左上角專案選單,選擇「**新增專案 (New Project)**」。將專案命名為易於辨識的名稱(例如:n8n-try),若無所屬機構可選擇「無組織」,接著點擊「建立」。 進入 API 服務: 專案建立完成後,展開左側導覽選單,選擇「API 和服務」>「已啟用的 API 和服務」(建議將此選項加入星號釘選,未來會經常使用)。 啟用所需 API: 點擊上方的「**+ 啟用 API 和服務**」,在搜尋框中尋找並啟用以下服務: Gmail API (本次寄信必備) Google Calendar API (建議一併開啟) Google Drive API (建議一併開啟) 第二步:如何設定 OAuth 同意畫面與新增測試使用者?在取得金鑰之前,還要先設定 OAuth 同意畫面。這個畫面就是你在 n8n 點擊 Sign in with Google 時,Google 會跳出來要求你確認授權的那一頁。 設定同意畫面: 在「API 和服務」選單中點擊「OAuth 同意畫面」。 選擇使用者類型: 一般個人用戶請選擇「**外部 (External)**」,點擊建立。 填寫應用程式資訊: 應用程式名稱:輸入如 n8n-try。 使用者支援電子郵件:選擇你目前的 Google 帳號。 開發人員聯絡資訊:同樣填入你的 Google 帳號。 新增測試使用者 (非常重要):因為我們的應用程式仍在「測試中 (Testing)」狀態,並未經過 Google 官方審核發布,只有被加入「測試使用者」名單的帳號才能順利授權。 在「測試使用者」區塊,點擊「**+ ADD USERS**」。 輸入你即將用來「發送 Email」的 Google 帳號並儲存。 第三步:如何取得 Client ID 與密鑰 (Secret)?前面都設定好後,現在就可以正式建立 n8n 要使用的 OAuth2 憑證。 建立憑證: 點擊左側選單的「憑證」,接著點擊上方「**+ 建立憑證」,選擇「OAuth 用戶端 ID**」。 設定應用程式類型: 選擇「**網頁應用程式 (Web application)**」,並輸入名稱(如:n8n-try)。 設定重新導向 URI (Redirect URI): 回到你的 n8n 介面,新增一個 Gmail 節點,動作選擇 Send a message。 在認證 (Credential) 欄位選擇 Create new credential。 複製 n8n 介面上提供的 OAuth Redirect URL(例如:https://n8n-try.zeabur.app/rest/oauth2-credential/callback)。 將此網址貼回 Google Cloud 憑證設定的「已授權的重新導向 URI」欄位中(注意:網址結尾不可包含斜線 /)。 取得金鑰: 點擊「建立」後,系統會彈出視窗顯示你的 用戶端 ID (Client ID) 與 **用戶端密鑰 (Client Secret)**。請將這兩組字串妥善複製並保存。 專家提示: 密鑰 (Secret) 只會在第一次建立時完整顯示,請務必妥善備份。若不慎遺失或外洩,可回到憑證管理頁面刪除舊密鑰並重新生成。 第四步:如何回到 n8n 建立 Gmail Credential?Google 端的工作完成後,接下來就是把這組 OAuth2 憑證填回 n8n。 輸入憑證資訊: 回到 n8n 的 Credential 設定畫面,將剛剛取得的 Client ID 與 Client Secret 貼入對應欄位,點擊「Sign in with Google」。 完成安全授權: 登入你設定為「測試使用者」的 Google 帳號。 系統會出現「這個應用程式未經 Google 驗證」的警告。這是正常現象,請點擊左下方的「繼續 / 進階」,再點擊「**前往 n8n-try (不安全)**」。 勾選「全選」賦予讀寫信件的權限,最後點擊「繼續」,若顯示 Connection successful 即代表串接成功! 命名 Credential: 建議不要直接用預設名稱,可命名為像 Gmail (n8n-try) 或 Gmail (LINE 摘要通知),之後多個專案並存時比較好管理。 第五步:如何把 Gmail 應用到這個 LINE + AI 工作流?當 Credential 建好後,就可以把它接到你這份工作流裡的 Gmail 節點。你提供的 JSON 使用的是 Send a message1 節點,實際設定重點如下。 1. 先理解這條工作流的資料流這份工作流的順序是: Webhook -> If -> Edit Fields -> AI Agent -> HTTP Request + Gmail 其中最關鍵的資料轉換有兩段: Edit Fields 把 LINE 訊息抽成 input_text AI Agent 透過結構化輸出,回傳 summary、category、keywords、language 也因為如此,Gmail 節點裡的主旨與內文,就可以直接引用 AI Agent 的輸出欄位。 2. Gmail 節點的設定方式在 Gmail 節點中,至少要確認以下欄位: Resource / Operation: Message / Send Credential: 選擇剛剛建好的 Gmail OAuth2 憑證 To: 你的收件信箱,或團隊共用信箱 Email Type: Text 你提供的範例主旨使用這段 Expression: 1LINE 摘要通知|{{$json.output.category}} 信件內容則把 AI 整理後的資料與原始訊息一起寄出: 12345678910111213141516171819您好,已收到一則新的 LINE 文字內容,並完成自動整理如下:【摘要】{{$json.output.summary}}【分類】{{$json.output.category}}【關鍵字】{{$json.output.keywords.join('、')}}【語言】{{$json.output.language}}--------------------【原始內容】{{$('Edit Fields').item.json.input_text}} 這種寫法很適合通知型工作流,因為你不只會收到 AI 的摘要結果,也能同步保留原始內容做交叉檢查。 3. 為什麼這樣設計很實用?這份流程其實同時做了兩件事: 對外:透過 HTTP Request 呼叫 LINE Reply API,把摘要立即回覆給使用者 對內:透過 Gmail 把摘要寄給自己或團隊,形成通知與留存紀錄 如果你未來想把這條流程改造成客服摘要、業務回報、報名表單通知、或內部知識蒐集,這個架構都很容易擴充。 第六步:AI Agent 與 Structured Output 在這個流程中扮演什麼角色?這篇主題雖然是 Gmail OAuth2,但如果不了解前面的 AI 結構,很多人會在 Gmail 節點誤抓欄位,導致信件主旨或內文出現空值。 1. Edit Fields 做了什麼?Edit Fields 節點把原始 LINE Webhook 內容: 1{{ $json.body.events[0].message.text }} 整理成單一欄位: 1input_text 這樣做的好處是提示詞更乾淨,也比較不容易在後面節點重複寫深層路徑。 2. AI Agent 的提示詞邏輯你提供的 AI Agent 使用的是以下任務設定: 1234請讀取以下內容,輸出摘要、主題分類、3 個關鍵字。內容:{{$json.input_text}} 而 System Message 則限制模型: 使用繁體中文 不要捏造資訊 只輸出 JSON 必須包含 summary、category、language 資訊不足也要輸出合法 JSON 3. Structured Output Parser 為什麼重要?因為後面的 LINE Reply 與 Gmail 都不是要讀一大段自由文字,而是要讀固定欄位。 你的 JSON Schema 其實已經把這件事做得很完整: summary:摘要文字 category:限定在 AI工具、程式開發、商業、教育、其他 keywords:字串陣列 language:語言判斷 這代表 Gmail 節點可以穩定用下面這些欄位,而不是碰運氣讀模型輸出: `{{$json.output.summary}}` `{{$json.output.category}}` `{{$json.output.keywords.join('、')}}` `{{$json.output.language}}` 第七步:正式測試前,建議先檢查哪些地方?在你按下 Execute workflow 之前,建議先做一次快速檢查: Google Cloud 的 OAuth 同意畫面是否已加入正確的測試使用者。 Gmail Credential 中的 Client ID、Client Secret 是否來自同一個專案與同一組憑證。 OAuth Redirect URL 是否完整貼入 Google Cloud,而且沒有多餘斜線。 Gmail 節點是否真的選到正確的 Credential,而不是舊的或失效的憑證。 Gmail 節點中的 Expression 是否抓的是 AI Agent 的 output 欄位。 keywords 若要顯示成文字,是否已用 .join('、') 轉成字串。 If 節點是否限制只有 message.type = text 才往下走,避免貼圖或圖片事件直接報錯。 如果這幾個地方都正確,通常整條流程就能順利跑起來。 常見問答 (FAQ)Q:註冊 Google Cloud Platform (GCP) 需要綁定信用卡嗎?會不會被亂扣款?A:Google Cloud 通常會要求綁定信用卡做身分驗證,這是平台的常見流程。若你只是用來做 Gmail OAuth、Calendar 或 Drive 這類基礎串接,而且沒有另外啟用付費資源,通常不會因為這篇教學本身產生額外高額費用。不過還是建議你定期查看帳單與專案啟用服務,避免把測試專案長期放著不管。 Q:在 n8n 點擊 Sign in with Google 時,出現「Access denied」或「此應用程式尚未完成驗證」怎麼辦?A:最常見有兩種原因: 你用來登入授權的 Google 帳號,沒有被加入 OAuth 同意畫面的「測試使用者」 你登入的帳號和 Google Cloud 專案內設定的測試帳號不是同一個 先回到 Google Cloud 的「OAuth 同意畫面」,確認測試使用者名單,再重新回 n8n 授權一次。 Q:為什麼我明明已經拿到 Client ID 和 Client Secret,n8n 還是授權失敗?A:這通常不是金鑰本身錯,而是 Redirect URI 不一致。請重新比對: n8n Credential 畫面顯示的 OAuth Redirect URL Google Cloud 憑證中的「已授權的重新導向 URI」 兩邊只要少一個字、多一個 /、或網域不同,都可能導致授權失敗。 Q:Gmail 節點已經成功連上,但寄信時仍然失敗,應該先檢查哪裡?A:建議先檢查這四個點: Gmail 節點是否真的選到正確的 OAuth2 Credential。 To 欄位是否為合法 Email。 主旨與內文中的 Expression 是否抓得到值。 前一個 AI Agent 是否真的有成功輸出 output.summary、output.category 等欄位。 很多人以為是 Gmail 壞掉,實際上是前面節點沒有值,導致寄信內容組不起來。 Q:這份工作流中,為什麼 Gmail 節點要用 `{{$json.output.summary}}`,而不是 `{{$json.summary}}`?A:因為你這份流程使用的是 AI Agent + Structured Output Parser。在這種情況下,AI 的結構化輸出通常會包在 output 物件裡,所以 Gmail 與 HTTP Request 要抓的是: `{{$json.output.summary}}` `{{$json.output.category}}` `{{$json.output.keywords}}` `{{$json.output.language}}` 如果你直接寫 `{{$json.summary}}`,通常會抓不到值。 Q:keywords 是陣列,直接放到 Gmail 內文裡可以嗎?A:技術上可以,但顯示通常不夠友善。比較建議轉成一般文字,例如: 1{{$json.output.keywords.join('、')}} 這樣收件者看到的會是「AI、自動化、LINE Bot」這種格式,而不是原始陣列樣式。 Q:如果 LINE 傳來的是貼圖、圖片或非文字事件,這條流程會怎麼樣?A:你提供的工作流已經先用 If 節點判斷: 1{{ $json.body.events[0].message.type }} === text 這是必要的,因為後面的 Edit Fields 會直接讀 message.text。如果沒有先過濾,遇到非文字事件時就可能報錯。 Q:為什麼這個流程同時要回 LINE,又要寄 Gmail?不是重複通知嗎?A:兩者用途不同: LINE Reply 是給最終使用者的即時回覆 Gmail 是給自己或團隊的內部通知與紀錄留存 如果你之後想追蹤哪些訊息被分類成什麼主題、或想保留原始內容做人工覆核,Email 留存會非常實用。 Q:如果我的 Client Secret 不小心外洩了,應該怎麼補救?A:請立刻回到 Google Cloud Console 的「API 和服務」>「憑證」,找到對應的 OAuth 用戶端,重新產生新的密鑰,並在 n8n 更新成新的 Credential 設定。確認新密鑰可正常授權後,再停用或刪除舊密鑰。只要你懷疑有外洩,就不要繼續使用原本那組。 Q:這組 Google OAuth2 設定之後只能拿來寄 Gmail 嗎?A:不是。只要同一個 Google Cloud 專案有啟用對應 API,你之後通常還可以延伸用到 Google Calendar、Google Drive、Google Sheets 等服務。不過每種服務在 n8n 端可能會有不同的權限範圍與 Credential 類型,實作時還是要分開確認。