> Discover all available pages from the documentation index: https://mastra.zisheng.pro/llms.txt # 自定义模型 Gateway 自定义模型 Gateway 允许你通过 `MastraModelGatewayInterface` 接口或 `MastraModelGateway` 基类,实现私有或专用 LLM Provider 集成。 ## 概述 Gateway 负责处理访问语言模型时与 Provider 相关的逻辑: - Provider 配置和模型发现 - 认证和 API key 管理 - 构造 API endpoint URL - 创建语言模型实例 可以创建自定义 Gateway 来支持: - 私有或企业级 LLM 部署 - 自定义认证方案 - 专用路由逻辑 - 使用唯一 ID 的 Gateway 版本管理 ## 创建自定义 Gateway 如果使用普通对象 Gateway,请实现 `MastraModelGatewayInterface`;如果需要基类的默认行为,请扩展 `MastraModelGateway`。 ```typescript 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> { 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` 类: ```typescript 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> { 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 { return 'https://api.myprovider.com/v1' } /** * Get the API key for authentication * @param modelId - Full model ID */ async getApiKey(modelId: string): Promise { 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 { const baseURL = this.buildUrl(`${providerId}/${modelId}`) return createOpenAICompatible({ name: providerId, apiKey, baseURL, supportsStructuredOutputs: true, }).chatModel(modelId) } } ``` ### Gateway 自主管理认证 当凭据查询由 Gateway 管理时,请添加 `resolveAuth`。Mastra 会先调用此 hook,再 fallback 到 `getApiKey()`。 ```typescript const myPrivateGateway: MastraModelGatewayInterface = { // ...gateway fields and methods async resolveAuth() { const apiKey = process.env.MY_API_KEY return apiKey ? { apiKey, source: 'gateway' } : undefined }, } ``` ## 注册自定义 Gateway ### 初始化时注册 创建 Mastra 实例时,以 record 形式传入 Gateway: ```typescript import { Mastra } from '@mastra/core' const mastra = new Mastra({ gateways: { myGateway: new MyPrivateGateway(), anotherGateway: new AnotherGateway(), }, }) ``` ### 初始化后注册 使用 `addGateway` 动态添加 Gateway: ```typescript 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 ID 作为前缀,引用自定义 Gateway 中的模型: ```typescript 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,则 fallback 到内置 Gateway。 ### TypeScript 自动补全 #### 在开发环境中自动生成类型 在开发模式(`MASTRA_DEV=true`)下运行时,Mastra 会自动为自定义 Gateway 生成 TypeScript 类型。 1. **设置环境变量**: ```bash export MASTRA_DEV=true ``` 2. **注册 Gateway**: ```typescript const mastra = new Mastra({ gateways: { myGateway: new MyPrivateGateway(), }, }) ``` 3. **自动生成类型**: - 添加 Gateway 时,Mastra 会与 GatewayRegistry 同步 - registry 从自定义 Gateway 获取 Provider - 在 `~/.cache/mastra/` 中重新生成 TypeScript 类型 - IDE 会在数秒内识别新类型 4. **开始使用自动补全**: ```typescript const agent = new Agent({ model: 'my-gateway-id/my-provider/model-1', // Full autocomplete! }) ``` #### 工作原理 GatewayRegistry 每小时同步一次,并执行以下操作: - 对所有已注册 Gateway 调用 `fetchProviders()` - 生成 TypeScript 类型定义 - 将类型写入全局 cache 和项目的 `dist/` 目录 - TypeScript Server 自动识别变更 > **提示:** 第一次添加 Gateway 时,类型生成可能需要几秒钟。后续更新每小时在后台进行一次。 #### 手动生成类型的替代方案 如果未在开发模式下运行,或者需要立即更新类型: **方案 1:使用类型断言(最简单)** ```typescript 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:创建自定义联合类型(类型安全)** ```typescript 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(高级)** ```typescript // 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 管理 ### getGateway(key) 通过注册 key 获取 Gateway: ```typescript const gateway = mastra.getGateway('myGateway') console.log(gateway.name) // 'My Private Gateway' ``` ### getGatewayById(id) 通过唯一 ID 获取 Gateway: ```typescript 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() 获取所有已注册的 Gateway: ```typescript const gateways = mastra.listGateways() console.log(Object.keys(gateways)) // ['myGateway', 'anotherGateway'] ``` ## Gateway 属性 ### 必需属性 | 属性 | 类型 | 描述 | | ------ | -------- | ---------------------------------- | | `id` | `string` | Gateway 的唯一标识符,用作模型字符串的 Gateway 前缀 | | `name` | `string` | 便于阅读的 Gateway 名称 | ### 方法 | 方法 | 描述 | | ----------------------------- | ------------------------------- | | `fetchProviders()` | 获取 Provider 配置 | | `buildUrl(modelId, envVars?)` | 为模型构造 API URL | | `getApiKey(modelId)` | 获取用于认证的 API key | | `resolveLanguageModel(args)` | 创建语言模型实例 | | `getId()` | 获取 Gateway ID(返回 `id` 或 `name`) | ## Provider 配置 `fetchProviders()` 方法返回由 `ProviderConfig` 对象组成的 record: ```typescript 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 的区别 二者的区别如下: - **Key**:将 Gateway 添加到 Mastra 时使用的注册 key(record key) - **ID**:Gateway 的唯一标识符(来自 `id` 属性;未设置时使用 `name`) ```typescript 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 格式 通过自定义 Gateway 访问的模型遵循以下格式: ```text [gatewayId]/[provider]/[model] ``` 示例: - `private/my-provider/model-1` ## 高级示例 带 cache 的 token Gateway: ```typescript class TokenGateway extends MastraModelGateway { readonly id = 'token-gateway-v1' readonly name = 'Token Gateway' private tokenCache: Map = new Map() async fetchProviders(): Promise> { 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): Promise { 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 { 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 { const baseURL = await this.buildUrl(`${providerId}/${modelId}`) return createOpenAICompatible({ name: providerId, apiKey, baseURL, supportsStructuredOutputs: true, }).chatModel(modelId) } } ``` ## 错误处理 为常见失败场景提供清晰的错误信息: ```typescript class RobustGateway extends MastraModelGateway { // ... properties async getApiKey(modelId: string): Promise { 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): Promise { 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 测试结构示例: ```typescript 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` ```typescript readonly id = 'my-gateway-v1'; ``` 2. **实现恰当的错误处理**:抛出描述清晰且提供解决办法的错误 3. **缓存高开销操作**:在适当情况下缓存 token、URL 或 Provider 配置 4. **验证环境变量**:在 `getApiKey` 和 `buildUrl` 中检查必需的环境变量 5. **编写 Gateway 文档**:添加 JSDoc 注释,说明 Gateway 的用途和配置 6. **遵循命名约定**:为 Provider 和模型采用清晰一致的命名 7. **处理异步操作**:网络请求和 I/O 操作使用 `async/await` 8. **充分测试**:为所有 Gateway 方法编写单元测试 ## 在 Studio 中仅显示自定义 Gateway 默认情况下,**Studio** 会列出所有外部模型 Provider(例如 OpenAI、Anthropic 和 Gemini)以及已注册的自定义 Gateway。如需隐藏外部 Provider,请设置 `AUTO_BLOCK_EXTERNAL_PROVIDERS` 环境变量: ```bash AUTO_BLOCK_EXTERNAL_PROVIDERS=true ``` 当此变量设为 `true` 或 `1` 时,Mastra 只返回自行注册的 Gateway 所提供的 Provider。静态 Provider registry 和内置 Gateway(`models.dev`、`netlify` 和 `mastra`)会从模型选择器中隐藏。当所有模型流量都通过单个私有 Gateway 路由,并且不希望显示其他 Provider 时,这一设置很有用。 设置此变量后,如果未注册任何自定义 Gateway,模型选择器将为空。请至少注册一个自定义 Gateway 以显示其模型。 ## 内置 Gateway Mastra 提供以下内置 Gateway 作为参考实现: - **NetlifyGateway**:集成 token exchange 的 Netlify AI Gateway - **ModelsDevGateway**:来自 models.dev 的 OpenAI 兼容 Provider registry Gateway 用法示例请参阅 [Netlify](https://mastra.zisheng.pro/models/gateways/netlify)、[OpenRouter](https://mastra.zisheng.pro/models/gateways/openrouter) 和 [Vercel](https://mastra.zisheng.pro/models/gateways/vercel)。