iT邦幫忙

0

# Day 10全鏈路整合 LINE Bot × Dify × FastAPI 智慧美食 Agent

n8n
  • 分享至 

  • xImage
  •  

歷經了前 9 天的摸索與實作,我們從最底層的 Docker 容器環境、FastAPI 微服務、Dify 搭配 Google Gemini 大腦、ngrok 公網隧道,一路推進到了 LINE Messaging API 的事件監聽。

今天 Day 10,是整個實作系列的完結篇與總驗收!我們將把散落在各處的所有拼圖正式串聯起來,打造一條完整的端到端閉環(End-to-End Pipeline):
只要在手機 LINE 聊天室隨口說出一句想吃的需求,AI 大腦便會自動解析、微服務即時運算篩選,最後透過 LINE Reply API 將排版精美的推薦店家即時送回手機!


一、全系統端到端架構總覽

在正式把線路全部接在一起前,我們先回顧整條完整的資料鏈路流向:

[使用者手機 LINE 聊天室]
       │ 1. 使用者輸入口語需求(例如:「板橋有什麼 300 元內的安靜甜點店?」)
       ▼
[LINE Platform]
       │ 2. 觸發 Webhook (HTTPS POST)
       ▼
[ngrok 隧道] ➜ 轉發至本地連接埠 5678
       │
       ▼
[n8n 工作流 (Webhook 節點)]
       │ 3. 擷取 replyToken 與使用者文字
       ▼
[Dify API + Gemini 3.5 Flash-Lite]
       │ 4. 自然語言意圖辨識,提取 JSON(預算、地區、類別)
       ▼
[FastAPI 微服務 (POST /api/v1/recommend/)]
       │ 5. 執行商業邏輯與條件篩選,回傳推薦餐廳清單
       ▼
[n8n 訊息組裝 (Set / Code 節點)]
       │ 6. 格式化為友善對話文字或 LINE Flex Message
       ▼
[LINE Messaging API (POST /v2/bot/message/reply)]
       │ 7. 使用 replyToken 免費回覆訊息
       ▼
[使用者手機 LINE 聊天室即時收到推薦小卡!]

二、在 n8n 中組裝全功能工作流

請打開瀏覽器進入 n8n 介面(http://localhost:5678),打開昨天的 LINE Bot Core Workflow,依序完成以下節點的對齊與拼接:
節點 1:Webhook (LINE Receiver)
HTTP Method:POST

Path:line-webhook

Response Mode:On Received,Response Body 填寫 {"status": "ok"}

💡 關鍵觀念:LINE 伺服器要求 Webhook 必須在短時間內收到 200 回應,否則會判定逾時。將 Response Mode 設為 On Received 能讓 n8n 第一時間回傳 200 給 LINE,後續運算再非同步繼續執行。
節點 2:Code (Extract Event)
過濾並提取出關鍵欄位:

const event = $input.first().json.body.events[0];

if (!event || event.type !== 'message' || event.message.type !== 'text') {
  return [];
}

return {
  reply_token: event.replyToken,
  user_id: event.source.userId,
  user_message: event.message.text
};

節點 3:HTTP Request (Call Dify AI Intent)
將使用者的自然語言送入 Dify 的 Gemini 大腦進行參數解析:

Method:POST

URL:http://host.docker.internal/v1/chat-messages

Authentication:Header Auth

Name:Authorization

Value:Bearer <你的_DIFY_API_KEY>

Headers:Content-Type: application/json

JSON Body:

{
  "inputs": {},
  "query": "={{ $json.user_message }}",
  "response_mode": "blocking",
  "user": "={{ $json.user_id }}"
}

節點 4:Code (Parse AI JSON)
將 Dify 回傳的字串格式化為乾淨的 JSON 物件,同時保留 reply_token 以供後續回覆使用:

let rawAnswer = $input.first().json.answer;
rawAnswer = rawAnswer.replace(/```json/g, '').replace(/```/g, '').trim();

let parsedData = {};
try {
  parsedData = JSON.parse(rawAnswer);
} catch (e) {
  parsedData = {
    cuisine: "全部",
    budget_max: 500,
    location: "板橋區",
    notes: ""
  };
}

// 取得前一個節點保存的 reply_token
const replyToken = $('Extract Event').first().json.reply_token;

return {
  reply_token: replyToken,
  cuisine: parsedData.cuisine || "全部",
  budget_max: parsedData.budget_max || 500,
  location: parsedData.location || "板橋區",
  notes: parsedData.notes || ""
};

節點 5:HTTP Request (Call FastAPI Backend)
呼叫本機運行的 FastAPI 推薦微服務:

Method:POST

URL:http://host.docker.internal:8000/api/v1/recommend/

Headers:Content-Type: application/json

JSON Body:

{
  "user_id": "line_user",
  "cuisine": "={{ $json.cuisine }}",
  "budget_max": {{ $json.budget_max }},
  "location": "={{ $json.location }}",
  "notes": "={{ $json.notes }}"
}

節點 6:Code / Set (Format Reply Message)
根據推薦結果組裝回傳給使用者的文字排版:

const responseData = $input.first().json;
const replyToken = $('Parse AI JSON').first().json.reply_token;

let replyText = "";

if (!responseData.recommendations || responseData.recommendations.length === 0) {
  replyText = "抱歉,目前在該區域與預算條件下找不到合適的店家,建議放寬預算或更換料理分類再試試看哦!";
} else {
  const shop = responseData.recommendations[0];
  replyText = `🎉 收到!已為您找到最推薦的店家:\n\n` +
              `【店名】:${shop.name}\n` +
              `【類型】:${shop.cuisine}\n` +
              `【均消】:約 ${shop.price_avg} 元\n` +
              `【地點】:${shop.location}\n` +
              `【評分】:⭐️ ${shop.rating}\n` +
              `【招牌必點】:${shop.signature_dish}\n\n` +
              `💡 小編推薦筆記:${shop.reason || '無'}`;
}

return {
  reply_token: replyToken,
  reply_text: replyText
};

節點 7:HTTP Request (LINE Reply API)
最後一步,呼叫 LINE 官方的 Reply API 回傳訊息至聊天室:

Method:POST

URL:https://api.line.me/v2/bot/message/reply

Authentication:Header Auth

Name:Authorization

Value:Bearer <你的_LINE_CHANNEL_ACCESS_TOKEN>

Headers:Content-Type: application/json

JSON Body:

{
  "replyToken": "={{ $json.reply_token }}",
  "messages": [
    {
      "type": "text",
      "text": "={{ $json.reply_text }}"
    }
  ]
}

三、部署上線與端到端實測

Step 1:切換工作流至 Production 模式

1.確保 FastAPI 伺服器仍在執行(uvicorn app.main:app --host 0.0.0.0 --port 8000 --reload)。

2.確保 ngrok 隧道保持在線上狀態(ngrok http 5678)。

3.在 n8n 畫布右上角,將 Active 開關切換為 開啟(Active / Published)。

4.到 LINE Developers 後台,將 Webhook URL 確認為正式路徑:

[https://xxxx.ngrok-free.app/webhook/line-webhook](https://xxxx.ngrok-free.app/webhook/line-webhook)

Step 2:真機驗收

打開手機 LINE,進入美食小幫手的聊天室,傳送口語訊息進行測試:

使用者輸入:
「我人在板橋,預算大概抓 300,下午想找間安靜的甜點店吃蛋糕,有推薦的嗎?」

數秒之內,聊天室即時彈出回覆:
美食探險小幫手:
收到!已為您找到最推薦的店家:

【店名】:恬淡日常法式甜點
【類型】:甜點/下午茶
【均消】:約 280 元
【地點】:板橋區
【評分】:⭐️ 4.7
【招牌必點】:草莓戚風蛋糕、伯爵生乳捲

💡 小編推薦筆記:巷弄隱密甜點店,氣氛溫馨悠閒,適合放鬆聊天。


*提醒邦友,使用第三方服務/API 時,請務必評估資安風險與隱私保護
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言