跳至主要內容

觀察記憶

新增於: @mastra/memory@1.1.0

觀察記憶(Observational Memory,OM)是 Mastra 的長上下文 Agent 記憶系統。背景 Agent(即 ObserverReflector)會監察 Agent 的對話,並維護一份密集的觀察日誌;隨着日誌增長,它會取代原始訊息歷史記錄。

快速開始
快速開始 的直接連結

請確保項目已安裝 @mastra/memory。在 Memory 配置中設定 observationalMemory: true,即可啟用觀察記憶。

src/mastra/agents/agent.ts
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'

export const agent = new Agent({
id: 'my-agent',
name: 'my-agent',
instructions: 'You are a helpful assistant.',
model: 'openai/gpt-5-mini',
memory: new Memory({
options: {
observationalMemory: true,
},
}),
})

Agent 現在具備可跨對話保留、類似人類的長期記憶。設定 observationalMemory: true 時,預設會使用 google/gemini-2.5-flash。如要使用其他模型,請在配置物件中傳入模型:

const memory = new Memory({
options: {
observationalMemory: {
model: 'deepseek/deepseek-reasoner',
},
},
})

完整 API 詳情請參閱配置選項

注意

在客戶端應用程式中使用 OM 時,請從客戶端只傳送新訊息,而非完整的對話歷史記錄。

觀察記憶仍依賴已儲存的對話歷史記錄。傳送完整歷史記錄既多餘,也可能在客戶端時間戳與已儲存的時間戳發生衝突時,引致訊息排序錯誤。

AI SDK 範例請參閱使用 Mastra Memory

備註

OM 目前只支援 @mastra/pg@mastra/libsql@mastra/mysql@mastra/mongodb@mastra/convex@mastra/oracledb 儲存配接器。 它使用背景 Agent 管理記憶。未設定模型時,預設模型為 google/gemini-2.5-flash

時間間隔標記
時間間隔標記 的直接連結

如果對話串中上一則訊息發出後已經過足夠時間,時間間隔標記會在新的使用者訊息前插入簡短提示,讓 Agent 和 UI 知道對話是在一段值得留意的停頓後恢復。

時間間隔標記預設為停用。請在 observationalMemory 配置中設定 temporalMarkers: true 以啟用:

src/mastra/agents/agent.ts
import { Memory } from '@mastra/memory'
import { Agent } from '@mastra/core/agent'

export const agent = new Agent({
id: 'my-agent',
name: 'my-agent',
instructions: 'You are a helpful assistant.',
model: 'openai/gpt-5-mini',
memory: new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
temporalMarkers: true,
},
},
}),
})

當時間間隔至少為 10 分鐘時,Mastra 會插入時間間隔標記。此標記會儲存在記憶中,同時以暫時提示事件的形式發出,讓客戶端可以將其呈現為輕量的時間軸提示。

Observer 處理對話串時也會看到這些標記,因此它寫入的觀察記錄可將記憶與事件發生的時間連繫起來(例如「使用者在相隔 2 天後詢問部署事宜」)。

完整配置結構請參閱 API 參考

提早啟用
提早啟用 的直接連結

OM 可在達到 token 閾值前啟用已緩衝的觀察記錄。當提示快取可能即將到期,或 Agent 更換模型 Provider 時,這項功能十分實用。

頂層提早啟用設定預設套用於觀察記錄:

src/mastra/agents/agent.ts
const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
activateAfterIdle: 'auto',
activateOnProviderChange: true,
},
},
})

使用巢狀 observationreflection 設定,分別控制各個階段。反思的提早啟用須主動選用,因此頂層設定只會影響觀察記錄。

src/mastra/agents/agent.ts
const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
activateAfterIdle: '5m',
observation: {
activateAfterIdle: false,
},
reflection: {
activateAfterIdle: '10m',
activateOnProviderChange: true,
},
},
},
})

在此範例中,頂層閒置設定對觀察記錄停用,而反思則選擇啟用閒置及 Provider 變更時啟用的機制。

閒置時緩衝
閒置時緩衝 的直接連結

observation.bufferOnIdle 設為 true,即可在 Agent 的一輪互動結束並進入閒置狀態時,在背景執行觀察緩衝。對於希望短輪次也能被觀察,而無需等待下一輪或達到 messageTokens 閾值的應用程式,這項功能十分實用。

src/mastra/agents/agent.ts
const memory = new Memory({
options: {
observationalMemory: {
model: 'openai/gpt-5-mini',
observation: {
bufferOnIdle: true,
},
},
},
})

bufferOnIdle 預設為停用。它與 bufferTokens 分開運作:bufferTokens 控制步驟執行期間的非同步緩衝,而 bufferOnIdle 則控制閒置輪次在互動結束時的緩衝。

完整配置結構請參閱 API 參考

優點
優點 的直接連結

  • 提示快取:OM 的上下文保持穩定,觀察記錄會隨時間附加,而非在每輪執行時擷取。這可讓提示前綴保持可快取,從而降低成本。
  • 壓縮:原始訊息歷史記錄和 Tool 結果會壓縮成密集的觀察日誌。上下文越小,回應便越快,連貫的對話也能維持更久。
  • 零上下文劣化:Agent 看到的是相關資訊,而非嘈雜的 Tool 呼叫和無關 token,因此能在長時間工作階段中持續專注於任務。

運作方式
運作方式 的直接連結

你不會記得自己曾經歷的每次對話中的每一句話。你會在潛意識中觀察所發生的事,然後大腦作出反思,將內容重新整理、合併和濃縮成長期記憶。OM 的運作方式亦一樣。

每次 Agent 回應時,都會看到一個包含其系統提示、近期訊息記錄,以及任何注入內容的上下文視窗。上下文視窗的容量有限,即使 token 上限很高的模型,在視窗載滿時表現也會變差。這會導致兩個問題:

  • 上下文劣化:Agent 攜帶的原始訊息記錄越多,表現便越差。
  • 上下文浪費:這些記錄大部分都包含已不再需要、無助於 Agent 繼續執行當前任務的 token。

OM 將舊有上下文壓縮成密集的觀察記錄,從而解決這兩個問題。

觀察
觀察 的直接連結

當訊息記錄的 token 超過閾值(預設:30,000)時,Observer 會建立觀察記錄,以簡潔筆記記下所發生的事:

OM 使用快速的本機 token 估算來判斷是否達到閾值。文字使用 tokenx 估算,而圖像部分則使用考慮 Provider 的啟發式方法,讓多模態對話仍能在適當時機觸發觀察。當傳輸層把已上載的圖像正規化為檔案而非圖像部分時,同樣的方式也適用於類似圖像的 file 部分。例如,OpenAI 的圖像細節設定可能會實質影響 OM 決定執行觀察的時機。

Observer 也可以看到其檢視記錄中的附件。為方便閱讀,OM 會在文字記錄中保留 [Image #1: reference-board.png][File #1: floorplan.pdf] 等易讀的佔位符,並將實際附件部分連同文字一併轉交。OM 會盡可能把類似圖像的 file 部分升級為 Observer 的圖像輸入,而非圖像附件則會以檔案部分轉交,並使用正規化的 token 計算方式。這同時適用於一般 thread 觀察和批次 resource scope 觀察。

Extractor
Extractor 的直接連結

如要 OM 在觀察記錄旁持久保存特定值,請使用 Extractor。目前任務建議回應thread 標題等內置值,與自訂值使用相同的擷取流程。

以下範例從觀察記錄擷取精簡的用戶資料:

src/mastra/agents/agent.ts
import { Agent } from '@mastra/core/agent'
import { Extractor, Memory } from '@mastra/memory'
import { z } from 'zod'

const memory = new Memory({
options: {
observationalMemory: {
model: 'openai/gpt-5-mini',
observation: {
extract: [
new Extractor({
name: 'User profile',
instructions: 'Extract stable user profile facts that should be remembered.',
schema: z.object({
preferredName: z.string().optional(),
timezone: z.string().optional(),
tools: z.array(z.string()).optional(),
}),
}),
],
},
},
},
})

export const agent = new Agent({
id: 'assistant',
name: 'assistant',
instructions: 'You are a helpful assistant.',
model: 'openai/gpt-5-mini',
memory,
})

加入 schema 後,Extractor 會以後續結構化輸出請求的形式執行。沒有 schema 的 Extractor 是內嵌字串 Extractor,會直接在 Observer 或 Reflector 的回應中輸出。

src/mastra/agents/agent.ts
new Extractor({
name: 'Mood',
instructions: 'Extract the user mood as a short phrase.',
})

預設情況下,OM 會在後續執行時向 Extractor 顯示上一次擷取的值。如果不應讓 Observer 看到上一個值,請設定 includePreviousExtraction: false

src/mastra/agents/agent.ts
new Extractor({
name: 'Latest blocker',
instructions: 'Extract any blockers the agent is running into.',
includePreviousExtraction: false,
})

當 Extractor 需要執行階段上下文(例如目前使用中的 memory 執行個體或請求上下文)時,請使用執行階段 instructionsschema 函數:

src/mastra/agents/agent.ts
new Extractor({
name: 'Workspace summary',
instructions: ({ memory }) =>
memory ? 'Extract workspace facts for this memory instance.' : 'Extract workspace facts.',
})

從串流讀取擷取值
從串流讀取擷取值 的直接連結

OM 完成觀察或反思時,便會輸出 Extractor 結果。從串流讀取兩種完成資料部分:

src/mastra/run.ts
const stream = await agent.stream('Remember that I prefer dark mode.')

for await (const chunk of stream.fullStream) {
if (chunk.type === 'data-om-observation-end' || chunk.type === 'data-om-buffering-end') {
const { operationType, extractedValues = {}, extractionFailures = [] } = chunk.data

for (const [slug, value] of Object.entries(extractedValues)) {
console.log(`${operationType} extractor ${slug}:`, value)
}

for (const failure of extractionFailures) {
console.error(`Extractor ${failure.slug} failed:`, failure.error)
}
}
}

extractedValues 以每個 Extractor 的 slug 作為 key。兩個結果欄位皆為選填,而某個 Extractor 失敗亦不會移除成功 Extractor 的值。

data-om-observation-end 表示同步完成。data-om-buffering-end 表示背景工作完成。其 Extractor metadata 會立即持久保存,但緩衝內容在啟用前仍維持非使用中狀態。檢查 operationType,即可判斷已完成的工作屬於觀察還是反思。

如需完整 payload,請參閱 data-om-observation-enddata-om-buffering-end 參考表格。

更新 working memory
更新 working memory 的直接連結

使用 observationalMemory.observation.manageWorkingMemory,讓 Observer 自動管理 working memory。主要 Agent 處理用戶請求時,不再需要呼叫 working memory Tool,因此更新 working memory 不再取決於 Agent 是否記得執行相關操作。

這也讓 working memory 配合提示快取使用。Working memory 一般位於系統提示中,因此更新可能令提示快取失效。由 OM 管理的 working memory 會將 workingMemory.useStateSignals 預設為 true,把 working memory 移至狀態訊號中。

src/mastra/agents/agent.ts
import { Memory } from '@mastra/memory'

const memory = new Memory({
options: {
workingMemory: {
enabled: true,
},
observationalMemory: {
enabled: true,
observation: {
manageWorkingMemory: true,
},
},
},
})

此設定會加入 WorkingMemoryExtractor、將 workingMemory.agentManaged 預設為 false,並將 workingMemory.useStateSignals 預設為 true。如主要 Agent 仍應接收 working memory Tool 和指示注入,請設定 workingMemory.agentManaged: true

在自訂擷取值持久保存之前,使用 onExtracted 將值正規化或回應這些值:

src/mastra/agents/agent.ts
new Extractor({
name: 'Project status',
instructions: 'Extract the current project status.',
schema: z.string(),
async onExtracted({ current, sendSignal }) {
await sendSignal?.({
type: 'user-message',
contents: `Project status extracted: ${current}`,
})
return current.trim().toLowerCase()
},
})

Extractor 失敗會在 OM 標記中報告,且不會阻礙其他 Extractor 成功輸出值。如需完整的 Extractor 結構,請參閱 API 參考

如果你的 Observer 模型只支援文字,或其 API 拒絕多模態輸入,請將 observation.observeAttachments 設定為 false,在附件送達 Observer 前移除附件。易讀的佔位符([Image #1: ...][File #1: ...])仍會保留在文字記錄中,讓 Observer 即使沒有收到二進制 payload,仍可根據已分享的內容進行推理。相同的篩選器亦適用於包含圖像或檔案部分的 Tool 結果:

new Agent({
id: 'assistant',
name: 'assistant',
instructions: 'You are a helpful assistant.',
model: 'openai/gpt-5-mini',
memory: new Memory({
options: {
observationalMemory: {
observation: {
model: 'deepseek/deepseek-reasoner',
observeAttachments: false,
},
},
},
}),
})

你也可以傳入 mimeType glob 的允許清單(例如 ['image/*']),只轉交 Observer 能夠處理的類型。另一種做法是設定 observeAttachments: 'auto',讓 Mastra 根據 Provider 功能註冊表決定:當 Observer 模型支援多模態輸入時轉交附件,否則移除附件;如果該模型沒有可用的功能資料,則回退至 true

Date: 2026-01-15

- 🔴 12:10 User is building a Next.js app with Supabase auth, due in 1 week (meaning January 22nd 2026)
- 🔴 12:10 App uses server components with client-side hydration
- 🟡 12:12 User asked about middleware configuration for protected routes
- 🔴 12:15 User stated the app name is "Acme Dashboard"

壓縮率通常介乎 5 倍至 40 倍。Observer 亦會追蹤目前任務建議回應,讓 Agent 從上次中斷之處繼續。

如啟用 observation.threadTitle,當對話主題出現重大變化時,Observer 也可以建議簡短的 thread 標題。產生 thread 標題屬於選用功能,並會更新 thread metadata,讓 Mastra Code 等應用程式可在 thread 清單和狀態 UI 中顯示最新標題。

範例:使用 Playwright MCP 的 Agent,每個頁面快照可能有超過 50,000 個 token。有了 OM,Observer 會監察互動,並建立數百個 token 的觀察記錄,記下頁面上的內容和已執行的操作。Agent 無需攜帶每個原始快照,仍可專注於目前任務。

反思
反思 的直接連結

當觀察記錄超過閾值(預設:40,000 個 token)時,Reflector 會將其濃縮、合併相關項目,並反思當中的模式。

反思不會累積成獨立且不斷增長的層。每次反思都會重寫整份觀察記錄。Reflector 的輸出會成為新記錄,新觀察則附加在其後。下次記錄達到閾值時,Reflector 會重新處理所有內容,包括先前的反思。它會更大幅度地濃縮較舊的資訊,同時保留近期細節。無論對話持續多久,記憶大小都會維持在反思閾值附近。

最終形成一個三層系統:

  1. 近期訊息:目前任務的完整對話記錄
  2. 觀察:Observer 所見內容的記錄
  3. 反思:記憶過長時經濃縮的觀察記錄

上下文如何隨時間改變
上下文如何隨時間改變 的直接連結

使用預設設定時,上下文視窗不會無限增長,而會反覆經歷觀察並縮減的週期:

Chart of context tokens over the course of a conversation with Observational Memory enabled: message history repeatedly grows toward the 30,000 token observation threshold, then shrinks back to around 6,000 tokens as observations activate, while the observation log steps up with each cycle until it reaches the 40,000 token reflection threshold and the Reflector condenses it into reflections
  1. 0 → 30k 個 token:訊息記錄正常增長。在背景中,Observer 每累積約 ~6k 個 token 便緩衝觀察記錄(bufferTokens: 0.2)。
  2. 達到 30k:緩衝的觀察記錄會立即啟用。已觀察的訊息會從上下文視窗移除,僅保留約 ~6k 個 token 的近期記錄(bufferActivation: 0.8 會保留閾值的 20%)。移除的約 ~24k 個訊息 token,在一般 5 至 40 倍壓縮率下,會變成約 1 至 5k 個觀察 token。
  3. 重複:記錄從約 ~6k 再次增長至接近 30k,然後再次縮減。每個週期都會附加至觀察記錄,而觀察記錄的增長速度遠低於原始記錄。
  4. 觀察記錄達到 40k:Reflector 根據目前觀察記錄和任何先前反思建立較小的記錄。

在一般緩衝週期中,原始記錄會在約 6k 至 30k 個 token 之間變動。無論對話持續多久,觀察記錄都維持在約 40k 個 token。這些是啟用閾值,而非硬性上限。如果背景緩衝未能跟上,記錄可以超出閾值,直至 blockAfter(預設為 1.2)在約 ~36k 個 token(反思則為 ~48k)時強制執行同步觀察,作為安全上限。

啟用 shareTokenBudget 後,兩個預算會合併共用。當觀察記錄較小時,訊息記錄可以佔用尚未使用的觀察空間(使用預設值時最高約為 ~70k 個 token),之後才觸發觀察。隨着觀察記錄累積,訊息記錄便會縮減。

檢索模式
檢索模式 的直接連結

一般 OM 會將訊息壓縮成觀察記錄,這非常有助於專注執行任務,但會失去原文措辭。檢索模式會把每組觀察記錄與產生該記錄的原始訊息連結起來,從而解決此問題。當 Agent 需要摘要壓縮時所捨棄的確切措辭、Tool 輸出或時間次序,便可呼叫 recall Tool,逐頁瀏覽來源訊息。

僅瀏覽
僅瀏覽 的直接連結

設定 retrieval: true,啟用 recall Tool 來瀏覽原始訊息,無需使用向量儲存。預設情況下,recall Tool 可以瀏覽目前 resource 的所有 thread。

const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
retrieval: true,
},
},
})

設定 retrieval: { vector: true },同時啟用語意搜尋。這會重用已在 Memory 執行個體上設定的向量儲存和 embedder:

const memory = new Memory({
storage,
vector: myVectorStore,
embedder: myEmbedder,
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
retrieval: { vector: true },
},
},
})

設定向量搜尋後,系統會在緩衝時和同步觀察期間,自動為新的觀察群組建立索引(即發即棄、非阻塞)。語意搜尋會傳回相符的觀察群組及其原始來源訊息 ID 範圍,讓 recall Tool 在顯示摘要記憶時,也能一併顯示其來源位置。

限制為目前 thread
限制為目前 thread 的直接連結

recall Tool 的預設 scope 是 'resource',Agent 可以列出 thread、瀏覽其他 thread,以及搜尋所有對話。設定 scope: 'thread',將 Agent 限制為只能存取目前 thread:

const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
retrieval: { vector: true, scope: 'thread' },
},
},
})

自訂 recall 指引
自訂 recall 指引 的直接連結

Mastra 會注入考慮 scope 的指示,教導 Agent 何時搜尋、列出 thread,或讀取特定 thread。使用 instructions,在這些內置指示後附加應用程式專用指引。內置指示絕不會被取代:

const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
retrieval: {
vector: true,
instructions: `
Prefer the current conversation when it already contains the answer.
For an initial scan, use a small limit with detail="low".
`,
},
},
},
})

這會讓 recall 專用指引附加至 recall Tool,而非 Agent 的全域指示,因此不會影響無關的任務。

檢索所啟用的功能
檢索所啟用的功能 的直接連結

啟用檢索模式後,OM 會:

  • 在每個觀察群組上儲存一個 range(例如 startId:endId),指向產生該觀察群組的訊息
  • 在 Agent 的上下文中顯示範圍 metadata,讓 Agent 知道哪些觀察記錄對應哪些訊息
  • 註冊一個 Agent 可以呼叫的 recall Tool,以便:
    • 逐頁瀏覽任何觀察群組範圍背後的原始訊息
    • 按語意相似度搜尋(mode: "search" 並提供 query 字串);需要 vector: true
    • 列出所有 thread(mode: "threads")、瀏覽其他 thread(threadId),以及搜尋所有 thread(預設 scope: 'resource'
    • scope: 'thread' 時:將瀏覽和搜尋限制為目前 thread

如需完整 API(詳細程度、部分索引、分頁、跨 thread 瀏覽和 token 限制),請參閱 recall Tool 參考

Studio
Studio 的直接連結

如要實際查看運作方式,請開啟 Studio,然後前往已啟用 OM 的 Agent。Memory分頁會顯示:

  • Token 進度列:顯示訊息和觀察記錄目前的 token 數量,以及距離各自閾值還有多遠。將游標停留在資訊圖示上,即可查看 Observer 和 Reflector 的模型與閾值。

  • 使用中的觀察記錄:目前的觀察記錄會直接顯示。如有更早的觀察或反思記錄,請展開「Previous observations」瀏覽。

  • 背景處理:對話期間,Agent 在背景處理時,會顯示已緩衝的觀察區塊和反思狀態。

Agent 正在觀察或反思時,進度列會即時更新,並顯示經過時間和狀態徽章。

模型
模型 的直接連結

Observer 和 Reflector 會在背景執行。任何支援 Mastra 模型路由provider/model)的模型皆可使用。如果沒有設定模型,預設模型為 google/gemini-2.5-flash

Mastra 建議使用具備大型上下文視窗(128K+ 個 token),並且速度足以在背景執行而不會拖慢操作的模型。

如果不確定應使用哪個模型,請先使用預設的 google/gemini-2.5-flash。我們亦已成功測試 openai/gpt-5-minianthropic/claude-haiku-4-5deepseek/deepseek-reasonerdeepseek/deepseek-v4-prodeepseek/deepseek-v4-flashxai/grok-4-1-fastqwen3glm-4.7

const memory = new Memory({
options: {
observationalMemory: {
model: 'deepseek/deepseek-reasoner',
},
},
})

如要為每個 Agent 使用不同模型,請參閱模型設定

備註

google/gemini-2.5-flash 特別擅長在長輸出中保留細節。因此,即使達到壓縮重試次數上限,Reflector 所產生的反思仍可能高於設定的 reflection.observationTokens 閾值。發生這種情況時,Reflector 會傳回重試期間產生的最小非退化候選結果,讓循環終止,而非無限執行。

如想讓 Reflector 更大幅度地壓縮,可改用更容易濃縮內容的模型,例如 xai/grok-4-1-fastdeepseek/deepseek-v4-prodeepseek/deepseek-v4-flash。你可以繼續為 Observer 使用 google/gemini-2.5-flash,並為 Reflector 使用另一個模型。請參閱為每個 Agent 使用不同模型

按 token 分級選擇模型
按 token 分級選擇模型 的直接連結

新增於: @mastra/memory@1.10.0

你可以使用 ModelByInputTokens,根據輸入 token 數量為 Observer 或 Reflector 指定不同模型。OM 會在執行階段根據設定的 upTo 閾值,選擇相符的模型級別。

import { Memory, ModelByInputTokens } from '@mastra/memory'

const memory = new Memory({
options: {
observationalMemory: {
observation: {
model: new ModelByInputTokens({
upTo: {
// Faster, cheaper models for smaller inputs; stronger models for larger contexts
5_000: 'openrouter/mistralai/ministral-8b-2512',
20_000: 'openrouter/mistralai/mistral-small-2603',
40_000: 'openai/gpt-5-mini',
1_000_000: 'google/gemini-3.1-flash-lite-preview',
},
}),
},
reflection: {
model: new ModelByInputTokens({
upTo: {
20_000: 'openai/gpt-5-mini',
100_000: 'google/gemini-2.5-flash',
},
}),
},
},
},
})

upTo key 是包含端點的上限。OM 會計算 Observer 或 Reflector 呼叫的實際輸入 token 數量,直接解析相符級別,並在該次執行中使用對應的具體模型。

如果輸入超過已設定的最大閾值,系統便會拋出錯誤。請確保閾值涵蓋所有可能的輸入大小,或在最高級別使用上下文視窗足夠大的模型。

作用域
作用域 的直接連結

Thread 作用域(預設)
Thread 作用域(預設) 的直接連結

每個 thread 都有各自的觀察記錄。此作用域已經過充分測試,作為通用記憶系統時表現良好,尤其適合長期運作的 Agent 使用情境。

const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
scope: 'thread',
},
},
})

Thread 作用域要求呼叫 Agent 時提供有效的 threadId。如果缺少 threadId,Observational Memory 會拋出錯誤。這可防止多個 thread 在不知情下共用同一筆觀察記錄,否則可能會造成資料庫死鎖。

Resource 作用域(實驗性)
Resource 作用域(實驗性) 的直接連結

觀察記錄會在同一 resource(通常是使用者)的所有 thread 之間共用,從而實現跨對話記憶。

const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
scope: 'resource',
},
},
})

Resource 作用域可以運作,但目前仍標示為實驗性,直至我們證實它能在多個同時持續進行的 thread 之間維持任務遵循能力和連貫性。 目前,你可能需要調整 system prompt,避免某個 thread 接續另一個 thread 已開始(但尚未完成)的工作。

這是因為在 resource 作用域中,每個 thread 都是檢視該 resource 所有 thread 的一個視角。

這對你的使用情境而言未必是問題,因此實際效果可能因情況而異。

注意

在 resource 作用域中,所有 thread 內尚未觀察的訊息會一併處理。對於已有大量 thread 的使用者,這個過程可能很慢。現有應用程式應使用 thread 作用域。

Token 預算
Token 預算 的直接連結

OM 使用 token 閾值來決定何時進行觀察和反思。詳情請參閱 token 預算設定

const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
observation: {
// when to run the Observer (default: 30,000)
messageTokens: 30_000,
},
reflection: {
// when to run the Reflector (default: 40,000)
observationTokens: 40_000,
},
// let message history borrow from observation budget
// requires bufferTokens: false (temporary limitation)
shareTokenBudget: false,
},
},
})

Token 計數快取
Token 計數快取 的直接連結

OM 會在訊息 metadata 中快取 token 估算值,以減少執行閾值檢查和作出緩衝決定時的重複計數工作。

  • 每個 part 的估算值會儲存在 part.providerMetadata.mastra,並在後續處理中於快取版本/tokenizer 來源相符時重用。
  • 對於只有字串的訊息內容(不含 part),OM 會使用訊息層級的 metadata 後備快取。
  • 每次處理仍會重新計算訊息和對話的額外開銷。快取只儲存 payload 估算值,因此計數語意維持不變。
  • data-*reasoning part 仍會略過,不會快取。

呼叫方為檔案 part 提供的 token 估算值
呼叫方為檔案 part 提供的 token 估算值 的直接連結

你可以使用 providerMetadata.mastra.tokenEstimate,直接將 token 估算值附加至 imagefile part。Token Counter 會原樣採用這個值,並略過本身的估算器:

const filePart = {
type: 'file',
data: 'storage://bucket/large-report.pdf',
mimeType: 'application/pdf',
filename: 'large-report.pdf',
providerMetadata: {
mastra: {
tokenEstimate: {
v: 0,
source: 'client',
key: 'client',
tokens: 100_000,
},
},
},
}

tokenEstimate 物件的結構與 Token Counter 內部快取估算值所用的結構相同:

  • v:快取 schema 版本。請設為 0。呼叫方提供的項目不受 framework 的版本檢查約束,因此不會讀取此值。
  • source:快取來源標記。必須是 'client'。它會告知 Token Counter 此項目具權威性,應原樣採用,而不是重新計算或覆寫。
  • key:內容 fingerprint 欄位。請設為 'client'。Framework 項目會在此處使用內容 hash,讓項目在 payload 變更時失效。'client' sentinel 可讓呼叫方估算值在多次寫入之間保持穩定。
  • tokens:要使用的 token 數量。必須是有限的非負數。

其他注意事項:

  • 估算值只會在 imagefile part 上獲採用。texttool-invocation part 一律會正常計數,即使它們包含 tokenEstimate 亦然。

非同步緩衝
非同步緩衝 的直接連結

如果不使用非同步緩衝,當訊息達到閾值時,Observer 會同步執行;Agent 會在對話途中暫停,直至 Observer LLM 呼叫完成。使用非同步緩衝(預設啟用)後,系統會隨對話增長,在背景預先計算觀察記錄。達到閾值時,已緩衝的觀察記錄會即時啟用,過程毋須暫停。

運作方式
運作方式 的直接連結

隨着 Agent 進行對話,訊息 token 會不斷累積。系統會按固定間隔(bufferTokens)在背景呼叫 Observer,而不會阻塞 Agent。每次呼叫都會產生一個觀察記錄「區塊」,並儲存在緩衝區中。

當訊息 token 達到 messageTokens 閾值時,已緩衝的區塊便會啟用:其中的觀察記錄會移至作用中的觀察日誌,而相應的原始訊息會從上下文視窗中移除。Agent 全程都不會暫停。

已緩衝的觀察記錄亦包括接續提示、建議的下一個回覆及目前任務,因此啟用緩衝內容並縮減上下文視窗後,主要 Agent 仍可維持對話連貫性。

如果 Agent 產生訊息的速度快過 Observer 的處理速度,blockAfter 安全閾值會作為最後手段,強制執行同步觀察。啟用已緩衝內容時,仍會保留最低限度的剩餘上下文(約 1k token 或已設定保留下限,取兩者中較小者)。

反思的運作方式相近:當觀察記錄達到反思閾值的某個比例時,Reflector 便會在背景執行。

設定
設定 的直接連結

設定預設值控制內容
observation.bufferTokens0.2執行緩衝的頻率。0.2 表示每達到 messageTokens 的 20% 便執行一次。若使用預設的 30k 閾值,即大約每 6k token 執行一次。亦可使用絕對 token 數量(例如 5000)。
observation.bufferActivation0.8啟用時清除訊息視窗的積極程度。0.8 表示移除足夠的訊息,讓剩餘內容只佔 messageTokens 的 20%。較低的值會保留更多訊息歷史。
observation.blockAfter1.2緩衝速度不足時的安全機制。從 1 至 100 以內(不包括 100)的值會乘以 messageTokens:設為 1.2 時,系統會在 36k token(1.2 × 30k)強制執行同步觀察。100 或以上的值則代表絕對 token 數量(例如 50_000)。
activateAfterIdle即使尚未達到 observation.messageTokens,亦會在閒置一段時間後強制啟用已緩衝的觀察記錄。接受以毫秒表示的數值(例如 300_000)、"5m""1hr" 等持續時間字串,亦可設為 "auto",以使用配合 Provider 的 prompt 快取 TTL。
activateOnProviderChangefalse如果下一個步驟使用的 provider/model 與產生最新 assistant 步驟的 provider/model 不同,便會強制啟用已緩衝的觀察記錄。切換 Provider 或模型會令 prompt 快取無法重用時,請使用此設定。
reflection.bufferActivation0.5開始背景反思的時機。0.5 表示當觀察記錄達到 observationTokens 閾值的 50% 時,便開始反思。
reflection.activateAfterIdle讓已緩衝的反思選擇加入閒置啟用機制。反思不會繼承最上層的 activateAfterIdle
reflection.activateOnProviderChangefalse讓已緩衝的反思選擇加入 Provider 變更啟用機制。反思不會繼承最上層的 activateOnProviderChange
reflection.blockAfter1.2反思的安全閾值,邏輯與觀察相同。

如果你依賴 prompt 快取,請將 activateAfterIdle 設為 "auto" 或特定的快取 TTL。這樣,當 thread 閒置時間足以令快取過期後,下一個請求可先啟用已緩衝的觀察記錄,再傳送較小且已壓縮的上下文視窗。

使用 "auto" 時,Mastra 會根據作用中模型的 Provider 選擇閒置啟用 TTL:

Provider自動 TTL
Anthropic、OpenRouter、未知 Provider、xAI5 分鐘
DeepSeek1 小時
Google Gemini24 小時
Groq2 小時
使用 providerOptions.openai.promptCacheRetention: "24h" 的 OpenAI1 小時
使用 providerOptions.openai.promptCacheRetention: "in_memory" 的 OpenAI5 分鐘
OpenAI gpt-4*gpt-5gpt-5-*,以及由 gpt-5.1gpt-5.4(包括帶有 - 後綴的變體)5 分鐘
其他 OpenAI 模型1 小時
const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
activateAfterIdle: 'auto',
activateOnProviderChange: true,
},
},
})

使用 "auto" 時,此功能會根據作用中 Provider 的 prompt 快取行為啟用已緩衝的觀察記錄,讓下一個未快取的 prompt 使用已壓縮的觀察記錄,而非較大的原始訊息視窗。如果你偏好固定的 5 分鐘 TTL,請使用 "5m"300_000

在 thread 進行期間變更模型或 Provider,會令 prompt 快取失效。如果你的 Agent 可以在 thread 進行期間切換 Provider 或模型,activateOnProviderChange: true 會在新 Provider 執行前強制啟用已緩衝的觀察記錄。這可避免將大型原始視窗傳送至無法重用先前 prompt 快取的 Provider。

停用
停用 的直接連結

如要停用非同步緩衝,改用同步觀察/反思:

const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
observation: {
bufferTokens: false,
},
},
},
})

設定 bufferTokens: false 會同時停用觀察和反思的非同步緩衝。完整 API 詳情請參閱 非同步緩衝設定

備註

scope: 'resource' 不支援非同步緩衝。系統會在 resource 作用域中自動將其停用。

Observer 上下文最佳化
Observer 上下文最佳化 的直接連結

根據預設設定,Observer 處理新訊息時會收到完整的觀察記錄歷史作為上下文。Observer 亦會收到先前的 current-tasksuggested-response metadata(如有),因此即使觀察上下文被截短,仍能掌握目前情況。對於觀察記錄日益龐大的長時間對話,你可以選擇啟用上下文最佳化,以減少 Observer 的輸入成本。

設定 observation.previousObserverTokens 可限制傳送至 Observer 的先前觀察記錄 token 數量。觀察記錄會從尾部截短,保留最新的項目。當有已緩衝的反思等待處理時,系統會先自動以反思摘要取代已反思的行,然後才套用截短。

const memory = new Memory({
options: {
observationalMemory: {
model: 'google/gemini-2.5-flash',
observation: {
previousObserverTokens: 10_000, // keep only ~10k tokens of recent observations
},
},
},
})
  • previousObserverTokens: 2000 → 預設值。保留約 2k token 的近期觀察記錄。
  • previousObserverTokens: 0 → 完全省略先前的觀察記錄。
  • previousObserverTokens: false → 停用截短並保留完整的先前觀察記錄。

遷移現有 thread
遷移現有 thread 的直接連結

毋須手動遷移。OM 會讀取現有訊息,並在超出閾值時延後觀察它們。

  • Thread 作用域:thread 首次超出 observation.messageTokens 時,Observer 會處理積壓內容。
  • Resource 作用域:同一 resource 的所有 thread 中,尚未觀察的訊息會一併處理。對於已有大量 thread 的使用者,這可能需要相當長時間。

比較 OM 與其他記憶功能
比較 OM 與其他記憶功能 的直接連結

  • 訊息歷史:目前對話的高保真記錄
  • 工作記憶:用於使用者偏好、名稱及目標的小型結構化狀態(JSON 或 markdown)
  • Semantic Recall:以 RAG 為基礎,擷取相關的過往訊息
  • 多使用者 thread:當多人共用同一個 thread 時,OM 如何將事實歸屬至個別使用者

如果你使用工作記憶來儲存對話摘要,或儲存會隨時間增長的持續狀態,OM 會更合適。工作記憶用於小型結構化資料;OM 則用於長時間運作的事件日誌。OM 亦會自動管理訊息歷史,而 messageTokens 設定會控制執行觀察前保留多少原始歷史。

實際而言,OM 同時取代工作記憶和訊息歷史,而且比 Semantic Recall 更準確(成本亦更低)。