iT邦幫忙

2025 iThome 鐵人賽

DAY 9
0

今天的目標與挑戰

昨天成功將 AI 處理的結果寫入 Notion,今天的目標不只是要加入 LINE 通知,而且我希望能整個系統架構進行一次最佳化,解決在本地執行 AI 模型時遇到的效能瓶頸。

  • 改造工作流,建立非同步處理架構,使其能立即回應前端請求,解決超時問題
  • 將兩次 AI 呼叫合併為一次,提升處理效率並降低錯誤率
  • 整合 LINE 即時通知,採用 LINE Messaging API
  • 為不同平台 Notion 和 LINE 準備適合的資料格式
  • 加入自動重試機制,應對外部服務的臨時性故障

Step 1:建立 LINE Messaging API 服務並取得 Token

首先要先在 LINE 的開發者平台建立一個用於發送訊息的 Bot

1-1 註冊/登入 LINE Developers 帳戶

  1. 前往 LINE Developers 官網。
  2. 使用個人 LINE 帳號登入後,首次登入會要求建立 LINE 開發者帳號。
    Create LINE Developers Account

1-2 建立 Provider

Provider 是管理 Channel 的單位,可以想像成是「開發團隊」或「公司」。

  1. 登入後,在 LINE Developers Console 主控台的「Providers」區塊點擊「Create」。
  2. 填寫 Provider 名稱,像是 GIGI 工作室,然後點擊「Create」。

1-3 建立 Messaging API Channel

Channel 就是我們要建立的 Bot

  1. 在剛建立的 GIGI 工作室 Provider 內,點擊「Create a Messaging API channel」。
  2. 點擊「Create a LINE Official Account」按鈕。
    Create a LINE Official Account
    頁面會跳轉至「LINE Official Account Manager」的建立官方帳號頁面。
    建立官方帳號M2A Agent Bot
  3. 填寫官方帳號的基本資訊,也就是指我們的 Bot
    • 帳號名稱M2A Agent Bot
    • 電子郵件帳號:聯絡的 Email
    • 公司名稱:因為是選填,所以我沒有填
    • 業種:大分類與小分類我都選其他。
  4. 勾選同意相關條款,然後點擊「Create」。
  5. 完成建立後,會進入 Bot 的主頁面。

1-4 確認 Messaging API 已啟用

  1. Bot 的主頁面,點擊右上角的「設定」。
    M2A Agent Bot Home Page

  2. 在設定頁面中,點擊「Messaging API」。
    M2A Agent Bot Settings

  3. 會看到頁面顯示「狀態」為「使用中」,這表示官方帳號已經是一個可以透過 API 操作的 Channel。
    M2A Agent Bot Messaging API

1-5 取得 Channel Access Token

回到開發者網站 LINE Developers

  1. 回到 LINE Developers 官網並登入。
  2. GIGI 工作室 Provider 下,可以看到剛剛建立的 M2A Agent Bot 點擊進入 Channel 。
  3. 在 Channel 設定頁面中,點擊上方標籤頁的「Messaging API」。
    M2A Agent Bot Messaging API settings
  4. 在此頁面往下滑,會看到「Channel access token」的區塊,點擊「Issue」按鈕。
  5. 系統會生成一長串的「Token」,請將它複製妥善保存
    M2A Agent Bot Messaging API Channel access token

Step 2:架構非同步工作流

回到 n8n M2A Agent 的工作流,將工作流改造為非同步模式,以解決前端請求超時的問題。

2-1 設定「Respond to Webhook」節點

  1. 將「Respond to Webhook」節點,從最後面移動至「Webhook」節點後面
  2. 確保 Respond With 設定為 JSON,並將 Response Body 重新修改為以下內容
{
  "status": "processing_started",
  "message": "M2A Agent has received the request and is processing it in the background. Notification will be sent via LINE."
}

Step 3:建立 LINE Messaging API 認證

3-1 建立 LINE Messaging API 認證

使用 HTTP Request 節點來發送 API 請求,因此需要先設定好認證。

  1. 在 n8n 裡點擊左上角的加號「+」,再點擊「Credentials」。
  2. 搜尋並選擇「Header Auth」。
    Add new credential Header Auth
  3. 填寫認證資訊:
    • Credential NameLINE M2A Agent Credential
    • NameAuthorization (這是 HTTP Header 的欄位名稱,必須完全符合)
    • ValueBearer CHANNEL_ACCESS_TOKEN
      (將 CHANNEL_ACCESS_TOKEN 替換為在 Step 1.5 取得的「Token」。Bearer 後面有一個空格)。
      LINE M2A Agent Credential

Step 4:Markdown 轉純文字的格式化處理

為了讓 LINE 通知訊息乾淨易讀,必須在發送前,將 AI 生成的 Markdown 內容轉換為純文字。

4-1 新增格式化處理節點

  1. 在 Notion 的「寫入會議紀錄」節點之後,新增一個「Code」節點。
  2. 重新命名為「Markdown 格式化處理」。
  3. Mode: 選擇 Run Once for All Items
  4. Language: 選擇 JavaScript

4-2 撰寫格式化程式

const item = $input.item;

function markdownToPlainText(markdown) {
  if (!markdown || typeof markdown !== 'string') return '';
  let text = markdown;
  text = text.replace(/(\*|_)(.*?)\1/g, '$2');
  text = text.replace(/^#{1,6}\s+/gm, '');
  text = text.replace(/(\*\*|__)(.*?)\1/g, '$2');
  text = text.replace(/~~(.*?)~~/g, '$1');
  text = text.replace(/\[([^\]]+)\]\([^\)]+\)/g, '$1');
  text = text.replace(/!\[.*?\]\(.*?\)/g, '');
  text = text.replace(/^\s*[\*\-\+]\s+/gm, '• ');
  text = text.replace(/^\s*\d+\.\s+/gm, '');
  text = text.replace(/^(---|\*\*\*|___)\s*$/gm, '');
  text = text.replace(/``````/g, '');
  text = text.replace(/`([^`]+)`/g, '$1');
  text = text.replace(/\n{3,}/g, '\n\n');
  return text.trim();
}

const summary = $('AI 摘要與任務提取').item.json.summary;
const tasks = $('AI 摘要與任務提取').item.json.tasks;
const notionUrl = $('寫入會議紀錄').item.json.url;

item.json.summary = summary;
item.json.tasks = tasks;

const lineMessageText = `會議處理完成通知

- 專案:GIGI 工作室內部專案
- 日期:${new Date().toLocaleDateString('zh-TW')}
- Notion 頁面:${notionUrl}

--- 會議摘要 ---
${markdownToPlainText(summary)}

--- 行動任務 ---
${markdownToPlainText(tasks)}`;

item.json.lineApiPayload = {
  "messages": [
    { "type": "text", "text": lineMessageText }
  ]
};

return item;

Step 5:整合 LINE 節點到 n8n 工作流

將 LINE 通知功能加入到 M2A Agent 工作流。

5-1 新增並設定 HTTP Request 節點

  1. 回到 M2A Agent 工作流,在「Markdown 格式化處理」節點之後,新增一個「HTTP Request」節點。
  2. 將節點重新命名為「發送 LINE 通知」。
  3. 設定節點參數:
    • MethodPOST
    • URLhttps://api.line.me/v2/bot/message/broadcast
      (使用 broadcast API,向所有加入此機器人的好友發送訊息)
    • AuthenticationGeneric Credential Type
      • Generic Auth TypeHeader Auth
        • Header Auth: 選擇剛剛建立的 LINE M2A Agent Credential
    • Send Body: 開啟
    • Body Content TypeJSON
    • Specify Body: 在右側將模式從 Fixed 切換為 Expression單行表達式輸入框{{ $('Markdown 格式化處理').item.json.lineApiPayload }}
    • Settings 分頁:切換到「Settings」分頁,開啟「Retry on Fail」,並設定 Retries3 次,Retry Interval60 秒。

Step 6:最佳化 AI 核心

「AI 摘要與任務提取」節點是整個流程的大腦,我們將其最佳化為一次呼叫,以提升處理效率,且可以取得所有需要的資訊,並加入錯誤處理。

將「AI 摘要與任務提取」節點內的內容修改為以下的內容

const webhookData = $input.first().json.body;
const inputText = webhookData.text;
const instruction = webhookData.instruction || "請幫我整理出重點並提取任務";
console.log('開始處理 AI 摘要與任務提取 (合併模式)...');

// 一次請求,同時取得摘要與任務
async function generateSummaryAndTasks(text) {
  const payload = {
    model: "qwen2.5-taiwan-7b-instruct-i1",
    messages: [
      {
        role: "system",
        content: "你是一個專業的會議記錄分析師。你的任務是從提供的文本中,生成一份包含摘要和行動任務的 JSON 物件。這個 JSON 物件必須且只能包含兩個鍵:'summary' 和 'tasks'。'summary' 的值是會議摘要的字串,'tasks' 的值是行動任務的字串。請確保在這兩個字串的值中使用 Markdown 語法來格式化內容 (例如 **粗體** 和項目符號)。不要在你的回應中加入任何額外的解釋或 Markdown 程式碼區塊,直接回傳純粹的 JSON 物件。"
      },
      {
        role: "user",
        content: `請根據上述指令,分析以下會議內容:\n\n${text}`
      }
    ],
    temperature: 0.5,
    max_tokens: 1024
  };

  try {
    const response = await this.helpers.httpRequest({
      method: 'POST',
      url: 'http://host.docker.internal:1234/v1/chat/completions',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify(payload),
      timeout: 300000
    });
    
    const responseData = typeof response === 'string' ? JSON.parse(response) : response;
    
    if (responseData.choices && responseData.choices[^0] && responseData.choices[^0].message) {
        let aiContentString = responseData.choices[^0].message.content;
        
        const jsonMatch = aiContentString.match(/``````/);
        if (jsonMatch && jsonMatch[^1]) {
          aiContentString = jsonMatch[^1];
        }

        const structuredResult = JSON.parse(aiContentString);
        return structuredResult;

    } else {
        throw new Error('合併API回應格式異常');
    }

  } catch (error) {
    return { summary: `處理失敗:${error.message}`, tasks: "因處理失敗,無法提取任務" };
  }
}

// 主要處理流程
try {
  const aiResult = await generateSummaryAndTasks(inputText);

  const result = {
    summary: aiResult.summary,
    tasks: aiResult.tasks,
    processing_info: {
      input_length: inputText.length,
      summary_length: (aiResult.summary || '').length,
      tasks_length: (aiResult.tasks || '').length, 
      processed_at: new Date().toISOString(),
      status: 'success'
    }
  };
  
  return [{ json: result }];

} catch (error) {
  return [{
    json: {
      summary: `處理失敗:${error.message}`,
      tasks: "無法提取任務",
      processing_info: { status: 'error', error_message: error.message }
    }
  }];
}

Step 7:測試與驗證通知系統

可以使用之前建立過的測試程式來觸發整個流程。

7-1 執行測試

  1. ⭐重要⭐ 先確保 LINE 已加 M2A Agent Bot 為好友
    (可以透過 LINE Developers Channel 設定頁面中的「Messaging API」頁面裡面的 QR Codec 或 ID 加為好友)。
  2. 執行可以測試整個流程的腳本

7-2 驗證測試結果

需要檢查三個地方

  1. 終端機:確認腳本順利執行完畢。
  2. Notion:確認「會議記錄」資料庫新增了一筆資料,而且內容完整。
  3. LINE:確認收到了 M2A Agent Bot 發送的通知,且訊息格式乾淨、沒有 Markdown 語法。

成功的 LINE 通知訊息範例

會議處理完成通知

- 專案:GIGI 工作室內部專案
- 日期:2025/9/19
- Notion 頁面:https://www.notion.so/

--- 會議摘要 ---
會議討論了使用者認證系統的完成時間、開發環境的準備以及錯誤處理機制的研究,並安排了下週的壓力測試腳本編寫工作。

--- 行動任務 ---
• 志明 負責在週五前完成 Flask 應用程式的 JWT 集成和整個項目的 Dark 化,需在週三前準備好 DarkField 和 DarkCompose.yml。
• 志明 協助小美研究 N8n 的錯誤處理機制,並解決 Timeout 問題。
• 小美 完成 N8n 的工作流設計,特別是 Webhook 接收資料後寫入 notion 部分,在週四前準備測試版本供團隊測試,並開始規劃晚上的客製化規則以監控非預期的 API 呼叫。
• 志明 和 小美 分別在週五下午三點前完成系統壓力測試腳本並推上 GitHub,以便週末進行完整的整合測試。

關鍵挑戰

挑戰 1:處理耗時任務與前端超時

  • 狀況:測試程式因為等待過久而發生 Timeout 錯誤等
  • 問題分析:當 AI 模型處理較長文本時,整個工作流執行時間拉長
  • 解決方案:將 n8n 工作流的架構從「同步」升級為「非同步」。透過設定 Webhook 節點的 Respond 模式,並搭配 Respond to Webhook 節點,讓系統在接收到請求的當下就立即回覆「任務已開始」,然後在背景繼續執行耗時的 AI 運算與後續流程。

挑戰 2:Markdown 格式在不同平台的顯示問題

  • 狀況:Markdown 語法在 LINE 會造成閱讀困難
  • 問題分析:AI 生成的內容包含 Markdown 語法,Notion 支援 Markdown 語法,發送到 Notion 可以正常排版,但是發送到 LINE 會造成閱讀困難。
  • 解決方案:在 n8n 中插入一個 Code 節點「Markdown 格式化處理」。利用 JavaScript 的字串取代 (replace) 功能,撰寫一個 markdownToPlainText 函式,有效過濾各種 Markdown 符號,同時保留原始 Markdown 內容傳給 Notion 節點,達成「一源多用」的效果。

今天的成果總結

完成項目

  • 將 M2A Agent 重建為非同步處理架構
  • 成功建立 LINE Messaging API Channel
  • 加入 Markdown 格式化處理機制,確保通知訊息的易讀性
  • 在 n8n 工作流中透過 HTTP Request 節點整合 LINE 通知功能
  • 將兩次 AI 呼叫合併為一次,大幅縮短處理時間。
  • 為外部 API 呼叫加入了自動重試機制
  • 完成了包含通知在內的端到端整合測試與驗證。

心得

今天學會了如何處理「異質性輸出」的問題,同一個 AI 生成的內容,在 Notion 中需要保留 Markdown 格式以獲得良好的排版,但在 LINE 中需要純文字。

透過在 n8n 中建立一個中間處理節點,成功地讓一份資料以不同的格式滿足不同平台的需求,讓我學到了自動化流程中「資料轉換」的精髓。

這些經驗讓我學會,一個穩定的自動化系統不僅是節點的串接,更重要的是對資料流的精準控制與轉換,還有漸漸開始真正的設計一個系統,從同步到非同步的架構轉變。

🎯 明天計劃
使用 Gradio 建立前端,讓使用者可上傳音訊與輸入處理指令,並且將專案結構標準化。


上一篇
Day 8 Notion API 整合
下一篇
Day 10 Gradio 前端開發與標準化專案結構
系列文
打造基於 MCP 協議與 n8n 工作流的會議處理 Agent11
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言