|
| 1 | +Models.dev Platform |
| 2 | +=================== |
| 3 | + |
| 4 | +The models.dev bridge provides auto-discovered model catalogs for many AI |
| 5 | +providers using data from the `models.dev`_ community registry. It leverages |
| 6 | +the Generic bridge under the hood, so any provider with an OpenAI-compatible |
| 7 | +API works out of the box. |
| 8 | + |
| 9 | +Installation |
| 10 | +------------ |
| 11 | + |
| 12 | +.. code-block:: terminal |
| 13 | +
|
| 14 | + $ composer require symfony/ai-models-dev-platform |
| 15 | +
|
| 16 | +Authentication |
| 17 | +-------------- |
| 18 | + |
| 19 | +Each provider requires its own API key. Set it as an environment variable: |
| 20 | + |
| 21 | +.. code-block:: bash |
| 22 | +
|
| 23 | + # Example for DeepSeek |
| 24 | + DEEPSEEK_API_KEY=your-api-key |
| 25 | +
|
| 26 | + # Example for Groq |
| 27 | + GROQ_API_KEY=your-api-key |
| 28 | +
|
| 29 | +Refer to each provider's documentation for how to obtain an API key. |
| 30 | + |
| 31 | +Usage |
| 32 | +----- |
| 33 | + |
| 34 | +Using the PlatformFactory |
| 35 | +~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 36 | + |
| 37 | +The simplest way to get started is with ``PlatformFactory``, which auto-detects |
| 38 | +the API base URL from the models.dev data:: |
| 39 | + |
| 40 | + use Symfony\AI\Platform\Bridge\ModelsDev\PlatformFactory; |
| 41 | + use Symfony\AI\Platform\Message\Message; |
| 42 | + use Symfony\AI\Platform\Message\MessageBag; |
| 43 | + |
| 44 | + // Auto-detect base URL from models.dev data |
| 45 | + $platform = PlatformFactory::create( |
| 46 | + provider: 'deepseek', |
| 47 | + apiKey: $_ENV['DEEPSEEK_API_KEY'], |
| 48 | + ); |
| 49 | + |
| 50 | + $messages = new MessageBag( |
| 51 | + Message::forSystem('You are a helpful assistant.'), |
| 52 | + Message::ofUser('What is the Symfony framework?'), |
| 53 | + ); |
| 54 | + |
| 55 | + $result = $platform->invoke('deepseek-chat', $messages); |
| 56 | + echo $result->asText(); |
| 57 | + |
| 58 | +For providers where models.dev does not publish an API base URL, you must provide it |
| 59 | +explicitly:: |
| 60 | + |
| 61 | + $platform = PlatformFactory::create( |
| 62 | + provider: 'groq', |
| 63 | + apiKey: $_ENV['GROQ_API_KEY'], |
| 64 | + baseUrl: 'https://api.groq.com/openai/v1', |
| 65 | + ); |
| 66 | + |
| 67 | +The factory accepts the same options as the Generic bridge factory, including |
| 68 | +custom HTTP clients, event dispatchers, and endpoint paths:: |
| 69 | + |
| 70 | + use Symfony\Component\HttpClient\HttpClient; |
| 71 | + |
| 72 | + $platform = PlatformFactory::create( |
| 73 | + provider: 'deepseek', |
| 74 | + apiKey: $_ENV['DEEPSEEK_API_KEY'], |
| 75 | + httpClient: HttpClient::create(), |
| 76 | + completionsPath: '/v1/chat/completions', |
| 77 | + embeddingsPath: '/v1/embeddings', |
| 78 | + ); |
| 79 | + |
| 80 | +Embeddings |
| 81 | +~~~~~~~~~~ |
| 82 | + |
| 83 | +Embedding models are automatically detected from models.dev data and routed to the |
| 84 | +``EmbeddingsModel`` class. Use them like any other embedding model:: |
| 85 | + |
| 86 | + $platform = PlatformFactory::create( |
| 87 | + provider: 'openai', |
| 88 | + apiKey: $_ENV['OPENAI_API_KEY'], |
| 89 | + baseUrl: 'https://api.openai.com/v1', |
| 90 | + ); |
| 91 | + |
| 92 | + $result = $platform->invoke('text-embedding-3-small', 'What is Symfony?'); |
| 93 | + $vectors = $result->asVectors(); |
| 94 | + |
| 95 | +Streaming |
| 96 | +~~~~~~~~~ |
| 97 | + |
| 98 | +All completions models include the ``OUTPUT_STREAMING`` capability. Enable |
| 99 | +streaming as you would with any other platform:: |
| 100 | + |
| 101 | + $result = $platform->invoke('deepseek-chat', $messages, [ |
| 102 | + 'stream' => true, |
| 103 | + ]); |
| 104 | + |
| 105 | + foreach ($result->getContent() as $chunk) { |
| 106 | + echo $chunk; |
| 107 | + } |
| 108 | + |
| 109 | +Tool Calling |
| 110 | +~~~~~~~~~~~~ |
| 111 | + |
| 112 | +Models that support tool calling are automatically flagged with the |
| 113 | +``TOOL_CALLING`` capability:: |
| 114 | + |
| 115 | + use Symfony\AI\Platform\Bridge\ModelsDev\ModelCatalog; |
| 116 | + |
| 117 | + $catalog = new ModelCatalog('deepseek'); |
| 118 | + $model = $catalog->getModel('deepseek-chat'); |
| 119 | + |
| 120 | + // Check if the model supports tool calling |
| 121 | + if ($model->supports(\Symfony\AI\Platform\Capability::TOOL_CALLING)) { |
| 122 | + // Use with an Agent that has tools configured |
| 123 | + } |
| 124 | + |
| 125 | +Adding Custom Models |
| 126 | +~~~~~~~~~~~~~~~~~~~~ |
| 127 | + |
| 128 | +If a model is missing from the data or you need to override its capabilities, |
| 129 | +pass additional models when creating the ``ModelCatalog``:: |
| 130 | + |
| 131 | + use Symfony\AI\Platform\Bridge\Generic\CompletionsModel; |
| 132 | + use Symfony\AI\Platform\Bridge\ModelsDev\ModelCatalog; |
| 133 | + use Symfony\AI\Platform\Capability; |
| 134 | + |
| 135 | + $catalog = new ModelCatalog('deepseek', additionalModels: [ |
| 136 | + 'deepseek-custom-finetune' => [ |
| 137 | + 'class' => CompletionsModel::class, |
| 138 | + 'capabilities' => [ |
| 139 | + Capability::INPUT_MESSAGES, |
| 140 | + Capability::OUTPUT_TEXT, |
| 141 | + Capability::OUTPUT_STREAMING, |
| 142 | + Capability::TOOL_CALLING, |
| 143 | + ], |
| 144 | + ], |
| 145 | + ]); |
| 146 | + |
| 147 | +Additional models are merged with and take precedence over the bundled data. |
| 148 | + |
| 149 | +Provider Registry |
| 150 | +~~~~~~~~~~~~~~~~~ |
| 151 | + |
| 152 | +The ``ProviderRegistry`` gives you access to provider metadata:: |
| 153 | + |
| 154 | + use Symfony\AI\Platform\Bridge\ModelsDev\ProviderRegistry; |
| 155 | + |
| 156 | + $registry = new ProviderRegistry(); |
| 157 | + |
| 158 | + // List all available providers |
| 159 | + $providerIds = $registry->getProviderIds(); |
| 160 | + // ['openai', 'anthropic', 'deepseek', 'groq', ...] |
| 161 | + |
| 162 | + // Check if a provider exists |
| 163 | + $registry->has('deepseek'); // true |
| 164 | + |
| 165 | + // Get provider name |
| 166 | + $registry->getProviderName('deepseek'); // "DeepSeek" |
| 167 | + |
| 168 | + // Get API base URL (null if not published by models.dev) |
| 169 | + $registry->getApiBaseUrl('deepseek'); // "https://api.deepseek.com" |
| 170 | + |
| 171 | +Symfony Bundle Configuration |
| 172 | +---------------------------- |
| 173 | + |
| 174 | +When using the AI Bundle, configure the models.dev bridge under the ``generic`` |
| 175 | +platform section. The ``ModelCatalog`` replaces the manually curated model |
| 176 | +list: |
| 177 | + |
| 178 | +.. code-block:: yaml |
| 179 | +
|
| 180 | + # config/packages/ai.yaml |
| 181 | + ai: |
| 182 | + platform: |
| 183 | + generic: |
| 184 | + deepseek: |
| 185 | + base_url: 'https://api.deepseek.com' |
| 186 | + api_key: '%env(DEEPSEEK_API_KEY)%' |
| 187 | + model_catalog: 'Symfony\AI\Platform\Bridge\ModelsDev\ModelCatalog' |
| 188 | + agent: |
| 189 | + deepseek: |
| 190 | + platform: 'ai.platform.generic.deepseek' |
| 191 | + model: 'deepseek-chat' |
| 192 | + tools: false |
| 193 | +
|
| 194 | + services: |
| 195 | + Symfony\AI\Platform\Bridge\ModelsDev\ModelCatalog: |
| 196 | + arguments: |
| 197 | + $providerId: 'deepseek' |
| 198 | +
|
| 199 | +Multiple Providers |
| 200 | +~~~~~~~~~~~~~~~~~~ |
| 201 | + |
| 202 | +Configure multiple providers in the same application: |
| 203 | + |
| 204 | +.. code-block:: yaml |
| 205 | +
|
| 206 | + # config/packages/ai.yaml |
| 207 | + ai: |
| 208 | + platform: |
| 209 | + generic: |
| 210 | + deepseek: |
| 211 | + base_url: 'https://api.deepseek.com' |
| 212 | + api_key: '%env(DEEPSEEK_API_KEY)%' |
| 213 | + model_catalog: 'app.model_catalog.deepseek' |
| 214 | + groq: |
| 215 | + base_url: 'https://api.groq.com/openai/v1' |
| 216 | + api_key: '%env(GROQ_API_KEY)%' |
| 217 | + model_catalog: 'app.model_catalog.groq' |
| 218 | +
|
| 219 | + services: |
| 220 | + app.model_catalog.deepseek: |
| 221 | + class: 'Symfony\AI\Platform\Bridge\ModelsDev\ModelCatalog' |
| 222 | + arguments: |
| 223 | + $providerId: 'deepseek' |
| 224 | +
|
| 225 | + app.model_catalog.groq: |
| 226 | + class: 'Symfony\AI\Platform\Bridge\ModelsDev\ModelCatalog' |
| 227 | + arguments: |
| 228 | + $providerId: 'groq' |
| 229 | +
|
| 230 | +Supported Providers |
| 231 | +------------------- |
| 232 | + |
| 233 | +The models.dev registry includes many providers. Use the ``ProviderRegistry`` |
| 234 | +to list all available providers and check which have auto-detected base URLs:: |
| 235 | + |
| 236 | + $registry = new ProviderRegistry(); |
| 237 | + foreach ($registry->getProviderIds() as $id) { |
| 238 | + $url = $registry->getApiBaseUrl($id) ?? '(manual)'; |
| 239 | + echo sprintf("%s: %s\n", $id, $url); |
| 240 | + } |
| 241 | + |
| 242 | +.. note:: |
| 243 | + |
| 244 | + Not all providers in the models.dev registry use the OpenAI-compatible API format. |
| 245 | + Providers like Anthropic and Google use their own API formats. The models.dev bridge |
| 246 | + works best with providers that are OpenAI-compatible, which is the majority. |
| 247 | + |
| 248 | +Resources |
| 249 | +--------- |
| 250 | + |
| 251 | + * `Contributing <https://symfony.com/doc/current/contributing/index.html>`_ |
| 252 | + * `Report issues <https://github.com/symfony/ai/issues>`_ and |
| 253 | + `send Pull Requests <https://github.com/symfony/ai/pulls>`_ |
| 254 | + in the `main Symfony AI repository <https://github.com/symfony/ai>`_ |
| 255 | + |
| 256 | +.. _models.dev: https://models.dev/ |
0 commit comments