Skip to content

Commit a3a1bf3

Browse files
committed
[AI Bundle][Platform] Add ModelCatalog
This PR revolutionizes model configuration in the Symfony AI bundle by simplifying the way models are configured and eliminating the need for explicit class definitions in most use cases. The changes make model configuration more intuitive and maintainable while providing full backwards compatibility. - **Added platform-specific ModelCatalog classes** for OpenAI, Anthropic, Mistral, Perplexity, Gemini, and Cerebras - **Automatic model class inference** based on platform and capabilities - **Eliminates need for explicit class configuration** in most scenarios - Each platform now provides its own model catalog with predefined capabilities - **Direct model string support**: `model: 'gpt-4o-mini?temperature=0.5&max_tokens=1000'` - **Query parameter parsing** embedded directly in model names - **Traditional name/options structure** still supported for backwards compatibility - **Validation prevents conflicting configurations** (query string + options object) - **New `PlatformInterface::getModelCatalog()` method** for accessing platform model catalogs - **Enhanced `AbstractModelCatalog`** with validation for empty model names - **New `AutoDiscoveryModelCatalog`** for automatic capability detection - **Updated platform factories** to create bridge-specific model catalogs - **Updated AI Bundle configuration** (`config/options.php`) to support direct model strings - **Enhanced bundle class** (`AiBundle.php`) to handle new model configuration patterns - **Removed hardcoded model class assumptions** throughout the bundle - **Updated 40+ test files** to use Model objects instead of raw strings - **Enhanced InputProcessor tests** to validate new configuration patterns - **Added comprehensive test coverage** for all new ModelCatalog implementations - **Updated agent tests** to use proper Model instances ```yaml ai: model: openai: custom-gpt-4: class: OpenAi\Gpt capabilities: - input_messages - output_text - tool_calling ``` ```yaml ai: agent: my_agent: platform: openai model: 'gpt-4o-mini?temperature=0.5&max_tokens=1000' ai: agent: my_agent: platform: openai model: name: gpt-4o-mini options: temperature: 0.5 max_tokens: 1000 ai: model: openai: custom-gpt-4: capabilities: - !php/const Symfony\AI\Platform\Capability::INPUT_MESSAGES - !php/const Symfony\AI\Platform\Capability::OUTPUT_TEXT - !php/const Symfony\AI\Platform\Capability::TOOL_CALLING agent: my_agent: platform: openai model: 'custom-gpt-4?temperature=0.3' ``` 1. **Dramatically Simplified Configuration**: No more need to specify model classes for standard platform models 2. **Enhanced Developer Experience**: Intuitive query parameter syntax for model options 3. **Type Safety**: Enum constants ensure valid capability values 4. **Automatic Model Discovery**: Platform-specific catalogs automatically infer appropriate model classes 5. **Validation**: Built-in prevention of conflicting configuration patterns 6. **Full Backwards Compatibility**: Existing configurations continue to work unchanged - **ModelCatalog Interface**: Each platform now implements its own model catalog - **Query String Parser**: Parses model options from URL-style query parameters - **Capability Auto-Detection**: Automatically determines model capabilities based on platform standards - **Configuration Validation**: Prevents invalid combinations of configuration approaches - **Seamless Migration**: Existing model configurations work without modification This change significantly reduces configuration complexity while maintaining the full power and flexibility of the Symfony AI platform integration.
1 parent 0b390c7 commit a3a1bf3

File tree

337 files changed

+5977
-2101
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

337 files changed

+5977
-2101
lines changed

demo/config/packages/ai.yaml

Lines changed: 6 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,27 @@ ai:
44
api_key: '%env(OPENAI_API_KEY)%'
55
agent:
66
blog:
7-
model:
8-
class: 'Symfony\AI\Platform\Bridge\OpenAi\Gpt'
9-
name: !php/const Symfony\AI\Platform\Bridge\OpenAi\Gpt::GPT_4O_MINI
7+
model: 'gpt-4o-mini'
108
tools:
119
- 'Symfony\AI\Agent\Toolbox\Tool\SimilaritySearch'
1210
- service: 'clock'
1311
name: 'clock'
1412
description: 'Provides the current date and time.'
1513
method: 'now'
1614
stream:
17-
model:
18-
class: 'Symfony\AI\Platform\Bridge\OpenAi\Gpt'
19-
name: !php/const Symfony\AI\Platform\Bridge\OpenAi\Gpt::GPT_4O_MINI
15+
model: 'gpt-4o-mini'
2016
prompt: |
2117
You are an example chat application where messages from the LLM are streamed to the user using
2218
Server-Sent Events via `symfony/ux-turbo` / Turbo Streams. This example does not use any custom
2319
javascript and solely relies on the built-in `live` & `turbo_stream` Stimulus controllers.
2420
Whatever the user asks, tell them about the application & used technologies.
2521
tools: false
2622
youtube:
27-
model:
28-
class: 'Symfony\AI\Platform\Bridge\OpenAi\Gpt'
29-
name: !php/const Symfony\AI\Platform\Bridge\OpenAi\Gpt::GPT_4O_MINI
23+
model: 'gpt-4o-mini'
3024
tools: false
3125
wikipedia:
3226
model:
33-
class: 'Symfony\AI\Platform\Bridge\OpenAi\Gpt'
34-
name: !php/const Symfony\AI\Platform\Bridge\OpenAi\Gpt::GPT_4O_MINI
27+
name: 'gpt-4o-mini'
3528
options:
3629
temperature: 0.5
3730
prompt:
@@ -40,9 +33,7 @@ ai:
4033
tools:
4134
- 'Symfony\AI\Agent\Toolbox\Tool\Wikipedia'
4235
audio:
43-
model:
44-
class: 'Symfony\AI\Platform\Bridge\OpenAi\Gpt'
45-
name: 'gpt-4o-mini?temperature=1.0'
36+
model: 'gpt-4o-mini?temperature=1.0'
4637
prompt: 'You are a friendly chatbot that likes to have a conversation with users and asks them some questions.'
4738
tools:
4839
# Agent in agent 🤯
@@ -55,9 +46,7 @@ ai:
5546
collection: 'symfony_blog'
5647
vectorizer:
5748
openai:
58-
model:
59-
class: 'Symfony\AI\Platform\Bridge\OpenAi\Embeddings'
60-
name: !php/const Symfony\AI\Platform\Bridge\OpenAi\Embeddings::TEXT_ADA_002
49+
model: 'text-embedding-ada-002'
6150
indexer:
6251
blog:
6352
loader: 'Symfony\AI\Store\Document\Loader\RssFeedLoader'

examples/aimlapi/chat.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,21 +9,19 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
use Symfony\AI\Platform\Bridge\AiMlApi\Completions;
1312
use Symfony\AI\Platform\Bridge\AiMlApi\PlatformFactory;
1413
use Symfony\AI\Platform\Message\Message;
1514
use Symfony\AI\Platform\Message\MessageBag;
1615

1716
require_once dirname(__DIR__).'/bootstrap.php';
1817

1918
$platform = PlatformFactory::create(env('AIMLAPI_API_KEY'), http_client());
20-
$model = new Completions(Completions::GEMINI_2_0_FLASH);
2119

2220
$messages = new MessageBag(
2321
Message::forSystem('You are a pirate and you write funny.'),
2422
Message::ofUser('What is the Symfony framework?'),
2523
);
26-
$result = $platform->invoke($model, $messages, [
24+
$result = $platform->invoke('gemini-2.0-flash', $messages, [
2725
'max_tokens' => 500, // specific options just for this call
2826
]);
2927

examples/aimlapi/image-input-binary.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,14 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
use Symfony\AI\Platform\Bridge\AiMlApi\Completions;
1312
use Symfony\AI\Platform\Bridge\AiMlApi\PlatformFactory;
14-
use Symfony\AI\Platform\Capability;
1513
use Symfony\AI\Platform\Message\Content\Image;
1614
use Symfony\AI\Platform\Message\Message;
1715
use Symfony\AI\Platform\Message\MessageBag;
1816

1917
require_once dirname(__DIR__).'/bootstrap.php';
2018

2119
$platform = PlatformFactory::create(env('AIMLAPI_API_KEY'), http_client());
22-
$model = new Completions(
23-
name: Completions::GOOGLE_GEMMA_3_27B_IT,
24-
capabilities: [...Completions::DEFAULT_CAPABILITIES, Capability::INPUT_IMAGE]
25-
);
2620

2721
$messages = new MessageBag(
2822
Message::forSystem('You are an image analyzer bot that helps identify the content of images.'),
@@ -31,6 +25,6 @@
3125
Image::fromFile(dirname(__DIR__, 2).'/fixtures/image.jpg'),
3226
),
3327
);
34-
$result = $platform->invoke($model, $messages);
28+
$result = $platform->invoke('google/gemma-3-27b-it', $messages);
3529

3630
echo $result->getResult()->getContent().\PHP_EOL;

examples/aimlapi/toolcall.php

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,24 +13,18 @@
1313
use Symfony\AI\Agent\Toolbox\AgentProcessor;
1414
use Symfony\AI\Agent\Toolbox\Tool\Wikipedia;
1515
use Symfony\AI\Agent\Toolbox\Toolbox;
16-
use Symfony\AI\Platform\Bridge\AiMlApi\Completions;
1716
use Symfony\AI\Platform\Bridge\AiMlApi\PlatformFactory;
18-
use Symfony\AI\Platform\Capability;
1917
use Symfony\AI\Platform\Message\Message;
2018
use Symfony\AI\Platform\Message\MessageBag;
2119

2220
require_once dirname(__DIR__).'/bootstrap.php';
2321

2422
$platform = PlatformFactory::create(env('AIMLAPI_API_KEY'), http_client());
25-
$model = new Completions(
26-
name: Completions::GOOGLE_GEMINI_2_5_FLASH,
27-
capabilities: [...Completions::DEFAULT_CAPABILITIES, Capability::TOOL_CALLING]
28-
);
2923

3024
$wikipedia = new Wikipedia(http_client());
3125
$toolbox = new Toolbox([$wikipedia], logger: logger());
3226
$processor = new AgentProcessor($toolbox);
33-
$agent = new Agent($platform, $model, [$processor], [$processor], logger: logger());
27+
$agent = new Agent($platform, 'google/gemini-2.5-flash', [$processor], [$processor], logger: logger());
3428

3529
$messages = new MessageBag(Message::ofUser('Who is the current chancellor of Germany?'));
3630
$result = $agent->call($messages);

examples/aimlapi/vectorizing.php

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,14 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
use Symfony\AI\Platform\Bridge\AiMlApi\Embeddings;
1312
use Symfony\AI\Platform\Bridge\AiMlApi\PlatformFactory;
1413
use Symfony\AI\Store\Document\Vectorizer;
1514

1615
require_once dirname(__DIR__).'/bootstrap.php';
1716

1817
$platform = PlatformFactory::create(env('AIMLAPI_API_KEY'), http_client());
19-
$embeddings = new Embeddings(
20-
name: Embeddings::TEXT_EMBEDDING_3_SMALL
21-
);
2218

23-
$vectorizer = new Vectorizer($platform, $embeddings);
19+
$vectorizer = new Vectorizer($platform, 'text-embedding-3-small');
2420

2521
$string = 'Hello World';
2622
$vector = $vectorizer->vectorize($string);

examples/albert/chat.php

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,13 @@
1010
*/
1111

1212
use Symfony\AI\Platform\Bridge\Albert\PlatformFactory;
13-
use Symfony\AI\Platform\Bridge\OpenAi\Gpt;
1413
use Symfony\AI\Platform\Message\Message;
1514
use Symfony\AI\Platform\Message\MessageBag;
1615

1716
require_once dirname(__DIR__).'/bootstrap.php';
1817

1918
$platform = PlatformFactory::create(env('ALBERT_API_KEY'), env('ALBERT_API_URL'), http_client());
2019

21-
$model = new Gpt('gpt-4o');
22-
2320
$documentContext = <<<'CONTEXT'
2421
Document: AI Strategy of France
2522
@@ -42,6 +39,6 @@
4239
Message::ofUser('What are the main objectives of France\'s AI strategy?'),
4340
);
4441

45-
$result = $platform->invoke($model, $messages);
42+
$result = $platform->invoke('llama-3.3-70b-instruct', $messages);
4643

4744
echo $result->getResult()->getContent().\PHP_EOL;

examples/anthropic/chat.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,20 +9,18 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
1312
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
1413
use Symfony\AI\Platform\Message\Message;
1514
use Symfony\AI\Platform\Message\MessageBag;
1615

1716
require_once dirname(__DIR__).'/bootstrap.php';
1817

1918
$platform = PlatformFactory::create(env('ANTHROPIC_API_KEY'), httpClient: http_client());
20-
$model = new Claude(Claude::SONNET_37);
2119

2220
$messages = new MessageBag(
2321
Message::forSystem('You are a pirate and you write funny.'),
2422
Message::ofUser('What is the Symfony framework?'),
2523
);
26-
$result = $platform->invoke($model, $messages);
24+
$result = $platform->invoke('claude-3-5-sonnet-20241022', $messages);
2725

2826
echo $result->getResult()->getContent().\PHP_EOL;

examples/anthropic/image-input-binary.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
1312
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
1413
use Symfony\AI\Platform\Message\Content\Image;
1514
use Symfony\AI\Platform\Message\Message;
@@ -18,7 +17,6 @@
1817
require_once dirname(__DIR__).'/bootstrap.php';
1918

2019
$platform = PlatformFactory::create(env('ANTHROPIC_API_KEY'), httpClient: http_client());
21-
$model = new Claude(Claude::SONNET_37);
2220

2321
$messages = new MessageBag(
2422
Message::forSystem('You are an image analyzer bot that helps identify the content of images.'),
@@ -27,6 +25,6 @@
2725
'Describe this image.',
2826
),
2927
);
30-
$result = $platform->invoke($model, $messages);
28+
$result = $platform->invoke('claude-3-5-sonnet-20241022', $messages);
3129

3230
echo $result->getResult()->getContent().\PHP_EOL;

examples/anthropic/image-input-url.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
1312
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
1413
use Symfony\AI\Platform\Message\Content\ImageUrl;
1514
use Symfony\AI\Platform\Message\Message;
@@ -18,7 +17,6 @@
1817
require_once dirname(__DIR__).'/bootstrap.php';
1918

2019
$platform = PlatformFactory::create(env('ANTHROPIC_API_KEY'), httpClient: http_client());
21-
$model = new Claude(Claude::SONNET_37);
2220

2321
$messages = new MessageBag(
2422
Message::forSystem('You are an image analyzer bot that helps identify the content of images.'),
@@ -27,6 +25,6 @@
2725
'Describe this image.',
2826
),
2927
);
30-
$result = $platform->invoke($model, $messages);
28+
$result = $platform->invoke('claude-3-5-sonnet-20241022', $messages);
3129

3230
echo $result->getResult()->getContent().\PHP_EOL;

examples/anthropic/pdf-input-binary.php

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@
99
* file that was distributed with this source code.
1010
*/
1111

12-
use Symfony\AI\Platform\Bridge\Anthropic\Claude;
1312
use Symfony\AI\Platform\Bridge\Anthropic\PlatformFactory;
1413
use Symfony\AI\Platform\Message\Content\Document;
1514
use Symfony\AI\Platform\Message\Message;
@@ -18,14 +17,13 @@
1817
require_once dirname(__DIR__).'/bootstrap.php';
1918

2019
$platform = PlatformFactory::create(env('ANTHROPIC_API_KEY'), httpClient: http_client());
21-
$model = new Claude(Claude::SONNET_37);
2220

2321
$messages = new MessageBag(
2422
Message::ofUser(
2523
Document::fromFile(dirname(__DIR__, 2).'/fixtures/document.pdf'),
2624
'What is this document about?',
2725
),
2826
);
29-
$result = $platform->invoke($model, $messages);
27+
$result = $platform->invoke('claude-3-5-sonnet-20241022', $messages);
3028

3129
echo $result->getResult()->getContent().\PHP_EOL;

0 commit comments

Comments
 (0)