fbpx

讓 Claude 直接讀取你的資料庫 解放大語言模型的數據分析能力

使用大語言模型最讓人遺憾的一塊,始終是它讀不到你實際執行層面的數據。想分析銷售趨勢?得把資料複製貼上。資料量稍大?直接失敗。Google Sheet 手動維護?時間成本極高。這樣的流程,讓 AI 只能扮演文字助理,而不是真正的數據夥伴。

這幾天,我們終於把 Claude 與自己的 MySQL 資料庫直接串接起來。從此,「查一下今年 momo 各月業績」、「比較無痕與棉感的全通路銷量趨勢」這類問題,Claude 直接連資料庫跑 SQL 給你答案。這篇文章記錄整個過程,包含踩到的坑,希望對想做同樣事情的人有幫助。

為什麼要這樣做?

❌ 過去的痛點

每次要分析數據,都要先從系統匯出 CSV、複製貼上給 AI、等它處理。資料量大時直接超出 context window。資料一更新就得重來一遍。

✅ 串接後的體驗

直接問 Claude「幫我看今年 Q1 的 momo 業績」,它自己查資料庫、回傳結果、做分析。資料永遠是即時的,不需要任何手動匯出。

整體架構

串接的核心概念是讓 Claude 能透過 HTTP API 送出 SQL 查詢,伺服器收到後去打 MySQL,把結果回傳。架構如下:

Claude ──── HTTPS POST ────▶ Cloudflare Tunnel
Flask Webhook ──── SQL Query ────▶ MySQL

中間的 Cloudflare Tunnel 是解決網路問題的關鍵,後面會詳細說明為什麼需要它。


第一步:建立 Webhook 端點

我們的伺服器已經有一個跑在 GCP 上的 Flask 服務,所以直接在現有專案裡加一個新的 route。核心程式碼很簡單:

from flask import Flask, request, jsonify
import mysql.connector

app = Flask(__name__)

@app.route('/webhook/sql-query', methods=['POST'])
def sql_query():
    # 驗證 auth key
    auth = request.headers.get('auth')
    if auth != 'your-secret-key':
        return jsonify({'error': 'Unauthorized'}), 401

    sql = request.json.get('sql', '')

    # 只允許 SELECT,防止誤操作
    if not sql.strip().upper().startswith('SELECT'):
        return jsonify({'error': 'Only SELECT allowed'}), 400

    conn = mysql.connector.connect(
        host='localhost',
        user='your_user',
        password='your_password',
        database='ragic_database'
    )
    cursor = conn.cursor(dictionary=True)
    cursor.execute(sql)
    result = cursor.fetchall()
    conn.close()
    return jsonify(result)
Python / Flask

服務是用 systemd 管理,部署後 reload 即可:

sudo systemctl restart your-service.service
bash

第二步:發現網路問題

Flask 跑起來後,我從本地 Mac 打 API 是通的。但當 Claude 嘗試呼叫時,卻一直 timeout。

關鍵發現Claude 的出口 IP 是 34.135.250.196,也是 GCP 的 IP。GCP 的網路架構讓同網段的 GCP IP 之間透過外部 IP 的流量會被路由丟棄,所以 Claude 的請求根本到不了我們的 VM。

用 tcpdump 在伺服器上監控,確認 Claude 的封包根本沒有到達 VM,在 GCP 網路層就消失了。這跟防火牆設定無關。

第三步:用 Cloudflare Tunnel 繞過問題

Cloudflare Tunnel 的原理是讓 VM 主動向 Cloudflare 建立連線,外部請求透過 Cloudflare 中繼進來,完全不需要開防火牆,也不受 GCP 網路限制。

安裝 cloudflared

# Debian/Ubuntu
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-public-v2.gpg | \
  sudo tee /usr/share/keyrings/cloudflare-public-v2.gpg >/dev/null

echo 'deb [signed-by=/usr/share/keyrings/cloudflare-public-v2.gpg] \
  https://pkg.cloudflare.com/cloudflared any main' | \
  sudo tee /etc/apt/sources.list.d/cloudflared.list

sudo apt-get update && sudo apt-get install cloudflared
bash

在 Cloudflare Dashboard 建立 Tunnel

  1. 建立 Cloudflare 帳號

    前往 cloudflare.com 免費註冊,並把你的網域加入 Cloudflare(DNS 指向 Cloudflare nameserver)。

  2. 進入 Zero Trust → Networks → Connectors

    選擇「Create a tunnel」→「Select Cloudflared」→「Name your tunnel」,輸入名稱(例如 sql-webhook)。

  3. 安裝 Tunnel 為 systemd 服務

    複製 Dashboard 提供的安裝指令,在 VM 上執行:

sudo cloudflared service install eyJhIjoiXXXXX...(你的 token)
sudo systemctl start cloudflared
sudo systemctl status cloudflared
bash

設定 DNS 與 Ingress 規則

在 Cloudflare DNS 新增一筆 CNAME 記錄,讓 db.your-domain.com 指向你的 tunnel:

Type:   CNAME
Name:   db
Target: {tunnel-id}.cfargotunnel.com
Proxy:  Proxied(橘色雲朵)
Cloudflare DNS 設定

然後用 Cloudflare API 設定 tunnel 的 ingress 規則,告訴 tunnel 要把流量導向本機哪個 port:

curl -X PUT \
  "https://api.cloudflare.com/client/v4/accounts/{account_id}/cfd_tunnel/{tunnel_id}/configurations" \
  -H "X-Auth-Email: your@email.com" \
  -H "X-Auth-Key: your-global-api-key" \
  -H "Content-Type: application/json" \
  -d '{
    "config": {
      "ingress": [
        {
          "hostname": "db.your-domain.com",
          "service": "http://localhost:8000"
        },
        {
          "service": "http_status:404"
        }
      ]
    }
  }'
bash / Cloudflare API

最後,建立 /etc/cloudflared/config.yml,設定 tunnel token 與 ingress:

tunnel: {tunnel-id}
token: eyJhIjoiXXXXX...

ingress:
  - hostname: db.your-domain.com
    service: http://localhost:8000
  - service: http_status:404
/etc/cloudflared/config.yml

重啟服務:

sudo systemctl restart cloudflared
bash

第四步:驗證串接成功

從任何地方都可以打這個 API 測試:

curl -X POST https://db.your-domain.com/webhook/sql-query \
  -H "Content-Type: application/json" \
  -H 'auth: your-secret-key' \
  -d '{"sql": "SELECT 1 AS test"}'

# 預期回應:
[{"test": 1}]
bash
✓ Claude 成功呼叫 webhook
✓ MySQL 查詢正常執行
✓ 資料即時回傳
✓ systemd 確保服務開機自動啟動

第五步:讓 Claude 學會怎麼用

串接完成後,還需要讓 Claude 知道這個 API 的用法、資料表結構、以及業務邏輯(例如品名的款式對應)。我們把這些寫成 Skill 檔案,讓 Claude 每次對話都能自動載入:

def query(sql):
    import urllib.request, json
    url = 'https://db.your-domain.com/webhook/sql-query'
    data = json.dumps({'sql': sql}).encode()
    req = urllib.request.Request(url, data=data, headers={
        'Content-Type': 'application/json',
        'auth': 'your-secret-key',
        'User-Agent': 'curl/7.88.1'  # 避免被 Cloudflare WAF 擋
    })
    with urllib.request.urlopen(req, timeout=30) as res:
        return json.loads(res.read().decode())
Python / Claude Skill
注意事項Python 的預設 User-Agent 會被 Cloudflare WAF 擋下來,記得改成 curl/7.88.1 或其他瀏覽器 User-Agent。

踩到的坑整理

  1. GCP 同網段 IP 無法互通

    Claude 跟我們的 VM 都在 GCP,但透過外部 IP 的請求會被路由丟棄。必須透過 Cloudflare Tunnel 這類「主動連出」的機制才能繞過。

  2. Cloudflare SSL 模式設錯

    預設 SSL 模式是 Full,會嘗試用 HTTPS 連 origin server。但 Flask 只跑 HTTP,所以需要改成 Flexible,或讓 Tunnel 的 ingress 指向 http://localhost

  3. Token 模式下 config.yml 的 ingress 不生效

    用 token 安裝的 tunnel,ingress 規則要透過 Cloudflare API 設定,本機的 config.yml 只負責認證,ingress 從 Dashboard/API 讀取。

  4. Python User-Agent 被 Cloudflare WAF 擋

    Python 的 urllib 預設 User-Agent 會觸發 Cloudflare 的 bot 偵測,記得手動設定 User-Agent。

  5. UNSIGNED CAST 遇到空值爆炸

    SQL 裡用 CAST(field AS UNSIGNED) 遇到空白字串或負數會得到一個巨大的數字。改用 CAST(field AS SIGNED) 或加 NULL check。


這件事真正改變了什麼

串接完成後,我們第一次體驗到真正意義上的 AI 數據分析。不再是把資料貼給 AI 讓它幫你解讀,而是 AI 直接去資料庫問問題、自己跑 SQL、自己整理答案。

「幫我比較今年和去年 momo 各月業績」、「全通路無痕款和棉感款的銷量趨勢」、「寶雅今年各月夜用的進貨量」——這些問題現在只要用說的,幾秒內就有答案。

大語言模型處理大量數據的能力,真正被解放了。