所有入門單元免費開放 · 課程內容持續更新中

系統提示與多輪對話

用系統提示替模型設定角色與規則,再自己保存對話歷史,讓模型「記得」前面聊過什麼,做出一個能在終端機裡聊天的小程式。

第 10.3 堂約 13 分鐘

還記得上一堂課最後提到的嗎?模型不會記得上一次呼叫。你問完「我叫小明」,下一次再問「我叫什麼?」,它答不出來。

這堂課要解決兩件事:

  1. 讓模型用固定的身分和規則回答,不用每次都在問題前面重講一遍。
  2. 讓模型記得前面的對話,做出真正能來回聊天的程式。

系統提示:寫給模型的工作說明

系統提示(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 輪流。

三輪對話的 messages 清單:system 固定在最上面,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 數,它會一直變大。因為每一輪都把前面所有對話重送一次。

這代表兩件事:

  • 聊越久,每次呼叫越貴。費用怎麼算,第六堂課會細講。
  • 對話不能無限長。模型一次能讀的內容有上限,稱為上下文視窗。遇到很長的對話該怎麼辦,會在下一個單元的「上下文與記憶」處理。

現階段只要記得:歷史是你在管理的,你決定要送什麼給模型。

可以這樣問 AI

這是我的終端機聊天程式。請幫我加一個指令:輸入 /reset 時清空對話歷史重新開始;輸入 /history 時印出目前歷史裡有幾則訊息。保持程式簡單,加上中文註解。

行動練習
  1. 執行聊天程式,先自我介紹,再問一個需要記得前文才答得出來的問題,確認它記得。
  2. 把 SYSTEM 改成另一個角色,例如「嚴格但友善的英文老師,會指出文法錯誤」,觀察回答風格的改變。
  3. 連續聊五輪,記下每輪的輸入 token 數,看看它怎麼增加。
  4. 想一想:如果每輪都改成只送 [{"role": "user", "content": user_text}],不送歷史,會發生什麼事?改改看驗證你的猜測,再改回來。

讀完了嗎?

標記完成後,單元與專案的進度會自動更新(只存在這台裝置的瀏覽器)。

卡住了?讓 AI 當你的家教複製這段提問範本,貼到 Claude 或其他 AI 工具,再補上你卡住的地方。

留言與討論

卡關了、有心得,或發現內容需要更新?都歡迎留言。留言使用 GitHub 帳號登入。

留言區即將開放。現在可以先到 GitHub 討論區 發問,或看看 交流頁 的其他管道。