返回首頁Dialogflow

Dialogflow Fulfillment 與 API 整合完整教學

20 min 分鐘閱讀
#Dialogflow#Fulfillment#Webhook#API#Cloud Functions

Dialogflow Fulfillment 與 API 整合完整教學

Dialogflow Fulfillment 與 API 整合完整教學

靜態回覆只能做簡單的 FAQ 機器人。要讓機器人真正有用,必須連接後端系統:查訂單、查庫存、處理預約。

Dialogflow 透過 Fulfillment(Webhook)讓你的機器人能呼叫外部 API,實現動態回覆。這篇文章從零開始,教你開發 Webhook、部署到 Cloud Functions、整合第三方 API。

如果你還不熟悉 Dialogflow 基礎,建議先閱讀 Dialogflow 完整指南Intent 與 Context 教學


Fulfillment 基礎概念

什麼時候需要 Fulfillment

不需要 Fulfillment 的場景

  • 回答固定問題(營業時間、地址)
  • 純粹的閒聊對話
  • 提供靜態資訊

需要 Fulfillment 的場景

  • 查詢即時資訊(訂單狀態、庫存數量)
  • 執行動作(建立訂單、預約)
  • 根據條件動態回覆
  • 連接外部系統(CRM、ERP)

Webhook 運作原理

使用者 → Dialogflow → Webhook → 你的後端 → Webhook → Dialogflow → 使用者
  │          │          │          │          │          │          │
「查訂單」   意圖理解   呼叫API    查資料庫    回傳結果   組合回覆   「您的訂單...」

流程說明

  1. Dialogflow 偵測到需要 Fulfillment 的 Intent
  2. 發送 HTTP POST 請求到你設定的 Webhook URL
  3. 你的 Webhook 處理請求,呼叫資料庫或 API
  4. 回傳結構化的 JSON 給 Dialogflow
  5. Dialogflow 把內容發送給使用者

ES vs CX Fulfillment 差異

差異ESCX
Request 格式v2 API 格式v3 API 格式
Response 格式fulfillmentText / messagesfulfillmentResponse
Context 處理outputContextssessionInfo.parameters
觸發方式Intent 級別啟用Page/Route 級別啟用
官方 SDKdialogflow-fulfillment無官方 SDK

本文主要以 ES 為例,CX 的 Webhook 開發請參考 Dialogflow CX 教學


建立 Webhook 服務

使用 Cloud Functions(推薦)

Google Cloud Functions 是最簡單的 Webhook 部署方式,免管伺服器、自動擴展。

Step 1:建立 Cloud Function

  1. 前往 Google Cloud Console
  2. 選擇你的專案(與 Dialogflow Agent 相同)
  3. 搜尋「Cloud Functions」並進入
  4. 點擊「Create Function」

基本設定

  • Function name:dialogflow-webhook
  • Region:asia-east1(台灣)
  • Trigger type:HTTPS
  • Authentication:Allow unauthenticated invocations

Step 2:撰寫程式碼

選擇 Runtime:Node.js 20

package.json

{
  "name": "dialogflow-webhook",
  "version": "1.0.0",
  "dependencies": {
    "dialogflow-fulfillment": "^0.6.1"
  }
}

index.js

const { WebhookClient } = require('dialogflow-fulfillment');

exports.dialogflowWebhook = (request, response) => {
  const agent = new WebhookClient({ request, response });

  console.log('Intent: ' + agent.intent);
  console.log('Parameters: ' + JSON.stringify(agent.parameters));

  function welcome(agent) {
    agent.add('歡迎使用我們的服務!請問有什麼可以幫您?');
  }

  function fallback(agent) {
    agent.add('抱歉,我不太理解您的意思。');
  }

  function checkOrder(agent) {
    const orderId = agent.parameters.order_id;
    // 這裡呼叫你的訂單系統
    agent.add(`訂單 ${orderId} 的狀態是:處理中,預計明天出貨。`);
  }

  const intentMap = new Map();
  intentMap.set('Default Welcome Intent', welcome);
  intentMap.set('Default Fallback Intent', fallback);
  intentMap.set('check_order', checkOrder);

  agent.handleRequest(intentMap);
};

Step 3:部署

  1. 點擊「Deploy」
  2. 等待部署完成(約 1-2 分鐘)
  3. 複製觸發 URL

Step 4:在 Dialogflow 設定

  1. 進入 Dialogflow Console
  2. 點擊左側「Fulfillment」
  3. 啟用「Webhook」
  4. 貼上 Cloud Functions 的 URL
  5. 點擊「Save」

Step 5:啟用 Intent 的 Fulfillment

  1. 進入需要 Fulfillment 的 Intent
  2. 滾動到最下方
  3. 展開「Fulfillment」區塊
  4. 勾選「Enable webhook call for this intent」
  5. 儲存

使用 Node.js + Express

如果你想在自己的伺服器部署:

const express = require('express');
const { WebhookClient } = require('dialogflow-fulfillment');

const app = express();
app.use(express.json());

app.post('/webhook', (req, res) => {
  const agent = new WebhookClient({ request: req, response: res });

  function handleIntent(agent) {
    agent.add('這是自訂伺服器的回覆');
  }

  const intentMap = new Map();
  intentMap.set('my_intent', handleIntent);

  agent.handleRequest(intentMap);
});

app.listen(3000, () => {
  console.log('Webhook server running on port 3000');
});

注意:自建伺服器需要:

  • HTTPS(可用 ngrok 測試)
  • 公開可存取的 URL
  • 處理擴展性問題

使用 Python Flask

from flask import Flask, request, jsonify

app = Flask(__name__)

@app.route('/webhook', methods=['POST'])
def webhook():
    req = request.get_json()

    intent_name = req['queryResult']['intent']['displayName']
    parameters = req['queryResult']['parameters']

    if intent_name == 'check_order':
        order_id = parameters.get('order_id')
        response_text = f'訂單 {order_id} 的狀態是:處理中'
    else:
        response_text = '收到您的訊息'

    return jsonify({
        'fulfillmentText': response_text
    })

if __name__ == '__main__':
    app.run(port=5000)

部署與 HTTPS 設定

本地測試用 ngrok

# 安裝 ngrok
npm install -g ngrok

# 啟動本地伺服器
node server.js

# 另一個終端機
ngrok http 3000

# 複製 ngrok 給的 HTTPS URL,貼到 Dialogflow

正式部署選項

  • Google Cloud Functions(推薦)
  • Google Cloud Run
  • AWS Lambda
  • Heroku
  • 自建伺服器 + SSL 憑證

Dialogflow API 呼叫

除了被動接收 Webhook,你也可以主動呼叫 Dialogflow API。

DetectIntent API

DetectIntent API 讓你從自己的應用程式發送訊息給 Dialogflow。

使用場景

  • 自建聊天介面
  • 整合到現有 App
  • 批次測試對話

服務帳戶與驗證設定

Step 1:建立服務帳戶

  1. 前往 Google Cloud Console > IAM & Admin > Service Accounts
  2. 點擊「Create Service Account」
  3. 輸入名稱(如:dialogflow-client)
  4. 授予角色:「Dialogflow API Client」
  5. 建立金鑰(JSON 格式)
  6. 下載並安全保存金鑰檔案

Step 2:設定環境變數

export GOOGLE_APPLICATION_CREDENTIALS="/path/to/service-account-key.json"

範例程式碼

Node.js

const dialogflow = require('@google-cloud/dialogflow');
const uuid = require('uuid');

async function detectIntent(projectId, text) {
  const sessionId = uuid.v4();
  const sessionClient = new dialogflow.SessionsClient();
  const sessionPath = sessionClient.projectAgentSessionPath(projectId, sessionId);

  const request = {
    session: sessionPath,
    queryInput: {
      text: {
        text: text,
        languageCode: 'zh-TW',
      },
    },
  };

  const [response] = await sessionClient.detectIntent(request);
  const result = response.queryResult;

  console.log('Intent:', result.intent.displayName);
  console.log('Response:', result.fulfillmentText);

  return result;
}

// 使用範例
detectIntent('your-project-id', '我要訂位');

Python

from google.cloud import dialogflow_v2 as dialogflow
import uuid

def detect_intent(project_id, text):
    session_client = dialogflow.SessionsClient()
    session_id = str(uuid.uuid4())
    session = session_client.session_path(project_id, session_id)

    text_input = dialogflow.TextInput(text=text, language_code='zh-TW')
    query_input = dialogflow.QueryInput(text=text_input)

    response = session_client.detect_intent(
        request={'session': session, 'query_input': query_input}
    )

    result = response.query_result
    print(f'Intent: {result.intent.display_name}')
    print(f'Response: {result.fulfillment_text}')

    return result

# 使用範例
detect_intent('your-project-id', '我要訂位')

GitHub 範例專案

官方範例庫介紹

Google 提供官方範例程式碼:

Dialogflow ES

Dialogflow CX

社群推薦專案

專案語言功能
dialogflow-fulfillment-nodejsNode.js官方 Fulfillment 函式庫
flask-dialogflow-webhookPythonFlask Webhook 模板
dialogflow-angularTypeScriptAngular 整合範例

快速部署模板

一鍵部署到 Cloud Functions

# 克隆範例專案
git clone https://github.com/your-repo/dialogflow-webhook-template.git
cd dialogflow-webhook-template

# 部署
gcloud functions deploy dialogflow-webhook \
  --runtime nodejs20 \
  --trigger-http \
  --allow-unauthenticated \
  --region asia-east1

進階整合

連接資料庫(Firestore / MySQL)

Firestore 範例

const { Firestore } = require('@google-cloud/firestore');
const firestore = new Firestore();

async function checkOrder(agent) {
  const orderId = agent.parameters.order_id;

  const doc = await firestore.collection('orders').doc(orderId).get();

  if (!doc.exists) {
    agent.add('找不到這筆訂單,請確認訂單編號是否正確。');
    return;
  }

  const order = doc.data();
  agent.add(`訂單 ${orderId} 的狀態是:${order.status},預計 ${order.delivery_date} 送達。`);
}

MySQL 範例

const mysql = require('mysql2/promise');

async function checkInventory(agent) {
  const productName = agent.parameters.product;

  const connection = await mysql.createConnection({
    host: process.env.DB_HOST,
    user: process.env.DB_USER,
    password: process.env.DB_PASSWORD,
    database: process.env.DB_NAME,
  });

  const [rows] = await connection.execute(
    'SELECT stock FROM products WHERE name = ?',
    [productName]
  );

  if (rows.length > 0) {
    agent.add(`${productName} 目前庫存 ${rows[0].stock} 件。`);
  } else {
    agent.add('找不到這個商品。');
  }

  await connection.end();
}

呼叫第三方 API

天氣 API 範例

const axios = require('axios');

async function getWeather(agent) {
  const city = agent.parameters['geo-city'];

  try {
    const response = await axios.get(
      `https://api.openweathermap.org/data/2.5/weather?q=${city}&appid=${process.env.WEATHER_API_KEY}&units=metric&lang=zh_tw`
    );

    const weather = response.data;
    agent.add(`${city} 目前天氣:${weather.weather[0].description},氣溫 ${weather.main.temp}°C。`);
  } catch (error) {
    agent.add('抱歉,無法取得天氣資訊,請稍後再試。');
  }
}

非同步處理與長時間任務

Dialogflow Webhook 有 5 秒的 timeout 限制。如果任務需要更久:

方法 1:快速回覆 + 後續通知

async function processLongTask(agent) {
  const taskId = generateTaskId();

  // 立即回覆
  agent.add(`收到您的請求,處理中...我們會在完成後通知您(任務編號:${taskId})`);

  // 非同步處理(不等待)
  processTaskInBackground(taskId);
}

async function processTaskInBackground(taskId) {
  // 執行長時間任務
  const result = await someHeavyOperation();

  // 完成後發送通知(透過 LINE Push、Email 等)
  await sendNotification(taskId, result);
}

方法 2:使用 Cloud Tasks

把任務放入佇列,另一個服務處理:

const { CloudTasksClient } = require('@google-cloud/tasks');

async function queueTask(agent) {
  const client = new CloudTasksClient();

  const task = {
    httpRequest: {
      httpMethod: 'POST',
      url: 'https://your-worker-service.com/process',
      body: Buffer.from(JSON.stringify({ data: agent.parameters })).toString('base64'),
    },
  };

  await client.createTask({ parent: queuePath, task });

  agent.add('您的請求已加入處理佇列,稍後會通知您結果。');
}

錯誤處理與重試機制

async function robustApiCall(agent) {
  const maxRetries = 3;
  let lastError;

  for (let i = 0; i < maxRetries; i++) {
    try {
      const result = await callExternalApi();
      agent.add(`查詢結果:${result}`);
      return;
    } catch (error) {
      lastError = error;
      console.error(`Attempt ${i + 1} failed:`, error.message);

      if (i < maxRetries - 1) {
        await sleep(1000 * (i + 1)); // 指數退避
      }
    }
  }

  // 所有重試都失敗
  console.error('All retries failed:', lastError);
  agent.add('系統暫時忙碌,請稍後再試。如急需協助,請撥打客服專線。');
}

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

整合做不出來?後端整合是技術門檻最高的部分,牽涉到資安、效能、錯誤處理。預約技術諮詢,讓有經驗的人幫你解決整合難題。


部署與維運

監控與日誌

Cloud Functions 日誌

  1. 前往 Google Cloud Console > Cloud Functions
  2. 選擇你的 Function
  3. 點擊「Logs」分頁

設定告警

  1. 前往 Cloud Monitoring
  2. 建立告警政策
  3. 設定條件:錯誤率 > 5%、延遲 > 2 秒
  4. 設定通知管道(Email、Slack)

效能優化

1. 減少冷啟動

// 在 Function 外初始化連線,避免每次都重新連
const firestore = new Firestore();

exports.webhook = async (req, res) => {
  // 使用已建立的連線
  const doc = await firestore.collection('orders').doc('123').get();
  // ...
};

2. 使用快取

const NodeCache = require('node-cache');
const cache = new NodeCache({ stdTTL: 300 }); // 5 分鐘快取

async function getData(key) {
  let data = cache.get(key);

  if (!data) {
    data = await fetchFromDatabase(key);
    cache.set(key, data);
  }

  return data;
}

3. 設定 minimum instances

避免冷啟動延遲:

gcloud functions deploy webhook \
  --min-instances 1 \
  --max-instances 10

安全性考量

1. 驗證請求來源

確認請求真的來自 Dialogflow:

// 檢查 User-Agent
if (!req.headers['user-agent'].includes('Google-Dialogflow')) {
  return res.status(403).send('Forbidden');
}

2. 環境變數管理

敏感資訊不要寫在程式碼中:

// ❌ 不好
const apiKey = 'sk-xxxxx';

// ✓ 好
const apiKey = process.env.API_KEY;

3. 限制存取範圍

服務帳戶只給需要的權限,不要用 Owner 權限。

如果需要整合到行動 App,請參考 Dialogflow 行動開發整合教學。LINE Bot 整合請參考 Dialogflow LINE Bot 串接教學

常見問題 FAQ

Q1: Dialogflow ES 和 Dialogflow CX 哪個比較好用?新專案該選哪個?

新專案首選 Dialogflow CX。(1) Dialogflow ES(Essentials,舊版)——免費額度較大、設定簡單、Intent-based 設計適合簡單問答。但限制:(A) 沒有 state machine 概念,複雜流程用 context 硬湊;(B) 每個 agent 只能 20 個 context/10,000 intents;(C) 不支援 flow-level 分組;(D) Google 開發投資已減少,新功能優先上 CX。(2) Dialogflow CX(舊稱 Conversational Agents)——付費(每次對話 $0.007 起)、visual flow builder、原生 state machine、Flow / Page / Route 概念清晰;適合複雜對話(預約、訂票、金融諮詢)。限制:(A) 學習曲線較陡;(B) 價格較高(每月可能 $500–5,000+);(C) 有些功能 overkill 簡單使用情境。選擇建議:(A) FAQ bot / 簡單客服 → Dialogflow ES(免費額度夠用);(B) 多步驟流程(註冊、預約、購買) → Dialogflow CX;(C) 企業 production 產品 → Dialogflow CX(免費方案長期維運風險);(D) 已用 ES 想遷移 → 可以共存,但重構 flow logic 大約需 2–4 週。2025 趨勢:Google 推出 Conversational Agents(整合 Gemini + CX + Dialogflow),未來可能是統一平台。

Q2: Fulfillment 一定要用 Webhook 嗎?Inline Editor 的 Cloud Functions 模式夠用嗎?

看規模和需求。(1) Inline Editor(Cloud Functions)——Dialogflow 內建的 Node.js 函數編輯器;優點:不用自己部署、免費額度夠小規模、設定簡單、適合原型。限制:(A) 只支援 Node.js(沒 Python);(B) 無法 import 大量套件;(C) 函數冷啟動 500ms–2 秒;(D) 難以整合複雜 middleware;(E) 不易做單元測試。(2) Webhook(自架伺服器 / Cloud Run / Lambda)——優點:(A) 任何語言(Python、Go、Java);(B) 任何 library;(C) 可 pre-warm 消除冷啟動;(D) 完整 CI/CD、監控、log;(E) 可與既有系統 tight integration。缺點:要自己維運、要有認證機制。選擇原則:(A) 原型 / FAQ bot / 小規模 → Inline Editor;(B) 中大型 production、需要查 DB、串第三方 API → Webhook;(C) 金融 / 醫療 / 敏感資料 → 一定 Webhook(資料不能放 Google);(D) 用 Python / Go 開發 → Webhook。實戰建議:Cloud Run 是 Webhook 的最佳選擇——serverless、按需付費、與 Dialogflow 在同一 GCP project 整合 IAM 簡單。

Q3: Webhook 驗證該怎麼做?Dialogflow 發來的 request 怎麼確認是真的?

三層驗證。(1) JWT Token 驗證(官方推薦)——Dialogflow 可以設定呼叫 webhook 時帶 Bearer token,你在 webhook 端驗證。(A) 在 Dialogflow Agent 設定裡設 webhook URL 和 auth header(如 Authorization: Bearer YOUR_SECRET);(B) webhook 端檢查:if request.headers['Authorization'] != 'Bearer YOUR_SECRET': return 403;(C) token 存在 Secret Manager 每 90 天輪替。(2) Request signature 驗證——Dialogflow CX 支援 webhook 簽章:你 webhook 用 shared secret 驗證 request 沒被竄改。(3) IP 白名單(較弱但常用)——Google 的 Dialogflow request 來自特定 IP range(查 Google 官方文件),webhook 只接受這些 IP。常見錯誤:(A) 不驗證 webhook 呼叫者——任何人知道你的 webhook URL 都能打,可能被濫用或洩密;(B) JWT secret hardcode 在 code 裡——要存 Secret Manager;(C) 沒做 payload schema validation——惡意 payload 可能讓 webhook 崩潰。production checklist:(1) HTTPS only(不接受 HTTP);(2) Authorization header 驗證;(3) rate limiting(同一 session 不超過 60 req/min);(4) request/response logging(debug 用);(5) Cloud Armor / WAF 在前擋 DDoS。

Q4: 對話機器人要存對話紀錄、跨 session 記憶,該怎麼設計?

Dialogflow 本身不保留對話紀錄(隱私設計),要自己做。架構模式:(1) Session state(短期記憶)——Dialogflow 的 Context / Session Parameters 本身已經夠用,session 期間自動維持;(2) Conversation history(長期儲存)——每次 webhook 呼叫時把 user input、bot response、timestamp、user_id、session_id 存到 DB(Firestore、PostgreSQL、MongoDB 都可),以 user_id 當 key 查詢歷史;(3) User profile(跨 session)——獨立 table 存使用者資料(偏好、過往購買、聯絡資訊),每次 webhook 時 user_id 查出來餵給邏輯。實作方式(Python + Firestore):webhook handler 裡呼叫 db.collection('conversations').document().set({user_id, session_id, user_input, bot_response, timestamp: firestore.SERVER_TIMESTAMP})隱私與合規:(1) 儲存對話紀錄要告知使用者(privacy policy);(2) GDPR 要求提供「查看和刪除」功能;(3) 敏感資料(信用卡、密碼)不要存——要做 redaction;(4) 保留期限——一般 6–12 個月足夠,超過刪除。進階:用對話歷史增強 AI 回應——把最近 5–10 輪對話放進 prompt 餵給 LLM(Gemini、Claude),讓 AI 有 context 做更自然回答——這是 2025 年常見做法。

Q5: Dialogflow 的費用要怎麼算?500 個 DAU 的 Chatbot 月費大概多少?

Dialogflow ES 多數情境免費,CX 要仔細算。(1) Dialogflow ES 定價——(A) Text:$0.002 per request(每月前 15,000 requests 免費);(B) Voice input:$0.065/分鐘;(C) Voice output:$0.0065/字元。500 DAU × 10 rounds/day = 5,000 requests/day × 30 days = 150,000/month → 前 15,000 免費 + 付費 135,000 × $0.002 = $270/月。(2) Dialogflow CX 定價——(A) Text:$0.007 per request(無免費額度);(B) Voice input:$0.06/分鐘;(C) Voice output:同 ES。同樣 500 DAU × 10 rounds/day → 150,000 requests × $0.007 = $1,050/月。(3) 額外費用——(A) Vertex AI fulfillment(如果用了 generative features)—— 每次 LLM 呼叫 $0.001–0.005;(B) Webhook 運行費(Cloud Run)——可能 $20–200/月;(C) 資料儲存(Firestore)——$20–100/月;(D) Cloud Logging——$10–50/月。總 TCO:ES 500 DAU 約 $300–400/月,CX 500 DAU 約 $1,200–1,500/月。省錢技巧:(1) 分類 intents——免費方案的 quota 不要浪費在 low-value 閒聊上;(2) 用 entity 不要 regex——省 training 時間;(3) fulfillment 加 cache——常見查詢(如「營業時間」)的結果 cache,avoid 每次都打 DB;(4) 監控哪些 intent 被濫用——有人用 bot 玩就限制。


下一步

掌握 Fulfillment 開發後,你可以:

  1. 優化對話設計Dialogflow Intent 與 Context 完整教學
  2. 學習 CX 版本Dialogflow CX 教學:從入門到進階
  3. 整合 LINE BotDialogflow LINE Bot 串接教學
  4. 行動 App 整合Dialogflow 行動開發整合教學

後端整合需要協助?

好的後端架構能讓系統穩定、安全、易於擴展。不好的架構會在流量增加時出問題,或成為資安漏洞。

如果你需要:

  • 設計可擴展的 Webhook 架構
  • 整合複雜的企業系統
  • 處理高流量場景
  • 確保資安合規

預約架構諮詢,讓有經驗的工程師幫你設計穩健的後端架構。

諮詢完全免費,我們會在 24 小時內回覆。


需要專業的雲端建議?

無論您正在評估雲平台、優化現有架構,或尋找節費方案,我們都能提供協助

預約免費諮詢

相關文章