在前一篇文章中,我們學會了如何簡易開發生成式 AI Chat。但有一個關鍵問題還沒解決:如何讓 AI 記住之前說過的話?
大多數初學者的第一個 AI 應用都是「單次問答」—— 每次都是全新的對話,AI 完全不記得剛才討論了什麼。但真正實用的 AI 助手需要能夠:
今天介紹最簡單且實用的解決方案:用 List 管理對話歷史。
無記憶的尷尬情況
# 第一次對話
user: "我今年 25 歲,想要減重"
ai: "好的,根據您 25 歲的年齡,建議每日攝取..."
# 第二次對話(沒有上下文)
user: "那我應該做什麼運動?"
ai: "請問您的年齡和減重目標是什麼?我需要更多資訊才能給建議"
這種體驗對用戶來說非常frustrating,明明剛說過的事情,AI 馬上就忘記了。
有記憶的流暢對話
# 有上下文管理的對話
conversation_history = [
{"role": "user", "parts": [{"text": "我今年 25 歲,想要減重"}]},
{"role": "model", "parts": [{"text": "好的,根據您 25 歲的年齡,建議每日攝取..."}]},
{"role": "user", "parts": [{"text": "那我應該做什麼運動?"}]}
]
# AI 可以基於完整歷史回答
ai: "基於您 25 歲的年齡和減重目標,我推薦以下運動..."
基礎版本
class SimpleChat:
def __init__(self):
self.conversation_history = []
self.model = genai.GenerativeModel('gemini-pro')
def add_message(self, role, content):
"""新增訊息到對話歷史"""
message = {
"role": role,
"parts": [{"text": content}]
}
self.conversation_history.append(message)
def chat(self, user_input):
"""進行對話"""
# 1. 將用戶訊息加入歷史
self.add_message("user", user_input)
# 2. 將完整歷史送給模型
response = self.model.generate_content(self.conversation_history)
# 3. 將 AI 回應也加入歷史
self.add_message("model", response.text)
return response.text
# 使用範例
chat = SimpleChat()
print(chat.chat("我今年 25 歲,想要減重"))
print(chat.chat("那我應該做什麼運動?"))
print(chat.chat("我比較喜歡室內運動"))
進階版本:加入 System Prompt
class SmartChat:
def __init__(self, system_prompt="你是一位專業的健康顧問"):
self.system_prompt = system_prompt
self.conversation_history = []
self.model = genai.GenerativeModel('gemini-pro')
def add_message(self, role, content):
message = {
"role": role,
"parts": [{"text": content}]
}
self.conversation_history.append(message)
def get_full_context(self):
"""組合 System Prompt + 對話歷史"""
messages = []
# 先加入 System Prompt
if self.system_prompt:
messages.append({
"role": "user",
"parts": [{"text": f"請扮演這個角色:{self.system_prompt}"}]
})
messages.append({
"role": "model",
"parts": [{"text": "我了解了,我會扮演這個角色來協助您。"}]
})
# 再加入對話歷史
messages.extend(self.conversation_history)
return messages
def chat(self, user_input):
# 1. 用戶訊息加入歷史
self.add_message("user", user_input)
# 2. 取得完整上下文(System Prompt + 歷史)
full_context = self.get_full_context()
# 3. 送給模型處理
response = self.model.generate_content(
full_context,
generation_config={
"temperature": 0.7,
"max_output_tokens": 1000
}
)
# 4. AI 回應加入歷史
self.add_message("model", response.text)
return response.text
# 使用範例
health_assistant = SmartChat(
system_prompt="你是一位專業的健康顧問,會根據用戶的個人資訊提供客製化建議"
)
print(health_assistant.chat("我今年 25 歲,想要減重"))
print(health_assistant.chat("我平常工作很忙,沒時間去健身房"))
隨著對話進行,conversation_history
會越來越長,最終可能:
class ManagedChat:
def __init__(self, system_prompt="", max_history_length=10):
self.system_prompt = system_prompt
self.conversation_history = []
self.max_history_length = max_history_length # 最多保留幾輪對話
self.model = genai.GenerativeModel('gemini-pro')
def add_message(self, role, content):
message = {
"role": role,
"parts": [{"text": content}]
}
self.conversation_history.append(message)
# 保持歷史長度在限制內
if len(self.conversation_history) > self.max_history_length:
# 移除最舊的對話(但保留成對的 user-model 對話)
self.conversation_history = self.conversation_history[-self.max_history_length:]
def get_memory_summary(self):
"""將舊對話總結成摘要"""
if len(self.conversation_history) <= 4: # 對話還不夠長,不需要摘要
return ""
# 取出最舊的幾輪對話來做摘要
old_messages = self.conversation_history[:6] # 前3輪對話
summary_prompt = f"""
請將以下對話總結成重點摘要,保留重要的用戶資訊:
{old_messages}
摘要格式:用戶基本資訊、主要需求、已討論的重點
"""
# 這裡可以呼叫另一個模型來產生摘要
# 為了簡化,我們先用簡單的文字描述
return "之前討論摘要:用戶關心健康議題,想要專業建議"
def chat(self, user_input):
self.add_message("user", user_input)
# 組合上下文:系統提示 + 記憶摘要 + 近期對話
context = []
if self.system_prompt:
context.append({
"role": "user",
"parts": [{"text": self.system_prompt}]
})
# 加入記憶摘要(如果有的話)
memory_summary = self.get_memory_summary()
if memory_summary:
context.append({
"role": "user",
"parts": [{"text": memory_summary}]
})
# 加入近期對話
context.extend(self.conversation_history[-6:]) # 只用最近3輪對話
response = self.model.generate_content(context)
self.add_message("model", response.text)
return response.text
實際應用:健康諮詢助手
class HealthChatBot:
def __init__(self):
self.system_prompt = """
你是一位專業的健康顧問助手。請根據用戶提供的資訊:
- 記住用戶的個人資料(年齡、體重、目標等)
- 提供個人化的建議
- 如果涉及醫療診斷,請建議諮詢專業醫師
- 保持友善且專業的語調
"""
self.conversation_history = []
self.user_profile = {} # 用來記錄用戶的基本資料
self.model = genai.GenerativeModel('gemini-pro')
def extract_user_info(self, user_input):
"""從用戶輸入中提取個人資訊"""
# 這裡可以用更複雜的 NLP 技術,簡化版本用關鍵字
if "歲" in user_input:
# 提取年齡資訊
import re
age_match = re.search(r'(\d+)歲', user_input)
if age_match:
self.user_profile['age'] = age_match.group(1)
if "公斤" in user_input or "kg" in user_input.lower():
# 提取體重資訊
weight_match = re.search(r'(\d+(?:\.\d+)?)\s*(?:公斤|kg)', user_input.lower())
if weight_match:
self.user_profile['weight'] = weight_match.group(1)
def chat(self, user_input):
# 提取用戶資訊
self.extract_user_info(user_input)
# 建構包含用戶資料的上下文
context = []
# System Prompt
context.append({
"role": "user",
"parts": [{"text": self.system_prompt}]
})
# 用戶資料摘要
if self.user_profile:
profile_text = "用戶資料:" + ", ".join([f"{k}: {v}" for k, v in self.user_profile.items()])
context.append({
"role": "user",
"parts": [{"text": profile_text}]
})
# 對話歷史
context.extend(self.conversation_history[-6:]) # 最近3輪對話
# 當前用戶輸入
context.append({
"role": "user",
"parts": [{"text": user_input}]
})
# 呼叫模型
response = self.model.generate_content(
context,
safety_settings=[
{"category": "HARM_CATEGORY_DANGEROUS_CONTENT", "threshold": "BLOCK_ONLY_HIGH"}
]
)
# 更新對話歷史
self.conversation_history.append({
"role": "user",
"parts": [{"text": user_input}]
})
self.conversation_history.append({
"role": "model",
"parts": [{"text": response.text}]
})
return response.text
# 使用範例
bot = HealthChatBot()
print("=== 健康諮詢助手 ===")
print(bot.chat("你好,我今年 28 歲,體重 75 公斤,想要減重"))
print("\n" + "="*50 + "\n")
print(bot.chat("我平常很少運動,應該從什麼開始?"))
print("\n" + "="*50 + "\n")
print(bot.chat("我的目標是減到 70 公斤,大概需要多久?"))
用 List 來存對話紀錄,超直覺也很好 debug、維護起來不麻煩。
不過有幾個缺點: