Aller au contenu principal

Passerelles de modèles personnalisées

Les passerelles de modèles personnalisées permettent d’implémenter des intégrations LLM privées ou spécialisées avec l’interface MastraModelGatewayInterface ou la classe de base MastraModelGateway.

Vue d’ensemble
Lien direct vers Vue d’ensemble

Les passerelles gèrent la logique propre aux Providers pour accéder aux modèles de langage :

  • Configuration des Providers et découverte des modèles
  • Authentification et gestion des clés API
  • Construction des URL des points de terminaison d’API
  • Création d’instances de modèles de langage

Créez des passerelles personnalisées pour prendre en charge :

  • Déploiements LLM privés ou d’entreprise
  • Mécanismes d’authentification personnalisés
  • Logique de routage spécialisée
  • Gestion des versions des passerelles avec des ID uniques

Créer une passerelle personnalisée
Lien direct vers Créer une passerelle personnalisée

Implémentez MastraModelGatewayInterface pour une passerelle sous forme d’objet simple, ou étendez MastraModelGateway lorsque vous souhaitez les valeurs par défaut de la classe de base.

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);
},
};

L’exemple suivant étend la classe 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);
}
}

Authentification gérée par la passerelle
Lien direct vers Authentification gérée par la passerelle

Ajoutez resolveAuth lorsque la passerelle gère la recherche des identifiants. Mastra utilise ce hook avant de recourir à getApiKey().

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

Enregistrer des passerelles personnalisées
Lien direct vers Enregistrer des passerelles personnalisées

Lors de l’initialisation
Lien direct vers Lors de l’initialisation

Transmettez les passerelles sous forme d’enregistrement lors de la création de votre instance Mastra :

import { Mastra } from '@mastra/core';

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

Après l’initialisation
Lien direct vers Après l’initialisation

Ajoutez des passerelles dynamiquement avec addGateway :

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)

Utiliser des passerelles personnalisées
Lien direct vers Utiliser des passerelles personnalisées

Référencez les modèles de votre passerelle personnalisée en utilisant l’ID de la passerelle comme préfixe :

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');

Lorsque vous créez un Agent ou utilisez un modèle, le routeur de modèles de Mastra sélectionne automatiquement la passerelle appropriée selon l’ID du modèle. L’ID de la passerelle sert de préfixe. Si aucune passerelle personnalisée ne correspond, il revient aux passerelles intégrées.

Autocomplétion TypeScript
Lien direct vers Autocomplétion TypeScript

Génération automatique des types en développement
Lien direct vers Génération automatique des types en développement

En mode développement (MASTRA_DEV=true), Mastra génère automatiquement les types TypeScript de vos passerelles personnalisées.

  1. Définissez la variable d’environnement :

    export MASTRA_DEV=true
  2. Enregistrez vos passerelles :

    const mastra = new Mastra({
    gateways: {
    myGateway: new MyPrivateGateway(),
    },
    });
  3. Les types sont générés automatiquement :

    • Lorsque vous ajoutez une passerelle, Mastra se synchronise avec le GatewayRegistry
    • Le registre récupère les Providers depuis votre passerelle personnalisée
    • Les types TypeScript sont régénérés dans ~/.cache/mastra/
    • Votre IDE détecte les nouveaux types en quelques secondes
  4. L’autocomplétion fonctionne désormais :

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

Fonctionnement
Lien direct vers Fonctionnement

Le GatewayRegistry exécute une synchronisation horaire qui :

  • appelle fetchProviders() sur toutes les passerelles enregistrées ;
  • génère les définitions de types TypeScript ;
  • les écrit dans le cache global et dans le répertoire dist/ de votre projet ;
  • permet à votre serveur TypeScript de détecter automatiquement les modifications.
astuce

La première fois que vous ajoutez une passerelle, la génération des types peut prendre quelques secondes. Les mises à jour suivantes sont effectuées en arrière-plan toutes les heures.

Autres méthodes de génération manuelle des types
Lien direct vers Autres méthodes de génération manuelle des types

Si vous n’exécutez pas le mode développement ou avez besoin de mises à jour immédiates des types :

Option 1 : utiliser une assertion de type (méthode la plus simple)

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
});

Option 2 : créer une union de types personnalisée (avec sûreté des types)

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,
});

Option 3 : étendre ModelRouterModelId globalement (avancé)

// 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'];
}
}

Cela étend le type intégré pour inclure vos modèles personnalisés et vous offre une prise en charge complète de l’autocomplétion.

Gestion des passerelles
Lien direct vers Gestion des passerelles

getGateway(key)
Lien direct vers getGateway(key)

Récupérez une passerelle par sa clé d’enregistrement :

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

getGatewayById(id)
Lien direct vers getGatewayById(id)

Récupérez une passerelle par son ID unique :

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

Cela est utile lorsque :

  • les passerelles possèdent des ID explicites différents de leurs clés d’enregistrement ;
  • vous devez rechercher une passerelle par son ID parmi différentes instances ;
  • vous prenez en charge la gestion des versions des passerelles (par exemple, 'gateway-v1', 'gateway-v2').

listGateways()
Lien direct vers listGateways()

Obtenez toutes les passerelles enregistrées :

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

Propriétés de la passerelle
Lien direct vers Propriétés de la passerelle

Obligatoire
Lien direct vers Obligatoire

PropriétéTypeDescription
idstringIdentifiant unique de la passerelle, utilisé comme préfixe de passerelle dans la chaîne du modèle
namestringNom lisible de la passerelle

Méthodes
Lien direct vers Méthodes

MéthodeDescription
fetchProviders()Récupère les configurations des Providers
buildUrl(modelId, envVars?)Construit l’URL d’API d’un modèle
getApiKey(modelId)Obtient la clé API d’authentification
resolveLanguageModel(args)Crée une instance de modèle de langage
getId()Obtient l’ID de la passerelle (renvoie id ou name)

Configuration du Provider
Lien direct vers Configuration du Provider

La méthode fetchProviders() renvoie un enregistrement d’objets ProviderConfig :

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
}

ID et clés de passerelle
Lien direct vers ID et clés de passerelle

Comprendre la distinction :

  • Clé : clé d’enregistrement utilisée lors de l’ajout de la passerelle à Mastra (clé de l’enregistrement)
  • ID : identifiant unique de la passerelle (via la propriété id, ou name si elle n’est pas définie)
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

Format de l’ID de modèle
Lien direct vers Format de l’ID de modèle

Les modèles accessibles via des passerelles personnalisées suivent ce format :

[gatewayId]/[provider]/[model]

Exemples :

  • private/my-provider/model-1

Exemple avancé
Lien direct vers Exemple avancé

Passerelle fondée sur des jetons avec cache :

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);
}
}

Gestion des erreurs
Lien direct vers Gestion des erreurs

Fournissez des erreurs descriptives pour les scénarios d’échec courants :

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;
}
}

Tester des passerelles personnalisées
Lien direct vers Tester des passerelles personnalisées

Exemple de structure de test :

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();
});
});

Bonnes pratiques
Lien direct vers Bonnes pratiques

  1. Utilisez des ID explicites pour la gestion des versions : définissez des valeurs id explicites lorsque vos passerelles doivent être versionnées

    readonly id = 'my-gateway-v1';
  2. Implémentez une gestion appropriée des erreurs : levez des erreurs descriptives accompagnées de messages exploitables

  3. Mettez en cache les opérations coûteuses : mettez en cache les jetons, les URL ou les configurations de Provider lorsque cela est pertinent

  4. Validez les variables d’environnement : vérifiez les variables d’environnement requises dans getApiKey et buildUrl

  5. Documentez votre passerelle : ajoutez des commentaires JSDoc qui expliquent son objectif et sa configuration

  6. Respectez les conventions de nommage : utilisez des noms clairs et cohérents pour les Providers et les modèles

  7. Gérez les opérations asynchrones : utilisez async/await pour les requêtes réseau et les opérations d’E/S

  8. Testez minutieusement : écrivez des tests unitaires pour toutes les méthodes de la passerelle

N’afficher que les passerelles personnalisées dans Studio
Lien direct vers N’afficher que les passerelles personnalisées dans Studio

Par défaut, Studio liste chaque Provider de modèles externe (tel qu’OpenAI, Anthropic ou Gemini) en plus des passerelles personnalisées que vous enregistrez. Pour masquer les Providers externes, définissez la variable d’environnement AUTO_BLOCK_EXTERNAL_PROVIDERS :

AUTO_BLOCK_EXTERNAL_PROVIDERS=true

Lorsque cette variable vaut true ou 1, Mastra ne renvoie que les Providers des passerelles que vous enregistrez vous-même. Le registre statique des Providers et les passerelles intégrées (models.dev, netlify et mastra) sont masqués du sélecteur de modèles. C’est utile lorsque vous acheminez tout le trafic de modèles par une passerelle privée unique et ne souhaitez pas afficher les autres Providers.

Avec cette variable définie et sans passerelle personnalisée enregistrée, le sélecteur de modèles est vide. Enregistrez au moins une passerelle personnalisée pour exposer ses modèles.

Passerelles intégrées
Lien direct vers Passerelles intégrées

Mastra inclut des passerelles intégrées comme implémentations de référence :

  • NetlifyGateway : intégration de Netlify AI Gateway avec échange de jetons
  • ModelsDevGateway : registre des Providers compatibles avec OpenAI provenant de models.dev

Consultez Netlify, OpenRouter et Vercel pour des exemples d’utilisation des passerelles.