5.4 實現生成器整合
組好提示詞,接上 LLM,並處理沒有金鑰、呼叫失敗這些實際情況。
檢索器回傳資料後,生成端只需要負責兩件事:組提示詞,以及呼叫 LLM。把兩個步驟分成獨立函式,之後替換模型或修改提示詞時比較不會互相牽連。
提示詞
接續第 4 章的設計:指示放在 system,參考資料和問題放在使用者訊息。
SYSTEM = """你是公司的行政助理。請只根據「參考資料」回答問題。
規則:
1. 資料裡沒有答案時,回答「資料中沒有提到」,不要猜。
2. 用到哪一段資料,就在句子後面標上編號,例如 [1]。
3. 用繁體中文,簡短回答。"""
def build_prompt(question, hits):
blocks = [f"[{n}]({h['source']} > {h['headings']})\n{h['text']}" for n, h in enumerate(hits, 1)]
return "# 參考資料\n" + "\n\n".join(blocks) + f"\n\n# 問題\n{question}"
每一段資料都有編號和來源,這樣模型才能標出處(4.6)。
呼叫 LLM
下面用 Anthropic 的 Python SDK 當例子。如果你用別家的模型,換成對應的呼叫方式,整體結構是一樣的:把指示和使用者訊息送過去,取回文字。
import os
LLM_MODEL = "claude-sonnet-5-5" # 換成你要用的模型
def generate(prompt):
if os.environ.get("ANTHROPIC_API_KEY"):
import anthropic
reply = anthropic.Anthropic().messages.create(
model=LLM_MODEL,
max_tokens=500,
system=SYSTEM,
messages=[{"role": "user", "content": prompt}],
)
return reply.content[0].text
return "(沒有設定 API 金鑰,這裡不呼叫模型,只顯示送給模型的提示詞)"
幾個重點:
- 有金鑰才呼叫:沒有設定環境變數時,函式不會報錯,而是回傳一段說明。這讓你在沒有金鑰的時候,也能把整條流程跑通,檢查檢索和提示詞。
max_tokens:限制答案的最大長度,要夠長,免得被截斷。- 模型名稱用常數:模型名稱經常更換,放在最上面方便修改。
- SDK 會自動讀金鑰:
anthropic.Anthropic()會自己從ANTHROPIC_API_KEY讀取,不需要在程式裡傳金鑰。
注意 這個呼叫我沒有實際執行,因為我手邊沒有設定金鑰。檢索、提示詞組裝這些部分我都跑過,但
generate()裡呼叫模型的那一段,請你用自己的金鑰測試。模型名稱和 SDK 用法也請以官方文件為準。
實際使用時還要處理的事
範例刻意寫得簡單,正式的系統要多考慮:
| 問題 | 做法 |
|---|---|
| 呼叫失敗(網路、額度、被限流) | 加上錯誤處理和重試,失敗時回傳友善的訊息 |
| 回應很慢 | 設定逾時;考慮串流輸出,邊產生邊顯示 |
| 成本 | 記錄每次呼叫用了多少 token |
| 隨機性 | 視需要調低溫度,讓答案穩定 |
| 換模型 | 把呼叫包在 generate() 這一個函式裡,其他地方不用動 |
最後一點很重要:把和特定廠商相關的程式碼,都關在 generate() 裡。這樣以後換模型、換服務,只要改一個函式。
沒有雲端 API 時的選擇
- 本機模型:用 Ollama 之類的工具在自己的電腦上跑開源模型,資料不外流,但需要足夠的硬體,品質也依模型而異。
- 只做到提示詞:像範例那樣,先驗證檢索和提示詞,等有金鑰再接上模型。
不管用哪一種,generate(prompt) 這個介面都不用變:進去是提示詞,出來是答案。