iT邦幫忙

2026 iThome 鐵人賽

DAY 7
0
AI 自動化

AaaS from Scratch: 從一次性定義,到規模化分析系列 第 7

[Day 7] 實作Datasource,並提供給Agent使用

  • 分享至 

  • xImage
  •  

昨天我們先建立了 config layer,今天實作真正的 datasource。

我還是會沿用前面的方式:start from the end

與其一開始就先想 CSV reader 或 database connection,我會先決定 Agent 最後應該看到什麼。

目前我希望只提供兩個 datasource tools:

def read_file(filename):
    ...

def query_database(query):
    ...

從 Agent 的角度來看,這樣就夠了。

它只需要知道:

  • 資料來自 file 時,使用 read_file()
  • 資料來自 database 時,使用 query_database()

Agent 不需要知道 file 是怎麼 parse,也不需要知道 database connection 是怎麼建立的。

這些細節都留在 datasource implementation 裡。

整體 flow 會是:

Agent
  ↓
read_file / query_database
  ↓
Datasource implementation

這就是今天要完成的內容。

File Datasource

先從 CSV file 開始,Agent 最後應該可以這樣呼叫:

read_file("youtube_trending_cleaned_us.csv")

tool 大概長這樣:

def read_file(filename: str):
    path = cfg.data.path.parent / filename
    return CsvFileSource(path).read()

真正讀取 CSV 的邏輯則放在 datasource implementation:

from pathlib import Path

import pandas as pd


class CsvFileSource:
    def __init__(self, path: Path):
        self.path = path

    def read(self) -> pd.DataFrame:
        return pd.read_csv(self.path)

如果資料很大很多欄位的話,可以改用polars。

整個 flow 就會變成:

Agent
  ↓
read_file()
  ↓
CsvFileSource
  ↓
pandas.read_csv()

Agent 不需要知道 pandas.read_csv() 是怎麼運作的。

之後如果要支援 XLSX、PDF 或其他 file format,可以再補上對應的 implementation,read_file() 不需要跟著改變。

Local PostgreSQL

接著需要準備一個 database。

這個 demo 會使用 Docker Compose 在 local 啟動 PostgreSQL。

services:
  postgresdb:
    image: postgres:18
    container_name: postgres_ithome
    restart: always

    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_DB: ${POSTGRES_DB}

    ports:
      - "5435:5432"

    volumes:
      - postgres_data:/var/lib/postgresql

volumes:
  postgres_data:

PostgreSQL 預設通常使用 port 5432,不過我的 local machine 上 5432 已經被占用,所以這裡改成使用 5435

5435:5432

代表:

localhost:5435 → PostgreSQL inside container:5432

credentials 放在 .env

POSTGRES_USER=agent
POSTGRES_PASSWORD=agent
POSTGRES_DB=analytics

接著啟動 PostgreSQL:

docker compose up -d

這個 demo 也會把同一份 YouTube dataset 匯入 PostgreSQL。

今天不會花太多篇幅處理 data upload,因為這篇的重點是 Agent 要怎麼從不同 datasource 讀資料,而不是使用者怎麼把資料上傳進 system。

之後在做 frontend data-management flow 時,再把 file upload、backend 與 PostgreSQL 串起來。

Database Datasource

對 database 來說,我希望 Agent 可以直接呼叫:

query_database(
    """
    SELECT channel, SUM(views) AS total_views
    FROM videos
    GROUP BY channel
    ORDER BY total_views DESC
    LIMIT 10
    """
)

Agent 負責提供 query。

database connection 和 query execution 則留在 datasource implementation。

例如:

async def query_database(query: str):
    source = PostgresSource(cfg.database.dsn)
    return await source.query(query)

PostgreSQL implementation 可以像這樣:

import asyncpg


class PostgresSource:
    def __init__(self, dsn: str):
        self.dsn = dsn

    async def query(self, sql: str) -> list[dict]:
        conn = await asyncpg.connect(self.dsn)

        try:
            rows = await conn.fetch(sql)
            return [dict(row) for row in rows]
        finally:
            await conn.close()

整個 flow:

Agent
  ↓
query_database()
  ↓
PostgresSource
  ↓
PostgreSQL

同樣地,Agent 不需要知道:

asyncpg.connect
database credentials
connection handling
query execution details

它只需要知道怎麼取得需要的資料。

Why Two Different Tools?

雖然 file 和 database 都是 datasource,但它們本來就有不同的使用方式。

對 file 來說,直接讀取 dataset 很合理:

read_file(filename)

但 database 通常不需要整份讀進來。

Agent 可以只取得當前 Analysis 真正需要的資料:

query_database(query)

例如:

SELECT channel, SUM(views) AS total_views
FROM videos
GROUP BY channel
ORDER BY total_views DESC
LIMIT 10

而不是把整個 database 都載入 memory。

所以我不打算為了讓它們看起來一致,就強迫 file 和 database 使用完全一樣的方式。

它們可以有相同的目的,但不一定要有相同的 implementation。

Keep the Agent-Facing Tools Simple

目前 Agent 只會看到:

read_file
query_database

底下的 implementation 可以獨立變動。

例如之後可能會:

  • 增加 XLSX 或 PDF support
  • 替換 CSV reader
  • 改變 PostgreSQL connection 的管理方式
  • 加入 connection pooling
  • 支援其他 database

這些改動最好都留在 datasource implementation 裡,而不是一直影響 Agent。

核心想法就是:

Agent 應該看到它需要的能力,而不是底層 implementation details。

Final Flow

目前整體結構會變成:

Agent
  ↓
Tools
  ↓
Datasource implementation
  ↓
File / Database

對 file:

Agent
  ↓
read_file()
  ↓
CsvFileSource
  ↓
CSV

對 database:

Agent
  ↓
query_database()
  ↓
PostgresSource
  ↓
PostgreSQL

到這裡,Agent 已經有一個方式可以讀取 file 與 database。

下一步就可以真的讓 Agent 使用這些 tools,理解目前有哪些資料,並開始產生 analysis code。


上一篇
[Day 6] 從 Config 開始建立 Datasource System
下一篇
[Day 8]:介紹 Deep Agents
系列文
AaaS from Scratch: 從一次性定義,到規模化分析9
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言