想像你是團隊裡第一個要畫「AI 功能架構圖」的人。最容易畫出來的版本長這樣:前端 → 你的 API → OpenAI,三個框、兩支箭頭,會議上大家點頭通過。三個月後這張圖的代價陸續到期:想寫測試,發現業務邏輯跟 SDK 呼叫纏在一起;想換模型或加 RAG,發現 prompt 散在十個 handler 裡;資安問了一句「哪些客戶資料進過 prompt?」,沒有人答得出來。今天這篇要給你一張經得起這三個問題的參考架構圖,以及每一層存在的理由。
昨天(Day 1)的結論是:LLM 是一個把不確定性帶進回傳值的下游依賴。順著這個結論,GenAI backend 的架構其實由三個問題決定,「用了哪些服務」只是回答完之後的產物:
「只包一層 SDK」的做法之所以撐不久,就是因為它對這三個問題的答案都是「沒有答案」。

從請求進來到回應出去,一層一層看它在防什麼。
認證、輸入驗證、rate limit、correlation ID 都發生在這裡。它存在的理由只有一個:對外的 API 合約必須比模型穩定。模型會換、prompt 會改、RAG 會加,但 client 看到的 request/response schema 與錯誤格式不該跟著抖動。這層也是成本的第一道閘門:輸入長度上限設在這裡,Day 1 說的「空白支票」問題在資料進系統的第一步就擋掉。
對話狀態管理、prompt 組裝、要不要先做檢索(RAG)、允許模型使用哪些工具(Agent)。這些政策全部集中在這層。關鍵特徵:這一層是確定性的函式。給它相同的輸入與狀態(包括模型上一步回了什麼),它就組出相同的 prompt、做出相同的路由決策。模型的選擇會影響流程走向,但那個選擇是從 adapter 介面進來的資料,不是藏在這層裡的隨機性。也因此這層的政策與控制流程可以用一般的單元測試覆蓋,不需要碰任何真模型。
第二個問題(什麼資料能進 prompt)的答案也鎖在這裡:prompt 組裝集中在一個地方,你才有辦法回答哪些資料被送往哪個模型 deployment、有沒有先遮罩、適用哪一套保留政策,也才有位置實施過濾。prompt 散在十個 handler 裡的系統,這個問題在結構上就是無法回答的。
LLM 呼叫、向量檢索這些「會慢、會錯、會不確定」的外部互動,各自包在一個薄的 adapter 後面,介面由你定義,不照抄 SDK。這帶來三件事:模型可以換(Azure OpenAI 換版本、換供應商,SDK 與 transport 的改動集中在一個檔案;prompt 表現與能力差異當然還是要重新驗證,但那是評估工作,不是重寫工作);測試可以假(fake adapter 回固定答案,整條業務邏輯鏈在毫秒內測完);行為可以量(timeout、重試、熔斷都實作在這一層,而不是散落各處)。
這就是「把不確定性關進最小的籠子」的具體意思:模型與檢索供應商帶來的不確定性,都必須經過這幾個可識別的介面進入系統。資料庫競態、時間與其他外部依賴當然仍存在;這個邊界保證的是,核心政策可以在 fake adapter 下用確定性的單元測試驗證。
模型(Azure OpenAI)、檢索(Azure AI Search)、對話狀態儲存都在系統邊界外側。供應商可以代管對話狀態,但本系列會在 Day 5 選擇 store=False,因此跨 request 的記憶由 backend 組裝。狀態放哪裡、留多久、誰能讀,會成為 Day 7 的治理與架構題。
correlation ID 從 API 層進來,跟著請求穿過每一層,最後跟 token 用量、延遲、模型版本一起落到遙測(Application Insights)。這是第三個問題的答案:成本異常、品質退化、安全事件,全部要靠這條線事後重建現場。它畫成虛線,但它是這張圖上最不能省的部分。
忍喵:「虛線最容易被砍,因為 demo 沒有它也會動。等你需要它的那天,資料已經沒在收了。」
「直接在 handler 呼叫 SDK」:最快看到 demo 的路,也是三個月後重寫的路。否決它的跟優不優雅無關,是那三個問題:不確定性無處不在(測不了)、prompt 無處可管(答不了資安)、觀測事後才補(查不了帳單)。
「一開始就上編排框架全家桶」:LangChain 這類框架解決的是真問題,但對一個剛起步的系統,你等於把「邊界畫在哪」這個最重要的決策外包給框架的抽象。我的選擇是先用 Protocol + adapter 自己畫邊界(總共幾十行程式碼),等痛點真的出現再評估框架,那時你至少知道自己在買什麼。
忍喵:「幾十行 adapter 換一個看得見的邊界,很划算。框架不是不能買,是別在不知道自己要買什麼的時候刷卡。」
適用:單一團隊、單一 deployable、功能會從 Chat 長到 RAG 與 Agent 的系統(也就是本系列要蓋的東西)。
不適用:已經有平台團隊提供 LLM gateway 的大組織(你的 adapter 層會往外移)、或者確定只做一次性 demo 的專案(三個框兩支箭頭真的就夠,別過度設計)。
維運成本也講清楚:這個架構本身不增加雲端費用(分層是程式碼結構,不是部署拓撲),但觀測面有實際成本。遙測 ingestion 是要錢的,Day 27 會談怎麼在免費額度內活著。
這張圖落到本系列的 repo,就是這個套件結構:api/(API 層)、core/(編排與設定)、services/(adapter 層)、models/(跨層的 DTO)、prompts/(prompt 資產)。
Day 3 會把這個骨架實際建起來,你會看到目錄結構直接對應這張圖的責任邊界。這是概念上的對應,不是「一層永遠等於一個目錄」;編排邏輯長大後,可能再從 core/ 拆出專門的模組。本篇的完整英文版架構文件與 Mermaid 原始圖在 repo 的 day-02 tag。
| 工程需求 | Azure / Microsoft 對應服務 | 在這張圖的位置 |
|---|---|---|
| 模型推論 | Azure OpenAI Service | adapter 層後方的外部依賴(Day 4 接入) |
| 向量檢索 | Azure AI Search | adapter 層後方的外部依賴(Day 11–15) |
| 遙測與追蹤 | Application Insights | 貫穿四層的觀測面(Day 27) |
GenAI backend 的參考架構不是服務清單,是三個問題的答案:外部與模型驅動的不確定性經由明確的 adapter 介面進入系統,prompt 資料邊界鎖在編排層的單一組裝點,觀測面從第一天就貫穿全部。這張圖現在還是紙上談兵。明天(Day 3)就把它變成能跑的專案骨架:uv、FastAPI、測試、CI,一次到位。
(本篇無新增雲端資源;服務對照表列的是各服務在架構中的位置,實際接入從 Day 4 開始。)
本文由作者規劃與撰寫,AI(Claude)協助草稿整理與程式碼驗證;技術內容與觀點由作者確認並負責。