跳至主要內容

查詢指標

Mastra 透過三種介面提供相同的五種 OLAP 查詢(getMetricAggregategetMetricBreakdowngetMetricTimeSeriesgetMetricPercentiles 及探索輔助函式):處理程序內儲存區存取器、執行階段 HTTP API,以及 mastra api metric CLI。三者接受相同且經 Zod 驗證的輸入格式,因此你可以從一次性的 CLI 調查轉移到程式化的儀表板 Tool,而不必重新學習 API。

適用情境
「適用情境」的直接連結

  • 在 Studio 旁建立自訂儀表板或 KPI 圖塊。
  • 建立排程警示,在 token 成本或延遲超過臨界值時觸發。
  • 為 Agent 提供能讀取自身效能指標並在聊天中解釋的 Tool。
  • 從終端機使用 mastra api metric ... 進行一次性調查。

若要設定可觀測性儲存區本身,請參閱指標總覽。若要查看可查詢的指標名稱清單,請參閱自動指標參考

備註

指標查詢由可觀測性領域提供,因此需要支援 OLAP 的儲存區(本機使用 DuckDB,正式環境使用 ClickHouse)。設定方式請參閱指標總覽。若未設定可觀測性儲存區,getStore('observability') 會回傳 null

介面
「介面」的直接連結

處理程序內
「處理程序內」的直接連結

在 Tool、伺服器路由或 Workflow 步驟內,從 Mastra 儲存空間取得可觀測性儲存區:

src/mastra/tools/agent-latency-tool.ts
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'

export const agentLatencyTool = createTool({
id: 'agentLatency',
description: 'Average agent latency over the last hour.',
inputSchema: z.object({}),
execute: async (_input, context) => {
const observability = await context.mastra!.getStorage()!.getStore('observability')
if (!observability) {
throw new Error('Observability domain is not configured (requires DuckDB or ClickHouse)')
}

const result = await observability.getMetricAggregate({
name: ['mastra_agent_duration_ms'],
aggregation: 'avg',
filters: {
timestamp: { start: new Date(Date.now() - 60 * 60 * 1000) },
},
})

return { averageMs: result.value }
},
})

當設定的後端不支援 OLAP 查詢時,getStore('observability') 會回傳 null

HTTP
「HTTP」的直接連結

mastra dev 伺服器(以及任何已部署的 Mastra 執行階段)會在 /api/observability/metrics/* 下提供相同的查詢。彙總、細分、時間序列及百分位數端點會使用 POST 接收 JSON 內文。探索端點則使用帶有查詢參數的 GET

curl -sS -X POST http://localhost:4111/api/observability/metrics/aggregate \
-H "content-type: application/json" \
-d '{"name":["mastra_agent_duration_ms"],"aggregation":"avg"}'

可用路由:

  • POST /api/observability/metrics/aggregate
  • POST /api/observability/metrics/breakdown
  • POST /api/observability/metrics/timeseries
  • POST /api/observability/metrics/percentiles
  • GET /api/observability/metrics(原始資料列、分頁)
  • GET /api/observability/discovery/metric-names
  • GET /api/observability/discovery/metric-label-keys
  • GET /api/observability/discovery/metric-label-values

@mastra/client-js SDK 將相同路由封裝為 mastraClient.getMetricAggregate(...)getMetricBreakdown(...) 等方法。

CLI
「CLI」的直接連結

mastra api metric ... 以單一 JSON 引數呼叫相同端點,因此 Agent 或 shell 指令碼無須撰寫任何程式碼即可擷取指標:

mastra api metric aggregate \
'{"name":["mastra_agent_duration_ms"],"aggregation":"avg"}' \
--url http://localhost:4111

CLI 預設以託管的 Mastra 可觀測性服務(https://observability.mastra.ai)為目標。傳入 --url http://localhost:4111 即可查詢本機 mastra dev 伺服器。完整命令清單請參閱 mastra api metric aggregate 及其相鄰項目。

查詢
「查詢」的直接連結

getMetricAggregate
「getmetricaggregate」的直接連結

回傳單一純量,是 KPI 卡片的基礎元件。

輸入:

  • name:由一或多個指標名稱組成的陣列。
  • aggregation'sum' | 'avg' | 'min' | 'max' | 'count' | 'count_distinct' | 'last' 之一。
  • filters:選用的篩選器物件
  • comparePeriod:選用的 'previous_period' | 'previous_day' | 'previous_week',用於逐期比較。

回應:

  • valuepreviousValuechangePercent
  • token 指標會包含 estimatedCostcostUnitpreviousEstimatedCostcostChangePercent
src/mastra/tools/token-cost-tool.ts
const observability = await mastra.getStorage()!.getStore('observability')

const cost = await observability!.getMetricAggregate({
name: ['mastra_model_total_input_tokens', 'mastra_model_total_output_tokens'],
aggregation: 'sum',
comparePeriod: 'previous_day',
})

console.log(cost.value, cost.estimatedCost, cost.costUnit, cost.changePercent)

getMetricBreakdown
「getmetricbreakdown」的直接連結

依一或多個維度將資料列分組,並彙總每個群組,是前 N 名表格(例如「各 Agent 的 token 數」)的基礎元件。

輸入:

  • name:指標名稱陣列。
  • groupBy:作為分組依據的欄位陣列(例如 ['entityName'])。
  • aggregation:與上述相同的列舉值。
  • limit:伺服器端的前 K 名上限。高基數 groupBy 必須提供此值。
  • orderDirection'ASC' | 'DESC'(預設為 DESC)。
  • filters:選用。

回應:groups[],每個群組包含 dimensions(群組鍵值的記錄)、valueestimatedCost

const byAgent = await observability!.getMetricBreakdown({
name: ['mastra_model_total_input_tokens'],
groupBy: ['entityName'],
aggregation: 'sum',
limit: 10,
orderDirection: 'DESC',
})

getMetricTimeSeries
「getmetrictimeseries」的直接連結

依固定間隔將值分桶,是折線圖及長條圖的基礎元件。

輸入:

  • name:指標名稱陣列。
  • interval'1m' | '5m' | '15m' | '1h' | '1d' 之一。
  • aggregation:相同的列舉值。
  • groupBy:選用。省略時,多個指標名稱會加總為一個序列。若要分開保留,請為每個指標各呼叫一次。
  • filters:選用。

回應:series[],每個序列包含 namecostUnit,以及由 { timestamp, value, estimatedCost } 組成的 points[]

const inputTokens = await observability!.getMetricTimeSeries({
name: ['mastra_model_total_input_tokens'],
aggregation: 'sum',
interval: '1h',
filters: {
timestamp: { start: new Date(Date.now() - 24 * 60 * 60 * 1000) },
},
})

getMetricPercentiles
「getmetricpercentiles」的直接連結

回傳依時間分桶的百分位數值,是延遲圖表的基礎元件。

輸入:

  • name:單一指標名稱(字串,而非陣列)。
  • percentiles:介於 01 之間的數字陣列,例如 [0.5, 0.95, 0.99]
  • interval:與 getMetricTimeSeries 相同的列舉值。
  • filters:選用。

回應:series[],每個序列包含 percentile,以及由 { timestamp, value } 組成的 points[]

const latency = await observability!.getMetricPercentiles({
name: 'mastra_agent_duration_ms',
percentiles: [0.5, 0.95],
interval: '1h',
})

探索
「探索」的直接連結

使用這些端點填入下拉式選單,或向 Agent 提供可用於篩選的值清單。所有探索路由皆為 GET,並位於 /api/observability/discovery/ 下。

指標專用(也以 mastra api metric 子命令提供):

方法引數路徑後綴CLI
getMetricNames{ prefix?, limit? }metric-namesmastra api metric names
getMetricLabelKeys{ metricName }metric-label-keysmastra api metric label-keys
getMetricLabelValues{ metricName, labelKey, prefix?, limit? }metric-label-valuesmastra api metric label-values

與 Trace 及記錄共用(僅限 HTTP,沒有專用 CLI 子命令):

方法引數路徑後綴
getEntityTypes{}entity-types
getEntityNames{ entityType? }entity-names
getServiceNames{}service-names
getEnvironments{}environments
getTags{ entityType? }tags

篩選
「篩選」的直接連結

每項查詢都接受相同的 filters 物件。最實用的欄位如下:

  • name:限制為特定指標名稱。(最上層的 name 已會對彙總、細分及時間序列執行此限制。若要在單一查詢中混合多個指標,請使用 filters.name。)
  • timestamp{ start, end, startExclusive, endExclusive }。兩個邊界皆為選用。省略 end 代表「直到現在」。
  • providermodelcostUnit:適用於 token 與成本指標。
  • labels:精確比對指標標籤的鍵值,例如期間指標可使用 { status: 'error' }
  • 關聯欄位:entityTypeentityNameparentEntityNamerootEntityNameuserIdorganizationIdresourceIdrunIdsessionIdthreadIdrequestIdexecutionSourceenvironmentserviceNameexperimentIdtags

相同的 filters 格式適用於全部三種介面:

// In-process
await observability!.getMetricAggregate({
name: ['mastra_tool_duration_ms'],
aggregation: 'avg',
filters: { entityName: 'weatherTool', labels: { status: 'error' } },
})
# CLI
mastra api metric aggregate \
'{"name":["mastra_tool_duration_ms"],"aggregation":"avg","filters":{"entityName":"weatherTool","labels":{"status":"error"}}}' \
--url http://localhost:4111
# HTTP
curl -sS -X POST http://localhost:4111/api/observability/metrics/aggregate \
-H "content-type: application/json" \
-d '{"name":["mastra_tool_duration_ms"],"aggregation":"avg","filters":{"entityName":"weatherTool","labels":{"status":"error"}}}'

一律提供時間範圍
「一律提供時間範圍」的直接連結

filters.timestamp 是選用欄位,但對正式環境儲存區執行的任何查詢,都應將它視為必填欄位。可觀測性資料表通常依事件時間分割(TimescaleDB 則會分塊)。提供 timestamp.start(理想情況下也提供 end)時,後端可排除不與範圍重疊的分割區,通常只需存取一或兩個分割區。若未提供時間範圍,規劃器就必須掃描每個分割區;保留一年的資料可能產生數百個區段,這也是由 Postgres 支援的儲存區中,OLAP 查詢緩慢最常見的原因。

臨時查詢可安全地預設為過去 24 小時;警示與儀表板則應符合實際的評估時間範圍:

await observability!.getMetricAggregate({
name: ['mastra_agent_duration_ms'],
aggregation: 'p95',
filters: {
timestamp: { start: new Date(Date.now() - 24 * 60 * 60 * 1000) },
},
})

此指引適用於所有後端(ClickHouse、Postgres v-next、DuckDB),但對 Postgres v-next 最為重要,因為每缺少一個時間邊界,就會直接多掃描一個分割區。

範例:建立自訂 KPI 圖塊
「範例:建立自訂 KPI 圖塊」的直接連結

以下 Tool 會回傳過去一小時的輸入 token 數量與預估成本。Agent 或儀表板可透過 structuredContent 呼叫它,而不必重新實作查詢。

src/mastra/tools/token-kpi-tool.ts
import { createTool } from '@mastra/core/tools'
import { z } from 'zod'

export const tokenKpiTool = createTool({
id: 'tokenKpi',
description: 'Returns input-token volume and estimated cost for the last hour.',
inputSchema: z.object({}),
outputSchema: z.object({
inputTokens: z.number().nullable(),
estimatedCost: z.number().nullable(),
costUnit: z.string().nullable(),
changePercent: z.number().nullable(),
}),
execute: async (_input, context) => {
const observability = await context.mastra!.getStorage()!.getStore('observability')
if (!observability) {
throw new Error('Observability domain is not configured (requires DuckDB or ClickHouse)')
}

const result = await observability.getMetricAggregate({
name: ['mastra_model_total_input_tokens'],
aggregation: 'sum',
filters: {
timestamp: { start: new Date(Date.now() - 60 * 60 * 1000) },
},
comparePeriod: 'previous_period',
})

return {
inputTokens: result.value,
estimatedCost: result.estimatedCost ?? null,
costUnit: result.costUnit ?? null,
changePercent: result.changePercent ?? null,
}
},
})