-
-
Notifications
You must be signed in to change notification settings - Fork 501
Update symfony/ai-bundle #1452
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Update symfony/ai-bundle #1452
Conversation
OskarStark
commented
Sep 23, 2025
Q | A |
---|---|
License | MIT |
Doc issue/PR | Needs symfony/ai#640 |
Thanks for the PR 😍 How to test these changes in your application
Diff between recipe versionsIn order to help with the review stage, I'm in charge of computing the diff between the various versions of patched recipes. |
This PR was squashed before being merged into the main branch. Discussion ---------- [AI Bundle][Platform] Add `ModelCatalog` | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | Docs? | yes | Issues | -- | License | MIT Recipe-PR: * symfony/recipes#1452 # ModelCatalog Architecture Refactoring ### BC Breaks *⚠️ All model constants removed *⚠️ Child model class constructors were changed and now have an `$capabilities` parameter *⚠️ `PlatformFactory` constructor changed for all bridges to be able to receive a `ModelCatalogInterface` *⚠️ `PlatformInterface` now has an additional `getModelCatalog` method *⚠️ `PlatformInterface::__invoke` no receives an model as string (before `Model`) *⚠️ `Vectorizer::__construct` no receives an model as string (before `Model`) *⚠️ `Agent::__construct` no receives an model as string (before `Model`) ## Overview This PR refactors how models are defined and managed in the Symfony AI Platform, moving from constants in Model classes to centralized ModelCatalogs. ## Before (Old Configuration) ### Defining Models Models were defined as constants in Model classes: ```php // src/platform/src/Bridge/OpenAi/Gpt.php class Gpt extends Model { public const GPT_4O = 'gpt-4o'; public const GPT_4O_MINI = 'gpt-4o-mini'; // ... more constants public function __construct(string $name = self::GPT_4O, array $options = []) { $capabilities = [ Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, // ... capabilities determined in constructor ]; if (self::GPT_4O_AUDIO === $name) { $capabilities[] = Capability::INPUT_AUDIO; } // ... more logic parent::__construct($name, $capabilities, $options); } } ``` ### Using Models ```php use Symfony\AI\Platform\Bridge\OpenAi\Gpt; use Symfony\AI\Platform\Bridge\Voyage\Voyage; // Had to create Model objects $model = new Gpt('gpt-4o-mini'); $result = $platform->invoke($model, $input); // Or with constants $embeddings = new Voyage(Voyage::V3); $result = $platform->invoke($embeddings, $text); ``` ### Adding Custom Models There was no standardized way to add custom models. You had to: - Either extend a Model class and override the constructor - Or create a Model instance with hardcoded capabilities ## After (New Configuration) ### Defining Models Models are now defined in centralized ModelCatalog classes: ```php // src/platform/src/Bridge/OpenAi/ModelCatalog.php final class ModelCatalog extends AbstractModelCatalog { public function __construct(array $additionalModels = []) { $defaultModels = [ 'gpt-4o' => [ 'class' => Gpt::class, 'capabilities' => [ Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STREAMING, Capability::TOOL_CALLING, Capability::INPUT_IMAGE, Capability::OUTPUT_STRUCTURED, ], ], 'gpt-4o-mini' => [ 'class' => Gpt::class, 'capabilities' => [ Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STREAMING, Capability::TOOL_CALLING, Capability::INPUT_IMAGE, Capability::OUTPUT_STRUCTURED, ], ], // ... more models ]; $this->models = array_merge($defaultModels, $additionalModels); } } ``` ### Using Models ```php // Just pass model name as string - much simpler! $result = $platform->invoke('gpt-4o-mini', $input); // Works with any platform $result = $platform->invoke('voyage-3', $text); ``` ### Adding Custom Models #### Option 1: Via ModelCatalog Constructor ```php use Symfony\AI\Platform\Bridge\OpenAi\ModelCatalog; use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory; $customModels = [ 'custom-gpt-4' => [ 'class' => Gpt::class, 'capabilities' => [ Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STREAMING, Capability::TOOL_CALLING, Capability::OUTPUT_STRUCTURED, ], ], ]; $modelCatalog = new ModelCatalog($customModels); $platform = new Platform($modelClients, $resultConverters, $modelCatalog, $contract); // Use the custom model $result = $platform->invoke('custom-gpt-4', $input); ``` #### Option 2: Via Symfony Configuration (if using AI Bundle) ```yaml # config/packages/ai.yaml ai: platform: openai: models: custom-gpt-4: class: OpenAi\Gpt capabilities: - input_messages - output_text - output_streaming - tool_calling - output_structured ``` ## Benefits 1. **Cleaner API**: Use simple strings instead of Model objects 2. **Centralized Model Management**: All models defined in one place per platform 3. **Easier Custom Models**: Add custom models via constructor or configuration 4. **Better Testing**: Standardized ModelCatalogTestCase for all implementations 5. **No More Constants**: Model classes are simpler, no need for constants 6. **Flexible Capabilities**: Capabilities defined per model, not in constructor logic ## Migration Guide ### For Application Code ```diff - $result = $platform->invoke(new Gpt(Gpt::GPT_4O), $input); + $result = $platform->invoke('gpt-4o', $input); ``` ### For Custom Platforms ```php // Before: Had to extend Model class or handle in constructor class MyModel extends Model { public function __construct() { // Complex capability logic } } // After: Just add to ModelCatalog $catalog = new ModelCatalog([ 'my-model' => [ 'class' => MyModel::class, 'capabilities' => [...], ], ]); ``` ## Special Cases ### HuggingFace HuggingFace ModelCatalog accepts any model name since they support thousands of models: ```php final class ModelCatalog extends DynamicModelCatalog { // HuggingFace supports a wide range of models dynamically // Models are identified by repository/model format (e.g., "microsoft/DialoGPT-medium") } ``` ## Testing All ModelCatalogs can now be tested using the base `ModelCatalogTestCase`: ```php final class MyModelCatalogTest extends ModelCatalogTestCase { protected function createCatalog(): ModelCatalogInterface { return new MyModelCatalog(); } public static function modelsProvider(): iterable { yield 'model-name' => [ 'model-name', ModelClass::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT], ]; } } ``` Commits ------- 4f06377 [AI Bundle][Platform] Add `ModelCatalog`
symfony/ai#640 is now merged. |
This PR was squashed before being merged into the main branch. Discussion ---------- [AI Bundle][Platform] Add `ModelCatalog` | Q | A | ------------- | --- | Bug fix? | no | New feature? | yes | Docs? | yes | Issues | -- | License | MIT Recipe-PR: * symfony/recipes#1452 # ModelCatalog Architecture Refactoring ### BC Breaks *⚠️ All model constants removed *⚠️ Child model class constructors were changed and now have an `$capabilities` parameter *⚠️ `PlatformFactory` constructor changed for all bridges to be able to receive a `ModelCatalogInterface` *⚠️ `PlatformInterface` now has an additional `getModelCatalog` method *⚠️ `PlatformInterface::__invoke` no receives an model as string (before `Model`) *⚠️ `Vectorizer::__construct` no receives an model as string (before `Model`) *⚠️ `Agent::__construct` no receives an model as string (before `Model`) ## Overview This PR refactors how models are defined and managed in the Symfony AI Platform, moving from constants in Model classes to centralized ModelCatalogs. ## Before (Old Configuration) ### Defining Models Models were defined as constants in Model classes: ```php // src/platform/src/Bridge/OpenAi/Gpt.php class Gpt extends Model { public const GPT_4O = 'gpt-4o'; public const GPT_4O_MINI = 'gpt-4o-mini'; // ... more constants public function __construct(string $name = self::GPT_4O, array $options = []) { $capabilities = [ Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, // ... capabilities determined in constructor ]; if (self::GPT_4O_AUDIO === $name) { $capabilities[] = Capability::INPUT_AUDIO; } // ... more logic parent::__construct($name, $capabilities, $options); } } ``` ### Using Models ```php use Symfony\AI\Platform\Bridge\OpenAi\Gpt; use Symfony\AI\Platform\Bridge\Voyage\Voyage; // Had to create Model objects $model = new Gpt('gpt-4o-mini'); $result = $platform->invoke($model, $input); // Or with constants $embeddings = new Voyage(Voyage::V3); $result = $platform->invoke($embeddings, $text); ``` ### Adding Custom Models There was no standardized way to add custom models. You had to: - Either extend a Model class and override the constructor - Or create a Model instance with hardcoded capabilities ## After (New Configuration) ### Defining Models Models are now defined in centralized ModelCatalog classes: ```php // src/platform/src/Bridge/OpenAi/ModelCatalog.php final class ModelCatalog extends AbstractModelCatalog { public function __construct(array $additionalModels = []) { $defaultModels = [ 'gpt-4o' => [ 'class' => Gpt::class, 'capabilities' => [ Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STREAMING, Capability::TOOL_CALLING, Capability::INPUT_IMAGE, Capability::OUTPUT_STRUCTURED, ], ], 'gpt-4o-mini' => [ 'class' => Gpt::class, 'capabilities' => [ Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STREAMING, Capability::TOOL_CALLING, Capability::INPUT_IMAGE, Capability::OUTPUT_STRUCTURED, ], ], // ... more models ]; $this->models = array_merge($defaultModels, $additionalModels); } } ``` ### Using Models ```php // Just pass model name as string - much simpler! $result = $platform->invoke('gpt-4o-mini', $input); // Works with any platform $result = $platform->invoke('voyage-3', $text); ``` ### Adding Custom Models #### Option 1: Via ModelCatalog Constructor ```php use Symfony\AI\Platform\Bridge\OpenAi\ModelCatalog; use Symfony\AI\Platform\Bridge\OpenAi\PlatformFactory; $customModels = [ 'custom-gpt-4' => [ 'class' => Gpt::class, 'capabilities' => [ Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT, Capability::OUTPUT_STREAMING, Capability::TOOL_CALLING, Capability::OUTPUT_STRUCTURED, ], ], ]; $modelCatalog = new ModelCatalog($customModels); $platform = new Platform($modelClients, $resultConverters, $modelCatalog, $contract); // Use the custom model $result = $platform->invoke('custom-gpt-4', $input); ``` #### Option 2: Via Symfony Configuration (if using AI Bundle) ```yaml # config/packages/ai.yaml ai: platform: openai: models: custom-gpt-4: class: OpenAi\Gpt capabilities: - input_messages - output_text - output_streaming - tool_calling - output_structured ``` ## Benefits 1. **Cleaner API**: Use simple strings instead of Model objects 2. **Centralized Model Management**: All models defined in one place per platform 3. **Easier Custom Models**: Add custom models via constructor or configuration 4. **Better Testing**: Standardized ModelCatalogTestCase for all implementations 5. **No More Constants**: Model classes are simpler, no need for constants 6. **Flexible Capabilities**: Capabilities defined per model, not in constructor logic ## Migration Guide ### For Application Code ```diff - $result = $platform->invoke(new Gpt(Gpt::GPT_4O), $input); + $result = $platform->invoke('gpt-4o', $input); ``` ### For Custom Platforms ```php // Before: Had to extend Model class or handle in constructor class MyModel extends Model { public function __construct() { // Complex capability logic } } // After: Just add to ModelCatalog $catalog = new ModelCatalog([ 'my-model' => [ 'class' => MyModel::class, 'capabilities' => [...], ], ]); ``` ## Special Cases ### HuggingFace HuggingFace ModelCatalog accepts any model name since they support thousands of models: ```php final class ModelCatalog extends DynamicModelCatalog { // HuggingFace supports a wide range of models dynamically // Models are identified by repository/model format (e.g., "microsoft/DialoGPT-medium") } ``` ## Testing All ModelCatalogs can now be tested using the base `ModelCatalogTestCase`: ```php final class MyModelCatalogTest extends ModelCatalogTestCase { protected function createCatalog(): ModelCatalogInterface { return new MyModelCatalog(); } public static function modelsProvider(): iterable { yield 'model-name' => [ 'model-name', ModelClass::class, [Capability::INPUT_MESSAGES, Capability::OUTPUT_TEXT], ]; } } ``` Commits ------- 4f063776 [AI Bundle][Platform] Add `ModelCatalog`