【實戰】Day 19:從 PostgreSQL 開發 REST API:為 Agent 打造 JSON 數據橋樑

【實戰】Day 19:從 PostgreSQL 開發 REST API:為 Agent 打造 JSON 數據橋樑

延續鞋墊廠訂單專案,這篇文章我們將使用 FastAPI 為 PostgreSQL 建立一層 REST API,將關聯式資料庫的查詢結果轉換為標準的 JSON 格式,為 AI Agent 的串接做好萬全準備。


在上一篇文章中,我們已經成功將鞋墊廠的原始訂單資料去識別化,並存入 PostgreSQL 中。

這時很多開發者會想:「那我是不是可以直接讓 AI Agent 去連這個資料庫,自己寫 SQL 來查資料?」雖然這被稱為 Text-to-SQL,但在企業實戰中,我們非常不建議這麼做

最安全、最現代化的做法是:開發一層 REST API,讓 Agent 只能透過 API 來拿 JSON 資料(也就是 API-Driven Agent 架構)。


為什麼 Agent 需要 API 而不是直接下 SQL?

把 AI 直接連上資料庫,就像是讓一個實習生直接進到金庫自己拿錢,風險極高。相對地,API 就像是銀行的櫃檯窗口。

Loading Diagram...

這樣做有三大好處:

  1. 嚴格的權限控管:Agent 只能呼叫你寫好的 API 端點(Endpoint),完全阻絕了它胡亂下達 DELETE 或跑出無限迴圈拖垮資料庫的可能。
  2. 結構化輸出 (JSON):大語言模型天生非常擅長解析 JSON 格式。透過 API,我們能保證給 LLM 的資料格式永遠是標準且一致的。
  3. 邏輯解耦:如果未來鞋墊廠的資料庫從 PostgreSQL 換成了 MongoDB,你只需要修改 API 裡的邏輯,完全不用去動 AI Agent 的程式碼。

實作解析:使用 FastAPI 開發訂單 API

在 Python 生態系中,目前開發 API 首選的框架就是 FastAPI,它不僅效能極高,還內建了強大的型別檢查功能。

以下是一段概念程式碼,示範如何開出一個查詢「特定品牌訂單」的 API 接口:

from fastapi import FastAPI, HTTPException
import psycopg2 # PostgreSQL 連線套件
import json

app = FastAPI()

# 連接我們昨天建立的 PostgreSQL 中介庫
def get_db_connection():
    return psycopg2.connect(
        host="localhost",
        database="ai_database",
        user="ai_user",
        password="password"
    )

@app.get("/api/v1/orders/")
def get_orders(brand_name: str, start_date: str = None, end_date: str = None):
    """
    讓 Agent 透過品牌名稱 (如 Nike) 來查詢訂單資料
    """
    conn = get_db_connection()
    cursor = conn.cursor()
    
    # 防呆機制與基礎 SQL 組合
    query = "SELECT order_id, order_date, brand_name, insole_type, unit_price, order_qty, total_amount FROM safe_orders WHERE brand_name = %s"
    params = [brand_name]
    
    if start_date and end_date:
        query += " AND order_date BETWEEN %s AND %s"
        params.extend([start_date, end_date])
        
    cursor.execute(query, tuple(params))
    rows = cursor.fetchall()
    
    if not rows:
        raise HTTPException(status_code=404, detail="找不到該品牌的訂單")
        
    # 將關聯式資料轉換為 JSON 格式 (List of Dictionaries)
    result = []
    for row in rows:
        result.append({
            "order_id": row[0],
            "order_date": str(row[1]),
            "brand_name": row[2],
            "insole_type": row[3],
            "unit_price": float(row[4]),
            "order_qty": int(row[5]),
            "total_amount": float(row[6])
        })
        
    cursor.close()
    conn.close()
    
    return {"status": "success", "data": result}

API 回傳的 JSON 結構

當未來的 AI Agent 想要知道「Nike 最近的訂單狀況」,它就會去打 http://localhost:8000/api/v1/orders/?brand_name=Nike,並收到如下標準的 JSON 格式:

{
  "status": "success",
  "data": [
    {
      "order_id": "ORD-1001",
      "order_date": "2024-01-15",
      "brand_name": "Nike",
      "insole_type": "PU 發泡鞋墊",
      "unit_price": 1.2,
      "order_qty": 50000,
      "total_amount": 60000.0
    },
    {
      "order_id": "ORD-1006",
      "order_date": "2024-03-15",
      "brand_name": "Nike",
      "insole_type": "EVA 成型鞋墊",
      "unit_price": 0.85,
      "order_qty": 15000,
      "total_amount": 12750.0
    }
  ]
}

透過這種方式,AI 拿到的是最純粹的數據,它可以非常輕易地計算總金額、或是比較不同鞋墊類型的佔比。


實用建議:三個起步行動

如果你正準備為公司的 Agent 寫 API,請留意這三個原則:

步驟 1:定義清晰的 Endpoint 與參數

不要想寫一個「萬能」的 API。最好把查詢拆細,例如 /api/orders (查訂單)、/api/inventory (查庫存)、/api/customers (查客戶)。參數越明確,Agent 在呼叫時就越不容易出錯。

步驟 2:限制回傳的資料筆數 (Pagination)

AI 的 Context Window(上下文視窗)是有限且昂貴的。如果你一次回傳 10 萬筆訂單,不僅浪費 Token,還會導致模型當機。務必在 API 中加入 LIMIT 或分頁機制(例如預設最多回傳 100 筆)。

步驟 3:撰寫詳盡的 API 文件 (OpenAPI/Swagger)

FastAPI 會自動產生 OpenAPI 規格文件。這份文件不僅是給人類開發者看的,更是給 AI Agent 看的說明書。把每一個參數的定義寫清楚,Agent 才能精準判斷何時該呼叫這支 API。


我的反思

在建構企業級 AI 應用的過程中,「API」的角色往往被低估了。

很多人以為 AI 無所不能,應該讓它直接去面對資料庫。但在真實的商業環境中,系統的穩定性與可控性永遠是第一順位。API-Driven 的設計哲學,其實就是為 AI 設下一道「溫柔的邊界」。我們不限制 AI 的推理能力,但我們嚴格規範它取得知識的途徑。

現在,我們已經把 Oracle 轉成了安全的 PostgreSQL,也用 FastAPI 開發出了標準的 JSON 介面。萬事俱備,明天,我們終於可以把這些工具綁定到 AI Agent 的大腦上了!