10 min給工具使用者

Library、SDK、Framework、API 到底差在哪?先看誰呼叫誰

Library、SDK、Framework、API 的差別不只在功能名稱,更在誰啟動程式、誰決定何時呼叫,以及錯誤發生在哪一層。用 Python 標準函式庫與教學用 Runner 比較控制權,並透過可重跑案例辨認介面與框架的責任邊界。

Aaron Huang系統、產品與 AI 實作

Library、SDK、Framework、API 到底差在哪?先看誰呼叫誰

Library(函式庫)提供可由程式主動呼叫的功能;SDK(軟體開發套件)提供針對特定平台或服務的開發工具組合;Framework(框架)通常掌握主要執行流程,並在約定時機呼叫你提供的程式;API(應用程式介面)則是雙方約定如何使用能力的介面。 四者不是互斥的產品分類:一個 SDK 可以包含 library、提供 API 的包裝,而 framework 本身也會提供 API。

你已經能從第三篇〈從一段 Python 走到一個可重跑的小專案〉找到入口與函數。本篇不再重教 import 或拆檔,而是回答遇到陌生工具時更關鍵的問題:入口在誰手上?下一個函數由誰呼叫?資料交給誰?出錯先看哪一層?

目錄

四個名稱描述的不是同一個維度

名稱 核心角色 一般由誰決定何時使用 遇到問題先看
Library(函式庫) 已寫好的可重用功能,例如 Python 標準函式庫 statistics 你的程式決定何時呼叫 傳入值與函數契約
SDK(軟體開發套件) 面向某平台的開發工具組合,可能包含 library、範例、文件與其他工具 你的程式呼叫其中的介面;不保證所有 SDK 都相同 SDK 的方法、設定與版本,以及底層服務
Framework(框架) 提供應用程式骨架與部分生命週期,依規則呼叫使用者程式 框架通常決定何時觸發你登記的處理函數 登記規則、生命週期、傳入資料
API(應用程式介面) 定義可用操作及輸入/輸出的契約 由該介面的呼叫者發起 名稱、參數、回傳與錯誤契約

API 不等於網路請求。 statistics.mean([10, 20]) 也是在使用 Python 函式提供的程式介面;服務提供的 API 則可能透過 SDK 使用。至於外部服務的一次 HTTP 請求與 JSON 回應,留到系列第七篇再深入,避免把「介面是什麼」和「資料怎麼跨網路傳」混成一件事。

同一個需求,控制權可以放在不同地方

假設我們要把合成的學習分鐘數算出平均值。

寫法 A:程式主動呼叫 library。

from statistics import mean

minutes = [10, 20, 30]
average = mean(minutes)
print(f"average={average:.1f}")

這裡是你啟動 Python → 你的程式呼叫 mean → library 回傳 20 → 你的程式印出結果。Library 沒有決定你的主程式何時開始、下一步要做什麼。

寫法 B:把處理函數交給控制流程。 真正的 framework 不只是「有 callback(回呼函數:先交給另一段程式,在約定時機由對方呼叫)的 library」:它通常還管理啟動、事件派送、設定或其他生命週期。為了看清楚呼叫方向,下面只實作一個教學用極簡框架模擬器,不宣稱它是正式框架,也不要求安裝任何產品。

你啟動 main()
  → 教學用 Runner.run() 掌控迴圈
    → Runner 呼叫你登記的 on_record(record)
      → on_record 回傳結果
    → Runner 收集結果

差別不是「框架不用寫程式」,而是你把何時呼叫處理函數的決定權交給了 Runner。這個方向經常稱為控制反轉(Inversion of Control,IoC):不是程式隨時主動呼叫框架的所有功能,而是框架在約定的時機反過來呼叫你的程式。實際工具可能同時存在兩種方向,必須看具體執行入口,不能只靠名稱判斷。

SDK 又位在哪裡?以 AWS 官方 Boto3 文件的低階 client 為例:應用程式先建立 client,再由程式呼叫 client 提供的服務操作方法;該 client 對應 AWS 服務 API。呼叫方向是「你的程式 → Boto3 client(SDK 提供的程式介面)→ 服務操作」,回傳值或錯誤再交回呼叫端。這裡僅分析官方文件的介面關係,沒有安裝 Boto3、建立 client、設定帳號或呼叫 AWS 服務。SDK 不是 API 的另一個名字:API 是可用操作的契約,SDK 是協助開發者使用這些能力的一套工具。沒有指定真實產品時,不應虛構所有 SDK 都會自動重試、驗證或處理認證。

重跑練習:看見框架模擬器反過來呼叫函數

在新資料夾 control-flow-lab 建立一個 main.py,使用 Python 3 執行。以下全部是合成資料與示範程式,只用 Python 標準功能、不連線、不安裝套件。

# main.py — educational framework simulator, not a production framework
from statistics import mean

class Runner:
    def __init__(self):
        self.handler = None

    def register(self, handler):
        if not callable(handler):
            raise TypeError("handler must be callable")
        self.handler = handler

    def run(self, batches):
        if self.handler is None:
            raise RuntimeError("no handler registered")
        output = []
        for batch in batches:
            print("Runner -> handler")
            output.append(self.handler(batch))
        return output

def on_record(values):
    if not values:
        raise ValueError("empty batch")
    return round(mean(values), 1)

def main():
    runner = Runner()
    runner.register(on_record)
    print(runner.run([[10, 20, 30], [40, 50]]))

if __name__ == "__main__":
    main()

從資料夾執行:

python main.py

Codex R1 實跑觀察(Windows/PowerShell/Python 3.14.6;不是所有 Python 版本保證):

Runner -> handler
Runner -> handler
[20, 45]

先預測再改:把第二筆輸入改成 [40, 50, 60],你應預期第二個結果變成 50,但 Runner -> handler 仍印兩次。資料內容改變,不一定會改變呼叫次數。

控制錯誤:定位失敗的責任層次

先保留原檔,每次只做一個修改,觀察錯誤後還原。

  1. 把 runner.register(on_record) 暫時註解。預期 RuntimeError: no handler registered:Runner 需要的登記條件未成立,錯誤在模擬器使用契約,不是 Python 語法錯。
  2. 還原登記後,把第二筆改成 []。預期先印兩次 Runner -> handler,再從 on_record 拋出 ValueError: empty batch:Runner 已正確派送,失敗來自你提供的處理函數對輸入的要求。
  3. 再還原輸入;將 runner.register(on_record) 改為 runner.register("on_record")。預期 TypeError: handler must be callable:名稱字串不是可呼叫的函數物件。這是登記參數錯誤,不必重寫整個 Runner。

上述六個情境(library 範例、正常流程、輸入變體、三個控制錯誤)已由 Codex 在 Windows/PowerShell/Python 3.14.6 實跑;失敗案例預期以非零結束碼結束。這只驗證列出的程式和環境,不代表所有 Python 版本或真實框架均通過。若執行結果不同,先讀 traceback 最後一行的例外型別,再往上找是哪個函數提出例外、誰把資料交給它。不要看到 framework 或 SDK 的字樣就將問題歸咎於 Python 語法或網路。

面對陌生工具,用四個問題判斷

拿到一份教學或程式碼,先標出:

  1. 誰啟動? 你執行 main.py、呼叫一個 library 函數,還是由 framework 的執行器啟動?
  2. 誰呼叫誰? 你的程式呼叫套件,還是框架透過登記、繼承或事件機制呼叫你的 callback(回呼函數)?
  3. 資料怎麼走? 入口收到什麼、傳給哪個介面、回傳什麼;哪些細節被 SDK/框架封裝?
  4. 失敗在哪一層? 是 Python 語法、登記契約、callback 邏輯,還是外部服務?只依可觀察的錯誤與文件判斷,不憑工具名稱猜。

選工具也從需求出發:只缺一個轉換功能,先找適合的 library;需要使用特定平台的多項能力,再評估它提供的 SDK;需要既定生命週期、路由或事件管理,才考慮 framework。不是抽象層越多就越進階。抽象省掉重複控制流程,也隱藏部分執行細節;好處與診斷成本必須一起看。

驗收與停止線

不看程式答案,試著畫出兩段箭頭:「你 → mean → 回傳」與「你啟動 Runner → Runner → on_record → Runner」。能指出三次控制錯誤分別在哪個契約邊界、能修改不同輸入並預測結果,就是本篇的最低驗收;真正能力仍須以你親自執行並解釋輸出為證據。

到這裡就可以進下一篇。 不必為了比較安裝 FastAPI、Django 或多套 SDK,也不要求重構現有專案。先前的 Python 執行環境、資料流與小專案各有自己的教學範圍;Git 留給第五、六篇,HTTP/JSON 的服務呼叫留給第七篇。第七篇尚未提供已驗證的公開 URL,因此不預先建立連結。

教材依據:《AI_Engineering_Foundations_v1.0》課程節 S04(2026-09-23;保留摘錄為第 12 頁擷取文字),以及已接受的 AI Engineering Foundations 系列規劃。本篇的 Runner 是為說明控制權而設計的合成示例,不代表任何真實 framework 的完整行為。

技術資料與證據界線

以下資料於 2026-10-08 查閱;產品文件隨版本可能更新。課程的篇章界線另依《AI_Engineering_Foundations_v1.0》S04(2026-09-23)及已接受的系列規劃。