4.5 生成最終回覆
提示詞交給模型之後,怎麼控制輸出、讓答案穩定,以及拿到答案之後的處理。
提示詞交給 LLM 後,模型會根據問題與參考資料合成答案。輸出並不是不可控的黑盒子;取樣參數、輸出格式、拒答規則和後處理都會改變結果。
模型怎麼用提示詞
模型會閱讀整份提示詞:指示、參考資料、問題,然後一個 token 一個 token 地產生答案。因為它看得到資料,所以產生的內容會受資料牽引,這就是 RAG 比單純問答更準確的原因。
呼叫模型的程式碼,結構大致是這樣(以下是示意,不綁定特定廠商,實際請依你用的服務調整):
def call_llm(system, user_message):
"""呼叫你選的 LLM,回傳文字。這裡只是占位,要換成實際的 API 呼叫"""
...
answer = call_llm(
system=SYSTEM, # 指示放這裡
user_message=f"# 參考資料\n{context}\n\n# 問題\n{question}",
)
我沒有在這章接上真的模型,所以不放執行結果。這章把重點放在提示詞的設計和後處理。
可以調整的參數
呼叫 LLM 時,有幾個常見的參數會影響輸出,實際名稱和範圍依服務而異:
| 參數 | 作用 | RAG 的建議 |
|---|---|---|
| temperature(溫度) | 控制隨機程度。越低越穩定、越保守 | RAG 通常設低一點,讓答案穩定、貼著資料 |
| max tokens(最大輸出長度) | 答案最長能多長 | 要夠長,免得答案被攔腰截斷 |
| stop / 停止條件 | 遇到特定字串就停止 | 一般用不到 |
| 輸出格式 | 要求 JSON、固定欄位 | 需要程式處理答案時很有用 |
一個重點:RAG 追求的是忠於資料,不是創意,所以通常偏向低隨機性。
控制輸出的格式
如果答案之後要由程式處理,例如顯示引用、記錄日誌,可以要求模型用固定的結構輸出:
請用以下 JSON 格式回答:
{
"answer": "答案內容",
"sources": [1, 2],
"found": true
}
這樣的好處是:
found可以明確知道資料裡有沒有答案,不用靠解析文字。sources方便直接顯示引用。
很多服務有提供「結構化輸出」的功能可以強制格式,請查閱你使用的 API 文件。
處理「資料中沒有」
當檢索到的資料裡沒有答案時,好的 RAG 系統應該誠實說明,而不是硬編。幾個設計點:
- 提示詞要明確允許並要求這個回答(4.2)。
- 檢索分數都很低時,甚至可以在送給模型之前就先判斷「找不到相關資料」,直接回覆。
- 回覆時可以給使用者下一步建議,例如「換個說法再問」或「請洽人資部」。
串流輸出
模型產生答案需要時間,可以用串流(streaming),讓文字一邊產生一邊顯示。使用者能更早看到開頭,感覺比較快。
拿到答案之後
模型回傳答案後,系統通常還要做一些後處理:
- 解析引用:找出答案裡的
[1]、[2],對應回來源(4.6)。 - 檢查格式:如果要求 JSON,確認有沒有解析成功。
- 過濾:視需要檢查有沒有不該出現的內容。
- 記錄:把問題、檢索到的資料、提示詞、答案都記下來。之後要評估或除錯(第 6 章)時,這些紀錄非常重要。
注意 建議從一開始就記錄「檢索到什麼」和「模型答了什麼」。RAG 出錯時,需要知道問題是出在檢索,還是出在生成,沒有紀錄就很難判斷。
回答品質的常見問題
| 現象 | 可能的原因 | 方向 |
|---|---|---|
| 答案和資料不符 | 模型忽略資料,或溫度太高 | 加強指示、降低溫度 |
| 明明有資料卻說沒有 | 檢索沒找到,或資料太雜 | 回頭檢查檢索(第 2、3 章) |
| 混入資料裡沒有的內容 | 模型用自己的記憶補充 | 強化「只根據資料」,並用評估檢查 |
| 答案太冗長或太簡略 | 沒有規定格式和長度 | 在指示裡寫明 |
| 引用的編號對不上 | 模型記錯編號 | 後處理驗證(4.6) |
這些問題要靠系統性的評估才能找到並改善,第 6 章會專門處理。