上線:可觀測性、安全與成本Production: observability, security, cost
LLM 系統上線後,問題通常不是「當掉」,而是「安靜地變差」:回答品質下滑、成本慢慢上升、某個 prompt 注入讓它做了不該做的事。這一章談怎麼讓這些問題看得見、擋得住、查得出來。
Once live, LLM systems rarely crash; they degrade quietly. Answer quality slips, cost creeps up, a prompt injection makes them do something they shouldn't. This chapter is about making those problems visible, containable and traceable.
讀完這章你能夠After this chapter you can
- 定義每個請求要記錄的追蹤欄位,讓任何一次錯誤回答都能重現原因。
- 用架構而不是 prompt 來降低提示注入的風險。
- 找出成本與延遲的主要來源,並按優先順序處理。
- 依資料限制、能力需求、用量與維運能力,決定用雲端 API 還是自己架設模型。
- 規劃逾時、重試、降級、分階段發布與交接。
- Define the trace fields to record per request so any bad answer can be explained.
- Reduce prompt-injection risk through architecture rather than prompts.
- Find the main drivers of cost and latency and address them in order.
- Decide between a cloud API and a self-hosted model based on data constraints, capability, volume and ops capacity.
- Plan timeouts, retries, degraded modes, staged rollout and handover.
可觀測性:每個請求都要能重現Observability: every request reproducible
客戶拿著截圖說「它昨天這樣回答」。你需要在幾分鐘內知道:當時用了哪個 prompt 版本、哪個模型、檢索到哪些文件、呼叫了哪些工具、驗證重試了幾次。一般的應用程式 log 不夠,你需要以請求為單位的追蹤(trace)。
A customer shows a screenshot: "it answered like this yesterday". Within minutes you need to know which prompt version and model were used, which documents were retrieved, which tools were called and how many validation retries happened. Ordinary application logs aren't enough; you need per-request traces.
{
"trace_id": "8f2c1d0e", "tenant": "acme", "user_hash": "u_51b2…",
"prompt_version": "clause-assess@14", "model": "claude-opus-5-5",
"steps": [
{"step": "retrieve", "latency_ms": 41, "candidates": 10,
"returned": ["CLAUSE-004", "CLAUSE-003"], "acl_groups": ["everyone"]},
{"step": "generate", "latency_ms": 3810, "input_tokens": 2214, "output_tokens": 377,
"cache_read_input_tokens": 1800, "stop_reason": "end_turn"},
{"step": "validate", "attempts": 2, "errors": ["mitigation: placeholder text 'TBD'"]}
],
"status": "ok", "total_latency_ms": 7930, "cost_usd": 0.0187,
"user_feedback": null
}
- 版本化所有東西:prompt、schema、檢索設定、模型 ID。沒有版本,就沒辦法比較改動前後。
- log 裡也有個資。決定哪些欄位要遮蔽、誰能查、保留多久,和正式資料一樣嚴格。
- 標準化:OpenTelemetry 已有針對生成式 AI 的語意慣例,可以讓追蹤資料接到既有的監控平台。
- Version everything: prompts, schemas, retrieval settings, model IDs. Without versions you can't compare before and after.
- Logs contain personal data too. Decide which fields to mask, who can query them and how long they're kept, as strictly as for production data.
- Standardise: OpenTelemetry has semantic conventions for generative AI, so traces can flow into existing monitoring platforms.
要監控與告警的指標Metrics to monitor and alert on
| 指標Metric | 異常代表An anomaly suggests |
|---|---|
| 驗證失敗率、修復重試次數Validation failure rate, repair retries | 模型行為改變或輸入分布改變Model behaviour or input distribution changed |
拒答率、stop_reason 分布Refusal rate, stop_reason mix | prompt 問題、輸出被截斷、安全機制觸發Prompt issues, truncation, safety triggers |
| 檢索結果為空的比例Empty-retrieval rate | 索引過期、權限設定錯誤、新類型的問題Stale index, permission misconfiguration, new question types |
| P95 延遲、每請求成本P95 latency, cost per request | context 變長、快取失效、重試增加Growing context, cache misses, more retries |
| 倒讚率、轉人工率Thumbs-down, escalation rate | 品質下降,即使其他指標都正常Quality drop, even when everything else looks fine |
| 待核准佇列長度與等待時間Approval queue length and wait | 核准流程卡住,或核准太多導致疲勞Approvals stuck, or so many that reviewers fatigue |
安全:提示注入Security: prompt injection
只要模型會讀到不可信的內容(使用者輸入、網頁、email、上傳的文件、工具回傳的資料),那些內容就可能包含指令,而模型可能照做。目前沒有任何過濾器或 prompt 寫法能可靠地完全防止。所以要從架構下手:假設注入一定會成功,然後限制它能造成的傷害。
Whenever a model reads untrusted content (user input, web pages, email, uploaded files, tool results), that content may contain instructions the model follows. No filter or prompt wording reliably prevents this today. So work at the architecture level: assume injection will succeed and limit the damage it can do.
致命三要素The lethal trifecta
Simon Willison 提出的框架很實用:當一個 agent 同時具備以下三項能力,攻擊者就可能竊取資料。拿掉任何一項,這條攻擊路徑就斷了。
Simon Willison's framing is practical: when an agent has all three of the following, an attacker can steal data. Remove any one and that attack path closes.
能存取機密資料Access to private data
客戶資料庫、內部文件、使用者的信箱。
Customer databases, internal documents, a user's inbox.
會讀到不可信內容Exposure to untrusted content
外部信件、網頁、使用者上傳的檔案、公開的 issue。
External email, web pages, user uploads, public issues.
能對外傳送資料Ability to communicate externally
呼叫外部 API、寄信、產生會被瀏覽器載入的連結或圖片網址。
Calling external APIs, sending email, emitting links or image URLs a browser will load.
具體措施Concrete measures
- 最小權限:工具只拿得到這個使用者、這個任務需要的資料(第 5、6 章)。
- 對外動作需要確認:寄信、付款、修改設定,都由人核准確切內容。
- 小心輸出被渲染:模型輸出的 Markdown 圖片
會讓瀏覽器自動送出資料。限制可載入的網域,或不渲染模型產生的外部圖片與連結。 - 區隔內容與指令:把不可信內容放在明確標記的區塊中,並告訴模型那只是資料。這能降低機率,但不是安全邊界。
- 機密不進 prompt:API key、密碼不要出現在模型看得到的任何地方。
- 測試:把注入攻擊案例加進測試集(第 7 章),每次改動都跑。
- Least privilege: tools reach only the data this user and this task need (chapters 5 and 6).
- Confirm outbound actions: sending email, payments, configuration changes all require human approval of the exact content.
- Beware rendered output: a Markdown image in model output such as
makes the browser send data automatically. Restrict loadable domains, or don't render external images and links produced by the model. - Separate content from instructions: wrap untrusted content in clearly marked blocks and tell the model it is data. This lowers the odds but is not a security boundary.
- Keep secrets out of prompts: API keys and passwords must never appear anywhere the model can see.
- Test it: add injection cases to your test set (chapter 7) and run them on every change.
個資與資料治理Personal data and governance
- 最小化:只把完成任務需要的欄位送進模型。身分證字號、卡號通常不需要。
- 送出前遮蔽:用規則或專門的偵測工具替換成代號,回應後再換回來。
- 確認供應商條款:資料是否被保留、保留多久、是否用於訓練、在哪個區域處理。這些通常有企業方案或設定可以調整,要在合約階段確認。
- 保留期限:對話紀錄、trace、測試集都要有明確的保留與刪除規則。
- Minimise: send only the fields the task needs. National IDs and card numbers usually aren't.
- Mask before sending: replace sensitive values with tokens via rules or a detection tool, and restore them in the response.
- Check vendor terms: whether data is retained, for how long, whether it's used for training, and where it's processed. Enterprise plans and settings usually govern these; confirm them at contract time.
- Retention: conversation logs, traces and test sets all need explicit retention and deletion rules.
成本與延遲Cost and latency
先量測,再優化。trace 裡有每一步的 token 與延遲之後,通常會發現成本集中在少數地方。常見的手段,大致依「不影響品質」到「需要取捨」排列:
Measure, then optimise. Once traces record tokens and latency per step, cost usually turns out to be concentrated in a few places. Common levers, roughly from "free" to "trade-off":
- Prompt caching:把不變的內容(system prompt、工具定義、固定文件)放在前面,讓 provider 快取。prompt 開頭只要有一個字元不同(例如放了時間戳記),快取就失效。
- 縮短 context:檢索結果取需要的數量、移除重複段落、限制對話歷史長度。
- 限制輸出長度,並在 UI 用串流,讓使用者更早看到第一個字。
- 離線工作用批次 API:不需要即時回應的大量處理,通常有較低的價格。
- 依任務選模型:簡單的分類步驟可能用較小的模型就夠。這是品質取捨,要用評測確認,不要憑感覺降級。
- Prompt caching: put stable content (system prompt, tool definitions, fixed documents) first so the provider can cache it. A single changed character early in the prompt (say, a timestamp) invalidates the cache.
- Shorter context: retrieve only as many chunks as needed, drop duplicates, cap conversation history.
- Cap output length, and stream in the UI so users see the first token sooner.
- Batch APIs for offline work: bulk processing that needn't be immediate is usually priced lower.
- Choose models per task: a simple classification step may be fine on a smaller model. This trades quality, so confirm it with evals; don't downgrade on a hunch.
選模型:雲端 API 還是自己架Choosing a model: cloud API or self-hosted
到目前為止,課程都假設你呼叫雲端的模型 API。但在客戶現場,常常會遇到另一個問題:「我們的資料不能離開公司,可以用自己架的模型嗎?」這一節整理這個決定要考慮的事。
So far the course has assumed a cloud model API. At customer sites you'll often hear: "our data can't leave the company; can we run our own model?" This section covers what that decision involves.
兩個不同的維度Two different dimensions
常聽到「前沿模型 vs 開源模型」,但它們其實在描述不同的事:
People often say "frontier vs open-source models", but those terms describe different things:
- 前沿(frontier)描述的是能力:目前能力最頂尖、用最大規模算力訓練的模型。
- 開源權重(open-weight)描述的是開放程度:模型權重公開,可以下載到自己的機器上執行、微調。
- Frontier describes capability: the most capable models, trained with the most compute.
- Open-weight describes openness: the weights are published, so you can download, run and fine-tune them yourself.
目前能力最頂尖的模型多半只透過 API 提供,但也有接近頂尖水準的開源權重模型。所以真正要做的決定不是「前沿還是開源」,而是「透過雲端 API 使用」還是「自己架設執行」。
Today the most capable models are mostly API-only, but some open-weight models come close. So the real decision isn't "frontier or open" but "use a cloud API" or "host it yourself".
| 雲端 APICloud API | 自己架設(開源權重)Self-hosted (open weights) | |
|---|---|---|
| 資料去向Where data goes | 送到供應商的伺服器,依合約條款保護To the vendor's servers, protected by contract terms | 留在自己的機器或內網,可以完全隔離Stays on your machines or network; can be fully isolated |
| 能力Capability | 可以用到目前最強的模型Access to the strongest current models | 受限於你的硬體能跑多大的模型Limited by how large a model your hardware can run |
| 成本結構Cost structure | 依 token 計費,不用買硬體;用量大時累積很快Pay per token, no hardware; adds up quickly at volume | 硬體、電費、維運人力;用量越大,單位成本可能越低Hardware, power, ops staff; unit cost may fall as volume grows |
| 維運負擔Ops burden | 供應商負責The vendor's | 你負責:部署、監控、升級、擴充、故障處理Yours: deployment, monitoring, upgrades, scaling, incidents |
| 客製化Customisation | prompt、檢索、供應商提供的有限調整Prompts, retrieval, whatever tuning the vendor offers | 可以微調權重、改推論設定Fine-tune weights, change inference settings |
| 版本控制Version control | 指定明確的模型 ID;舊版本會被淘汰,需要規劃升級Pin explicit model IDs; old versions retire, so plan upgrades | 自己決定何時升級;權重、量化、推論引擎都要一起管版本You decide when to upgrade; version weights, quantisation and engine together |
具體的模型名稱與能力排名變化很快,這裡刻意不列。需要時,請查各供應商與模型社群的最新資訊,並記下查詢日期。
Specific model names and rankings change quickly, so they're deliberately omitted. When you need them, check the vendors' and model communities' latest information and note the date.
怎麼決定:先問需求,不是先挑模型Deciding: ask about requirements, not models
這些問題在第 02 章的需求訪談就要問:
Ask these during discovery (chapter 02):
- 資料能不能送到外部服務?先確認法規、合約與公司政策。如果可以,再看雲端供應商的資料保留與區域條款能不能接受(見上面的「個資與資料治理」)。半導體製程、金融、醫療、國防等領域,答案常常是「不行」。
- 需要多強的能力?用你的測試集(第 07 章)實際比較,而不是看公開排行榜。小模型在你的任務上夠不夠用,只有你的資料能回答。
- 用量多大?每天幾十次和每天幾十萬次,成本結論完全不同。
- 誰來維運?自己架設等於多了一套要顧的系統。客戶有沒有人能處理 GPU 伺服器的部署、監控與升級?
- May data go to an external service? Check regulation, contracts and company policy first. If yes, see whether the vendor's retention and region terms are acceptable (see "Personal data and governance" above). In semiconductor manufacturing, finance, healthcare or defence the answer is often no.
- How much capability is needed? Compare on your test set (chapter 07), not public leaderboards. Only your data can say whether a small model is good enough for your task.
- What volume? Dozens of calls a day and hundreds of thousands lead to completely different cost conclusions.
- Who operates it? Self-hosting adds a system to run. Does the customer have people for GPU server deployment, monitoring and upgrades?
混合架構Hybrid architectures
實務上常常不是二選一。例如:機密資料的摘要與分類用內網的開源模型;不含機密的高難度推理交給雲端 API。這和上面「依任務選模型」是同一個原則:每一種分工都要用評測確認品質,不要憑感覺。中級篇的機器人就是這樣設計的:I1 的 LLM 介面可以切換雲端 Claude、本機 Ollama 與離線假模型,再用 I6 的評測比較。
In practice it's often not either/or. For example: summarise and classify confidential data with an in-house open model, and send non-confidential hard reasoning to a cloud API. It's the same principle as "choose models per task" above: validate every split with evals, not intuition. The intermediate bot is built this way: I1's LLM interface switches between cloud Claude, local Ollama and the offline fake, and I6's evals compare them.
硬體:記憶體決定放不放得下,頻寬決定跑多快Hardware: memory decides whether it fits, bandwidth decides how fast
- 記憶體容量:模型權重要整個放進記憶體(GPU 顯存,或 Apple 晶片的統一記憶體)。粗估:每 10 億(1B)參數,16 位元精度約需 2 GB;量化成 4 位元約需 0.5 到 0.6 GB。例如 8B 模型約 16 GB,4 位元量化後約 5 GB。
- 對話越長,需要越多記憶體:模型要記住前面的內容(KV cache),上下文越長佔用越多。只算權重的大小,常常會低估。
- 記憶體頻寬決定速度:每產生一個 token,都要把權重讀過一遍。所以頻寬高的 GPU 遠快於一般 CPU。
- 量化有代價:位元數越低,越省記憶體,但品質可能下降。量化前後要用測試集比較。
- Memory capacity: the weights must fit entirely in memory (GPU VRAM, or Apple silicon's unified memory). Rough guide: per billion parameters, about 2 GB at 16-bit precision and 0.5–0.6 GB at 4-bit. An 8B model needs about 16 GB, or about 5 GB quantised to 4-bit.
- Longer conversations need more memory: the model keeps earlier context in a KV cache that grows with context length. Counting weights alone usually underestimates.
- Memory bandwidth sets speed: every generated token reads through the weights, which is why high-bandwidth GPUs far outpace ordinary CPUs.
- Quantisation has a cost: fewer bits save memory but can lower quality. Compare before and after on your test set.
| 硬體Hardware | 大約能跑Roughly runs | 適合Good for |
|---|---|---|
| 一般筆電(只有 CPU,8–32 GB 記憶體)Ordinary laptop (CPU only, 8–32 GB RAM) | 1B–8B,4 位元量化1B–8B, 4-bit quantised | 學習、概念驗證;速度較慢Learning, proofs of concept; slow |
| Apple 晶片 Mac(大容量統一記憶體)Apple silicon Mac (large unified memory) | 依記憶體大小,可到數十 BUp to tens of billions, depending on memory | 個人開發、小型專案Personal development, small projects |
| 消費級顯卡(12–24 GB 顯存)Consumer GPU (12–24 GB VRAM) | 7B–14B 較順;更大的模型需要多張卡或更強的量化7B–14B comfortably; larger needs multiple cards or heavier quantisation | 工程師開發機、少數人使用的內部工具Developer machines, internal tools for a few users |
| 資料中心 GPU 伺服器Data-centre GPU servers | 大型模型、高併發Large models, high concurrency | 正式的企業部署,搭配 vLLM 等推論伺服器Production enterprise deployment with an inference server such as vLLM |
| 雲端租用 GPU(按小時計費,例如 Colab)Rented cloud GPUs (hourly, e.g. Colab) | 依租用的規格Depends on what you rent | 測試與比較,不用先買硬體Testing and comparison without buying hardware |
表格只是大致的方向。實際速度會隨模型、量化方式、上下文長度與推論工具差很多,請在自己的機器上量。
The table is only a rough guide. Real speed varies widely with model, quantisation, context length and inference software, so measure on your own machine.
常見的誤解Common misconceptions
權重固定不等於輸出固定。隨機抽樣、批次處理方式、量化版本、推論引擎的更新,都可能讓結果改變。自己架設一樣要固定所有版本,並在每次更新後跑評測。
Fixed weights don't mean fixed outputs. Sampling, batching, quantisation versions and inference-engine updates can all change results. Self-hosting still means pinning every version and running evals after each update.
沒有 API 帳單,但有硬體、電費、機房,以及最貴的:維運人力。成本比較要算總持有成本,而且要用實際的用量估算。
There's no API bill, but there's hardware, power, space and, most expensive of all, operations staff. Compare total cost of ownership using real expected volume.
公開排行榜測的是通用能力,不是你的任務。小模型常常在工具呼叫、遵守 JSON 格式、中文專業用語上差距較大。用你的測試集量。
Public leaderboards test general ability, not your task. Small models often lag on tool use, following JSON formats and domain terminology in Chinese. Measure on your test set.
指定明確的模型 ID(不要用會自動更新的別名),並在 CI 跑評測,就能控制大部分的風險。真正要規劃的是舊版本淘汰時的升級流程(見下面的「分階段發布」)。
Pinning explicit model IDs (not auto-updating aliases) and running evals in CI controls most of the risk. What really needs planning is the upgrade path when old versions retire (see "Staged rollout" below).
動手試:用本機開源模型跑中級篇的機器人Try it: run the intermediate bot on a local open model
# 1. 安裝 Ollama(https://ollama.com),然後下載模型
ollama pull qwen2.5:3b # 約 2 GB,一般筆電可以跑
# 2. 用本機模型聊天、跑評測(資料不離開你的電腦)
python -m labs.intermediate.chat --ollama
python -m labs.intermediate.evals --ollama
# 3. 和其他模型比較
python -m labs.intermediate.evals --ollama --model qwen2.5:7b # 需要更多記憶體
python -m labs.intermediate.evals --real # 雲端 Claude(需要 API key)
把三個結果的通過率與失敗類型並排比較,就是一份很實用的選型報告。電腦跑不動的話,可以在 Google Colab 的 GPU 執行個體上安裝 Ollama 來跑同樣的評測。
Put the pass rates and failure types side by side and you have a genuinely useful model-selection report. If your computer can't cope, install Ollama on a Google Colab GPU instance and run the same evals there.
可靠性Reliability
- 逾時:每個外部呼叫都要有逾時,並注意「逾時 × 重試次數」才是最壞情況的總時間。
- 只重試可重試的錯誤:429、5xx、連線錯誤。400 類錯誤重試也不會成功。官方 SDK 通常內建退避重試,先了解預設值再決定要不要自己包一層。
- 降級模式:模型不能用時,系統還能提供什麼?例如只回傳檢索到的文件,或轉給人工。
- 處理
stop_reason:輸出被截斷(max_tokens)或模型拒答(refusal)時,不要把內容當成正常結果使用。
- Timeouts: every external call has one, and remember timeout × retries is the worst-case total.
- Retry only retryable errors: 429, 5xx, connection errors. A 400 won't succeed on retry. Official SDKs usually retry with backoff already; know the defaults before wrapping your own.
- Degraded mode: what can the system still offer when the model is unavailable? Retrieved documents alone, or a handoff to a human.
- Handle
stop_reason: when output is truncated (max_tokens) or declined (refusal), don't treat it as a normal result.
import anthropic
client = anthropic.Anthropic(timeout=30.0, max_retries=2) # SDK 會對 429/5xx/連線錯誤退避重試
def answer(question: str, chunks: list[dict]) -> dict:
try:
response = client.messages.create(
model="claude-opus-5-5",
max_tokens=4000,
system=SYSTEM_PROMPT, # 固定內容放前面,方便快取
messages=[{"role": "user", "content": build_prompt(question, chunks)}],
)
except (anthropic.RateLimitError, anthropic.InternalServerError, anthropic.APIConnectionError):
# 降級:至少給使用者找到的文件 / degraded mode: return the sources
return {"answer": None, "sources": chunks, "notice": "AI answer temporarily unavailable"}
if response.stop_reason in ("max_tokens", "refusal"):
return {"answer": None, "sources": chunks, "notice": f"no usable answer ({response.stop_reason})"}
text = "".join(b.text for b in response.content if b.type == "text")
return {"answer": text, "sources": chunks}
分階段發布Staged rollout
- Shadow 新系統在背景處理真實請求,結果不給使用者看,只用來比較。The new system processes real requests in the background; results are compared, not shown.
- 只建議Suggest-only 結果給使用者參考,由人決定是否採用。採用率本身就是品質指標。Results are shown as suggestions; a person decides. The adoption rate is itself a quality metric.
- 小比例開放Small cohort 開給一部分使用者或一個部門,監控指標正常再擴大。Open to some users or one department; widen while metrics hold.
- 全面開放,保留開關Full launch, kill switch kept 一個設定就能關掉 AI 功能並回到原流程。One setting turns the AI feature off and restores the old flow.
固定使用明確的模型 ID。新模型推出時,先在測試集上比較,再走一次分階段發布。新模型在整體上更強,不代表在你的任務上每一類都更好;API 行為與參數也可能改變。
Pin explicit model IDs. When a new model ships, compare it on your test set, then roll it out in stages. A model that is stronger overall isn't necessarily better on every category of your task, and API behaviour and parameters can change too.
交接清單Handover checklist
| 項目Item | 內容Contents |
|---|---|
| Runbook | 每個告警的意義、排查步驟、回滾與關閉 AI 功能的方法、升級聯絡人Meaning of each alert, investigation steps, how to roll back and disable the AI feature, escalation contacts |
| 擁有者Owners | prompt 與 schema、測試集、模型升級、API 費用、資料保留,各由誰負責Who owns prompts and schemas, the test set, model upgrades, API spend and data retention |
| 評測Evals | 測試集、baseline、在 CI 中的執行方式、更新 baseline 的流程Test set, baseline, how it runs in CI, the baseline update process |
| 儀表板Dashboards | 上面列出的指標,以及告警門檻The metrics above with alert thresholds |
| 決策紀錄Decision records | ADR:為什麼這樣設計、考慮過哪些替代方案(第 2 章)ADRs: why it's built this way and what alternatives were considered (chapter 2) |
| 成功條件回顧Success review | 對照第 1 階段寫下的條件,逐條確認並由判定者簽核Each criterion from phase 1 checked and signed off by its owner |