**先講結論:**Service 是為使用者完成一項工作所需的系統邊界,也包含對結果、依賴與失敗行為的責任。
Day 8 把 AI 系統的 Reliability、Quality、Safety 分開看。接下來要談 failure model,得先回答一個更基本的問題:故障發生時,我們口中的「服務」到底是哪一段?邊界沒畫清楚,SLO、on-call、告警和事後檢討都很容易各講各的。
傳統 Web API 的圖通常長這樣:
Client
↓
API
├── DB
└── External API
↓
Response
使用者看見的是「查詢訂單」或「新增預約」;實際上,API 可能要驗證身分、讀資料庫、呼叫付款或物流服務,才有辦法回應。
若把 Service 理解成「這個 API process 還活著」,很快會遇到盲點:process 正常、HTTP 200 也正常,資料庫可能已回傳舊資料,外部付款服務可能拒絕請求,或最後回覆的內容根本沒有完成使用者要做的事。
在 SRE 的語境裡,Service 要說清楚使用者要完成什麼工作、請求會穿過哪些依賴,以及依賴失敗時系統怎麼回應。
畫出邊界,是為了在 incident 發生時判斷使用者受影響的訊號與處理責任。
同一個元件可以同時出現在不同 Service 的邊界裡。
以「查詢訂單」為例,訂單 API 對 App 團隊是一個 Service;資料庫團隊提供的 PostgreSQL 也是另一個 Service;付款供應商則是外部 Service。它們有各自的使用者、契約與責任人,但一筆使用者請求會把它們串成一條路徑。
使用者要查訂單
↓
Order API ──讀取──→ PostgreSQL
│
└──查詢──→ Payment Provider
這裡有兩個容易混在一起的概念:
| 名稱 | 問的問題 | 例子 |
|---|---|---|
| 元件(component) | 這是什麼程式、資料庫或基礎設施? | order-api pod、PostgreSQL instance |
| Service | 它替誰提供什麼能力,失敗時誰承擔結果? | 「使用者能查到正確訂單狀態」 |
一個 Service 可由很多元件組成;一個元件也可能同時服務多條使用者流程。把兩者畫上等號,最常見的後果是只監測 container health,卻沒發現使用者已經查不到正確結果。
GitHub 在 2026 年 9 月的一次事故中,內部資料清理工作把權限資料庫主節點的連線數寫到用盡。當時唯一被監看的健康訊號是 replica 延遲,而 replica 延遲全程正常;安全機制沒有察覺主節點正在逼近極限,直到請求開始大量逾時。監測的元件「健康」,使用者能不能登入、建 issue 卻早已不健康。GitHub 事故報告
Google 的 SRE 書也把服務視為有使用者期待的行為,而非單一機器:SLI 與 SLO 要先從使用者在意的行為出發,再決定如何量測。Google SRE Book:Service Level Objectives
不是每個呼叫失敗都同樣嚴重。關鍵在於它對對外能力的影響。
Order API
├── PostgreSQL:訂單資料的必要依賴
├── Payment Provider:付款狀態的必要依賴
└── Recommendation API:可選依賴,失敗時可省略推薦區塊
這三條箭頭看起來很像,行為卻不同:
dependency map 除了列名稱,也要寫下失敗時的預期行為與可觀測訊號。
| 依賴 | 為何需要 | 失敗時的預期行為 | 可觀測訊號 |
|---|---|---|---|
| PostgreSQL | 讀取訂單資料 | 回受控錯誤,不回傳猜測資料 | query error、latency、資料庫連線狀態 |
| Payment Provider | 顯示付款狀態 | 明示狀態暫不可確認,排入補查 | dependency timeout、補查 backlog |
| Recommendation API | 推薦商品 | 降級為不顯示推薦 | fallback rate、dependency error |
「預期行為」要在設計階段寫進 dependency map,而非 incident 後才補上。若團隊沒有決定 fallback,程式通常會等到 timeout、丟 500,或回一份看似完整但其實不可信的資料。
AI 應用常被包成一個 /ask endpoint,實際的服務路徑卻比傳統 API 長得多:
Client
↓
Gateway
↓
Prompt / Policy
↓
Retriever ──→ Vector DB
↓
Model ──→ LLM Provider
↓
Tool Executor ──→ Internal / External tools
↓
Validator
↓
Response
其中每一段都可能是另一個 Service,也可能是同一個團隊維護的元件。方塊數量不決定 Service boundary;是否要對契約與風險負責,才是判斷依據。
以公司差旅問答為例,使用者問「國際機票需要誰核准?」:
Question
↓
Retriever 找政策文件
↓
LLM 依文件產生答案與引用
↓
Validator 檢查引用是否允許、格式是否符合 contract
↓
Answer
這條路徑至少有四種不同的失敗:
| 發生位置 | 使用者可能看見的結果 | 不該草率下的結論 |
|---|---|---|
| Retriever | 找不到正確政策 | 「模型不會回答」 |
| Vector DB | 檢索逾時 | 「LLM provider 壞了」 |
| LLM Provider | 429、5xx 或 latency 增加 | 「RAG 的資料品質下降」 |
| Validator | 擋下不允許的引用或越權 action | 「API 成功就代表任務成功」 |
Day 8 的三條軸在這裡仍然成立。Provider timeout 是 Reliability 問題;引用無關文件卻自信作答是 Quality 問題;Agent 嘗試執行未授權操作則是 Safety 問題。它們可能同時發生,也可能只發生其中一種。別把整條 workflow 壓成 success: true。
「模型 API 回 200」不等於 AI Service 完成工作。同樣地,「我們用的是外部模型」也不等於所有可靠性責任都能交出去。
團隊無法控制 LLM provider 的內部系統,仍可決定自己的呼叫方式與失敗策略。包含 timeout、可重試的錯誤、rate limit 預算、資料不足時的拒答,以及 provider 不可用時要降級還是停止服務。
外部依賴出問題時,修復並不總是只靠「等待對方恢復」。AWS 在 2021 年 12 月 us-east-1 事件中提到,內部網路受影響後,monitoring 與 deployment systems 也受影響,讓排查與修復在能見度降低的狀態下進行。AWS 的事件報告 監控、部署與身分驗證等 control plane 能力,同樣應出現在 dependency map;它們壞掉時,資料面可能還在處理部分流量,恢復能力卻已經變弱。
對 AI workflow 而言,還要額外問幾個問題:
阻擋付款與顯示推薦商品的風險不同,故障預設值也應不同。把這個選擇寫下來,才能討論與測試。
複雜系統不需要第一天就畫出全公司的服務地圖。先挑一個使用者工作,畫出完成它所需的最短路徑。
使用者取得「有來源、符合權限」的差旅政策答案
↓
Gateway 接受並驗證請求
↓
Retriever 取回允許的政策文件
↓
LLM 產生可解析的回覆
↓
Validator 驗證來源與權限
↓
回傳答案或明確說明無法完成的原因
這條 critical path 讓量測有對象、告警有上下文,也能及早討論 provider 故障或資料不足時的降級方式。這些是產品與風險決策,不是 SRE 一個人替大家決定。
Google 也提醒,服務間的 production dependencies 會形成巢狀關係;上游服務的放置與效能要求,會受下游依賴限制。Google SRE Book:Developing Software for Complex Machines 這也是為什麼只看自己服務的 CPU、memory 或 container restart 次數,通常不足以判斷使用者路徑是否健康。
先畫出 Service boundary,再挑 SLI。不是所有 trace 裡看得到的欄位,都已經是能用來管理可靠性的訊號。
以 /ask 為例,下面幾種狀態都可能出現在 telemetry:
| 訊號 | 可以先量什麼 | 還不知道什麼 |
|---|---|---|
| Gateway | request rate、5xx、end-to-end latency | 低延遲是否代表答案有用 |
| Retriever | retrieval latency、empty-result rate | 找到的內容是否真的支持回答 |
| LLM Provider | timeout、429、token usage | 模型輸出是否正確或安全 |
| Validator | block rate、format failure rate | block 是精準攔截還是誤擋 |
| Tool Executor | execution success、denied action count | 工具成功執行是否完成使用者任務 |
前一欄是可操作的候選 SLI;後一欄需要 golden dataset、抽樣 review 或任務完成證據,才能用於判定。缺少這些證據時,就標成 UNKNOWN,不要用一個方便取得的 proxy 假裝它已被量測。
retrieval latency 正常
≠
retrieved context 足以支持答案
tool execution success
≠
使用者任務已安全完成
可觀測性讓我們看見系統狀態;SLI 則是經過定義、能對應使用者期待並支撐決策的量測。Day 10 開始拆 failure 時,這個區別會很有用:有些訊號告訴我們哪裡壞了,有些訊號才告訴我們使用者是否真的受影響。
畫出依賴,是為了讓每個 Service owner 清楚自己的契約、可觀測性與降級行為。
較好的分法是:每個 Service owner 對自己的契約、可觀測性和已知降級行為負責;使用它的團隊則對「把這個依賴放進使用者路徑後,自己的 Service 如何失敗」負責。兩邊都要做事。
例如 LLM provider 429 時,provider 負責恢復其服務;應用團隊仍要決定 retry policy、排隊上限、使用者訊息與是否切換備援。若每一層都只說「那是下游的問題」,最後使用者看到的只會是自己的問題。
這也是 Service boundary 能當共同語言的原因:產品能說清楚哪個使用者工作最重要;開發者能說清楚 contract;SRE 能把可用性、延遲、依賴與降級行為變成可觀察的訊號;安全或領域專家能界定哪些操作絕不能 fail open。
Google 的 SRE Book 也把這件事寫進制度:postmortem 的目的是釐清根因、訂出可執行的預防措施,並作為全公司的學習機會。Service boundary 與依賴責任要先畫清楚;否則事後檢討容易變成追究個人責任,系統問題反而沒有被修正。Google SRE Book:Postmortem Culture
這個 DIY 不需要先寫程式。挑一個你現在的 API 或 AI workflow,花 20 分鐘把它畫成一條使用者路徑。這個練習要找出使用者要完成什麼,以及中間卡住時系統會怎樣。完整架構文件不在本次範圍。
不要寫「RAG service」或「訂單 API」。試著寫成使用者結果,例如:
已登入的員工可以查到有來源、符合權限的差旅政策答案。
這句話就是你暫時要守住的 Service contract。契約除了回傳文字,也要包含來源與權限。
沿著一個 request 寫下它經過的元件。先畫最短路徑即可:
Client → Gateway → Retriever → Vector DB → LLM Provider → Validator → Response
每一個方塊旁邊補三個欄位:owner、必要或可選、失敗時的預期行為。若你寫不出最後一欄,不必硬湊答案,直接標 UNKNOWN。這表示失敗時的預期行為尚未定義。
例如假設 LLM provider 回 429,依序回答:
把答案寫進 dependency map。若答案是「不知道」,一樣保留。它比在 incident 當下才發現沒人知道更有用。
從你的圖上挑一個容易量到、卻不能直接代表使用者結果的數字,例如 token usage、retrieval latency 或 tool execution success。替它寫下缺少的證據,再標為 UNKNOWN。這一步用來記錄 proxy 與使用者結果之間仍缺少的證據。
做完後,你應該能拿出一張含使用者結果、依賴、失敗預期與候選訊號的圖。這張圖記錄的是目前的設計假設。壓力測試與 incident drill 仍需另外進行;Day 10 分析 Fault → Error → Failure 時會以它作為共同座標。
這裡是讀者可自行完成的設計檢查。本文沒有建立 Day9/DIY、安裝依賴、啟動服務或執行以下檢查,因此不宣稱任何程式或架構已驗證。
UNKNOWN,不把它直接當 SLI。Service 是一項對外能力連同它的依賴與失敗行為。傳統系統的 API、DB 與外部服務如此;AI workflow 裡的 Retriever、LLM provider、Tool Executor、Validator 也一樣。
先畫出使用者的 critical path,再替每個依賴寫下失敗時的預期行為。下一次 timeout、錯誤答案或被阻擋的 action 出現時,這些邊界能幫助團隊判斷問題落在哪裡、接下來該問什麼。
有了 Service 與 dependency 的邊界,下一步才能分清楚一個經常混用的因果鏈:程式裡的 bug、系統內的錯誤狀態,和使用者真正看見的失敗,並不是同一件事。Day 10 會用 Fault → Error → Failure 把它們拆開。