回到部落格

2026-04-16

【LLM應用】第一關:管線編排——先把積木想清楚,再談運行效果

【LLM應用】第一關:管線編排——先把積木想清楚,再談運行效果

你有沒有遇過這種狀況:prompt 寫得好好的,跑了幾次都沒問題,突然某一次輸出就歪掉了。你改了一個字,又好了。但你完全不知道為什麼好、也不知道為什麼歪。

說真的,問題通常不在 prompt,是你還沒把「東西從哪裡進、從哪裡出」這件事想清楚。


有個故事是這樣的,有一個名叫阿哲的工程師,花了一個週末把自己的 AI 閱讀筆記助理做出來了,拿給朋友 demo,朋友說「哇!超酷!」

但阿哲說不清楚這個東西「到底在做什麼」。筆記從哪裡進去?模型怎麼決定要回什麼?對話記錄存在哪?

說不清楚,就是架構還沒想清楚。架構沒想清楚,之後每次出問題都只能靠猜。

這篇就是要帶你把這件事想清楚。

還沒看過上一篇的話,可以先去看看 [做 LLM 應用,你在第幾關?],比較有脈絡唷。


Pipeline 是什麼感覺?

搭樂高的時候,你不會先去想「這塊積木是怎麼生出來的」,你只想「它接在哪、接上去形狀對不對」。

Pipeline 思維也是類似這樣——我們不用管模型裡面在幹嘛,只要定義清楚:資料從哪裡進、中間怎麼處理、怎麼產出

在動手寫 code 之前,先把這三個問題回答清楚:

  1. 輸入是什麼? 你丟給它什麼、有沒有夾帶資料、上下文是什麼
  2. 模型需要知道什麼? 除了你說的話,還要餵它哪些資訊
  3. 輸出要長什麼樣子? 純文字?JSON?還是要觸發某個動作?

這三個問題想清楚,骨架就出來了,其他都是填肉。

畫出來大概長這樣:

你的輸入
    ↓
前處理(清洗、格式化)
    ↓
組裝 Prompt(System + User + 記憶 + 查到的資料)
    ↓
丟給模型
    ↓
後處理(解析輸出、格式轉換)
    ↓
拿到結果

乍看之下很簡單對吧?但每一個箭頭,都是可以出問題的地方。


三個核心積木

積木一:I/O 結構化

核心就一句話:System Prompt 是你幫模型設定的角色,User Prompt 是你每次丟給它的任務

System Prompt 告訴模型「你是誰、你要怎麼回答」,通常不太會動它。User Prompt 才是每次互動帶進去的內容,會隨著你的輸入一直變。

兩個混在一起寫是這一關最常見的錯誤,等一下地雷區會重點講這個。

積木二:基礎 RAG

RAG 全名是 Retrieval-Augmented Generation,翻成白話文就是:讓模型回答之前,先去查一下你自己的資料

流程大概是:你問問題 → 去你的資料庫撈相關內容 → 把撈到的東西跟問題一起塞給模型 → 模型根據這些資料回答你。

這樣模型就不是只靠訓練資料在那邊猜,而是真的有看你的東西在說話。

積木三:對話記憶

模型本身沒有記憶,這件事很多人一開始不知道。每次呼叫 API,它都是第一次見到你,上次說了什麼它完全不知道。

所以記憶這件事要你自己做——把對話歷史存起來,每次呼叫的時候一起帶進去,它才知道我們之前聊過什麼。

但這裡有個常見陷阱:對話越來越長,塞進去的 token 越來越多,API 費用就越來越高。要記幾輪、要不要壓縮舊對話,這是這個積木要想清楚的地方。


三個積木接起來

說了這麼多,接起來長這樣:

# 示意寫法,重點是架構邏輯,不是可以直接執行的程式碼

system_prompt = "你是我的閱讀筆記助理,幫我整理與回答問題,請用繁體中文回答。"

# 積木二:RAG,先去我的筆記庫撈相關內容
relevant_notes = vector_db.search(my_query)

# 積木三:帶入最近幾輪對話歷史
history = memory.get_last_n_turns(n=5)

# 積木一:組裝 Prompt,各司其職
messages = [
    {"role": "system", "content": system_prompt},    # 角色設定,放這裡
    *history,                                          # 歷史對話,放這裡
    {"role": "user", "content": f"{my_query}\n\n參考筆記:{relevant_notes}"}
]

response = llm.call(messages)

仔細觀察一下——三個積木各自負責一件事,不會打架。出了問題,你也知道要去哪裡查,不用整包程式碼從頭猜。


這一關的三個地雷

地雷一:System Prompt 跟 User Prompt 混著寫

這個最要命,而且很常見——因為很多坊間「快速上手」的課,示範的就是這種寫法:把角色設定、任務指令、範例格式全部塞在同一個 message 裡,然後說「看!這樣就能跑了!」

能跑是真的,但你繼承了一個隱藏炸彈。

之後你想調角色設定,要在一坨字裡面翻;想換任務指令,又怕改到角色設定;想加格式要求,不知道放哪。每次改都是在祈禱,改完了還要自己人工驗一遍有沒有壞掉。

這不是在寫 prompt,這是在玩俄羅斯輪盤。(誤

把它們分開,不麻煩,但差超多。

地雷二:對話歷史無限增長

初版通常是「全部帶進去就好」,短期沒問題。但對話越來越長,某一天 token 超限直接炸掉,或是 API 費用突然暴增,你才發現要回頭補這個設計——而那時候已經很痛了。

限制帶幾輪、或是把舊對話壓縮成摘要,要趁還沒出問題的時候先想好。

地雷三:RAG 查到的東西塞太多

直覺上覺得「查越多、模型越強、回答越準」,但塞太多雜訊進去,模型反而更容易答非所問。

少而精,比多而雜好多了。


地基打穩了,再往前走

這一關難的不是技術,是習慣——習慣把輸入輸出想清楚,習慣每個積木各司其職,習慣在還很輕鬆的時候就把邊界定好。

養成這個習慣,進第二關的時候會輕鬆非常多,相信我。

下一篇,我們進第二關:工程落地——當你開始在意格式怎麼一直亂掉、API 費用怎麼一直在燒的時候,那些解法是什麼。

若喜歡這樣的文章,還請給我幾個掌聲,您的支持是我寫下去的原動力!

我是一個半路出家卻把 coding 當作興趣,且不斷鑽研技巧的開發者,希望有朝一日能成為全然獨當一面的技術大神。

祝大家天天有 coding,天天有成長!