> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-TW/llms.txt # Memory processor Memory processor 會在訊息通過已啟用 Memory 的 Agent 時轉換並篩選訊息。它們可管理 context window 上限、移除不必要的內容,並最佳化送往語言模型的資訊。 在 Agent 上啟用 Memory 後,Mastra 會將 Memory processor 加入 Agent 的 processor pipeline。這些 processor 會擷取訊息歷史、working memory 與語意相關的訊息,然後在模型回應後保存新訊息。 Memory processor 是專門處理 Memory 相關訊息與狀態的 [processor](https://mastra.zisheng.pro/zh-TW/docs/agents/processors)。 ## 內建 Memory processor 啟用 Memory 後,Mastra 會自動加入下列 processor: ### `MessageHistory` 擷取訊息歷史並保存新訊息。 **進行以下設定時:** ```typescript memory: new Memory({ lastMessages: 10, }) ``` **Mastra 內部會:** 1. 建立 `limit: 10` 的 `MessageHistory` processor 2. 將它加入 Agent 的輸入 processor(在 LLM 前執行) 3. 將它加入 Agent 的輸出 processor(在 LLM 後執行) **執行內容:** - **輸入**:從儲存空間擷取最近 10 則訊息,並放到對話前方 - **輸出**:模型回應後,將新訊息保存至儲存空間 **範例:** ```typescript import { Agent } from '@mastra/core/agent' import { Memory } from '@mastra/memory' import { LibSQLStore } from '@mastra/libsql' import { openai } from '@ai-sdk/openai' const agent = new Agent({ id: 'test-agent', name: 'Test Agent', instructions: 'You are a helpful assistant', model: 'openai/gpt-5.6-sol', memory: new Memory({ storage: new LibSQLStore({ id: 'memory-store', url: 'file:memory.db', }), lastMessages: 10, // MessageHistory processor automatically added }), }) ``` ### `SemanticRecall` 依據目前輸入擷取語意相關的訊息,並為新訊息建立嵌入向量。 **進行以下設定時:** ```typescript memory: new Memory({ semanticRecall: { enabled: true }, vector: myVectorStore, embedder: myEmbedder, }) ``` **Mastra 內部會:** 1. 建立 `SemanticRecall` processor 2. 將它加入 Agent 的輸入 processor(在 LLM 前執行) 3. 將它加入 Agent 的輸出 processor(在 LLM 後執行) 4. 要求同時設定向量儲存與 embedder **執行內容:** - **輸入**:執行向量相似度搜尋以找出相關的過往訊息,並將它們放到對話前方 - **輸出**:為新訊息建立嵌入向量並儲存至向量儲存,以供日後擷取 **範例:** ```typescript import { Agent } from '@mastra/core/agent' import { Memory } from '@mastra/memory' import { LibSQLStore } from '@mastra/libsql' import { PineconeVector } from '@mastra/pinecone' import { OpenAIEmbedder } from '@mastra/openai' import { openai } from '@ai-sdk/openai' const agent = new Agent({ name: 'semantic-agent', instructions: 'You are a helpful assistant with semantic memory', model: 'openai/gpt-5.6-sol', memory: new Memory({ storage: new LibSQLStore({ id: 'memory-store', url: 'file:memory.db', }), vector: new PineconeVector({ id: 'memory-vector', apiKey: process.env.PINECONE_API_KEY!, }), embedder: new OpenAIEmbedder({ model: 'text-embedding-3-small', apiKey: process.env.OPENAI_API_KEY!, }), semanticRecall: { enabled: true }, // SemanticRecall processor automatically added }), }) ``` ### `WorkingMemory` 管理跨對話的 working memory 狀態。 **進行以下設定時:** ```typescript memory: new Memory({ workingMemory: { enabled: true }, }) ``` **Mastra 內部會:** 1. 建立 `WorkingMemory` processor 2. 將它加入 Agent 的輸入 processor(在 LLM 前執行) 3. 要求設定儲存 adapter **執行內容:** - **輸入**:擷取目前 thread 的 working memory 狀態,並放到對話前方 - **輸出**:不執行輸出處理 **範例:** ```typescript import { Agent } from '@mastra/core/agent' import { Memory } from '@mastra/memory' import { LibSQLStore } from '@mastra/libsql' import { openai } from '@ai-sdk/openai' const agent = new Agent({ name: 'working-memory-agent', instructions: 'You are an assistant with working memory', model: 'openai/gpt-5.6-sol', memory: new Memory({ storage: new LibSQLStore({ id: 'memory-store', url: 'file:memory.db', }), workingMemory: { enabled: true }, // WorkingMemory processor automatically added }), }) ``` ## 手動控制與去除重複項目 若手動將 Memory processor 加入 `inputProcessors` 或 `outputProcessors`,Mastra **不會**再自動加入該 processor。你可以藉此完整控制 processor 的順序: ```typescript import { Agent } from '@mastra/core/agent' import { Memory } from '@mastra/memory' import { MessageHistory } from '@mastra/core/processors' import { TokenLimiter } from '@mastra/core/processors' import { LibSQLStore } from '@mastra/libsql' import { openai } from '@ai-sdk/openai' // Custom MessageHistory with different configuration const customMessageHistory = new MessageHistory({ storage: new LibSQLStore({ id: 'memory-store', url: 'file:memory.db' }), lastMessages: 20, }) const agent = new Agent({ name: 'custom-memory-agent', instructions: 'You are a helpful assistant', model: 'openai/gpt-5.6-sol', memory: new Memory({ storage: new LibSQLStore({ id: 'memory-store', url: 'file:memory.db' }), lastMessages: 10, // This would normally add MessageHistory(10) }), inputProcessors: [ customMessageHistory, // Your custom one is used instead new TokenLimiter({ limit: 4000 }), // Runs after your custom MessageHistory ], }) ``` ## Processor 執行順序 將 guardrail 與 Memory 搭配使用時,瞭解執行順序相當重要: ### 輸入 processor ```text [Memory Processors] → [Your inputProcessors] ``` 1. **Memory processor 最先執行**:`WorkingMemory`、`MessageHistory`、`SemanticRecall` 2. **你的輸入 processor 隨後執行**:guardrail、篩選器、驗證器 因此,Memory 會在你的 processor 驗證或篩選輸入前載入訊息歷史。 ### 輸出 processor ```text [Your outputProcessors] → [Memory Processors] ``` 1. **你的輸出 processor 最先執行**:guardrail、篩選器、驗證器 2. **Memory processor 隨後執行**:`SemanticRecall`(嵌入向量)、`MessageHistory`(保存) 此順序的設計是為了**確保預設安全**:若輸出 guardrail 呼叫 `abort()`,Memory processor 便不會執行,且**不會儲存任何訊息**。 ## Guardrail 與 Memory 預設執行順序可提供安全的 guardrail 行為: ### 輸出 guardrail(建議) 輸出 guardrail 會在 Memory processor 儲存訊息**之前**執行。若 guardrail 中止: - 觸發 tripwire - 跳過 Memory processor - **不會將任何訊息保存至儲存空間** ```typescript import { Agent } from '@mastra/core/agent' import { Memory } from '@mastra/memory' import { openai } from '@ai-sdk/openai' // Output guardrail that blocks inappropriate content const contentBlocker = { id: 'content-blocker', processOutputResult: async ({ messages, abort }) => { const hasInappropriateContent = messages.some(msg => containsBadContent(msg)) if (hasInappropriateContent) { abort('Content blocked by guardrail') } return messages }, } const agent = new Agent({ id: 'safe-agent', name: 'safe-agent', instructions: 'You are a helpful assistant', model: 'openai/gpt-5.6-sol', memory: new Memory({ lastMessages: 10 }), // Your guardrail runs BEFORE memory saves outputProcessors: [contentBlocker], }) // If the guardrail aborts, nothing is saved to memory const result = await agent.generate('Hello') if (result.tripwire) { console.log('Blocked:', result.tripwire.reason) // Memory is empty - no messages were persisted } ``` ### 輸入 guardrail 輸入 guardrail 會在 Memory processor 載入歷史**之後**執行。若 guardrail 中止: - 觸發 tripwire - 絕不呼叫 LLM - 跳過輸出 processor(包括 Memory 保存) - **不會將任何訊息保存至儲存空間** ```typescript // Input guardrail that validates user input const inputValidator = { id: 'input-validator', processInput: async ({ messages, abort }) => { const lastUserMessage = messages.findLast(m => m.role === 'user') if (isInvalidInput(lastUserMessage)) { abort('Invalid input detected') } return messages }, } const agent = new Agent({ id: 'validated-agent', name: 'validated-agent', instructions: 'You are a helpful assistant', model: 'openai/gpt-5.6-sol', memory: new Memory({ lastMessages: 10 }), // Your guardrail runs AFTER memory loads history inputProcessors: [inputValidator], }) ``` ### 摘要 | Guardrail 類型 | 執行時間 | 中止時的結果 | | ------------ | ------------ | -------------- | | 輸入 | Memory 載入歷史後 | 不呼叫 LLM,也不儲存內容 | | 輸出 | Memory 儲存前 | 不將任何內容儲存至儲存空間 | 兩種情境都很安全,guardrail 會防止不當內容保存至 Memory。 ## 處理大型附件 部分儲存 Provider 會限制記錄大小,而 Base64 編碼的檔案附件可能超過該限制: | Provider | 記錄大小上限 | | --------------------------------------------------------------------------------- | ------ | | [DynamoDB](https://mastra.zisheng.pro/zh-TW/reference/storage/dynamodb) | 400 KB | | [Convex](https://mastra.zisheng.pro/zh-TW/reference/storage/convex) | 1 MiB | | [Cloudflare D1](https://mastra.zisheng.pro/zh-TW/reference/storage/cloudflare-d1) | 1 MiB | PostgreSQL、MongoDB 與 libSQL 的上限較高,通常不受影響。 請使用輸入 processor 將附件上傳至外部儲存空間,接著以 URL 參照取代附件,再保存訊息。 ```typescript import type { Processor } from '@mastra/core/processors' import type { MastraDBMessage } from '@mastra/core/memory' export class AttachmentUploader implements Processor { id = 'attachment-uploader' async processInput({ messages }: { messages: MastraDBMessage[] }) { return Promise.all(messages.map(message => this.processMessage(message))) } async processMessage(message: MastraDBMessage) { const attachments = message.content.experimental_attachments if (!attachments?.length) return message const uploaded = await Promise.all( attachments.map(async attachment => { if (!attachment.url?.startsWith('data:')) return attachment const url = await this.upload(attachment.url, attachment.contentType) return { ...attachment, url } }), ) return { ...message, content: { ...message.content, experimental_attachments: uploaded } } } async upload(dataUri: string, contentType?: string): Promise { const base64 = dataUri.split(',')[1] const buffer = Buffer.from(base64, 'base64') throw new Error('Implement upload() with your storage provider') } } ``` 在 Agent 中使用此 processor: ```typescript import { Agent } from '@mastra/core/agent' import { Memory } from '@mastra/memory' import { AttachmentUploader } from '../processors/attachment-uploader' export const supportAgent = new Agent({ id: 'support-agent', name: 'Support agent', instructions: 'Answer customer support questions.', model: 'openai/gpt-5.6-sol', memory: new Memory({ lastMessages: 10 }), inputProcessors: [new AttachmentUploader()], }) ``` ## 相關文件 - [Processor](https://mastra.zisheng.pro/zh-TW/docs/agents/processors):一般 processor 概念與自訂 processor 的建立方式 - [Guardrail](https://mastra.zisheng.pro/zh-TW/docs/agents/guardrails):安全性與驗證 processor - [Memory 概覽](https://mastra.zisheng.pro/zh-TW/docs/memory/overview):Memory 類型與設定 建立自訂 processor 時,請避免直接修改輸入的 `messages` 陣列或其中的物件。