跳至主要內容

Working memory

訊息歷史語意回憶可協助 Agent 記住對話,而 working memory 則能讓 Agent 在多次互動間持續保留使用者資訊。

Working memory 是 Agent 的主動暫存區:其中保存隨時可用的使用者或工作相關重要資訊。它可以在對話期間保留某人的名稱、偏好或其他重要細節。

對於維持持續存在、始終相關且應隨時提供給 Agent 的狀態,這項功能很實用。

若使用 Observational MemoryobservationalMemory.observation.manageWorkingMemory 可讓 OM 更新 Agent 的 working memory。

📹 觀看影片

觀看 Mastra working memory,瞭解 Agent 如何在互動之間持續提供使用者脈絡。

Working memory 可保存於兩種不同的作用域:

  • Resource 作用域(預設):同一位使用者的所有對話 thread 都會保存 Memory
  • Thread 作用域:每個對話 thread 的 Memory 彼此隔離

**必要條件:**切換作用域後,Agent 不會看到另一個作用域中的 Memory。Thread 作用域 Memory 與 resource 作用域 Memory 完全分離。

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

以下是為 Agent 設定 working memory 的最小範例:

import { Agent } from '@mastra/core/agent'
import { Memory } from '@mastra/memory'

// Create agent with working memory enabled
const agent = new Agent({
id: 'personal-assistant',
name: 'PersonalAssistant',
instructions: 'You are a helpful personal assistant.',
model: 'openai/gpt-5.6-sol',
memory: new Memory({
options: {
workingMemory: {
enabled: true,
},
},
}),
})

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

Working memory 是一段 Markdown 文字,Agent 可以持續更新,以儲存一直相關的資訊。

Memory 保存作用域
「Memory 保存作用域」的直接連結

Working memory 可在兩種不同的作用域中運作,讓你選擇跨對話保存 Memory 的方式:

Resource 作用域 Memory(預設)
「Resource 作用域 Memory(預設)」的直接連結

Working memory 預設會在同一位使用者(resourceId)的所有對話 thread 中保存,提供持久的使用者記憶:

const memory = new Memory({
storage,
options: {
workingMemory: {
enabled: true,
scope: 'resource', // Memory persists across all user threads
template: `# User Profile
- **Name**:
- **Location**:
- **Interests**:
- **Preferences**:
- **Long-term Goals**:
`,
},
},
})

使用情境:

  • 能記住使用者偏好的個人助理
  • 能維持客戶脈絡的客服機器人
  • 能追蹤學生進度的教育應用程式

搭配 Agent 使用
「搭配 Agent 使用」的直接連結

使用 resource 作用域 Memory 時,請務必在 Memory 選項中傳入 resource 參數:

// Resource-scoped memory requires resource
const response = await agent.generate('Hello!', {
memory: {
thread: 'conversation-123',
resource: 'user-alice-456', // Same user across different threads
},
})

Thread 作用域 Memory
「Thread 作用域 Memory」的直接連結

Thread 作用域 Memory 會將 working memory 隔離至各個對話 thread。每個 thread 都維護自己獨立的 Memory:

const memory = new Memory({
storage,
options: {
workingMemory: {
enabled: true,
scope: 'thread', // Memory is isolated per thread
template: `# User Profile
- **Name**:
- **Interests**:
- **Current Goal**:
`,
},
},
})

使用情境:

  • 分別討論不同主題的對話
  • 暫時或工作階段專屬的資訊
  • 每個 thread 都需要 working memory,但 thread 是暫時存在且彼此無關的 Workflow

儲存 adapter 支援
「儲存 adapter 支援」的直接連結

Resource 作用域 working memory 需要支援 mastra_resources 資料表的特定儲存 adapter:

支援的儲存 adapter
「支援的儲存 adapter」的直接連結

  • libSQL@mastra/libsql
  • PostgreSQL@mastra/pg
  • OracleDB@mastra/oracledb
  • Upstash@mastra/upstash
  • MongoDB@mastra/mongodb

自訂範本
「自訂範本」的直接連結

範本可引導 Agent 判斷要在 working memory 中追蹤與更新哪些資訊。若未提供範本,Mastra 會使用預設範本。請依 Agent 的使用情境定義自訂範本,讓它記住最相關的資訊。若 thread 由多位使用者共用,請參閱多使用者 thread

以下是自訂範本範例。在此範例中,只要使用者傳送包含任何相關資訊的訊息,Agent 就會立即儲存使用者的名稱、位置、時區等內容:

const memory = new Memory({
options: {
workingMemory: {
enabled: true,
template: `
# User Profile

## Personal info

- Name:
- Location:
- Timezone:

## Preferences

- Communication Style: [e.g., Formal, Casual]
- Project Goal:
- Key Deadlines:
- [Deadline 1]: [Date]
- [Deadline 2]: [Date]

## Session state

- Last Task Discussed:
- Open Questions:
- [Question 1]
- [Question 2]
`,
},
},
})

設計有效的範本
「設計有效的範本」的直接連結

結構良好的範本能讓 Agent 直接剖析並更新資訊。請將範本視為一份希望助理持續更新的簡短表單。

  • **簡短且聚焦的標籤。**避免使用段落或很長的標題。標籤應保持簡短(例如 ## Personal Info- Name:),讓更新容易閱讀,也比較不會遭到截斷。
  • **使用一致的大小寫。**大小寫不一致(Timezone:timezone:)可能造成更新內容凌亂。標題與項目標籤請統一使用標題式大小寫或小寫。
  • **盡量簡化預留位置文字。**使用 [e.g., Formal][Date] 等提示,協助 LLM 填入正確位置。
  • **縮短很長的值。**若只需要簡短形式,請加入 - Name: [First name or nickname]- Address (short): 等指引,不要要求完整的法律文件文字。
  • **在 instructions 中說明更新規則。**你可以直接在 Agent 的 instructions 欄位中指示填寫或清除範本各部分的方式與時機。

其他範本樣式
「其他範本樣式」的直接連結

若只需要幾個項目,可以使用較短的單一區塊:

const basicMemory = new Memory({
options: {
workingMemory: {
enabled: true,
template: `User Facts:\n- Name:\n- Favorite Color:\n- Current Topic:`,
},
},
})

若偏好較具敘事性的樣式,也可以用簡短段落格式儲存重要事實:

const paragraphMemory = new Memory({
options: {
workingMemory: {
enabled: true,
template: `Important Details:\n\nKeep a short paragraph capturing the user's important facts (name, main goal, current task).`,
},
},
})

結構化 working memory
「結構化 working memory」的直接連結

Working memory 也可以使用結構化 schema 定義,不必使用 Markdown 範本。如此便能透過 Standard JSON SchemaZodValibotArkType 等)指定要追蹤的確切欄位與型別。使用 schema 時,Agent 會以符合 schema 的 JSON 物件查看並更新 working memory。

**必要條件:**你必須指定 templateschema,但不能同時指定兩者。

範例:以 schema 為基礎的 working memory
「範例:以 schema 為基礎的 working memory」的直接連結

import { z } from 'zod'
import { Memory } from '@mastra/memory'

const userProfileSchema = z.object({
name: z.string().optional(),
location: z.string().optional(),
timezone: z.string().optional(),
preferences: z
.object({
communicationStyle: z.string().optional(),
projectGoal: z.string().optional(),
deadlines: z.array(z.string()).optional(),
})
.optional(),
})

const memory = new Memory({
options: {
workingMemory: {
enabled: true,
schema: userProfileSchema,
// template: ... (do not set)
},
},
})

提供 schema 後,Agent 會以 JSON 物件接收 working memory。例如:

{
"name": "Sam",
"location": "Berlin",
"timezone": "CET",
"preferences": {
"communicationStyle": "Formal",
"projectGoal": "Launch MVP",
"deadlines": ["2025-07-01"]
}
}

以 schema 為基礎之 Memory 的合併語意
「以 schema 為基礎之 Memory 的合併語意」的直接連結

以 schema 為基礎的 working memory 使用合併語意,表示 Agent 只需包含要新增或更新的欄位。現有欄位會自動保留。

  • **物件欄位會深層合併:**只更新提供的欄位,其他欄位維持不變
  • **將欄位設為 null 即可刪除:**這會明確地從 Memory 移除該欄位
  • **陣列會整個取代:**提供陣列欄位時,會取代現有陣列(不會逐項合併陣列)

選擇範本或 schema
「選擇範本或 schema」的直接連結

  • 若希望 Agent 將 Memory 維護為自由格式的文字區塊,例如使用者個人資料或暫存區,請使用 範本(Markdown)。範本使用取代語意:Agent 每次更新都必須提供完整的 Memory 內容。
  • 若需要可驗證、型別安全且能以程式存取的 JSON 結構化資料,請使用 schemaworkingMemory.schema 欄位接受任何與 PublicSchema 相容的 schema(包括 Zod v3、Zod v4、JSON Schema 或已符合標準的 schema)。Schema 使用合併語意:Agent 只需提供要更新的欄位,現有欄位會繼續保留。
  • 一次只能啟用一種模式:不支援同時設定 templateschema

範例:跨多步驟保留
「範例:跨多步驟保留」的直接連結

以下簡化呈現 User Profile 範本在一小段使用者對話中的更新方式:

# User Profile

## Personal info

- Name:
- Location:
- Timezone:

--- After user says "My name is **Sam** and I'm from **Berlin**" ---

# User Profile
- Name: Sam
- Location: Berlin
- Timezone:

--- After user adds "By the way I'm normally in **CET**" ---

# User Profile
- Name: Sam
- Location: Berlin
- Timezone: CET

Agent 現在可以在後續回應中提及 SamBerlin,而不必再次要求提供資訊,因為這些內容已儲存在 working memory 中。

若 Agent 未在預期時正確更新 working memory,你可以在 Agent 的 instructions 設定中加入系統 instruction,說明使用此範本的方式與時機。

設定初始 working memory
「設定初始 working memory」的直接連結

Agent 通常會透過 updateWorkingMemory Tool 更新 working memory,但你也可以在建立或更新 thread 時,以程式設定初始 working memory。若想將使用者資料(例如名稱、偏好或其他資訊)提供給 Agent,卻不想在每次要求中傳入,這項功能就很實用。

透過 thread metadata 設定 working memory
「透過 thread metadata 設定 working memory」的直接連結

建立 thread 時,可以透過 metadata 的 workingMemory key 提供初始 working memory:

src/app/medical-consultation.ts
// Create a thread with initial working memory
const thread = await memory.createThread({
threadId: 'thread-123',
resourceId: 'user-456',
title: 'Medical Consultation',
metadata: {
workingMemory: `# Patient Profile
- Name: John Doe
- Blood Type: O+
- Allergies: Penicillin
- Current Medications: None
- Medical History: Hypertension (controlled)
`,
},
})

// The agent will now have access to this information in all messages
await agent.generate("What's my blood type?", {
memory: {
thread: thread.id,
resource: 'user-456',
},
})
// Response: "Your blood type is O+."

以程式更新 working memory
「以程式更新 working memory」的直接連結

你也可以更新現有 thread 的 working memory:

src/app/medical-consultation.ts
// Update thread metadata to add/modify working memory
await memory.updateThread({
id: 'thread-123',
title: thread.title,
metadata: {
...thread.metadata,
workingMemory: `# Patient Profile
- Name: John Doe
- Blood Type: O+
- Allergies: Penicillin, Ibuprofen // Updated
- Current Medications: Lisinopril 10mg daily // Added
- Medical History: Hypertension (controlled)
`,
},
})

直接更新 Memory
「直接更新 Memory」的直接連結

另一種方式是直接使用 updateWorkingMemory 方法:

src/app/medical-consultation.ts
await memory.updateWorkingMemory({
threadId: 'thread-123',
resourceId: 'user-456', // Required for resource-scoped memory
workingMemory: 'Updated memory content...',
})

唯讀 working memory
「唯讀 working memory」的直接連結

在某些情境中,你可能想讓 Agent 存取 working memory 資料,但不允許修改。這適用於:

  • 路由 Agent:需要脈絡,但不應更新使用者個人資料
  • 多 Agent 系統中的子 Agent:應參照 Memory,但不應擁有它

若要啟用唯讀模式,請在 Memory 選項中設定 readOnly: true

const response = await agent.generate('What do you know about me?', {
memory: {
thread: 'conversation-123',
resource: 'user-alice-456',
options: {
readOnly: true, // Working memory is provided but cannot be updated
},
},
})

選擇使用狀態訊號(實驗性)
「選擇使用狀態訊號(實驗性)」的直接連結

Working memory 預設會以系統訊息的一部分送達模型。你可以設定 useStateSignals: true,改以狀態訊號傳送:

const memory = new Memory({
storage: new LibSQLStore({ id: 'mastra-storage', url: 'file:./mastra.db' }),
options: {
workingMemory: {
enabled: true,
template: '# User\n- name:\n- location:',
useStateSignals: true, // experimental: deliver as state signal
},
},
})

變更內容:

  • **儲存方式相同。**讀寫的仍是相同 resource/thread workingMemory 欄位。
  • **Tool 具有相同結構,但以新名稱公開。**寫入仍會流經相同的底層 Tool;在此路徑上會註冊為 setWorkingMemory(而非 updateWorkingMemory)。重新命名可避免舊版 strip filter 移除 Tool 呼叫部分,使其保留為一般稽核軌跡,而下一個模型步驟會自動取得新值。
  • 只有傳送方式不同。Memory 不會將內容併入系統提示,而會自動附加 WorkingMemoryStateProcessor,以 stateId: 'working-memory' 將目前 working memory 發出為 state 訊號。

你會繼承標準狀態訊號的優點:thread 作用域的追蹤 metadata、透過 cacheKey 去除重複內容(相同快照只會發出一次),以及較舊快照離開視窗後,透過 contextWindow.hasSnapshot 重新注入。

預設值(useStateSignals: false)會維持現有系統訊息行為不變。範本 working memory version: 'vnext' 不支援 useStateSignals

範例
「範例」的直接連結