2025年6月24日 星期二

🚀 InsightForge 專案簡介:用務實態度打造 AI 數據分析平台

🚀 InsightForge 專案簡介:用務實態度打造 AI 數據分析平台

今天想跟大家介紹我的專案 InsightForge,這是一個結合了 LaravelFastAPIAI 數據分析平台。我們在這次實作過程中,將系統功能進行了務實的分層:將需要「跟人互動」和「管理業務」的這部分交給 Laravel,而那些需要「跑 AI 模型」和「做大量計算」的重活,則交給 FastAPI 來處理。中間還用了 Redis 幫忙傳話和加速。這樣分工合作,目的就是讓整個系統更穩、更快、更好管理。

點這裡前往 GitHub 專案


🌟 專案亮點:我們做了哪些考量?

在開發 InsightForge 時,我們特別注重以下幾個點:

  • 微服務解耦,分工合作: 把網頁介面和業務邏輯交給 Laravel 處理,而 AI 模型推論這種計算密集型的工作則由 FastAPI 負責。這樣各自獨立開發和部署,誰也不會拖累誰。
  • 異步高效,不塞車: 透過 Redis 佇列,可以有效「削峰填谷」,即使短時間內湧入大量任務,系統也能依序處理,不會一下子就卡住。
  • 即時快取,反應快: 用 Redis 暫存任務狀態和分析結果,並設定 TTL(Time To Live)讓過期資料自動清理。這樣能大幅減少資料庫壓力,讓使用者查詢結果時更快有回應。
  • 安全保障,有簽名有隔離: 服務間的 Webhook 回調會透過 HMAC 簽名來驗證資料來源和完整性。同時,Docker 內部網路隔離也確保了各服務之間的通訊安全。
  • 容器化部署,環境一致: 使用 Docker Compose 來管理所有服務的容器化部署,確保開發、測試到生產環境的配置都能保持一致,減少「我的電腦跑得動,你的就不行」這種情況。
  • 自動化 CI/CD,省心省力: 結合 GitHub Actions,讓程式碼測試和部署流程自動化,加速我們的開發和迭代速度。

🧱 系統架構圖:藍圖長這樣

簡單來說,整個系統的資料流和控制流大概是這樣跑的:

程式碼片段
graph TD
    A[用戶] -->|POST /api/upload| B[Nginx]
    B --> C[Laravel Web/API]
    C -->|儲存任務| D[MySQL]
    C -->|推至佇列| E[Redis 佇列]
    E --> F[Laravel Worker]
    F -->|HTTP 請求| G[FastAPI]
    G -->|儲存結果| E
    G -->|Webhook 回調| C
    C -->|查詢結果| A

⚙️ 關鍵技術與設計決策:為什麼選它們?

在技術選型上,我們都是有過一番考量的:

  • Laravel 10: 負責處理對外提供的 RESTful API、任務管理、以及將資料持久化到 MySQL。它是整個平台的業務邏輯核心。
  • FastAPI: 專責高效能的異步 AI 推論,並透過 Pydantic 模型來進行資料驗證。完成任務後,會以 Webhook 形式回調 Laravel。
  • Redis: 扮演雙重角色,既是 Laravel 的佇列後端來處理異步任務,也是 FastAPI 的快取,用於暫存任務狀態和結果,並設定 100 秒的 TTL。這大大提升了系統的反應速度和承載能力。
  • MySQL: 作為主要資料庫,儲存所有任務、結果和日誌,方便追蹤與查詢。
  • Nginx: 擔任反向代理的角色,統一所有外部流量的入口,並能提供基本的安全防護,同時為未來擴展預留空間。
  • Docker Compose: 用來編排多個容器服務,確保開發與部署環境的一致性,省去了一堆環境配置的麻煩。
  • GitHub Actions: 實現自動化測試與 Docker 映像推送,確保每次程式碼提交都能經過品質檢查。

技術選型細說:

  • Laravel + FastAPI 的組合: 選擇這兩者的主要原因在於 Laravel 擅長快速構建 Web 應用和處理傳統業務邏輯,而 FastAPI 則與 Python 龐大的 AI 生態系統高度相容,非常適合執行計算密集型的 AI 推論任務。這種分工讓各自發揮專長,但也帶來跨語言通訊和運維複雜度增加的挑戰。
  • 引入 Redis 的必要性: Redis 以其高性能的記憶體操作,成為佇列和快取的理想選擇。如果沒有 Redis,Laravel 將不得不同步調用 FastAPI,這會導致 API 響應時間增加,在高併發情境下,MySQL 也可能成為性能瓶頸。
  • Docker 的優勢: Docker 確保了開發、測試、生產環境的一致性,解決了「環境問題」。同時,容器化也提供了服務間的良好隔離,簡化了部署和管理流程。

角色分工細說:

  • Laravel: 扮演平台的 API 入口,負責接收使用者請求、創建分析任務、將任務推入佇列、將結果持久化到 MySQL,並接收來自 FastAPI 的 Webhook 回調。
  • FastAPI: 專注於接收任務請求、執行 AI 模型推論、將任務狀態與結果快取到 Redis,並在完成後透過 Webhook 回調 Laravel。
  • 協作機制: 兩者主要透過 Redis 佇列和 Webhook 實現異步通訊,確保任務能被高效處理。HMAC 簽名機制則保障了服務間通訊的安全性。

🚀 業界應用場景:這個平台能做什麼?

這個平台的設計彈性很高,可以應用在多種實際的業界場景:

  1. 數據分析: 自動處理銷售數據、用戶行為,生成洞察報告。
  2. 智能客服: 結合 NLP 模型,支援意圖識別與自動問答。
  3. 推薦系統: 根據用戶偏好或行為,實時生成個性化商品或內容推薦。
  4. 圖像分析: 執行物體檢測、人臉識別等圖像相關的 AI 推論。
  5. 金融風控: 分析交易模式,及時識別潛在的詐騙行為。
  6. IoT 維護: 預測設備可能出現的故障,並自動觸發工單進行維護。

🚀 快速啟動:動手試試看

想親身體驗 InsightForge 專案嗎?請依照以下步驟手動設置環境並啟動服務:

前置需求

在開始之前,請確保您的系統上已經安裝了這些基本工具:

  • Docker & Docker Compose
  • Composer
  • Python 3.9+
  • Git

手動設置

  1. 克隆專案:

    Bash
    git clone https://github.com/BpsEason/InsightForge.git
    cd InsightForge
    
  2. 初始化 Laravel 環境:

    Bash
    cd laravel-app
    composer install
    cp .env.example .env
    php artisan key:generate
    
  3. 初始化 FastAPI 環境:

    Bash
    cd ../ai-service
    python -m venv venv
    source venv/bin/activate  # Windows 環境請用:venv\Scripts\activate
    pip install -r requirements.txt
    
  4. 配置環境變數:

    • 編輯 laravel-app/.envai-service/.env
      • APP_KEY:請執行 php artisan key:generate 後貼入。
      • LARAVEL_WEBHOOK_SECRET:請確保兩邊的 Webhook 密鑰設定一致。
      • yourusername:替換成您自己的 Docker Hub 用戶名(如果需要推送到 Docker Hub)。
      • 請確認 REDIS_HOST=redisDB_HOST=db,確保容器間可以互相連線。
  5. 啟動容器:

    Bash
    cd ..
    docker-compose build
    docker-compose up -d
    
  6. 執行資料庫遷移:

    Bash
    docker-compose exec laravel-app php artisan migrate
    
  7. 訪問服務:

    • API 健康檢查: http://localhost/api/health
    • FastAPI 文檔 (Swagger UI): http://localhost/fastapi/docs

📁 目錄結構:一目瞭然

專案的結構設計得很直觀,方便您快速找到需要的檔案:

InsightForge/
├── laravel-app/                 # Laravel 應用程式核心
│   ├── app/Controllers/Api/DataUploadController.php  # 處理資料上傳的 API
│   ├── app/Jobs/ProcessAnalysisTask.php             # 處理 AI 分析任務的 Job
│   ├── database/migrations/                         # 資料庫遷移檔案
│   ├── routes/api.php                               # API 路由定義
│   ├── .env.example                                 # 環境變數範例
│   └── Dockerfile                                   # Laravel 服務的 Dockerfile
├── ai-service/                  # FastAPI AI 服務核心
│   ├── main.py                                      # FastAPI 主應用程式
│   ├── model/your_model.py                          # 模擬 AI 模型或真實模型載入邏輯
│   ├── tests/                                       # FastAPI 測試檔案
│   ├── .env.example                                 # 環境變數範例
│   └── Dockerfile                                   # FastAPI 服務的 Dockerfile
├── bin/                         # 實用腳本 (此處不再包含 setup.sh,若有其他腳本可保留)
├── nginx/nginx.conf             # Nginx 配置檔案
├── docker-compose.yml           # Docker Compose 配置檔案
└── .github/workflows/ci.yml     # GitHub Actions CI/CD 配置

🔑 關鍵程式碼:看看怎麼寫的

這裡我們挑選了 Laravel 和 FastAPI 中最核心的幾個片段,讓您了解它們是如何協同工作的。

Laravel:資料上傳與任務分發

這個控制器負責接收用戶上傳的資料,進行基本驗證,然後創建一個新的分析任務,並將它推送到 Redis 佇列,讓後台的 Worker 去處理。

PHP
// laravel-app/app/Http/Controllers/Api/DataUploadController.php
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\AnalysisTask;
use App\Jobs\ProcessAnalysisTask;
use Illuminate\Support\Str;

class DataUploadController extends Controller
{
    // 處理用戶上傳,創建任務並推至佇列
    public function upload(Request $request)
    {
        // 驗證輸入資料與任務類型
        $request->validate([
            'data' => 'required|json',
            'task_type' => 'required|string|in:sentiment_analysis,named_entity_recognition',
            'model_version' => 'required|string',
        ]);

        // 創建任務,生成唯一 UUID 作為 task_id
        $task = AnalysisTask::create([
            'task_id' => (string) Str::uuid(),
            'task_type' => $request->task_type,
            'data_payload' => $request->data,
            'model_version' => $request->model_version,
            'status' => 'pending',
        ]);

        // 分發任務至 Redis 佇列,由 ProcessAnalysisTask Job 異步處理
        ProcessAnalysisTask::dispatch($task);

        // 返回成功訊息和任務 ID,狀態碼 202 表示請求已接受但尚未完成
        return response()->json(['message' => '任務已接收', 'task_id' => $task->task_id], 202);
    }
}

FastAPI:任務處理與結果回調

FastAPI 這邊接收到來自 Laravel 的任務後,會進行 AI 推論,並將結果回報。

Python
# ai-service/main.py
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
import redis, json, requests, hmac, hashlib, asyncio
from dotenv import load_dotenv
import os, logging

# 配置日誌與環境變數
logging.basicConfig(level=logging.INFO)
logger = logging.getLogger(__name__)
load_dotenv()
app = FastAPI()

# 初始化 Redis 客戶端,用於任務狀態快取
redis_client = redis.StrictRedis(host=os.getenv('REDIS_HOST', 'redis'), port=6379, decode_responses=True)

# 模擬 AI 模型,執行推論
class MockAIModel:
    async def predict(self, data_payload: dict, task_type: str) -> dict:
        # 這裡模擬情感分析,根據文本中的關鍵字判斷情感
        text = data_payload.get('text', '')
        if task_type == 'sentiment_analysis':
            sentiment = 'Positive' if '好' in text else 'Neutral'
            return {'sentiment': sentiment, 'score': 0.95}
        # 如果有其他任務類型,可以繼續擴展
        return {}

# 定義請求資料模型,FastAPI 會自動驗證
class AnalyzeRequest(BaseModel):
    task_id: str
    data: str
    task_type: str
    model_version: str
    webhook_url: str
    webhook_secret: str | None # Webhook 密鑰用於 HMAC 簽名驗證

mock_model = MockAIModel() # 實例化模擬模型

# 處理分析任務的 API 端點
@app.post("/analyze")
async def analyze_task(request: AnalyzeRequest):
    # 將任務狀態設定為 'processing' 並儲存至 Redis,設定 100 秒過期
    redis_client.hmset(f"task:{request.task_id}", {'status': 'processing', 'data': request.data})
    redis_client.expire(f"task:{request.task_id}", 100)

    try:
        # 解析輸入資料並執行 AI 推論
        data_json = json.loads(request.data)
        result = await mock_model.predict(data_json, request.task_type)
        # 推論完成後,更新 Redis 中的任務狀態和結果
        redis_client.hmset(f"task:{request.task_id}", {'status': 'completed', 'result': json.dumps(result)})

        # 準備 Webhook 回調 payload
        payload = {'task_id': request.task_id, 'status': 'completed', 'result': result}
        headers = {'Content-Type': 'application/json'}
        # 如果有設定 webhook_secret,則生成 HMAC 簽名並加入到 Header 中
        if request.webhook_secret:
            signature = hmac.new(request.webhook_secret.encode(), json.dumps(payload).encode(), hashlib.sha256).hexdigest()
            headers['X-Webhook-Signature'] = signature
        # 發送 POST 請求回調 Laravel
        requests.post(request.webhook_url, json=payload, headers=headers)
    except Exception as e:
        # 如果處理過程中出錯,記錄錯誤狀態至 Redis 和日誌
        redis_client.hmset(f"task:{request.task_id}", {'status': 'failed', 'error': str(e)})
        logger.error(f"Task {request.task_id} failed: {e}")

    # 回應 Laravel 任務正在處理中
    return {'message': '任務處理中', 'task_id': request.task_id}

📜 API 文件與測試指南

為了方便開發和測試,我們提供了以下 API 訪問方式:

Swagger 文檔

FastAPI 內建了 Swagger UI,您可以直接透過瀏覽器訪問 http://localhost/fastapi/docs 來查看 /analyze 端點的詳細說明和試用界面。

  • POST /analyze: 接收任務資料,執行 AI 推論,並返回任務 ID。

Postman 測試示例

您可以使用 Postman 或類似的工具來測試 API。

  1. 上傳任務:

    向 http://localhost/localhost/api/data/upload 發送 POST 請求,並帶上 JSON 格式的數據。

    Bash
    curl -X POST http://localhost/api/data/upload \
    -H "Content-Type: application/json" \
    -d '{"data":"{\"text\":\"好消息!\"}","task_type":"sentiment_analysis","model_version":"v1.0"}'
    

    正常情況下,您會收到類似以下的成功回應:

    JSON
    {"message":"任務已接收","task_id":"uuid"}
    
  2. 查詢結果:

    目前用戶端查詢任務狀態和結果的方式,主要透過 FastAPI Webhook 回調自動更新到 MySQL。未來可以考慮提供一個 /api/result/{task_id} 的 API 讓用戶直接查詢。

測試流程建議:

  • 發送 /api/data/upload 請求後,您可以觀察 laravel-worker 的 Docker 日誌 (docker-compose logs laravel-worker),看任務是否被取出並處理。
  • 接著檢查 ai-service 的 Docker 日誌 (docker-compose logs ai-service),確認 AI 推論是否完成。
  • 最後,您可以登入 MySQL 資料庫,查看 analysis_tasks 表格,確認任務狀態是否已更新,以及 analysis_results 表格是否有新的結果數據。

📈 性能、擴展與優化策略

為了使 InsightForge 能應對實際的流量和變化,我們在性能、擴展和優化方面採取了多種策略:

11. 應對分析任務量激增與水平擴展

當分析任務量激增時,InsightForge 透過以下策略進行應對和擴展:

  • 佇列削峰: Redis 佇列作為緩衝區,能有效「削峰填谷」,避免瞬間流量高峰壓垮 Laravel API 服務,確保服務響應的穩定性。
  • 服務水平擴展:
    • Laravel Worker: 當佇列任務積壓時,可透過增加 laravel-worker 容器實例數量(例如 docker-compose scale laravel-worker=3)來並行處理任務。
    • FastAPI AI 服務: 當 AI 推論負載過高時,可增加 ai-service 容器實例。Nginx 作為反向代理可配置負載均衡,將請求均勻分發給多個 FastAPI 實例。
    • 基礎設施擴展: 必要時可擴展 Redis(集群)和 MySQL(主從複製)來分擔壓力。
  • 容器化優勢: Docker 容器化的特性使得各服務能夠非常方便地進行水平擴展,無論是在本地 Docker Compose 環境還是雲端容器編排平台(如 Kubernetes)。

12. AI 模型更新時的無停機部署

AI 模型不斷演進,實現無停機部署是關鍵。我們計劃採用以下策略:

  • 藍綠部署/金絲雀部署:
    • 藍綠部署: 新舊模型版本服務同時運行。待新版本穩定後,透過更新 Nginx 配置,將流量一次性或逐步從舊版本切換到新版本。舊版本服務在切換完成並確認無問題後才停止。
    • 金絲雀部署: 更為保守,新版本服務部署後,只將少量(例如 10%)流量路由到新版本,嚴密監控其錯誤率和性能。確認穩定後,再逐步增加新版本流量比例。
  • 模型版本管理: AnalysisTask 中包含 model_version 欄位,這使得即使在部署過渡期,舊任務仍可由舊模型處理,新任務由新模型處理。FastAPI 內部可維護多模型實例,根據請求的 model_version 動態路由。

13. 系統運行狀況監控

為確保系統穩定運行,我們將實施全面的監控策略:

  • 監控工具: 結合 Prometheus (指標收集)、Grafana (視覺化儀表板) 和 ELK Stack (Logstash, Elasticsearch, Kibana, 用於日誌分析)。
  • 日誌收集: 所有服務日誌(Laravel logs, FastAPI logs)將被統一收集並集中分析。
  • 告警機制: 設定關鍵指標的閾值,一旦觸發(如 CPU 使用率過高、佇列長度異常),即透過 Alertmanager 發出告警通知。
  • 關鍵監控指標:
    • 服務健康: Docker healthcheck 狀態、API 響應時間、錯誤率。
    • 任務處理: Redis 佇列長度、任務處理時間、任務失敗率。
    • 資源使用: 容器 CPU/記憶體使用率、Redis 記憶體、MySQL 查詢性能。
    • 網路狀況: Nginx 請求量、Webhook 延遲與失敗率。

14. 異常處理與資料一致性保障

系統異常難以避免,我們重視其處理與資料一致性:

  • 異常處理:
    • Laravel Job 重試: ProcessAnalysisTask Job 配置 3 次重試,超時 120 秒,失敗時記錄詳細日誌。
    • FastAPI 回調重試: (待實現) FastAPI 發送 Webhook 時應具備重試機制,確保結果送達。
    • 服務自動恢復: Docker Compose 的 healthcheck 可自動重啟不健康的容器。
    • 死信佇列: 失敗的任務可進入死信佇列,以便後續分析與手動介入。
  • 資料一致性:
    • 冪等性: task_id (UUID) 確保即使重複請求或回調,每個任務只被唯一處理,避免數據重複。
    • 資料庫事務: Laravel 在接收 Webhook 並更新資料庫時,將使用 DB::transaction,確保多個數據庫操作的原子性(要嘛全成功,要嘛全失敗)。
    • 最終一致性: Redis 作為快取可能與 MySQL 存在短暫不一致,但透過回調重試與資料庫事務,最終會達成數據一致。

15. 除了 Webhook Secret,其他安全措施

除了服務間通訊的 HMAC 簽名,我們還實施多層次安全防護:

  • API 認證: 對外提供的 API 將採用 OAuth2 或 JWT 等標準認證機制,確保只有合法用戶或服務能訪問。
  • 輸入驗證: Laravel Request::validate() 和 FastAPI Pydantic 模型對所有輸入資料進行嚴格驗證,防止惡意數據注入。
  • 網路安全: 啟用 HTTPS (TLS/SSL) 加密所有傳輸數據。Docker 內部網路隔離限制了外部對 FastAPI 的直接訪問。
  • 權限控制: (待實現) 針對管理後台和特定資源,將實施基於角色的訪問控制(RBAC)。
  • 防禦常見攻擊: Nginx 配置常見 HTTP Headers (如 X-Frame-Options) 和請求速率限制,防範點擊劫持、XSS 及 DDoS 攻擊。
  • 敏感資料保護: 所有敏感資訊(API 金鑰、資料庫密碼)儲存於環境變數中(.env),不直接寫入程式碼,並考慮對資料庫中的敏感欄位進行加密。

📈 未來展望與進階計畫

InsightForge 還有很大的成長空間,我們規劃了以下主要方向:

  • 功能擴展:
    • 即時狀態通知: 引入 WebSocket (如 Laravel Reverb) 實現任務狀態的即時更新,提升用戶體驗。
    • 視覺化儀表板: 開發一個更完善的 Vue.js 和 ECharts 儀表板,將分析結果以更直觀的方式呈現出來。
  • 雲端部署:
    • 規劃將平台部署至 AWS (ECS/EKS) 或 GCP (Cloud Run/GKE) 等雲端平台。
    • 利用雲端託管服務 (如 AWS RDS/ElastiCache, GCP Cloud SQL/Memorystore) 和 Auto Scaling,確保高可用性與彈性擴展。
    • 結合 GitHub Actions 自動化 CI/CD 流程,推送到雲端容器註冊表 (ECR, Artifact Registry)。
  • 模型生命週期管理:
    • 實現 A/B 測試,比較不同 AI 模型版本的實際效果。
    • 考慮整合 MLflow 或 Kubeflow Pipelines 等 MLOps 工具,管理 AI 模型的訓練、版本、部署與監控的整個生命週期。
    • 優化模型的動態載入與卸載機制,減少記憶體開銷。
  • 新增 AI 模型分析功能開發:
    • 當需要新增新的分析功能(例如文本分類)時,開發流程將涵蓋:
      1. ai-service/model/your_model.py 中實現新的模型邏輯,並更新 requirements.txt
      2. 修改 FastAPI main.py 中的 task_type 判斷邏輯並調用新模型。
      3. 更新 Laravel API 的驗證規則,並處理可能的資料庫或日誌調整。
      4. 進行全面的單元測試和端到端整合測試。
      5. 透過藍綠部署等策略安全地發布新功能。

沒有留言:

張貼留言

網誌存檔