現在 AI 工具變得很普及,雖然使用起來很方便,但在用的時候還是會遇到一些困擾。
有時候 AI 好像很了解我。前面提過的事情、我的習慣,甚至一些偏好,它都可以自然地接著使用;但有時候又完全相反,明明之前才說過的事情,換個對話或隔一段時間,它就像第一次見到我一樣,還要重新解釋一次。用久了其實很煩。尤其當我已經花時間交代過自己的背景、需求和偏好,下一次又要全部重講一次時,很容易出現一個想法:
AI到底記不記得我?
也因此我開始對 AI 的「記憶」產生興趣。AI 到底是怎麼記住一個人的?它是真的把我說過的事情保存下來,還是只是把以前的對話重新拿出來看?如果我要自己做一個會長期記住使用者的 AI,背後又需要處理哪些事情?
這就是我這 30 天想研究的起點。
這個系列我會從最基本的 Stateless LLM 開始,接著一路加入 Conversation History、Short-term Memory、Embedding、Semantic Search、Long-term Memory、Memory Lifecycle、Tool Calling 與 Agent,最後走到 Agentic Memory。
我也會一路實作同一個專案,目前把它叫做 Memora。
我的目標很簡單:從一個「聊完就忘」的 AI 開始,最後看看能不能真的做出一個會記得、會更新記憶,也知道什麼時候該忘記的 AI Agent。
不過第一天,我想先從一個最基本的問題開始:
AI 現在看起來會記得我,真的代表它有記憶嗎?
假設我先告訴 AI:
我的英文程度大概是 B1。
聊了幾句之後,我再問:
那幫我出五題適合我的英文題目。
AI 很可能會直接產生 B1 程度的題目。
從使用者的角度來看,這很自然會被理解成:
AI 記得我的程度是 B1。
但如果我開一個新的對話,只輸入:
幫我出五題適合我的英文題目。
情況就不一定一樣了。
AI 可能會反問:
請問你的英文程度大概是多少?
同樣是一個 AI,為什麼前面知道,現在卻不知道?
原因之一其實很單純:前一次回答時,它看得到「我的程度是 B1」;現在這一次,它看不到了。
例如我先說:
User:
我叫小明。
接著問:
User:
我叫什麼名字?
我們看到的介面好像只是「我問一句、AI 回一句」,但應用程式真正交給模型的內容可能長這樣:
User:
我叫小明。
Assistant:
你好,小明!
User:
我叫什麼名字?
模型回答「你叫小明」並不奇怪,因為答案其實就在它目前看到的內容裡。
所以從使用者的角度看起來是「AI 記得我」,但從系統的角度來看,更精確的說法是:
應用程式再次把先前的資訊提供給了模型。
這兩件事情差很多,也是理解 AI Memory 的第一個關鍵。
接下來要先認識一個重要概念:Stateless,中文通常翻成「無狀態」。
簡單來說,可以把每一次 Request 看成一次獨立的請求。前一次 Request 裡出現過的內容,不會因為「模型曾經看過」,就自動存在於下一次 Request。
例如第一次我傳:
Request 1
我的英文程度是 B1。
模型回答:
Response 1
了解。
接著第二次我只傳:
Request 2
我的英文程度是多少?
如果 Request 2 裡沒有再次提供「我的英文程度是 B1」這項資訊,那模型自然沒有足夠資料可以回答。
可以簡化成:
Request 1
「我的英文程度是 B1」
↓
LLM
↓
Response
Request 2
「我的英文程度是多少?」
↓
LLM
↓
無法得知
所以這裡真正發生的事情,不是模型「剛剛記得,突然失憶」,而是:
新的 Request 裡,本來就沒有上一個 Request 的資訊。
這也代表,如果我要讓一個 AI 應用可以持續對話,光有 LLM 還不夠。
應用程式本身還要負責保存先前發生過的事情,並且決定哪些內容需要在下一次重新提供給模型。
也可以先把兩者的責任分開:
LLM
負責:根據目前收到的資訊產生回答
Application
負責:決定要保存什麼,以及下一次要把什麼交給 LLM
後面我們會做的 Conversation History、Short-term Memory、Long-term Memory,其實都是在逐步補上 Application 這一層的能力。
這裡就會接到另一個很重要的詞:Context。
我會把 Context 定義成:
模型這一次產生回答時,可以使用的資訊。
例如一次簡單的聊天可能包含:
System:
你是一位英文學習助理。
User:
我的英文程度是 B1。
Assistant:
了解。
User:
幫我出五題適合我的英文題目。
這些內容一起交給模型,就構成了這一次回答所能使用的 Context。
可以畫成:
┌─────────────────────────┐
│ Context │
│ │
│ System Instructions │
│ Previous Messages │
│ Current User Message │
└────────────┬────────────┘
↓
LLM
↓
Response
所以很多時候,我們感覺 AI「記得」前面的事情,其實只是那段資訊還存在於它目前的 Context 裡。
我覺得這件事情可以用一句話記住:
看得到,不代表真的記住。
這句話之後會一直出現在這個系列裡。
Context 和 Memory 很容易被混在一起,但兩者其實處理的是不同問題。可以「桌面和書櫃」來理解。
假設我現在正在準備考試,桌面上可能放著今天要讀的課本、剛剛寫的筆記、老師提醒的重點。這些都是我現在可以直接拿來使用的東西,可以把它想成 Context。
但我的書櫃裡可能還有上個月的考卷、以前整理的單字、過去的錯題紀錄。這些資料還存在,只是現在沒有全部放在桌上,可以把它想成 Memory。
所以真正合理的流程不是每次都把整個書櫃搬到桌上,而是:
我現在要做什麼?
↓
有哪些舊資料跟這件事有關?
↓
把需要的資料找出來
↓
放到桌上使用
換成 AI,就是:
Current Query
↓
Retrieve Relevant Memory
↓
Put Memory into Context
↓
LLM
↓
Response
因此我會先這樣區分:
Context 處理的是「模型現在看得到什麼」;Memory 處理的是「哪些資訊被保存,以及之後如何再被找回來」。
這也是為什麼「有聊天紀錄」和「有長期記憶」不能直接畫上等號。
知道這些之後,很自然會想到一個方法:既然 AI 會忘,那我把所有聊天紀錄全部存下來,每次都重新傳給模型不就好了?
短對話確實可以這樣做。問題是,對話會越來越長怎辦?假設我已經和 AI 聊了一千次,每次都重新附上所有歷史內容,不只資料量會不斷增加,真正有用的資訊也會被大量無關內容淹沒。
例如我今天只問:
幫我安排今天的英文練習。
真正有用的過去資訊可能只有:
英文程度:B1
偏好:短篇內容
今天可學習時間:15 分鐘
最近常錯:現在完成式
至於幾個月前問過的 Python 問題、以前規劃過的旅行,甚至其他無關的聊天內容,都沒有必要在這一次重新交給模型。
所以當資料越來越多之後,問題其實會從:
怎麼把所有事情保存起來?
慢慢變成:
什麼值得保存?現在需要哪一段?怎麼把它找出來?
而這三個問題,就是後面 Memory System 真正開始變有趣的地方。
這次我不想一開始就使用完整的 Agent Framework,把很多底層行為直接包掉。我想真的走一次從 Stateless 到 Agentic Memory 的過程。
整個系列大致會是:
Stateless LLM
↓
Conversation History
↓
Short-term Memory
↓
Embedding
↓
Semantic Search
↓
Long-term Memory
↓
Memory Retrieval
↓
User Profile
↓
Memory Policy
↓
Memory Decay / Update
↓
Tool Calling
↓
Agent Loop
↓
Agentic Memory
這條路線也剛好對應我真正想知道的事情:一個原本完全不認識我的 LLM 應用,到底要加上多少東西,最後才會變成一個「看起來真的認識我」的 AI Agent?
這 30 天,我會一路開發同一個 Personal Learning Agent:Memora。
假設我曾經告訴它:
我的英文程度大約是 B1。
我比較喜歡短篇文章。
每天大概只能學 15 分鐘。
我最近很常搞混過去式和現在完成式。
過了一段時間,我重新開啟系統,只說:
幫我安排今天的英文練習。
我希望最後的 Memora 不需要再問一次我的程度、偏好和最近的弱點,而是能把真正相關的資訊找回來,再根據這些資訊決定今天的學習內容。
再往後一步,我希望它甚至可以自己判斷:這次需要查 Memory 嗎?這句話值得保存嗎?這是新的資訊,還是舊偏好的更新?某一條記憶是不是已經過期?如果使用者改變想法,舊記憶該怎麼處理?
到了這個階段,Memory 就不只是「資料庫裡放了一些資料」,而開始變成 Agent 可以主動使用和管理的一種能力。這也是這 30 天最後要走到 Agentic Memory 的原因。
第一天還沒有真正開始寫 Chatbot,不過在進入程式之前,我先把一個很容易混淆的問題拆開了。
今天最重要的幾個觀念是:
如果要把 Day 1 濃縮成一句話,我會留這一句:
AI 看起來「記得我」,和系統真的擁有長期記憶,是兩件不同的事情。
而要繼續往下理解 Memory,下一步就必須先搞清楚一件更基本的事情:LLM 到底是怎麼完成一次對話的?
下一篇,我會拆開一次最基本的 LLM 對話,看看我們輸入一句文字之後,Token、System / User / Assistant Message 和 Context 分別扮演什麼角色。
因為只有先知道「模型到底收到了什麼」,後面才有辦法真正理解 Conversation History 和 Memory 到底是怎麼被塞回模型裡的。