跳至主要內容

自訂模型 Gateway

自訂模型 Gateway 可讓你透過 MastraModelGatewayInterface 介面或 MastraModelGateway 基礎類別,實作私有或專用的 LLM Provider 整合。

概覽
「概覽」的直接連結

Gateway 會處理存取語言模型時各 Provider 專屬的邏輯:

  • Provider 設定與模型探索
  • 驗證與 API 金鑰管理
  • 建構 API 端點 URL
  • 建立語言模型執行個體

建立自訂 Gateway 以支援:

  • 私有或企業 LLM 部署
  • 自訂驗證機制
  • 專用路由邏輯
  • 使用唯一 ID 管理 Gateway 版本

建立自訂 Gateway
「建立自訂 Gateway」的直接連結

若要建立純物件 Gateway,請實作 MastraModelGatewayInterface;若要使用基礎類別的預設值,則擴充 MastraModelGateway

import { type MastraModelGatewayInterface, type ProviderConfig } from '@mastra/core/llm'
import { createOpenAICompatible } from '@ai-sdk/openai-compatible-v5'

const myPrivateGateway: MastraModelGatewayInterface = {
id: 'private',
name: 'My Private Gateway',
async fetchProviders(): Promise<Record<string, ProviderConfig>> {
return {
'my-provider': {
name: 'My Provider',
models: ['openai/gpt-5.6-sol'],
apiKeyEnvVar: 'MY_API_KEY',
gateway: 'private',
url: 'https://api.myprovider.com/v1',
},
}
},
buildUrl() {
return 'https://api.myprovider.com/v1'
},
async getApiKey() {
return process.env.MY_API_KEY ?? ''
},
async resolveLanguageModel({ modelId, providerId, apiKey }) {
return createOpenAICompatible({
name: providerId,
apiKey,
baseURL: 'https://api.myprovider.com/v1',
}).chatModel(modelId)
},
}

以下範例擴充 MastraModelGateway 類別:

import { MastraModelGateway, type ProviderConfig } from '@mastra/core/llm'
import { createOpenAICompatible } from '@ai-sdk/openai-compatible-v5'
import type { LanguageModelV2 } from '@ai-sdk/provider-v5'

class MyPrivateGateway extends MastraModelGateway {
// Required: Unique identifier for the gateway
// This ID is used as the prefix for all providers from this gateway
readonly id = 'private'

// Required: Human-readable name
readonly name = 'My Private Gateway'

/**
* Fetch provider configurations from your gateway
* Returns a record of provider configurations
*/
async fetchProviders(): Promise<Record<string, ProviderConfig>> {
return {
'my-provider': {
name: 'My Provider',
models: ['openai/gpt-5.6-sol', 'anthropic/claude-sonnet-4-6'],
apiKeyEnvVar: 'MY_API_KEY',
gateway: this.id,
url: 'https://api.myprovider.com/v1',
},
}
}

/**
* Build the API URL for a model
* @param modelId - Full model ID (e.g., "private/my-provider/model-1")
* @param envVars - Environment variables (optional)
*/
buildUrl(modelId: string, envVars?: Record<string, string>): string {
return 'https://api.myprovider.com/v1'
}

/**
* Get the API key for authentication
* @param modelId - Full model ID
*/
async getApiKey(modelId: string): Promise<string> {
const apiKey = process.env.MY_API_KEY
if (!apiKey) {
throw new Error(`Missing MY_API_KEY environment variable`)
}
return apiKey
}

/**
* Create a language model instance
* @param args - Model ID, provider ID, and API key
*/
async resolveLanguageModel({
modelId,
providerId,
apiKey,
}: {
modelId: string
providerId: string
apiKey: string
}): Promise<LanguageModelV2> {
const baseURL = this.buildUrl(`${providerId}/${modelId}`)

return createOpenAICompatible({
name: providerId,
apiKey,
baseURL,
supportsStructuredOutputs: true,
}).chatModel(modelId)
}
}

Gateway 自有驗證
「Gateway 自有驗證」的直接連結

當 Gateway 負責查找憑證時,請新增 resolveAuth。Mastra 會先使用此 hook,再退回使用 getApiKey()

const myPrivateGateway: MastraModelGatewayInterface = {
// ...gateway fields and methods
async resolveAuth() {
const apiKey = process.env.MY_API_KEY
return apiKey ? { apiKey, source: 'gateway' } : undefined
},
}

註冊自訂 Gateway
「註冊自訂 Gateway」的直接連結

初始化期間
「初始化期間」的直接連結

建立 Mastra 執行個體時,以 record 傳入 Gateway:

import { Mastra } from '@mastra/core'

const mastra = new Mastra({
gateways: {
myGateway: new MyPrivateGateway(),
anotherGateway: new AnotherGateway(),
},
})

初始化之後
「初始化之後」的直接連結

使用 addGateway 動態新增 Gateway:

const mastra = new Mastra()

// Add with explicit key
mastra.addGateway(new MyPrivateGateway(), 'myGateway')

// Add using gateway's ID
mastra.addGateway(new MyPrivateGateway())
// Stored with key 'my-private-gateway' (the gateway's id)

使用自訂 Gateway
「使用自訂 Gateway」的直接連結

使用 Gateway ID 作為前綴,參照自訂 Gateway 中的模型:

import { Agent } from '@mastra/core/agent'

const agent = new Agent({
id: 'my-agent',
name: 'My Agent',
instructions: 'You are a helpful assistant',
model: 'private/my-provider/openai/gpt-5.6-sol', // Uses MyPrivateGateway
})

mastra.addAgent(agent, 'myAgent')

建立 Agent 或使用模型時,Mastra 的模型路由器會根據模型 ID 自動選取適合的 Gateway。Gateway ID 會作為前綴。若沒有符合的自訂 Gateway,便會退回使用內建 Gateway。

TypeScript 自動完成
「TypeScript 自動完成」的直接連結

在開發環境中自動產生型別
「在開發環境中自動產生型別」的直接連結

以開發模式執行時(MASTRA_DEV=true),Mastra 會自動為自訂 Gateway 產生 TypeScript 型別。

  1. 設定環境變數

    export MASTRA_DEV=true
  2. 註冊 Gateway

    const mastra = new Mastra({
    gateways: {
    myGateway: new MyPrivateGateway(),
    },
    })
  3. 自動產生型別

    • 新增 Gateway 時,Mastra 會與 GatewayRegistry 同步
    • Registry 會從自訂 Gateway 擷取 Provider
    • TypeScript 型別會在 ~/.cache/mastra/ 中重新產生
    • IDE 會在數秒內取得新型別
  4. 現在可使用自動完成功能

    const agent = new Agent({
    model: 'my-gateway-id/my-provider/model-1', // Full autocomplete!
    })

運作方式
「運作方式」的直接連結

GatewayRegistry 每小時會執行一次同步:

  • 對所有已註冊的 Gateway 呼叫 fetchProviders()
  • 產生 TypeScript 型別定義
  • 將型別寫入全域快取與專案的 dist/ 目錄
  • TypeScript 伺服器會自動取得變更
提示

第一次新增 Gateway 時,可能需要幾秒鐘才能產生型別。後續更新會每小時在背景執行。

手動產生型別的替代方案
「手動產生型別的替代方案」的直接連結

如果未使用開發模式,或需要立即更新型別:

選項 1:使用型別斷言(最簡單)

const agent = new Agent({
id: 'my-agent',
name: 'my-agent',
instructions: 'You are a helpful assistant',
model: 'private/my-provider/model-1' as any, // Bypass type checking
})

選項 2:建立自訂聯集型別(型別安全)

import type { ModelRouterModelId } from '@mastra/core/llm'

// Define your custom model IDs
type CustomModelId =
| 'private/my-provider/model-1'
| 'private/my-provider/model-2'
| 'private/my-provider/model-3'

// Combine with built-in models
type AllModelIds = ModelRouterModelId | CustomModelId

const agent = new Agent({
id: 'my-agent',
name: 'my-agent',
instructions: 'You are a helpful assistant',
model: 'private/my-provider/model-1' satisfies AllModelIds,
})

選項 3:全域擴充 ModelRouterModelId(進階)

// In a types.d.ts file in your project
// The import is required: it makes this file a module, so the block below
// merges into the existing types instead of replacing the module.
import '@mastra/core/llm'

declare module '@mastra/core/llm' {
interface ProviderModelsMap {
'my-provider': readonly ['model-1', 'model-2', 'model-3']
}
}

這會擴充內建型別以納入自訂模型,提供完整的自動完成支援。

Gateway 管理
「Gateway 管理」的直接連結

getGateway(key)
「getGateway(key)」的直接連結

依註冊 key 取得 Gateway:

const gateway = mastra.getGateway('myGateway')
console.log(gateway.name) // 'My Private Gateway'

getGatewayById(id)
「getGatewayById(id)」的直接連結

依唯一 ID 取得 Gateway:

const gateway = mastra.getGatewayById('my-private-gateway')
console.log(gateway.name) // 'My Private Gateway'

這適用於:

  • Gateway 的明確 ID 與註冊 key 不同
  • 需要跨不同執行個體,依 ID 尋找 Gateway
  • 支援 Gateway 版本管理(例如 'gateway-v1''gateway-v2'

listGateways()
「listGateways()」的直接連結

取得所有已註冊的 Gateway:

const gateways = mastra.listGateways()
console.log(Object.keys(gateways)) // ['myGateway', 'anotherGateway']

Gateway 屬性
「Gateway 屬性」的直接連結

必要屬性
「必要屬性」的直接連結

屬性型別說明
idstringGateway 的唯一識別碼,用作模型字串的 Gateway 前綴
namestring易讀的 Gateway 名稱

方法
「方法」的直接連結

方法說明
fetchProviders()擷取 Provider 設定
buildUrl(modelId, envVars?)為模型建構 API URL
getApiKey(modelId)取得用於驗證的 API 金鑰
resolveLanguageModel(args)建立語言模型執行個體
getId()取得 Gateway ID(傳回 idname

Provider 設定
「Provider 設定」的直接連結

fetchProviders() 方法會傳回由 ProviderConfig 物件組成的 record:

interface ProviderConfig {
name: string // Display name
models: string[] // Available model IDs
apiKeyEnvVar: string | string[] // Environment variable(s) for API key
gateway: string // Gateway identifier
url?: string // Optional API base URL
apiKeyHeader?: string // Optional custom auth header
docUrl?: string // Optional documentation URL
}

Gateway ID 與 key 的差異
「Gateway ID 與 key 的差異」的直接連結

兩者的差異如下:

  • Key:將 Gateway 新增至 Mastra 時使用的註冊 key(record key)
  • ID:Gateway 的唯一識別碼(透過 id 屬性;若未設定,則使用 name
class VersionedGateway extends MastraModelGateway {
readonly id = 'my-gateway-v2' // Unique ID for versioning and prefixing
readonly name = 'My Gateway' // Display name
}

const mastra = new Mastra({
gateways: {
currentGateway: new VersionedGateway(), // Key: 'currentGateway'
},
})

// Retrieve by key
const byKey = mastra.getGateway('currentGateway')

// Retrieve by ID
const byId = mastra.getGatewayById('my-gateway-v2')

// Both return the same gateway
console.log(byKey === byId) // true

模型 ID 格式
「模型 ID 格式」的直接連結

透過自訂 Gateway 存取的模型會遵循以下格式:

[gatewayId]/[provider]/[model]

範例:

  • private/my-provider/model-1

進階範例
「進階範例」的直接連結

具備快取功能的 token 型 Gateway:

class TokenGateway extends MastraModelGateway {
readonly id = 'token-gateway-v1'
readonly name = 'Token Gateway'

private tokenCache: Map<string, { token: string; expiresAt: number }> = new Map()

async fetchProviders(): Promise<Record<string, ProviderConfig>> {
const response = await fetch('https://api.gateway.com/providers')
const data = await response.json()

return {
provider: {
name: data.name,
models: data.models,
apiKeyEnvVar: 'GATEWAY_TOKEN',
gateway: this.id,
},
}
}

async buildUrl(modelId: string, envVars?: Record<string, string>): Promise<string> {
const token = await this.getApiKey(modelId)
const siteId = envVars?.SITE_ID || process.env.SITE_ID

const response = await fetch(`https://api.gateway.com/sites/${siteId}/token`, {
headers: { Authorization: `Bearer ${token}` },
})

const { url } = await response.json()
return url
}

async getApiKey(modelId: string): Promise<string> {
const cached = this.tokenCache.get(modelId)

if (cached && cached.expiresAt > Date.now()) {
return cached.token
}

const token = process.env.GATEWAY_TOKEN
if (!token) {
throw new Error('Missing GATEWAY_TOKEN')
}

// Cache token for 1 hour
this.tokenCache.set(modelId, {
token,
expiresAt: Date.now() + 3600000,
})

return token
}

async resolveLanguageModel({
modelId,
providerId,
apiKey,
}: {
modelId: string
providerId: string
apiKey: string
}): Promise<LanguageModelV2> {
const baseURL = await this.buildUrl(`${providerId}/${modelId}`)

return createOpenAICompatible({
name: providerId,
apiKey,
baseURL,
supportsStructuredOutputs: true,
}).chatModel(modelId)
}
}

錯誤處理
「錯誤處理」的直接連結

針對常見失敗情境提供具體的錯誤訊息:

class RobustGateway extends MastraModelGateway {
// ... properties

async getApiKey(modelId: string): Promise<string> {
const apiKey = process.env.MY_API_KEY

if (!apiKey) {
throw new Error(
`Missing MY_API_KEY environment variable for model: ${modelId}. ` +
`Please set MY_API_KEY in your environment.`,
)
}

return apiKey
}

async buildUrl(modelId: string, envVars?: Record<string, string>): Promise<string> {
const baseUrl = envVars?.BASE_URL || process.env.BASE_URL

if (!baseUrl) {
throw new Error(
`No base URL configured for model: ${modelId}. ` +
`Set BASE_URL environment variable or pass it in envVars.`,
)
}

return baseUrl
}
}

測試自訂 Gateway
「測試自訂 Gateway」的直接連結

測試結構範例:

import { describe, it, expect, beforeEach } from 'vitest'
import { Mastra } from '@mastra/core'

describe('MyPrivateGateway', () => {
beforeEach(() => {
process.env.MY_API_KEY = 'test-key'
})

it('should fetch providers', async () => {
const gateway = new MyPrivateGateway()
const providers = await gateway.fetchProviders()

expect(providers['my-provider']).toBeDefined()
expect(providers['my-provider'].models).toContain('model-1')
})

it('should integrate with Mastra', () => {
const mastra = new Mastra({
gateways: {
private: new MyPrivateGateway(),
},
})

const gateway = mastra.getGateway('private')
expect(gateway.name).toBe('My Private Gateway')
})

it('should resolve models by ID', () => {
const mastra = new Mastra({
gateways: {
key: new MyPrivateGateway(),
},
})

const gateway = mastra.getGatewayById('my-private-gateway')
expect(gateway).toBeDefined()
})
})

最佳實務
「最佳實務」的直接連結

  1. 使用具體 ID 管理版本:需要管理 Gateway 版本時,請設定明確的 id

    readonly id = 'my-gateway-v1';
  2. 實作適當的錯誤處理:擲出具體且可據以採取行動的錯誤訊息

  3. 快取成本高昂的作業:適時快取 token、URL 或 Provider 設定

  4. 驗證環境變數:在 getApiKeybuildUrl 中檢查必要的環境變數

  5. 為 Gateway 撰寫文件:新增 JSDoc 註解,說明 Gateway 的用途與設定

  6. 遵循命名慣例:為 Provider 與模型採用清楚、一致的命名

  7. 處理非同步作業:使用 async/await 處理網路要求與 I/O 作業

  8. 完整測試:為所有 Gateway 方法撰寫單元測試

在 Studio 中只顯示自訂 Gateway
「在 Studio 中只顯示自訂 Gateway」的直接連結

根據預設,Studio 會列出所有外部模型 Provider(例如 OpenAI、Anthropic 與 Gemini),以及你註冊的所有自訂 Gateway。若要隱藏外部 Provider,請設定 AUTO_BLOCK_EXTERNAL_PROVIDERS 環境變數:

AUTO_BLOCK_EXTERNAL_PROVIDERS=true

此變數設為 true1 時,Mastra 只會傳回你自行註冊之 Gateway 中的 Provider。靜態 Provider Registry 與內建 Gateway(models.devnetlifymastra)都會從模型選擇器中隱藏。若所有模型流量都透過單一私有 Gateway 路由,而且不希望顯示其他 Provider,這項設定會很有用。

設定此變數且未註冊任何自訂 Gateway 時,模型選擇器會是空的。請至少註冊一個自訂 Gateway,才會顯示其中的模型。

內建 Gateway
「內建 Gateway」的直接連結

Mastra 包含下列內建 Gateway,作為參考實作:

  • NetlifyGateway:整合支援 token 交換的 Netlify AI Gateway
  • ModelsDevGateway:models.dev 中相容於 OpenAI 的 Provider Registry

如需 Gateway 使用方式的範例,請參閱 NetlifyOpenRouterVercel