iT邦幫忙

2026 iThome 鐵人賽

DAY 26
0

今天是雙主軸真正交會的一天。

  • 主軸一的讀者:這是 Day 13(延遲與吞吐)在 LLM 上的延伸,你的直覺全部適用,只是數字大一個量級。
  • 主軸二的讀者:這是你的系統能不能規模化的關鍵。做得出 demo 與撐得住一萬人,差別就在今天。

Day 02 提到 LLMOps 全台只有 19 筆職缺——但那是因為這個詞還沒進入招募用語。實際上做這件事的人,需求很大。

今天要解決的問題

三個階段性的問題,多數團隊會依序遇到:

第一階段(PoC):用 API,很順利,每月幾百塊。
第二階段(上線):使用者變多,帳單變成每月六位數。主管開始問「能不能便宜一點」。
第三階段(規模化):算了一下,自建 GPU 好像划算——但真的划算嗎? 而且法務說某些資料不能出境。

今天回答這三個問題:怎麼省、什麼時候該自建、自建要注意什麼。

📊 職缺訊號

「生成式 AI 部署與 LLMOps」出現在 38.7% 的生成式 AI 職缺中,同時「模型部署與推論服務」出現在 49.2% 的 MLOps 職缺。這兩個數字重疊的部分,就是今天的內容——也是目前市場上最稀缺的組合。


一、現象:LLM 服務的成本結構

LLM 成本儀表板

圖 26-1:LLM 成本的歸因、優化成效與單次請求拆解(示範性推估)。左圖顯示導入模型路由與快取後的成本下降;右圖是單次請求的成本組成。

先看右圖(Day 07 談過,今天要動手處理):最貴的是「固定前綴」與「輸出」。所以省錢的順序很明確:

順序 手段 典型效果 難度
1 限制輸出長度(max_tokens + 提示要求精簡) 20–40% 極低
2 prompt caching(固定前綴前置且逐字穩定) 輸入端約 50–60% 低
3 模型路由(簡單任務用小模型) 30–50% 中
4 語意快取(高重複性場景) 10–30% 中(有誤命中風險)
5 精簡檢索脈絡(提高檢索精準度後降 top-k) 10–20% 中
6 自建推論 規模夠大時 50%+ 高

注意「自建」排在最後。 前五項都是幾天內能做完的軟性優化,自建則是一個需要人力持續維護的決定。

二、原理:為什麼 vLLM 能快好幾倍

主軸二的讀者可能沒想過:同一張 GPU、同一個模型,換一個推論引擎,吞吐可以差三到四倍。原因在於 KV cache 的管理方式。

KV cache 記憶體與批次策略

圖 26-2:KV cache 記憶體(依公式精算)與批次策略的效益(示範性推估)。左圖:批次 × 長度的乘積效應;右圖:連續批次與 PagedAttention 對吞吐與顯存碎片的影響。

左圖的計算(Day 07 提過,這裡是完整版):

KV cache = 2(K 與 V)× 層數 × KV head 數 × head_dim × 位元組數 × 序列長度 × 批次

8B 模型(32 層、8 KV head、head_dim 128、fp16):
  每 token 每序列 = 2 × 32 × 8 × 128 × 2 B = 131,072 B = 128 KiB

批次 16、序列 8,192:128 KiB × 8192 × 16 ≈ 17.2 GB
加上權重 16 GB → 約 33 GB,一張 80GB 卡放得下但要留餘裕

右圖的三個改進:

  • 靜態批次:一批請求要全部跑完才換下一批。最短的請求要等最長的,GPU 大量閒置。
  • 連續批次(continuous batching):某個序列生成完就立刻離開,新請求馬上補進來。吞吐約 3.6 倍。
  • PagedAttention:借用作業系統分頁的概念管理 KV cache,把顯存碎片從 58% 降到 4%——同樣的顯存能塞更多併發。

💡 給主軸二讀者的白話版

你不需要看懂 PagedAttention 的實作。你需要知道的是:如果你現在用 Hugging Face transformers 的 generate() 直接對外服務,換成 vLLM 通常能立刻獲得數倍吞吐——不用改模型、不用改應用程式碼(因為它提供 OpenAI 相容 API)。

三、動手:自建服務與成本試算

3.1 起一個 OpenAI 相容的服務

uv add vllm

python -m vllm.entrypoints.openai.api_server \
  --model Qwen/Qwen2.5-7B-Instruct \
  --gpu-memory-utilization 0.90 \   # 保留 10% 給碎片與突發,別設 1.0
  --max-model-len 8192 \            # 直接決定 KV cache 上限,別設超過實際需求
  --max-num-seqs 64 \               # 最大併發序列數
  --port 8000

應用端幾乎不用改——因為它是 OpenAI 相容介面:

from openai import OpenAI
client = OpenAI(base_url="http://localhost:8000/v1", api_key="not-needed")
# 之後的呼叫方式與雲端 API 完全相同

三個參數的實務意義:

參數 設太大 設太小
--gpu-memory-utilization OOM 崩潰 併發數上不去
--max-model-len KV cache 吃光顯存,併發數暴跌 長文件請求被拒絕
--max-num-seqs 排隊變長、TTFT 惡化 吞吐上不去

3.2 壓測:LLM 服務要看的三個指標

"""bench.py —— LLM 服務的壓測,指標與傳統 API 不同。"""
import asyncio, time

async def one_request(client, prompt):
    t0 = time.perf_counter()
    ttft = None
    tokens = 0
    stream = await client.chat.completions.create(
        model=MODEL, messages=[{"role": "user", "content": prompt}],
        stream=True, max_tokens=300)
    async for chunk in stream:
        if chunk.choices[0].delta.content:
            if ttft is None:
                ttft = time.perf_counter() - t0      # 首個 token 抵達時間
            tokens += 1
    total = time.perf_counter() - t0
    return {"ttft": ttft, "total": total,
            "tpot": (total - ttft) / max(tokens - 1, 1),   # 每個後續 token 的時間
            "tokens": tokens}

# 三個必看指標:
#   TTFT  → 使用者的「等待感」(受 prefill 與排隊影響)
#   TPOT  → 生成的「流暢感」(受 decode 影響)
#   吞吐  → 你的容量(總輸出 token / 秒)

這三個指標要分開訂 SLO。 常見的目標:TTFT P95 < 1 秒(等待感)、TPOT < 50 ms(約每秒 20 字,比多數人閱讀速度快)。只看端到端延遲會看不出問題出在 prefill 還是 decode。

3.3 自建 vs API 的損益平衡

"""llm_cost.py —— 把假設攤開來算(Day 15 的方法,換成 LLM 情境)。"""
# API 方案
API_INPUT, API_OUTPUT = 1.0, 5.0      # 每百萬 token 的相對單價
daily_in, daily_out = 400_000_000, 20_000_000    # 每日 token 量

api_monthly = (daily_in / 1e6 * API_INPUT + daily_out / 1e6 * API_OUTPUT) * 30

# 自建方案(Day 15 的成本模型)
GPU_HOURLY = 3.0            # 雲端 GPU 每小時(或地端攤提)
GPUS_NEEDED = 3             # 由容量規劃決定:尖峰吞吐 ÷ 單卡吞吐 + 冗餘
OPS_MONTHLY = 400           # 維運人力分攤——自建最容易被低估的成本
selfhost_monthly = GPU_HOURLY * 24 * 30 * GPUS_NEEDED + OPS_MONTHLY

print(f"API 方案:{api_monthly:>10.0f} / 月")
print(f"自建方案:{selfhost_monthly:>10.0f} / 月")
print("建議:", "自建" if selfhost_monthly < api_monthly * 0.7 else "續用 API")
# 門檻設 0.7 而非 1.0:自建要明顯划算才值得承擔維運複雜度

📌 那個 0.7 是刻意的

自建除了帳面成本,還有隱形成本:模型升級要自己做、出事要自己修、半夜掛了要有人接。只有在明顯划算(省 30% 以上)時才值得——除非你的決策理由是資料主權,那就不是成本問題。

四、取捨:模型路由與發布管理

模型路由是最被低估的成本手段:不是所有請求都需要最強的模型。

"""router.py —— 依任務複雜度分流,簡單任務用便宜模型。"""
async def route_and_answer(question, context):
    # 用小模型先判斷複雜度(這次判斷本身很便宜)
    complexity = await classify_complexity(question)     # simple / standard / complex

    model = {"simple": SMALL_MODEL,       # 分類、擷取、格式轉換
             "standard": MID_MODEL,       # 一般問答、摘要
             "complex": LARGE_MODEL}[complexity]         # 多步推理、長文件分析

    try:
        return await call_llm(model=model, ...)
    except (RateLimitError, APIError):
        return await call_llm(model=FALLBACK_MODEL, ...)  # 跨供應商冗餘

LLM 服務的發布管理——這是 Day 11 品質門檻的 LLMOps 版本。要注意的是,LLM 服務有四種資產會變動:

資產 誰會改 發布前要做
模型(版本或供應商) 工程師/供應商自動升版 跑全套評測 + 人工抽查
提示 工程師、有時是 PM 跑全套評測(Day 24)
檢索索引 文件更新自動觸發 跑檢索端指標
工具定義與權限 工程師 跑注入測試(Day 25)

4.1 一個常被問到的問題:小模型真的夠用嗎?

「模型路由」聽起來很好,但實務上第一個疑問通常是:小模型的品質夠嗎?

答案取決於任務類型。經驗上的分界線是:任務越接近「格式轉換」,小模型越夠用;越接近「開放式推理」,差距越大。

任務 小模型是否夠用 說明
意圖分類、情緒判斷 ✅ 通常夠 選項有限,且可用 few-shot 補強
結構化欄位擷取 ✅ 通常夠 有明確的 schema 約束
查詢改寫(Day 19) ✅ 夠 高頻但簡單,用大模型是浪費
摘要 ⚠️ 視長度 短文可以,長文的重點取捨會明顯變差
多步推理、複雜問答 ❌ 差距明顯 這才是大模型的價值所在
程式碼生成 ❌ 差距明顯 錯一個字就不能跑,容錯率低

判斷方法還是回到評測(Day 24):把你的評測集用小模型跑一次,看掉多少分。如果只掉 2%、成本降 90%,那顯然值得;如果掉 15%,那就別省這個錢。這個決定不該靠感覺,一小時就能量出來。

⚠️ 一個 LLMOps 特有的風險:供應商自動升版

你沒有改任何東西,但供應商把 model-latest 指向了新版本,你的產品行為就變了。正式環境一定要釘住明確的模型版本號,並在自己決定的時間點升級——升級時走完整的評測與金絲雀流程。

這是傳統 MLOps 沒有的問題:你的相依項會自己動。


今日小結

  • 省錢的順序:限制輸出長度 → prompt caching → 模型路由 → 語意快取 → 精簡檢索脈絡 → 最後才考慮自建。前五項幾天內能做完。
  • KV cache 每 token 每序列 128 KiB(8B 級模型),批次 × 長度的乘積會迅速吃光顯存——這是併發上不去的真正原因。
  • vLLM 的優勢來自 continuous batching(約 3.6 倍吞吐)與 PagedAttention(顯存碎片 58% → 4%);提供 OpenAI 相容 API,應用端幾乎不用改。
  • 三個參數要一起調:gpu-memory-utilization、max-model-len、max-num-seqs。
  • LLM 服務要分開看 TTFT(等待感) 與 TPOT(流暢感),各訂 SLO;只看端到端延遲查不出問題在哪。
  • 自建要明顯划算(省 30% 以上)才值得,因為有維運隱形成本——除非決策理由是資料主權。
  • LLM 服務有四種會變動的資產(模型、提示、索引、工具),每一種都要有對應的發布檢核。
  • 正式環境要釘住模型版本號——你的相依項會自己動。

明天預告

技術面完成,明天處理制度面:治理。AI 風險矩陣怎麼畫、歐盟 AI Act 的時程對台灣團隊有什麼影響、模型檔案的供應鏈風險(那個很多人不知道的 pickle 問題),以及一套能真正落地的權限與稽核設計。

延伸閱讀

  • 📄 Kwon et al., Efficient Memory Management for Large Language Model Serving with PagedAttention (2023)——vLLM 的原始論文
  • 📄 vLLM 官方文件——參數調校與部署的第一手資料

上一篇
Day 25:安全 — OWASP LLM Top 10 與提示注入的縱深防禦
系列文
RE: 從 4,343 筆職缺到 AI Engineer:MLOps × GenAI Engineering 雙主軸實戰 共 26 篇
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言