系統提示與多輪對話
用系統提示替模型設定角色與規則,再自己保存對話歷史,讓模型「記得」前面聊過什麼,做出一個能在終端機裡聊天的小程式。
還記得上一堂課最後提到的嗎?模型不會記得上一次呼叫。你問完「我叫小明」,下一次再問「我叫什麼?」,它答不出來。
這堂課要解決兩件事:
- 讓模型用固定的身分和規則回答,不用每次都在問題前面重講一遍。
- 讓模型記得前面的對話,做出真正能來回聊天的程式。
系統提示:寫給模型的工作說明
系統提示(system prompt)是在對話開始前交給模型的一段說明,例如「你是一位旅遊顧問,回答要簡短、用條列式、價格用新台幣」。它對整段對話都有效。
為什麼不直接寫在使用者的問題裡?因為角色和規則是固定的,使用者的問題是每次不同的。分開放,程式比較好維護,模型也更清楚哪些是長期要遵守的規則。
from dotenv import load_dotenv
import anthropic
load_dotenv()
MODEL = "claude-sonnet-5-5" # 可以換成其他模型 ID
client = anthropic.Anthropic()
response = client.messages.create(
model=MODEL,
max_tokens=16000,
system="你是一位台灣的旅遊顧問。回答使用繁體中文,條列式,最多五點,價格用新台幣。",
messages=[{"role": "user", "content": "週末想去花蓮玩兩天,怎麼安排?"}],
)
for block in response.content:
if block.type == "text":
print(block.text)
注意 system 是獨立的參數,不放在 messages 清單裡。
messages 清單:對話的逐字稿
messages 是一份對話紀錄,每一則都有 role(誰說的)和 content(說了什麼):
user:使用者說的話。assistant:模型之前的回答。
規則很簡單:第一則必須是 user,之後通常是 user 與 assistant 輪流。
模型「記得」的原理:不是它有記憶,而是你每次都把整份逐字稿交給它。
做一個會記得前文的聊天程式
把上面的觀念寫成程式:用一個清單保存歷史,每輪把使用者的話加進去、送出、再把模型的回答也加進去。
from dotenv import load_dotenv
import anthropic
load_dotenv()
MODEL = "claude-sonnet-5-5"
client = anthropic.Anthropic()
SYSTEM = "你是一位親切的學習夥伴,用繁體中文回答,每次回答不超過 150 字。"
history = []
print("開始聊天,輸入 exit 結束。")
while True:
user_text = input("\n你:").strip()
if user_text.lower() == "exit":
break
if not user_text:
continue
history.append({"role": "user", "content": user_text})
response = client.messages.create(
model=MODEL,
max_tokens=16000,
system=SYSTEM,
messages=history,
)
# 把模型完整的回應內容存回歷史,原封不動
history.append({"role": "assistant", "content": response.content})
reply = "".join(b.text for b in response.content if b.type == "text")
print("AI:", reply)
print(f"(這輪送出 {response.usage.input_tokens} 個輸入 token)")
試著先說「我叫小明,正在學 Python」,再問「我在學什麼?」。這次它答得出來了。
為什麼存 response.content,而不是只存文字?
回應裡除了文字,有時還有模型的思考區塊等其他內容。把 response.content 整份原封不動存回去,是最不容易出錯的做法,下一個單元寫 Agent 時也會用一樣的寫法。只有要印給人看時,才把文字挑出來。
你可能會注意到的事
執行幾輪之後,看看每輪印出的輸入 token 數,它會一直變大。因為每一輪都把前面所有對話重送一次。
這代表兩件事:
- 聊越久,每次呼叫越貴。費用怎麼算,第六堂課會細講。
- 對話不能無限長。模型一次能讀的內容有上限,稱為上下文視窗。遇到很長的對話該怎麼辦,會在下一個單元的「上下文與記憶」處理。
現階段只要記得:歷史是你在管理的,你決定要送什麼給模型。
這是我的終端機聊天程式。請幫我加一個指令:輸入 /reset 時清空對話歷史重新開始;輸入 /history 時印出目前歷史裡有幾則訊息。保持程式簡單,加上中文註解。
- 執行聊天程式,先自我介紹,再問一個需要記得前文才答得出來的問題,確認它記得。
- 把
SYSTEM改成另一個角色,例如「嚴格但友善的英文老師,會指出文法錯誤」,觀察回答風格的改變。 - 連續聊五輪,記下每輪的輸入 token 數,看看它怎麼增加。
- 想一想:如果每輪都改成只送
[{"role": "user", "content": user_text}],不送歷史,會發生什麼事?改改看驗證你的猜測,再改回來。
讀完了嗎?
標記完成後,單元與專案的進度會自動更新(只存在這台裝置的瀏覽器)。
留言與討論
卡關了、有心得,或發現內容需要更新?都歡迎留言。留言使用 GitHub 帳號登入。