> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-TW/llms.txt # 多使用者 thread 單一 Mastra thread 可由多位使用者共用,每位使用者都有自己的名稱與功能角色。你可以在訊息內文中帶入發話者身分,讓 Agent 從單一共用 thread 讀取內容時,仍能區分不同使用者。 ## 何時使用多使用者 thread 當多人透過同一個 Agent 針對相同主題協作時,請使用多使用者 thread: - 由編輯者、審查者與核准者共同處理的協作文件 - 由一個助理服務多位參與者的群組聊天 - 不同角色具有不同權限的多方審查 ## 讓所有參與者共用一個 `resourceId` 一個 thread 只屬於一個 `resourceId`,因此共用 thread 上的所有參與者都必須傳入相同的值。請不要使用使用者 ID(單一使用者應用程式的預設做法),而是依對話本身設定 `resourceId`;例如,共用文件可使用 `doc_${docId}`,群組聊天則可使用 `room_${roomId}`。所有人都指向相同的 `resourceId` 後,便會讀寫同一份歷史。 ## 使用發話者身分標記每則使用者訊息 模型需要知道每一輪是誰在發話。訊息內文是唯一會保留至歷史並重新回到脈絡中的位置,因此請將每則使用者訊息包在簡短的 `` 標籤中,並帶入發話者的 ID、名稱與角色。此標籤會持續附在訊息上,因此回想先前輪次時,模型仍能看出每段話是誰說的。 使用簡短的輔助函式建立標籤。以下範例是其中一種做法;請複製到專案中,再依你的使用者資料結構調整: ```typescript export type Speaker = { id: string name: string role: string } function escapeAttr(value: string) { return value .replace(/&/g, '&') .replace(/"/g, '"') .replace(//g, '>') } export function asUserTurn(speaker: Speaker, text: string) { const id = escapeAttr(speaker.id) const name = escapeAttr(speaker.name) const role = escapeAttr(speaker.role) return { role: 'user' as const, content: ` ${text} `, } } ``` 在 Agent 的 instructions 中教它如何讀取 `` 標籤。Agent 必須設定 `memory`,才能以 `thread` 與 `resource` 呼叫: ```typescript import { Agent } from '@mastra/core/agent' import { Memory } from '@mastra/memory' import { LibSQLStore } from '@mastra/libsql' const memory = new Memory({ storage: new LibSQLStore({ id: 'collab-storage', url: 'file:./collab.db' }), options: { lastMessages: 20, }, }) export const collabAgent = new Agent({ id: 'collab', name: 'CollabAgent', model: 'openai/gpt-5-mini', memory, instructions: ` You are a collaborative document assistant. Multiple users talk to you in the SAME thread. Every user message is wrapped in a tag carrying the user's identity: ...message text... Rules: 1. Address users by their author_name. 2. Respect functional_role: editors propose changes, reviewers approve. 3. When attributing past statements, read author_name from the surrounding tag. 4. Do not echo the tags back at users. `.trim(), }) ``` 使用包裝後的訊息呼叫 Agent。每位參與者都共用相同的 `thread` 與 `resource`: ```typescript import { asUserTurn } from './identity' const docResourceId = 'doc_42' const docThreadId = 'doc_42' const alice = { id: 'u_alice', name: 'Alice', role: 'editor' } const bob = { id: 'u_bob', name: 'Bob', role: 'reviewer' } await collabAgent.generate([asUserTurn(alice, 'My favorite color is teal.')], { memory: { thread: docThreadId, resource: docResourceId }, }) await collabAgent.generate([asUserTurn(bob, 'I want QA sign-off before publish.')], { memory: { thread: docThreadId, resource: docResourceId }, }) ``` `` 標籤會保留在訊息內文中,因此日後回想歷史時,模型仍能看出每段話是誰說的。 ## 與 Memory 層搭配使用 使用者標記模式可與每個 Memory 層搭配使用。請依對話需要保留每位使用者事實的時間長度選擇合適的層: - **短對話**(單次工作階段,或 thread 小到足以放入 `lastMessages`),或需要逐字記錄誰說了什麼時:只使用[訊息歷史](#message-history-alone)即可。歷史中的使用者標籤已經足夠,不需要額外的 Memory 層。 - **長時間執行的 thread**(對話超出 `lastMessages`,而且每位使用者的事實必須在歷史遭移除後繼續保留):使用 [Observational Memory](#with-observational-memory-recommended)。 - **需要結構化參與者清單,或儲存 adapter 不支援 OM**(OM 需要 LibSQL、PG 或 MongoDB):使用 [working memory](#with-working-memory)。 建議使用 Observational Memory 或 working memory 其中之一,因為兩者涵蓋的需求有所重疊。同時執行只會增加延遲與 token 成本,效益不大。 ### 只使用訊息歷史 對於短對話,或需要逐字記錄誰說了什麼的情境,歷史中的使用者標籤已經足夠。`lastMessages` 會將先前輪次帶回脈絡,並完整保留其歸屬資訊: ```typescript import { Memory } from '@mastra/memory' import { LibSQLStore } from '@mastra/libsql' const memory = new Memory({ storage: new LibSQLStore({ id: 'collab-storage', url: 'file:./collab.db' }), options: { lastMessages: 20, }, }) ``` 模型會從目前訊息的 `` 標籤,以及透過 `lastMessages` 帶回的先前已標記訊息中讀取身分。 ### 搭配 Observational Memory(建議) [Observational Memory](https://mastra.zisheng.pro/zh-TW/docs/memory/observational-memory)(OM)會將每位使用者的事實擷取至背景記錄,不會占用 Agent 的 Tool 額度。預設 Observer 模型能直接讀取 `` 標籤,並產生如 `Alice stated her favorite color is teal.` 與 `Bob asked for QA sign-off before publish.` 的歸屬描述。 若儲存系統支援,多使用者 thread 應優先使用 OM,而非 working memory。OM 會自動擷取事實、可擴充至任意數量的參與者,也不需要維護範本。啟用時不需覆寫任何設定: ```typescript import { Memory } from '@mastra/memory' import { LibSQLStore } from '@mastra/libsql' const memory = new Memory({ storage: new LibSQLStore({ id: 'collab-storage', url: 'file:./collab.db' }), options: { lastMessages: 20, observationalMemory: true, }, }) ``` OM 需要支援它的儲存 adapter:`@mastra/libsql`、`@mastra/pg`、`@mastra/mongodb` 或 `@mastra/oracledb`。 > **備註:** 若將 Observer 改為較弱的模型後,發現事實都被歸為泛稱的 `User`,請使用 [`observation.instruction`](https://mastra.zisheng.pro/zh-TW/reference/memory/observational-memory) 教 Observer 如何讀取 `` 標籤。 ### 搭配 working memory 當 OM 不適用時,例如儲存 adapter 不支援 OM,或需要一份結構明確、具決定性且 Agent 每輪都能讀寫的參與者清單,請使用 working memory。 預設的 [working memory](https://mastra.zisheng.pro/zh-TW/docs/memory/working-memory) 範本假設每個 thread 只有一位使用者(「First Name」、「Last Name」等)。若是多使用者 thread,請提供包含參與者清單的範本: ```typescript import { Memory } from '@mastra/memory' import { LibSQLStore } from '@mastra/libsql' const memory = new Memory({ storage: new LibSQLStore({ id: 'collab-storage', url: 'file:./collab.db' }), options: { lastMessages: 20, workingMemory: { enabled: true, scope: 'thread', template: `# Document Collaboration State ## Participants ## Open Questions ## Decisions `, }, }, }) ``` 設定 `scope: 'thread'`,讓參與者清單屬於文件,而不是任何個別使用者。再加入一項 instruction,要求 Agent 每當新的 `author_id` 出現在 `` 中時,便將新參與者附加至清單。 如需範本的詳細資訊,請參閱[自訂範本](https://mastra.zisheng.pro/zh-TW/docs/memory/working-memory)。 ## 安全性 請從已驗證的要求脈絡設定 `speaker`,絕不要從要求內文取得。若用戶端可以自行選擇 `author_id`,使用者就能冒充他人。請使用 [Request Context](https://mastra.zisheng.pro/zh-TW/docs/server/request-context) 從驗證層讀取已驗證的使用者,並在呼叫 Agent 前於伺服器端建立 `` 標籤。 ## 相關資源 - [Working memory](https://mastra.zisheng.pro/zh-TW/docs/memory/working-memory) - [Observational Memory](https://mastra.zisheng.pro/zh-TW/docs/memory/observational-memory) - [在 Agent 之間共用 Memory](https://mastra.zisheng.pro/zh-TW/docs/memory/overview) - [`Memory` 參考資料](https://mastra.zisheng.pro/zh-TW/reference/memory/memory-class)