> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-TW/llms.txt
# 訊號
**新增於:** `@mastra/core@1.39.0`
> **Beta:** 此功能目前為 beta。在 API 穩定前,即使未提高主要版本,也可能發生破壞性變更。
訊號是透過對話串與 Agent 互動的方式。你不必每次都以 `agent.stream()` 開始互動,而是可以訂閱對話串,再傳送訊息或訊號。Mastra 會在對話串閒置時喚醒 Agent、將輸入放入正在執行的 Agent 迴圈,或將輸入排入下一輪佇列。
使用訊息 API 傳送使用者撰寫的輸入。較底層的系統情境(例如背景任務通知、政策提醒或 Processor 產生的情境)則使用 `sendSignal()`。
> **📹 觀看影片:** 觀看 [Mastra 訊號概觀](https://www.youtube.com/watch?v=7It2y89TVP4),瞭解訊號如何喚醒及引導長時間執行的 Agent。
## 何時使用訊號
Agent 對話串需要原始 `stream()` 呼叫以外的新輸入或情境時,請使用訊號。當使用者在執行作用中傳送後續訊息、背景系統需要將情境加入對話串,或外部事件應喚醒、更新或通知 Agent 時,訊號很有用。
使用 `sendMessage()` 和 `queueMessage()` 傳送使用者撰寫的輸入;使用 `sendSignal()` 傳送較底層的系統情境;持久型狀態通道使用 `sendStateSignal()`;外部事件應建立持久型通知收件匣記錄時,則使用 `sendNotificationSignal()`。
## 快速開始
建立 Agent、訂閱對話串,再將訊息傳送至該對話串。訊息喚醒 Agent 或進入執行中迴圈時,訂閱端會收到作用中的串流。
```typescript
import { Agent } from '@mastra/core/agent'
const agent = new Agent({
id: 'support-agent',
name: 'Support Agent',
instructions: 'Help the user compare options.',
model: 'openai/gpt-5.6-sol',
})
const thread = {
resourceId: 'user_123',
threadId: 'thread_456',
}
const subscription = await agent.subscribeToThread(thread)
await agent.sendMessage('Compare that with the previous option.', thread)
for await (const chunk of subscription.stream) {
console.log(chunk)
}
```
對話串有正在執行的 Agent 串流時,`sendMessage()` 會成為該 Agent 迴圈中的新輸入。對話串閒置時,Mastra 則會以此訊息作為第一筆輸入啟動串流。
## 訊息輸入
### 立即傳送訊息
當使用者希望作用中的 Agent 立即看到訊息時,請使用 `sendMessage()`。
```typescript
agent.sendMessage(
{
contents: 'Use the latest customer note too.',
attributes: { name: 'Jane', sentFrom: 'slack' },
},
{
resourceId: 'user_123',
threadId: 'thread_456',
},
)
```
模型會以 XML 包裝的使用者輸入接收含屬性的訊息:
```xml
Use the latest customer note too.
```
不含屬性的訊息會以純使用者輸入傳送。
### 將訊息排入下一輪
使用者傳送後續訊息,但作用中的模型呼叫應先完成時,請使用 `queueMessage()`。Mastra 會等待作用中執行完成,再於同一對話串啟動新的執行。
```typescript
agent.queueMessage('Also check whether the tests need updates.', {
resourceId: 'user_123',
threadId: 'thread_456',
})
```
對話串閒置時,`queueMessage()` 會立即啟動執行;對話串作用中時,則會在作用中執行完成後啟動新執行,以保留輪次順序。
## 訊號情境
### 控制底層訊號行為
需要傳送系統產生的情境,而不是使用者撰寫的輸入時,請使用 `sendSignal()`。外部事件使用 `type: 'notification'`。Mastra 預設會將訊號傳送至作用中執行,並喚醒閒置對話串。使用 `ifActive.behavior` 和 `ifIdle.behavior` 可變更此行為。
```typescript
const result = agent.sendSignal(
{
type: 'notification',
contents: 'GitHub CI failed on PR #123: 3 tests failed.',
},
{
resourceId: 'user_123',
threadId: 'thread_456',
ifIdle: {
behavior: 'persist',
},
},
)
await result.persisted
```
若閒置喚醒串流需要模型設定、Tool 或執行階段情境等選項,請傳入 `ifIdle.streamOptions`。`ifActive`、`ifIdle`、分支屬性及 `streamOptions` 請參閱 [`Agent.sendSignal()` 參考](https://mastra.zisheng.pro/zh-TW/reference/agents/agent)。
### 傳送通知情境
訊號具有語意上的 `type`,以及提供給 LLM 的 `tagName`。使用 `type` 描述訊號類別,並用 `tagName` 控制模型看到的 XML 標籤。
外部事件使用 `type: 'notification'`。Reactive 訊號保留給 Processor 或執行階段產生的情境,例如政策指引、背景任務結果及自動載入的指示。
```typescript
agent.sendSignal(
{
type: 'notification',
contents: 'PR #123 has a new review comment from User X about the API surface.',
attributes: {
source: 'github',
pr: '123',
},
},
{
resourceId: 'user_123',
threadId: 'thread_456',
},
)
```
模型會以下列情境形式接收訊號:
```xml
PR #123 has a new review comment from User X about the API surface.
```
請使用符合 XML 安全規則的 `tagName` 與屬性名稱。它們可以包含字母、數字、底線、句點及連字號,且必須以字母或底線開頭。
#### 儲存空間支援
支援較豐富記憶體及訊號 Workflow 的儲存空間配接器可使用通知收件匣儲存功能:[libSQL](https://mastra.zisheng.pro/zh-TW/reference/storage/libsql)、[PostgreSQL](https://mastra.zisheng.pro/zh-TW/reference/storage/postgresql) 及 [MongoDB](https://mastra.zisheng.pro/zh-TW/reference/storage/mongodb)。這些配接器透過 `getStore('notifications')` 公開通知記錄。
### 傳送 Processor 情境
Processor 可在執行期間傳送 Reactive 訊號。Processor 應檢查聊天記錄、回應特定觸發條件,並避免重複傳送相同情境。
下列範例示範 Tool 呼叫讀取 `AGENTS.md` 檔案後,注入 `AGENTS.md` 指示的 Processor。
```typescript
import type { Processor, ProcessInputStepArgs } from '@mastra/core/processors'
export const agentsMdReminderProcessor: Processor = {
id: 'agents-md-reminder',
async processInputStep({ messageList, sendSignal }: ProcessInputStepArgs) {
const messages = messageList.get.all.db()
const agentsMdPath = findAgentsMdPathFromToolCalls(messages)
if (!agentsMdPath || hasAlreadySentAgentsMdReminder(messages, agentsMdPath)) {
return messageList
}
await sendSignal?.({
type: 'reactive',
contents: readAgentsMdInstructions(agentsMdPath),
attributes: {
type: 'dynamic-agents-md',
path: agentsMdPath,
},
metadata: {
path: agentsMdPath,
},
})
return messageList
},
}
```
Reactive 訊號預設為 `tagName: 'system-reminder'`,因此模型會收到下列情境:
```xml
$agentsMdFileContents
```
訂閱的對話串作用中時,await `sendSignal()` 可保留串流回顯順序。
### 條件式屬性
使用 `ifActive.attributes` 和 `ifIdle.attributes`,可依 Agent 在傳送時為作用中或閒置狀態,為輸入加上情境標籤。頂層 `attributes` 一律適用;接受輸入時,Mastra 會將所選分支的 `attributes` 合併其中。各分支專屬屬性請參閱 [`Agent.sendMessage()` 參考](https://mastra.zisheng.pro/zh-TW/reference/agents/agent)與 [`Agent.sendSignal()` 參考](https://mastra.zisheng.pro/zh-TW/reference/agents/agent)。
## 狀態與通知訊號
### 狀態訊號
狀態訊號會公開具名稱、範圍限於對話串的情境通道。它適合瀏覽器狀態、編輯器狀態或背景監看器結果等會隨時間變化的持久情境。
外部產生端偵測到狀態變更時,請使用 `sendStateSignal()`。每個狀態訊號都會識別狀態通道、由產生端擁有的快取索引鍵,以及更新是快照或差異。
```typescript
await agent.sendStateSignal(
{
id: 'browser',
mode: 'snapshot',
cacheKey: 'browser:https://example.com:3-tabs',
contents: 'Browser is open. Active tab URL: https://example.com. 3 open tabs.',
value: {
activeUrl: 'https://example.com',
tabCount: 3,
open: true,
},
},
{
resourceId: 'user_123',
threadId: 'thread_456',
},
)
```
Mastra 接受狀態訊號時,會將精簡的追蹤中繼資料儲存於對話串。若該狀態仍為目前狀態,而產生端再次傳送相同 `cacheKey` 及模式,Mastra 會略過重複項目。
Processor 擁有狀態通道時,請使用 `computeStateSignal()`。Mastra 會在 `processInputStep()` 後的每個模型輸入步驟呼叫一次。狀態訊號欄位及傳回值請參閱 [`Agent.sendStateSignal()` 參考](https://mastra.zisheng.pro/zh-TW/reference/agents/agent)。
```typescript
import type { ComputeStateSignalArgs, Processor } from '@mastra/core/processors'
export const browserStateProcessor: Processor = {
id: 'browser-state',
stateId: 'browser',
computeStateSignal(args: ComputeStateSignalArgs) {
const browser = readCurrentBrowserState()
const previous = readMostRecentBrowserState(args.activeStateSignals)
const changed = previous ? diffBrowserState(previous, browser) : browser
const shouldRefreshSnapshot = Boolean(args.lastSnapshot && !args.contextWindow.hasSnapshot)
if (previous && Object.keys(changed).length === 0 && !shouldRefreshSnapshot) {
return
}
const isDelta = Boolean(previous && !shouldRefreshSnapshot)
return {
mode: isDelta ? 'delta' : 'snapshot',
cacheKey: stableBrowserStateCacheKey(browser),
contents: isDelta ? describeBrowserDelta(changed) : describeBrowserSnapshot(browser),
value: browser,
...(isDelta ? { delta: changed } : {}),
}
},
}
```
Mastra 會將 `lastSnapshot` 和 `deltasSinceSnapshot` 傳入 `computeStateSignal()`。當目前訊息清單不含最新快照時,系統會從訊息記錄解析它們。Processor 仍自行負責合併及差異邏輯。
`contextWindow.hasSnapshot` 會告知 Processor,作用中訊息視窗是否已包含此狀態通道的快照。若為 `false`,請傳回新的 `snapshot`,讓較舊的狀態訊息從情境視窗裁剪後,模型仍能看到目前狀態。
內建瀏覽器情境 Processor 會在 `browser` ID 下,以快照與差異模式發出狀態。
### 通知訊號
通知訊號代表 GitHub 活動、電子郵件、Slack 提及、CI 狀態、事件、錄製內容或即時訊息等外部事件。事件應建立持久型收件匣記錄時,請使用 `agent.sendNotificationSignal()`。
通知傳送分成兩個階段。擷取時,`agent.sendNotificationSignal()` 會儲存通知記錄,並解析 Agent 的傳送政策。分派時,Mastra 會取用到期記錄,並發出完整通知或摘要訊號。
預設傳送政策會考量優先順序。緊急通知會立即傳送;較低優先順序的通知則可能彙整為摘要,或等待對話串閒置。通知欄位請參閱 [`Agent.sendNotificationSignal()` 參考](https://mastra.zisheng.pro/zh-TW/reference/agents/agent),`notifications.deliveryPolicy` 設定請參閱 [`Agent` 建構函式參考](https://mastra.zisheng.pro/zh-TW/reference/agents/agent),收件匣 Tool 動作請參閱 [`createNotificationInboxTool()` 參考](https://mastra.zisheng.pro/zh-TW/reference/signals/create-notification-inbox-tool)。
```typescript
await agent.sendNotificationSignal(
{
source: 'github',
kind: 'ci-status',
priority: 'high',
summary: 'CI failed on main: 3 tests failed.',
payload: {
repository: 'acme/app',
branch: 'main',
},
dedupeKey: 'github:acme/app:main:ci',
},
{
resourceId: 'user_123',
threadId: 'thread_456',
},
)
```
模型會以情境形式接收完整通知:
```xml
CI failed on main: 3 tests failed.
```
通知摘要會告知模型,收件匣中仍有等待處理的記錄:
```xml
github: 3, email: 5, slack: 2
```
Mastra 發出摘要時,會清除 `summaryAt`,並在每筆已摘要記錄上設定 `summarySignalId`。記錄會保持待處理且可讀取。Mastra 發出完整通知時,會設定 `deliveredSignalId` 並將記錄標記為 `delivered`。若收件匣 Tool 先讀取通知,便可注入完整通知訊號並將記錄標記為 `seen`,以避免重複傳送完整通知。
若部分通知應等待不同的分派時段或摘要彙總,請在 Agent 上設定傳送政策。若要自動傳送延後的通知及摘要彙總,請在 Mastra 層級啟用排程分派。`notifications.deliveryPolicy` 請參閱 [`Agent` 建構函式參考](https://mastra.zisheng.pro/zh-TW/reference/agents/agent),執行階段通知分派設定請參閱 [`Mastra` 類別參考](https://mastra.zisheng.pro/zh-TW/reference/core/mastra-class)。
#### 通知收件匣 Tool
使用 `createNotificationInboxTool()`,可提供 Agent 一個處理收件匣動作的 Tool,而不必提供多個 CRUD Tool。Agent 在收到 `` 訊號後需要摘要背後的完整記錄時,請使用 `read`。通知內容會以訊號而非一般 Tool 輸出傳送。設定範例、輸入結構描述及動作行為請參閱 [`createNotificationInboxTool()` 參考](https://mastra.zisheng.pro/zh-TW/reference/signals/create-notification-inbox-tool)。
`sendNotificationSignal()` 需要支援 `notifications` 的儲存空間領域。只有較底層、應略過收件匣儲存的通知形式情境,才使用 `sendSignal({ type: 'notification' })`。
## 分散式與 Serverless 部署
訊號會透過 pub/sub 後端協調執行。訊號抵達實作 `LeaseProvider` 的後端時,Mastra 會取得目標對話串的 Lease,使同一時間只有一個處理程序擁有該對話,再喚醒 Agent 或將輸入導入執行中迴圈。不具 Lease 功能的後端會退回至一律授予擁有權的空操作;這適合單一處理程序,但不適合跨執行個體使用。
預設的記憶體內 pub/sub 無法跨越執行個體邊界。在 Vercel 等 Serverless 平台或任何多執行個體部署中,後續訊號可能被路由至與執行 Agent 不同的執行個體。
若沒有共用 pub/sub,該執行個體無法連線作用中執行,而會啟動自己的執行,使原始執行不受影響,並導致對話串被處理兩次。
請在 `Mastra` 執行個體上設定由 Redis Streams 支援的共用 pub/sub,讓 Lease 與訊號能跨執行個體協調:
```typescript
import { Mastra } from '@mastra/core'
import { RedisStreamsPubSub } from '@mastra/redis-streams'
export const mastra = new Mastra({
agents: { agent },
pubsub: new RedisStreamsPubSub({
url: process.env.REDIS_URL,
keyPrefix: 'mastra:my-app',
}),
})
```
`RedisStreamsPubSub` 同時實作事件傳送合約及分散式 Lease,因此單一後端即可處理跨執行個體訊號傳送與 Lease 擁有權。Vercel 的代管 Redis 整合與 Upstash Redis 都很適合。何時需要分散式 pub/sub 的詳細資訊,請參閱 [PubSub 指南](https://mastra.zisheng.pro/zh-TW/docs/server/pubsub)與 [`RedisStreamsPubSub` 參考](https://mastra.zisheng.pro/zh-TW/reference/pubsub/redis-streams)。
## 相容性與 API
### 相容性
Mastra 仍接受 `type: 'user-message'` 和 `type: 'system-reminder'` 等舊版訊號 payload,並在內部將其正規化為新的類別及標籤結構:
- `type: 'user-message'`:正規化為 `type: 'user'` 及 `tagName: 'user'`
- `type: 'system-reminder'`:正規化為 `type: 'reactive'` 及 `tagName: 'system-reminder'`
現有已儲存的訊號資料列及較舊用戶端仍會透過相容層載入。伺服器支援訊息路由時,新用戶端會呼叫這些路由;React 的對話串訊號路徑偵測到較舊伺服器時,則會退回舊版 `/signals` 路由。完整訊息、訊號及訂閱型別請參閱 [Agent 訊號參考](https://mastra.zisheng.pro/zh-TW/reference/agents/agent)。
### 核准 Tool 呼叫
已訂閱的執行因等待 Tool 核准而暫停時,請使用訂閱專用方法核准或拒絕 Tool 呼叫。恢復後的區塊會透過現有對話串訂閱抵達。請參閱 [`client.getAgent().sendToolApproval()` 參考](https://mastra.zisheng.pro/zh-TW/reference/client-js/agents)及[伺服器 Agent 路由](https://mastra.zisheng.pro/zh-TW/reference/server/routes),瞭解請求與回應結構。
### 使用 HTTP 路由
若直接透過 HTTP 呼叫 Mastra,立即訊息請使用 `POST /api/agents/:agentId/send-message`,下一輪訊息則使用 `POST /api/agents/:agentId/queue-message`。訂閱專用 Tool 核准請使用 `POST /api/agents/:agentId/send-tool-approval`。請求與回應結構描述請參閱[伺服器路由參考](https://mastra.zisheng.pro/zh-TW/reference/server/routes)。
### 使用用戶端 SDK
JavaScript 用戶端提供對話串訊號 API。
傳送對話串輸入前,請先使用 `subscribeToThread()`,使用戶端能呈現接收該輸入或因其喚醒而產生的串流。
```typescript
const agent = client.getAgent('supportAgent')
const subscription = await agent.subscribeToThread({
resourceId: 'user_123',
threadId: 'thread_456',
})
await agent.sendMessage({
message: 'Show the shorter version.',
resourceId: 'user_123',
threadId: 'thread_456',
})
await subscription.processDataStream({
onChunk: chunk => {
console.log(chunk)
},
reconnect: true,
})
```
長時間存在的訂閱請使用 `reconnect: true`。重新連線選項請參閱 [`client.getAgent().subscribeToThread()` 參考](https://mastra.zisheng.pro/zh-TW/reference/client-js/agents)。
### 讓自訂 SSE 訂閱保持作用
若你為對話串訂閱公開自己的 Server-Sent Events(SSE)端點,請在串流閒置時定期傳送心跳訊框。這能避免瀏覽器、Proxy 及 Load Balancer 在下一個訊號或模型區塊抵達前關閉連線。
下列範例每 25 秒傳送一則 SSE 註解:
```typescript
const heartbeat = setInterval(() => {
controller.enqueue(encoder.encode(': keep-alive\n\n'))
}, 25_000)
request.signal.addEventListener('abort', () => {
clearInterval(heartbeat)
})
```
請將心跳與用戶端重新連線邏輯搭配使用。心跳可減少閒置中斷,而當網路或執行階段仍關閉串流時,重新連線可恢復作業。
## 相關內容
- [`Agent.sendMessage()`](https://mastra.zisheng.pro/zh-TW/reference/agents/agent)
- [`Agent.queueMessage()`](https://mastra.zisheng.pro/zh-TW/reference/agents/agent)
- [`Agent.sendSignal()`](https://mastra.zisheng.pro/zh-TW/reference/agents/agent)
- [`Agent.sendStateSignal()`](https://mastra.zisheng.pro/zh-TW/reference/agents/agent)
- [`Agent.subscribeToThread()`](https://mastra.zisheng.pro/zh-TW/reference/agents/agent)
- [`createNotificationInboxTool()`](https://mastra.zisheng.pro/zh-TW/reference/signals/create-notification-inbox-tool)
- [`client.getAgent().sendMessage()`](https://mastra.zisheng.pro/zh-TW/reference/client-js/agents)
- [`client.getAgent().queueMessage()`](https://mastra.zisheng.pro/zh-TW/reference/client-js/agents)
- [`client.getAgent().sendSignal()`](https://mastra.zisheng.pro/zh-TW/reference/client-js/agents)
- [伺服器 Agent 路由](https://mastra.zisheng.pro/zh-TW/reference/server/routes)
- [`client.getAgent().subscribeToThread()`](https://mastra.zisheng.pro/zh-TW/reference/client-js/agents)
- [`client.getAgent().sendToolApproval()`](https://mastra.zisheng.pro/zh-TW/reference/client-js/agents)
- [`RedisStreamsPubSub`](https://mastra.zisheng.pro/zh-TW/reference/pubsub/redis-streams)
- 📹 [Mastra 訊號工作坊](https://www.youtube.com/watch?v=KLg6uFKz9aw\&t=3020s)