2026-04-17
【LLM應用】第二關:工程落地——開始用架構馴服模型

還記得阿哲嗎?上一篇他把閱讀筆記助理的 Pipeline 架起來了,跑得很開心。
上線第三週,他遇到了新問題。
第一個問題,輸出格式偶爾跑掉,他的腳本直接報錯。第二個問題,同樣的問題他自己問了好幾次(對,就是他自己問的,不是什麼大量使用者),每次都重打 API,月底帳單看了有點不對勁。第三個問題,所有任務都走同一個大模型,連「幫我翻譯這句話」這種事也不例外,貴得沒道理。
三個問題,每個都不大,但加在一起就是「這東西用起來有點煩」的感覺。這篇就是在聊這三個問題的解法。
還沒看過上一篇的話,可以先去看 [第一關:管線編排],不然這篇可能有點跳。
思維先轉一下
你有沒有看過路邊攤老闆在炒菜?
火候到了、鑊氣夠了,靠的是經驗跟手感,換一個人來炒就不一樣了。很多人對 LLM 的態度跟這個一樣——一直在調 prompt,覺得只要寫得夠好,模型就會乖乖照做。有時候有效,有時候沒效,很難說。
但你沒辦法靠手感開一間連鎖餐廳。
第二關要做的事,就是不要再賭模型今天心情好不好。與其一直調 prompt 祈禱它這次會乖,不如在 Pipeline 裡面加幾道保險:檢查輸出格式、把重複問題擋掉、簡單任務分流去便宜模型。模型偶爾還是會出包,但整個流程要能撐得住。
第一帖藥:格式一直跑掉 → 結構化輸出
結構化輸出要解的問題很直接:讓模型只能輸出你定義好的格式,不能多嘴。
你定義好 Schema——有哪些欄位、每個欄位是什麼型別——框架就會在收到回應之後自動比對。不符合就自動重試,符合才讓它出來。
# 示意寫法
class MyOutput(BaseModel):
summary: str # 摘要
tags: list[str] # 標籤
mood: str # 語氣
# 你拿到的是乾淨的物件,不是需要手動 parse 的一坨字串
# 格式不對,框架自動重試,不用你手動處理
result: MyOutput = llm.call(prompt, response_model=MyOutput)
print(result.summary) # 直接用,不用再 parse,也不用擔心格式跑掉
核心工具是 Pydantic 定義 Schema,Instructor 幫你把驗證邏輯接進去。概念不複雜,但能省掉一大堆每次都要手動驗格式的麻煩。
第二帖藥:API 費用跑太快 → 語意快取
假設你的工具每天有一百個請求,其中三成是語意差不多的重複問題。
沒有快取:一百次 API 呼叫,一百次費用。 有語意快取:七十次打 API,三十次直接回傳上次的結果,費用省了三成。
自己在用的工具,這個比例說不定還更高。(我自己跑工具的時候,常常是同樣的問題問了好幾次。)
語意快取跟一般快取不一樣的地方在於:不是問一模一樣才算同一個問題,語意接近就算。「幫我整理這段筆記的重點」跟「這段筆記的關鍵概念是什麼」,語意差不多,語意快取會直接回傳上次的結果,不重打 API。
# 示意寫法
cache = SemanticCache(similarity_threshold=0.85)
def ask(query):
if hit := cache.get(query):
return hit # 查過了,直接回傳,不打 API
result = llm.call(query)
cache.set(query, result)
return result
第三帖藥:什麼都用大模型 → 智能路由
講白一點:用對的模型做對的事。
「翻譯這句話」跟「分析這篇論文的論證架構」,需要一樣強的模型嗎?不需要吧。但一開始圖方便,就全部丟大模型——我也是這樣。(
智能路由做的事就是把任務依複雜度分流:簡單的走便宜的小模型,複雜的才交給大模型。
# 示意寫法
def ask(query, complexity):
if complexity == "low":
return small_model.call(query) # 便宜、夠用
return large_model.call(query) # 貴、但值得
小模型跟大模型的價差,有時候是五到十倍。省下來的拿去買咖啡也挺好的啦。(偷臭
三帖藥一起看
格式穩了,腳本不再莫名其妙報錯。費用降下來了,月底帳單看了比較不心疼。路由分清楚了,簡單的事不再花大錢。
三個不一定要一起上,有哪個痛點就先補哪個。
下一篇是最後一關:運維評估——當你開始問「我去睡覺了,這個東西還是好的嗎?」那就是第三關要解的問題了。
若喜歡這樣的文章,還請給我幾個掌聲,您的支持是我寫下去的原動力!
我是一個半路出家卻把 coding 當作興趣,且不斷鑽研技巧的開發者,希望有朝一日能成為全然獨當一面的技術大神。
祝大家天天有 coding,天天有成長!