> Discover all available pages from the documentation index: https://mastra.zisheng.pro/zh-HK/llms.txt
# Processors
Processor 會在訊息通過 Agent 時加以轉換、驗證或控制。它們會在 Agent 執行管線中的特定位置運行,讓你可以在輸入到達語言模型前修改輸入,或在輸出傳回使用者前修改輸出。
Processor 的設定方式如下:
- **`inputProcessors`**:在訊息到達語言模型前運行。
- **`outputProcessors`**:在語言模型產生回應後、但在回應傳回使用者前運行。
你可以使用個別 [`Processor`](https://mastra.zisheng.pro/zh-HK/reference/processors/processor-interface) 物件,亦可以運用 Mastra 的 Workflow 原語,將它們組合成 Workflow。Workflow 讓你可以進階控制 processor 的執行順序、平行處理及條件邏輯。
部分 processor 同時實作輸入及輸出邏輯,並可按轉換應發生的位置,用於其中一個陣列。
部分內置 processor 亦會傳送隱藏的系統提醒訊號。這些訊號會保留在原始記憶歷史記錄中,並在下一次模型呼叫前轉換為 `...` 上下文;不過,標準面向 UI 的訊息轉換及預設記憶喚回會隱藏這些訊號,除非你明確選擇加入。如要只為目前呼叫傳送訊號而不保留,請使用 `transient: true` 傳送。
## 何時使用 processor
使用 processor 可:
- 正規化或驗證使用者輸入
- 為 Agent 加入防護措施
- 偵測並防止提示詞注入或越獄嘗試
- 基於安全或合規要求審核內容
- 轉換訊息(例如翻譯語言、篩選 Tool 呼叫)
- 限制 token 用量或訊息歷史記錄長度
- 遮蔽敏感資料(PII)
- 對訊息套用自訂業務邏輯
Mastra 為常見使用情境提供多款 processor。你亦可以為應用程式的特定要求建立自訂 processor。
## 快速開始
匯入 processor 並建立實例,然後將其傳入 Agent 的 `inputProcessors` 或 `outputProcessors` 陣列:
```typescript
import { Agent } from '@mastra/core/agent'
import { ModerationProcessor } from '@mastra/core/processors'
export const moderatedAgent = new Agent({
id: 'moderated-agent',
name: 'moderated-agent',
instructions: 'You are a helpful assistant',
model: 'openai/gpt-5-mini',
inputProcessors: [
new ModerationProcessor({
model: 'openai/gpt-5-mini',
categories: ['hate', 'harassment', 'violence'],
threshold: 0.7,
strategy: 'block',
}),
],
})
```
## 執行順序
Processor 會按它們在陣列中出現的順序運行:
```typescript
inputProcessors: [new UnicodeNormalizer(), new PromptInjectionDetector(), new ModerationProcessor()]
```
對輸出 processor 而言,順序決定套用至模型回應的轉換次序。
### 啟用記憶時
在 Agent 啟用記憶後,記憶 processor 會自動加入管線:
**輸入 processor:**
```text
[Memory Processors] → [Your inputProcessors]
```
記憶會先載入訊息歷史記錄,然後才運行你的 processor。
**輸出 processor:**
```text
[Your outputProcessors] → [Memory Processors]
```
你的 processor 會先運行,之後記憶會保存訊息。
按照此順序,呼叫 `abort()` 的輸出防護措施會略過記憶 processor,並防止儲存訊息。詳情請參閱[記憶 Processor](https://mastra.zisheng.pro/zh-HK/docs/memory/memory-processors)。
## 將 processor 附加至 Agent
Processor 透過三個陣列在 Agent 上設定:
```typescript
import { Agent } from '@mastra/core/agent'
import { PrefillErrorHandler, TokenLimiter, ModerationProcessor } from '@mastra/core/processors'
const agent = new Agent({
id: 'support-agent',
name: 'support-agent',
model: 'openai/gpt-5',
instructions: '...',
inputProcessors: [
new TokenLimiter(4000),
new ModerationProcessor({ model: 'openai/gpt-5-nano' }),
],
outputProcessors: [new ModerationProcessor({ model: 'openai/gpt-5-nano' })],
errorProcessors: [new PrefillErrorHandler()],
})
```
- `inputProcessors` 在 LLM 前運行。
- `outputProcessors` 在 LLM 回應期間及之後運行。
- `errorProcessors` 在 LLM API 呼叫擲回錯誤時運行,因此可從 Provider 錯誤中復原。
每個陣列亦接受會傳回陣列的函式,因此可按每個請求從 `RequestContext` 建立 processor:
```typescript
new Agent({
id: 'processors-agent',
inputProcessors: ({ requestContext }) => {
const limit = requestContext.get('tokenLimit') ?? 4000
return [new TokenLimiter(limit)]
},
})
```
### 按每次呼叫覆寫 processor
`agent.generate()` 及 `agent.stream()` 接受相同的三個陣列。傳入其中一個陣列時,它只會在該次呼叫中**取代** Agent 上對應的陣列。記憶、Workspace 及其他由框架管理的 processor 仍會在你的陣列前後運行。
```typescript
await agent.stream('Summarize this', {
inputProcessors: [new TokenLimiter(2000)],
maxProcessorRetries: 5,
})
```
## 建立自訂 processor
自訂 processor 會實作 `Processor` 介面。
Processor 方法接收兩個用於存取對話的引數:
- `messages`:目前階段的 `MastraDBMessage` 物件快照陣列。
- `messageList`:即時的 `MessageList` 實例。使用它讀取其他階段,或就地加入、移除或取代訊息。
文字位於 `message.content.parts`,而非 `message.content` 本身。逐一處理 `parts`,並以 `part.type === 'text'` 篩選,以讀取使用者或助理文字。為了向後兼容,亦有扁平化的 `message.content.content` 字串可作後備。完整詳情請參閱 `Processor` 參考文件中的[訊息引數](https://mastra.zisheng.pro/zh-HK/reference/processors/processor-interface)。
### 轉換輸入訊息
```typescript
import type { Processor, ProcessInputArgs } from '@mastra/core/processors'
import type { MastraDBMessage } from '@mastra/core/memory'
export class CustomInputProcessor implements Processor {
id = 'custom-input'
async processInput({ messages }: ProcessInputArgs): Promise {
// Transform messages before they reach the LLM.
// Text lives in content.parts — iterate parts and rewrite text parts only.
return messages.map(msg => ({
...msg,
content: {
...msg.content,
parts: msg.content.parts?.map(part =>
part.type === 'text' ? { ...part, text: part.text.toLowerCase() } : part,
),
},
}))
}
}
```
`processInput()` 方法接收 `messages`、`systemMessages` 及 `abort()` 函式。傳回 `MastraDBMessage[]` 以取代訊息,或傳回 `{ messages, systemMessages }` 以同時修改系統訊息。
如要了解所有可用引數及傳回類型,請參閱 [`Processor` 參考文件](https://mastra.zisheng.pro/zh-HK/reference/processors/processor-interface)。
### 控制每個步驟
`processInput()` 在 Agent 開始執行時運行一次,而 `processInputStep()` 則會在 Agent 迴圈的**每個步驟**運行(包括 Tool 呼叫的後續步驟)。它支援按步驟變更設定,例如在運行時切換模型或修改 Tool 選項。
```typescript
import type {
Processor,
ProcessInputStepArgs,
ProcessInputStepResult,
} from '@mastra/core/processors'
export class DynamicModelProcessor implements Processor {
id = 'dynamic-model'
async processInputStep({
stepNumber,
model,
toolChoice,
messageList,
}: ProcessInputStepArgs): Promise {
// Use a fast model for initial response
if (stepNumber === 0) {
return { model: 'openai/gpt-5-mini' }
}
// Disable tools after 5 steps to force completion
if (stepNumber > 5) {
return { toolChoice: 'none' }
}
// No changes for other steps
return {}
}
}
```
此方法會接收目前的 `stepNumber`、`model`、`tools`、`toolChoice`、`messages` 等。傳回一個物件,當中包含你要為該步驟覆寫的任何屬性,例如 `{ model, toolChoice, tools, systemMessages }`。
如要了解所有可用引數及傳回類型,請參閱 [`Processor` 參考文件](https://mastra.zisheng.pro/zh-HK/reference/processors/processor-interface)。
### 在呼叫 Provider 前重寫 LLM 請求
如要重寫 Mastra 傳送至模型的最終提示詞,請使用 `processLLMRequest()`。此 hook 會在 Mastra 將 `MessageList` 轉換成面向 Provider 的提示詞格式(`LanguageModelV2Prompt`)後、緊接 Provider 呼叫前運行。
如要變更對話,請使用以訊息為基礎的 hook:
- `processInput()`:在 Agent 迴圈開始前變更一次對話。
- `processInputStep()`:在每次 LLM 呼叫前變更訊息或步驟設定。
- `processLLMRequest()`:只變更目前 Provider 呼叫的外送提示詞。
`processLLMRequest()` 傳回的變更是暫時性的。它們不會保存回 `MessageList`、記憶、UI 歷史記錄或日後的 Provider 呼叫。因此,此 hook 很適合用於 Provider 兼容性重寫、角色/內容正規化,或其他不應改變已儲存對話歷史記錄的模型特定提示詞變更。
此方法會接收 `prompt`、`model`、`stepNumber`、`steps`、`state` 及共用的 processor 上下文。從 `processLLMRequest()` 呼叫 `abort()` 會發出正常的 tripwire 回應,並停止呼叫。
如要了解所有可用引數及傳回類型,請參閱 [`Processor` 參考文件](https://mastra.zisheng.pro/zh-HK/reference/processors/processor-interface)。
### 在呼叫 Provider 後處理 LLM 回應
步驟完成且串流區塊已收集後,使用 `processLLMResponse()` 處理完成的 LLM 回應。此 hook 與 `processLLMRequest()` 配合使用:在請求 hook 中暫存狀態(例如快取 key),然後在回應 hook 中讀回,以執行寫入快取等副作用。
`state` 物件與同一步驟傳入 `processLLMRequest()` 的實例相同。當 `fromCache` 為 `true` 時,回應是從快取重播,而非由即時模型呼叫產生;在此情況下,寫入快取的 processor 應略過寫入。
此方法會接收 `chunks`、`model`、`stepNumber`、`steps`、`state`、`fromCache` 及共用的 processor 上下文。
如要了解所有可用引數及傳回類型,請參閱 [`Processor` 參考文件](https://mastra.zisheng.pro/zh-HK/reference/processors/processor-interface)。
### 使用 `prepareStep()` callback
`generate()` 或 `stream()` 上的 `prepareStep()` callback 是 `processInputStep()` 的簡寫。在內部,Mastra 會將它包裝在一個 processor 中,於每個步驟呼叫你的函式。它接受與 `processInputStep()` 相同的引數及傳回類型,但毋須建立 class:
```typescript
await agent.generate('Complex task', {
prepareStep: async ({ stepNumber, model }) => {
if (stepNumber === 0) {
return { model: 'openai/gpt-5-mini' }
}
if (stepNumber > 5) {
return { toolChoice: 'none' }
}
},
})
```
### 轉換輸出訊息
```typescript
import type { Processor } from '@mastra/core/processors'
import type { MastraDBMessage } from '@mastra/core/memory'
export class CustomOutputProcessor implements Processor {
id = 'custom-output'
async processOutputResult({ messages }): Promise {
// Transform messages after the LLM generates them
return messages.filter(msg => msg.role !== 'system')
}
}
```
此方法亦會接收 `result` 物件,當中包含完整的產生資料、`text`、`usage`(token 數量)、`finishReason` 及 `steps`(每個步驟均包含 `toolCalls`、`toolResults` 等)。使用它追蹤用量或檢查 Tool 呼叫:
```typescript
import type { Processor } from '@mastra/core/processors'
export class UsageTracker implements Processor {
id = 'usage-tracker'
async processOutputResult({ messages, result }) {
console.log(`Tokens: ${result.usage.inputTokens} in, ${result.usage.outputTokens} out`)
console.log(`Finish reason: ${result.finishReason}`)
return messages
}
}
```
### 篩選串流輸出
`processOutputStream()` 方法會在串流區塊到達 client 前加以轉換或篩選:
```typescript
import type { Processor } from '@mastra/core/processors'
import type { ChunkType } from '@mastra/core/stream'
export class StreamFilter implements Processor {
id = 'stream-filter'
async processOutputStream({ part }): Promise {
// Drop text-delta chunks that contain the word "secret"
if (part.type === 'text-delta' && part.payload.text.includes('secret')) {
return null
}
// Return the (possibly modified) chunk to emit it
return part
}
}
```
傳回值:
- `ChunkType` 會發出該區塊。傳回原始 `part` 可讓它不經修改直接通過。
- `null` 或 `undefined` 會捨棄該區塊。兩者的行為相同,因此沒有傳回任何內容的方法亦會捨棄區塊。
- 捨棄操作只會影響一個區塊。如要完全停止串流,請呼叫 `abort()`。
如要同時接收 Tool 透過 `writer.custom()` 發出的自訂 `data-*` 區塊,請在 processor 上設定 `processDataParts = true`。這讓你可在 Tool 發出的資料區塊到達 client 前檢查、修改或封鎖它們。
### 驗證每個回應
`processOutputStep()` 方法會在每個 LLM 步驟後運行,讓你驗證回應,並可選擇要求重試:
```typescript
import type { Processor } from '@mastra/core/processors'
export class ResponseValidator implements Processor {
id = 'response-validator'
async processOutputStep({ text, abort, retryCount }) {
const isValid = await validateResponse(text)
if (!isValid && retryCount < 3) {
abort('Response did not meet requirements. Try again.', { retry: true })
}
return []
}
}
```
如要進一步了解重試行為,請參閱進階模式中的[重試機制](#retry-mechanism)。
### 跨區塊及步驟保存資料
輸出方法會接收一個 `state` 物件,其存續期為一個請求。狀態以 processor 的 `id` 為 key,因此每個 processor 只會看見自己的資料,而狀態會在 `processOutputStream`、`processOutputStep` 及 `processOutputResult` 之間共用。每次新的 `agent.generate()` 或 `agent.stream()` 呼叫都會建立新的狀態物件。
```typescript
import type { Processor } from '@mastra/core/processors'
export class WordCounter implements Processor {
id = 'word-counter'
async processOutputStream({ part, state }) {
state.wordCount ??= 0
if (part.type === 'text-delta') {
state.wordCount += part.payload.text.split(/\s+/).filter(Boolean).length
}
return part
}
async processOutputResult({ messages, state }) {
console.log(`Total words: ${state.wordCount}`)
return messages
}
}
```
## 內置實用處理器
Mastra 提供用於常見任務的實用處理器:
**如需保安及驗證處理器**,請參閱[防護措施](https://mastra.zisheng.pro/zh-HK/docs/agents/guardrails)頁面,了解輸入/輸出防護措施及審核處理器。 **如需記憶體專用處理器**,請參閱[記憶體處理器](https://mastra.zisheng.pro/zh-HK/docs/memory/memory-processors)頁面,了解處理訊息記錄、語義回憶及工作記憶體的處理器。
### `TokenLimiter`
當 token 總數超出指定限制時,透過移除較舊的訊息來防止上下文視窗溢出。它會優先保留最近的訊息,並保留系統訊息。
```typescript
import { Agent } from '@mastra/core/agent'
import { TokenLimiter } from '@mastra/core/processors'
const agent = new Agent({
id: 'my-agent',
name: 'my-agent',
model: 'openai/gpt-5.6-sol',
inputProcessors: [new TokenLimiter(127000)],
})
```
請參閱 [`TokenLimiterProcessor` 參考文件](https://mastra.zisheng.pro/zh-HK/reference/processors/token-limiter-processor),了解自訂編碼、策略及計數模式選項。
### `ToolCallFilter`
從傳送至 LLM 的訊息中移除 Tool 呼叫及結果,從而節省冗長 Tool 互動所佔用的 token。你也可以選擇只排除特定 Tool。此篩選器只影響 LLM 輸入,經篩選的訊息仍會儲存至記憶體。
根據預設,`ToolCallFilter` 會在 Agent 迴圈開始前篩選初始輸入。使用 `filterAfterToolSteps`,亦可在每個迴圈步驟中進行篩選,同時保留最近產生 Tool 的步驟。
```typescript
new ToolCallFilter({
filterAfterToolSteps: 2,
})
```
設定 `preserveModelOutput: true`,即可為已篩選且完成的 Tool 結果保留精簡的 `toModelOutput` 記錄。此篩選器只保留面向模型的輸出,並移除原始 Tool 引數及原始結果。
```typescript
new ToolCallFilter({
preserveModelOutput: true,
})
```
請參閱 [`ToolCallFilter` 參考文件](https://mastra.zisheng.pro/zh-HK/reference/processors/tool-call-filter)以了解配置選項,並參閱[記憶體處理器](https://mastra.zisheng.pro/zh-HK/docs/memory/memory-processors)頁面以了解記憶體處理前的篩選方式。
### `ToolSearchProcessor`
為擁有大型 Tool 資料庫的 Agent 啟用執行階段 Tool 探索。此處理器不會預先提供所有 Tool,而是向 Agent 提供 `search_tools` 及 `load_tool` meta-tool,讓它按需要透過關鍵字尋找及載入 Tool,從而減少上下文 token 用量。
請參閱 [`ToolSearchProcessor` 參考文件](https://mastra.zisheng.pro/zh-HK/reference/processors/tool-search-processor),了解配置選項及使用範例。
### `ProviderHistoryCompat`
處理 Agent 在不同模型 Provider 之間重用訊息時,Provider 特有的記錄不相容問題。它可以在呼叫 Provider 前重寫傳出的 LLM 請求,或從已知的 Provider API 錯誤中恢復並重試。
當你需要 Provider 記錄相容性規則、回應式 API 錯誤恢復、自訂相容性規則或可預測的處理器順序時,請明確加入 `ProviderHistoryCompat`。
請參閱 [`ProviderHistoryCompat` 參考文件](https://mastra.zisheng.pro/zh-HK/reference/processors/provider-history-compat),了解設定、內置規則及自訂規則選項。
## 回應快取
> **Beta:** 此功能仍處於 beta 階段。在 API 穩定前,可能會出現不伴隨主要版本升級的破壞性變更。
當 Agent 收到相同請求時,回應快取會略過 LLM 呼叫,並重播先前快取的回應。你可使用此功能縮短延遲,並避免為重複呼叫付費。
快取是以 [`ResponseCache`](https://mastra.zisheng.pro/zh-HK/reference/processors/response-cache) 輸入處理器實作。Mastra 不提供 Agent 層級的選項。如要啟用快取,請明確註冊此處理器。這可在 Mastra 收集意見期間維持精簡的 API 介面。每次呼叫的覆寫值會透過 `RequestContext` 傳遞。
### 何時使用回應快取
當相同的請求結構在不同使用者或工作階段之間重複出現時,便適合使用回應快取,例如提示詞範本、建議提示詞按鈕、Agent 搜尋的重新提問,或反覆分類相同輸入的防護措施 LLM。如果呼叫會透過 Tool 觸發外部副作用,則不應使用,因為快取命中會重播 Tool 呼叫,而不會再次執行它們。
### 快速入門
將 `ResponseCache` 加入 Agent 的 `inputProcessors`,並傳入任何 `MastraServerCache` 作為後端。在開發環境中,`InMemoryServerCache` 無需額外設定即可使用:
```typescript
import { Agent } from '@mastra/core/agent'
import { InMemoryServerCache } from '@mastra/core/cache'
import { ResponseCache } from '@mastra/core/processors'
const cache = new InMemoryServerCache()
export const searchAgent = new Agent({
id: 'search-agent',
name: 'Search Agent',
instructions: 'You answer questions concisely.',
model: 'openai/gpt-5',
inputProcessors: [new ResponseCache({ cache, ttl: 600 })], // 10 minutes
})
```
第一次呼叫會正常執行 LLM,並將回應寫入快取。之後使用相同已解析提示詞的呼叫,會直接傳回快取回應,而不會呼叫 LLM。
### 透過 RequestContext 按呼叫覆寫
每次呼叫的配置會透過 `RequestContext` 傳遞。使用 `ResponseCache.context()` 建立全新的 context,或使用 `ResponseCache.applyContext()` 合併至現有的 context:
```typescript
import { ResponseCache } from '@mastra/core/processors'
import { RequestContext } from '@mastra/core/request-context'
// Fresh context with the override
await agent.stream('hello', {
requestContext: ResponseCache.context({ key: 'custom-key', bust: true }),
})
// Or merge into an existing context
const ctx = new RequestContext()
ctx.set('caller-meta', { userId: 'u-123' })
ResponseCache.applyContext(ctx, { bust: true })
await agent.stream('hello', { requestContext: ctx })
```
以下欄位可按每次呼叫覆寫:
- `key`:字串或函數。只為此請求覆寫自動衍生的快取 key。
- `scope`:字串或 `null`。只為此請求覆寫租戶/使用者 scope。`null` 會選擇不使用 scope。
- `bust`:布林值。略過讀取快取,但仍會在完成時寫入(適用於「強制重新整理」按鈕)。
`cache`、`ttl` 及 `agentId` 會保留在 constructor 上。它們是 instance 層級的事項,不宜按每次呼叫變更。
### 租戶 scope
根據預設,`ResponseCache` 會在 request context 中尋找 `MASTRA_RESOURCE_ID_KEY`,並將其用作快取 scope。這表示已經填入 resource id 的 Agent(例如透過記憶體)會自動按使用者隔離。使用者絕不會看到其他人的快取回應。
需要不同 scope 時,請明確覆寫:
```typescript
new Agent({
id: 'processors-agent',
inputProcessors: [
new ResponseCache({
cache,
scope: 'org-123', // explicit tenant scope
}),
],
})
```
傳入 `scope: null` 可刻意在所有呼叫者之間共享項目。此設定只應用於已知屬於公開且非個人化的內容。
### 自訂快取後端
`ResponseCache` 接受任何 `MastraServerCache`。在正式環境中,請使用 `@mastra/redis` 的 `RedisCache`:
```typescript
import { Agent } from '@mastra/core/agent'
import { ResponseCache } from '@mastra/core/processors'
import { RedisCache } from '@mastra/redis'
const cache = new RedisCache({ url: process.env.REDIS_URL })
export const agent = new Agent({
id: 'cached-agent',
name: 'Cached Agent',
instructions: '...',
model: 'openai/gpt-5',
inputProcessors: [new ResponseCache({ cache })],
})
```
如要使用自訂後端,請擴充 `MastraServerCache` 並實作其 abstract method(此處理器只會呼叫 `get` 及 `set`)。
### 快取的實作方式
`ResponseCache` 會接入 `processLLMRequest`(查找快取,命中時提早結束)及 `processLLMResponse`(完成時寫入快取)。兩者都會在記憶體載入,且較早的輸入處理器轉換提示詞\_之後\_,於 Agent 迴圈內執行。
這表示快取 key 衍生自 Mastra 即將傳送至模型、已解析的 `LanguageModelV2Prompt`。此 key 會在記憶體載入且較早的輸入處理器執行\_之後\_建立,而 Agent Tool 迴圈中的每個步驟都會獨立快取。
### 快取 key 包含的內容
如果你沒有提供 `key`,處理器會根據在此步驟中會改變 LLM 回應的輸入,以確定性方式衍生一個 key:`agentId`、`stepNumber`(因此 Tool 迴圈中的每個步驟都有自己的快取項目)、`scope`、模型身分(`provider`、`modelId`、規格版本),以及已解析的 `prompt`(記憶體及處理器處理後)。任何這些輸入的變更都會自動使快取失效。
多模態提示詞亦包括在內。圖像及檔案部分會按值加入 key:URL 會提供其完整 href,而內嵌二進制資料(`Uint8Array`、`ArrayBuffer`)則會提供其位元組的摘要。因此,兩個只在所引用圖像方面不同的請求,會取得不同的快取項目。
#### 自訂快取 key
在 constructor 或每次呼叫中以函數形式傳入 `key`,即可使用這些輸入的任何子集衍生自訂快取 key。此函數會接收確定性雜湊原本會使用的相同輸入,並傳回字串(或 `Promise`):
```typescript
import { ResponseCache, buildResponseCacheKey } from '@mastra/core/processors'
await agent.stream(input, {
requestContext: ResponseCache.context({
// Cache only on the model id and the resolved prompt tail — ignore
// step number, scope, etc.
key: ({ model, prompt }) => `qa:${model.modelId}:${JSON.stringify(prompt).slice(-200)}`,
}),
})
// Or reuse the deterministic helper while overriding individual fields:
await agent.stream(input, {
requestContext: ResponseCache.context({
key: inputs => buildResponseCacheKey({ ...inputs, scope: 'global' }),
}),
})
```
如果函數拋出錯誤,處理器會改用預設的 key 衍生方式,讓呼叫仍可受惠於快取。
### 快取命中的運作方式
當處理器找到快取命中時,會從 `processLLMRequest` 傳回快取的資料塊,以提早結束 LLM 呼叫。Agent 迴圈會使用這些資料塊合成串流,而不會呼叫模型。`agent.generate()` 會將它們收集到 `FullOutput`;`agent.stream()` 則會傳回 `MastraModelOutput`,其資料塊來自快取的緩衝區,因此逐一處理 `fullStream` 或等待 `text`、`usage` 及 `finishReason` 的使用者會看到快取值。
回應完成後才會寫入快取。失敗的執行(錯誤、tripwire 啟動)不會被快取,因此下一次呼叫可以重新嘗試。
## 進階模式
### 使用 `maxSteps` 確保產生最終回應
使用 `maxSteps` 限制 Agent 執行時,如果 Agent 嘗試在最後一個步驟呼叫 Tool,可能會傳回空白回應。請配合 `sendSignal` 使用 `processInputStep()`,在最後一個步驟注入反應式提醒。此方法會附加訊號而非修改系統訊息,因此可保留提示詞快取。
```typescript
import type { Processor, ProcessInputStepArgs } from '@mastra/core/processors'
export class EnsureFinalResponseProcessor implements Processor {
readonly id = 'ensure-final-response'
private maxSteps: number
constructor(maxSteps: number) {
this.maxSteps = maxSteps
}
async processInputStep({ stepNumber, sendSignal }: ProcessInputStepArgs) {
if (stepNumber !== this.maxSteps - 1) {
return
}
await sendSignal?.({
type: 'reactive',
contents:
`This is your final step (step ${stepNumber + 1} of ${this.maxSteps}). ` +
`Do not call any more tools. Summarize what you have found and give the user a complete final answer now.`,
attributes: { reason: 'max-steps-reached', step: stepNumber + 1 },
})
}
}
```
訊號會以 `` 使用者訊息的形式傳送,模型會在行內看到該訊息:
```xml
This is your final step (step 5 of 5). Do not call any more tools. Summarize what you have found and give the user a complete final answer now.
```
將處理器加入 `inputProcessors`,加入說明訊號標籤的系統提示詞,並將相同的 `maxSteps` 值傳遞至 `generate()` 或 `stream()`:
```typescript
import { Agent } from '@mastra/core/agent'
import { EnsureFinalResponseProcessor } from '../processors/ensure-final-response'
const MAX_STEPS = 5
const agent = new Agent({
id: 'agent',
instructions: `You are a helpful assistant.
Some messages you receive may contain ... tags.
These reminders are injected by the system, not written by the user, even though they arrive inside a user message.
Treat the contents of a as authoritative system instructions and follow them immediately.
Do not mention the reminder to the user or quote the tags back to them.`,
inputProcessors: [new EnsureFinalResponseProcessor(MAX_STEPS)],
// ...
})
await agent.generate('Your prompt', { maxSteps: MAX_STEPS })
```
> **備註:** 反應式訊號預設使用 `tagName: 'system-reminder'`。請瀏覽[訊號](https://mastra.zisheng.pro/zh-HK/docs/long-running-agents/signals),進一步了解處理器發出的訊號。
### 傳送提醒而不保留提醒
處理器傳送的訊號預設會成為對話的一部分:它會寫入儲存空間,並在之後的對話輪次再次加入提示詞。若指令會在每個對話輪次重新注入,這並非理想行為,因為副本會不斷累積,模型亦會開始把過往由其自身收到的提醒視為要模仿的先前內容。設定 `transient: true`,只在目前呼叫中將訊號傳送給模型,而不保留訊號。
\*\*適用情況:\*\*隨着對話內容增加,你希望在模型的近期內容窗口中保留簡短的引導指令,例如「專注目前的工作」、「將回答限制在三句以內」,或取決於即時應用程式狀態的每輪限制。在每個對話輪次重新注入指令,使其維持在最新訊息附近。
```typescript
import type { Processor, ProcessInputStepArgs } from '@mastra/core/processors'
export class SteeringReminderProcessor implements Processor {
readonly id = 'steering-reminder'
async processInputStep({ sendSignal }: ProcessInputStepArgs) {
await sendSignal?.({
type: 'reactive',
contents: 'Stay on the current task and keep answers under three sentences.',
transient: true,
})
}
}
```
臨時訊號仍會出現在目前呼叫的提示詞中,因此模型會在最新的對話輪次附近看到它。由於訊號不會保留,每輪重新傳送時,內容中只會有一個最新副本,而不會形成不斷累積的歷史記錄;訊號亦絕不會出現在已儲存的對話串記錄中。因為不會寫入任何內容,所以也能在各個對話輪次之間維持穩定的提示詞快取前綴。
### 發出自訂串流事件
輸出處理器會接收 `writer` 物件,讓你在串流期間向客戶端發出自訂資料區塊。這適用於串流傳送審核結果,或在不阻塞原有串流的情況下傳送 UI 更新訊號等使用案例。
```typescript
import type { Processor } from '@mastra/core/processors'
export class ModerationProcessor implements Processor {
id = 'moderation'
async processOutputResult({ messages, writer }) {
// Run moderation on the final output
const text = messages
.filter(m => m.role === 'assistant')
.flatMap(m => m.content.parts?.filter(p => p.type === 'text'))
.map(p => p.text)
.join(' ')
const result = await runModeration(text)
if (result.requiresChange) {
// Emit a custom event to the client with the moderated text
await writer?.custom({
type: 'data-moderation-update',
data: {
originalText: text,
moderatedText: result.moderatedText,
reason: result.reason,
},
})
}
return messages
}
}
```
在客戶端監聽串流中的自訂區塊類型:
```typescript
const stream = await agent.stream('Hello')
for await (const chunk of stream.fullStream) {
if (chunk.type === 'data-moderation-update') {
// Update the UI with moderated text
updateDisplayedMessage(chunk.data.moderatedText)
}
}
```
自訂區塊類型必須使用 `data-` 前綴(例如 `data-moderation-update`、`data-status`)。
`processOutputStream()` 預設會略過 `data-*` 區塊,以免意外處理 Tool 遙測資料或其他處理器的輸出。如要在處理器中檢查、修改或封鎖這些區塊,請在該處理器上設定 `processDataParts = true`:
```typescript
class ModerationCollector implements Processor {
id = 'moderation-collector'
processDataParts = true
async processOutputStream({ part, state }) {
if (part.type === 'data-moderation-update') {
state.warnings ??= []
state.warnings.push(part.data)
}
return part
}
}
```
### 為訊息加入 metadata
你可以在 `processOutputResult` 中為訊息加入自訂 metadata。你可透過回應物件存取此 metadata:
```typescript
import type { Processor } from '@mastra/core/processors'
import type { MastraDBMessage } from '@mastra/core/memory'
export class MetadataProcessor implements Processor {
id = 'metadata-processor'
async processOutputResult({
messages,
}: {
messages: MastraDBMessage[]
}): Promise {
return messages.map(msg => {
if (msg.role === 'assistant') {
return {
...msg,
content: {
...msg.content,
metadata: {
...msg.content.metadata,
processedAt: new Date().toISOString(),
customData: 'your data here',
},
},
}
}
return msg
})
}
}
```
透過 `generate()` 存取 metadata:
```typescript
const result = await agent.generate('Hello')
// The response includes uiMessages with processor-added metadata
const assistantMessage = result.response?.uiMessages?.find(m => m.role === 'assistant')
console.log(assistantMessage?.metadata?.customData)
```
如使用串流,請從 `finish` 區塊承載資料或 `stream.response` promise 存取 metadata。
### 將 Workflow 用作處理器
你可以將 Mastra Workflow 用作處理器,建立支援平行執行、條件式分支及錯誤處理的複雜處理管線:
```typescript
import { createWorkflow, createStep } from '@mastra/core/workflows'
import {
ProcessorStepSchema,
PromptInjectionDetector,
PIIDetector,
ModerationProcessor,
} from '@mastra/core/processors'
import { Agent } from '@mastra/core/agent'
// Create a workflow that runs multiple checks in parallel
const moderationWorkflow = createWorkflow({
id: 'moderation-pipeline',
inputSchema: ProcessorStepSchema,
outputSchema: ProcessorStepSchema,
})
.parallel([
createStep(
new PIIDetector({
strategy: 'redact',
}),
),
createStep(
new PromptInjectionDetector({
strategy: 'block',
}),
),
createStep(
new ModerationProcessor({
strategy: 'block',
}),
),
])
.map(async ({ inputData }) => {
return inputData['processor:pii-detector']
})
.commit()
// Use the workflow as an input processor
const agent = new Agent({
id: 'moderated-agent',
name: 'Moderated Agent',
model: 'openai/gpt-5.6-sol',
inputProcessors: [moderationWorkflow],
})
```
在 `.parallel()` 步驟之後,每個分支結果都會以其處理器 ID 作為索引鍵(例如 `processor:pii-detector`)。使用 `.map()` 選取下一個步驟應接收其輸出的分支。
如果分支使用 `redact` 等變更內容的策略,請對應至該分支,使其轉換後的訊息可繼續傳遞。如果所有分支都只使用 `block`,則任何分支均可。由於它們全都不會修改訊息,任選一個即可。
當 Agent 向 Mastra 註冊後,處理器 Workflow 亦會自動註冊為 Workflow,讓你在 [Studio](https://mastra.zisheng.pro/zh-HK/docs/studio/overview) 中查看及偵錯。
### 重試機制
處理器可要求 LLM 根據意見重試回應。這適用於實作質素檢查、輸出驗證或反覆改進:
```typescript
import type { Processor } from '@mastra/core/processors'
export class QualityChecker implements Processor {
id = 'quality-checker'
async processOutputStep({ text, abort, retryCount }) {
const qualityScore = await evaluateQuality(text)
if (qualityScore < 0.7 && retryCount < 3) {
// Request a retry with feedback for the LLM
abort('Response quality score too low. Please provide a more detailed answer.', {
retry: true,
metadata: { score: qualityScore },
})
}
return []
}
}
const agent = new Agent({
id: 'quality-agent',
name: 'Quality Agent',
model: 'openai/gpt-5.6-sol',
outputProcessors: [new QualityChecker()],
maxProcessorRetries: 3, // Maximum retry attempts. If unset, retries are disabled (unless errorProcessors are configured, in which case it defaults to 10).
})
```
重試機制:
- 適用於 `processOutputStep()` 及 `processInputStep()` 方法
- 重新執行步驟,並將中止原因作為 LLM 的內容加入
- 透過 `retryCount` 參數追蹤重試次數
- 必須在 Agent 或呼叫中明確設定 `maxProcessorRetries` 限制
### 錯誤處理器的重試限制
`processAPIError()` 有另一個預設值:已配置 `errorProcessors` 而省略 `maxProcessorRetries` 時,執行階段最多允許重試 `10` 次。需要有限的重試額度時,請明確設定限制。
使用 `StreamErrorRetryProcessor` 時,亦請將其 `maxRetries` 設定為相同值。其本身的預設值為 `1`,因此可能低於 Agent 上限。如果處理器是某項請求唯一的重試機制,請將模型重試次數維持在 `0`。
### 違規回呼
所有處理器均公開 `onViolation` 屬性,每當偵測到違反政策的情況便會觸發,包括呼叫 `abort()`(封鎖策略)及處理器發出警告(警告策略)時。你可用它發出警報、記錄或執行副作用,而不影響處理器的主要邏輯:
```typescript
import { ModerationProcessor, CostGuardProcessor } from '@mastra/core/processors'
const moderation = new ModerationProcessor({
model: 'openai/gpt-5-nano',
strategy: 'block',
})
moderation.onViolation = ({ processorId, message, detail }) => {
// Log to external monitoring, send alerts, update dashboards
monitor.track('processor_violation', { processorId, message, detail })
}
const costGuard = new CostGuardProcessor({
maxCost: 10.0,
scope: 'resource',
window: '30d',
})
costGuard.onViolation = ({ processorId, message, detail }) => {
alertSystem.notify(`[${processorId}] ${message}`)
}
```
回呼會接收包含以下內容的 `ProcessorViolation` 物件:
- `processorId`:偵測到違規情況的處理器 ID
- `message`:關於違規內容且可供人閱讀的說明
- `detail`:處理器專用的 metadata(例如成本用量、偵測到的 PII 類型、審核類別)
`onViolation` 是基礎 [`Processor` 介面](https://mastra.zisheng.pro/zh-HK/reference/processors/processor-interface)的一部分,因此任何自訂處理器亦可使用。當任何處理器呼叫 `abort()` 時,執行器會自動叫用此回呼。回呼內部拋出的錯誤會被靜默捕捉,避免干擾處理器管線。
### 中止及 tripwire 區塊
呼叫 `abort(reason, options)` 會拋出 `TripWire` 錯誤並結束處理。在串流中,Mastra 會發出客戶端可偵測的 `tripwire` 區塊:
```typescript
for await (const chunk of stream.fullStream) {
if (chunk.type === 'tripwire') {
console.log('Blocked by', chunk.payload.processorId, '-', chunk.payload.reason)
break
}
}
```
對於 `agent.generate()`,當 `result.finishReason === 'other'` 時,結果會以 `result.tripwire` 公開相同資訊。
`abort` 接受第二個 options 引數:
- `retry: true` 會要求 Agent 重試,而非結束處理。輸入及輸出處理器重試需要在 Agent 或呼叫中設定 `maxProcessorRetries`。
- `metadata` 會將結構化資料附加至 `tripwire` 區塊,讓下游使用者可根據 `pii`、`quality` 或 `moderation` 等類別建立分支。
## API 錯誤處理
`processAPIError` 方法會處理 LLM API 拒絕,即 API 拒絕請求的錯誤(例如 400 或 422 狀態碼),而非網絡或伺服器故障。當 API 因訊息格式而拒絕請求時,你可藉此修改請求並重試。
```typescript
import { APICallError } from '@ai-sdk/provider'
import type { Processor, ProcessAPIErrorArgs, ProcessAPIErrorResult } from '@mastra/core/processors'
export class ContextLengthHandler implements Processor {
id = 'context-length-handler'
processAPIError({
error,
messageList,
retryCount,
}: ProcessAPIErrorArgs): ProcessAPIErrorResult | void {
if (retryCount > 0) return
if (APICallError.isInstance(error) && error.message.includes('context length exceeded')) {
const messages = messageList.get.all.db()
if (messages.length > 4) {
messageList.removeByIds([messages[1]!.id, messages[2]!.id])
return { retry: true }
}
}
}
}
```
Mastra 包含內置的 [`PrefillErrorHandler`](https://mastra.zisheng.pro/zh-HK/reference/processors/prefill-error-handler),可自動處理 Anthropic 的「assistant message prefill」錯誤。此處理器會自動注入,毋須配置。
## 相關文件
- [防護措施](https://mastra.zisheng.pro/zh-HK/docs/agents/guardrails):保安及驗證處理器
- [記憶體處理器](https://mastra.zisheng.pro/zh-HK/docs/memory/memory-processors):記憶體專用處理器及自動整合
- [Processor 介面](https://mastra.zisheng.pro/zh-HK/reference/processors/processor-interface):處理器的完整 API 參考
- [ToolSearchProcessor 參考](https://mastra.zisheng.pro/zh-HK/reference/processors/tool-search-processor):執行階段 Tool 搜尋的 API 參考