前幾天,我已經讓 AI Companion 可以聽懂使用者說話、產生回覆,也加入 Streaming Voice Pipeline 與 Barge-in,讓整個語音互動開始比較接近真正的對話。
但目前還有一個很明顯的問題:
每次新的對話開始,AI 幾乎都像第一次認識使用者。
例如昨天跟 AI 說:
「我平常晚上喜歡出去散步。」
今天再問:
「今天晚上不知道要做什麼。」
如果系統沒有記憶,LLM 只能根據現在這一句話回答,可能會推薦看電影、聽音樂或休息。
但對 AI Companion 來說,我更希望它可以回答:
「你之前有提到晚上喜歡散步,如果今天精神還不錯,也可以出去走走。」
這種「它還記得我說過什麼」的感覺,是我認為 AI Companion 和一般 Chatbot 很重要的差別之一。
所以 Day 09,我開始替系統加入第一版 Memory。
一開始最直覺的方法,是直接把過去所有聊天紀錄都丟給 LLM。
例如:
User:我喜歡喝無糖綠茶
Assistant:好啊!
User:我今天去公園散步
Assistant:今天天氣不錯嗎?
User:最近晚上比較早睡
Assistant:保持規律作息很好
下一次對話時,再把這些紀錄全部放進 Prompt。
這種方式可以讓模型知道前面聊過什麼,但比較接近:
Conversation History
也就是短期對話上下文。
但如果 AI Companion 每天都在使用,一個月、半年甚至一年後,聊天紀錄會非常多。
不可能每次都把所有內容重新送給 LLM。
而且聊天內容中有很多資訊,其實根本不需要長期保存。
像是:
「今天好熱。」
「剛剛電視很好看。」
「等一下再聊。」
這些內容可能只對當下有意義。
因此 Long-term Memory 真正需要處理的問題是:
哪些資訊值得被留下來?
第一版我先把比較適合長期保存的資訊分成幾種類型。
例如:
使用者偏好
家人資訊
生活習慣
過去事件
健康相關資訊
像是:
「我不喜歡喝咖啡。」
→ 使用者偏好
「我女兒每個星期六會回來。」
→ 家人資訊
「我每天早上六點左右起床。」
→ 生活習慣
「上星期和朋友去台南玩。」
→ 過去事件
這些資訊未來都有可能影響 AI 的回答。
因此比起儲存完整的原始對話,我比較希望系統把對話轉換成一筆一筆結構化的 Memory。
因為這次 AI Companion 最後希望延伸到高齡智慧健康照護,因此我沒有把所有 Memory 都放在一起,而是先分成兩大類:
Memory
├─ General Memory
│ ├─ 喜好
│ ├─ 家人
│ ├─ 生活習慣
│ └─ 過去事件
│
└─ Health Memory
├─ 睡眠
├─ 飲食
├─ 活動
├─ 用藥
└─ 身體不適
General Memory 比較偏向了解「這個人是誰」。
例如:
喜歡散步
喜歡聽老歌
女兒星期六會回家
平常早上六點起床
而 Health Memory 則是比較可能和後面的健康狀態分析有關。
例如:
昨晚只睡四個小時
最近食慾比較差
今天走路時膝蓋有點痛
早上忘記吃藥
這兩種資訊未來的使用方式也不完全相同。
General Memory 主要會影響個人化對話,而 Health Memory 未來還會進一步交給 Health State Analysis,觀察一段時間內是否出現變化。
Day 09 先把資料結構建立起來,健康趨勢分析則留到後面再處理。
接下來最大的問題是:
難道每次都要人工決定哪一句話需要存進 Memory 嗎?
當然不可能。
所以第一版做法,是讓 LLM 在收到使用者訊息後,同時判斷:
這段話裡面有沒有值得長期保存的資訊?
例如使用者說:
「我平常晚上喜歡出去散步。」
經過 Memory Extraction 後,可以得到:
{
"memory_type": "general",
"category": "preference",
"content": "晚上喜歡散步"
}
如果使用者說:
「這幾天晚上都睡不太好。」
則可以抽成:
{
"memory_type": "health",
"category": "sleep",
"content": "最近幾天晚上睡眠狀況不好"
}
這樣未來系統真正保存的,就不是整段原始聊天,而是整理過、比較容易使用的資訊。
目前的第一版 Memory Schema 可以先保持簡單:
{
"user_id": "user_001",
"memory_type": "general",
"category": "preference",
"content": "晚上喜歡散步",
"created_at": "2026-09-23"
}
之後如果需要,也可以再加入:
importance
confidence
source
last_updated
expire_at
來處理重要程度、可信度、來源與過期問題。
不過 Day 09 先以「能正確抽取並保存」為目標。
當 LLM 抽取出 Memory 後,下一步就是把它存進資料庫。
第一版流程可以整理成:
User Speech
↓
STT
↓
User Message
↓
Memory Extraction
↓
是否有值得保存的資訊?
↓
General Memory / Health Memory
↓
Database
例如:
使用者:
「我平常晚上喜歡出去散步。」
↓
LLM Memory Extraction
↓
General Memory
{
"type": "preference",
"content": "晚上喜歡散步"
}
↓
Database
這樣即使這一輪 Conversation History 結束,這筆資訊依然可以保留下來。
也就是開始真正擁有「跨對話」的記憶。
有了資料庫之後,就可以做一個最簡單的測試。
第一次對話:
User:
我平常晚上喜歡出去散步。
系統建立:
Memory:
晚上喜歡散步
下一次重新開始對話:
User:
今天晚上不知道要做什麼。
系統找到之前的 Memory:
晚上喜歡散步
再把它一起提供給 LLM:
Relevant Memory:
- 使用者晚上喜歡散步
Current Message:
今天晚上不知道要做什麼。
最後產生:
「你之前有提到晚上喜歡散步,如果今天精神還不錯,也可以出去走走。」
這就是今天想完成的第一個 Memory Demo:
上次說過的事情,下一次 AI 還記得。
做到這裡之後,我發現 Memory 最困難的地方其實不是「怎麼存資料」,而是:
什麼資訊真的值得記住?
如果什麼都存,Memory 很快又會變成另一種形式的聊天紀錄。
例如:
今天午餐吃便當
剛剛看到一隻狗
下午下雨
現在有點累
這些資訊到底哪些需要長期保存,其實不一定。
另外也會出現一些更麻煩的問題。
例如使用者原本說:
「我喜歡喝咖啡。」
過了一段時間又說:
「最近不太喝咖啡了。」
這時候應該建立一筆新的 Memory,還是修改原本的 Memory?
如果同一件事情被講了很多次,又要怎麼避免資料庫出現大量重複資料?
健康資訊還會遇到另一個問題:
「今天頭有點痛。」
這可能只是一天的狀況,不代表長期健康狀態。
所以 Memory 並不是單純:
聊天內容 → 存進資料庫
而是需要處理:
是否值得記住
是否重複
是否需要更新
是否互相衝突
是否已經過期
這些問題之後都還需要慢慢補上。
Day 08,我讓 AI Companion 學會在使用者插話時停止說話,讓語音互動變得更自然。
Day 09,我開始處理另一個更重要的問題:
讓 AI 不再每次都從零開始認識使用者。
目前第一版流程變成:
使用者對話
↓
Memory Extraction
↓
判斷是否值得記住
↓
General Memory / Health Memory
↓
Database
↓
未來對話再次使用
今天真正完成的核心並不是「把聊天紀錄存起來」,而是開始建立一個概念:
Memory 應該保存對未來有價值的資訊,而不是保存所有說過的話。
不過現在還有一個問題。
當資料庫裡面只有幾筆 Memory 時,可以直接全部提供給 LLM。
但未來如果累積了幾百、幾千筆記憶,顯然不可能每次全部讀出來。
所以接下來要解決的是:
當使用者說一句話時,AI 要怎麼知道該想起哪一段記憶?
讓 AI 不只是「有記憶」,而是能在正確的時間,想起正確的事情。