# Provider Discovery and Loading Mechanism in aisuite's ProviderFactory

> Explore aisuite's ProviderFactory for dynamic LLM provider discovery and loading. Learn how it uses importlib and naming conventions to easily add new providers without code changes.

- Repository: [Andrew Ng/aisuite](https://github.com/andrewyng/aisuite)
- Tags: internals
- Published: 2026-06-15

---

**The `ProviderFactory` in aisuite dynamically discovers and loads LLM providers at runtime using a file-based naming convention and `importlib` for dynamic imports, allowing new providers to be added without modifying core factory code.**

aisuite is a Python library that unifies interactions with multiple large language model (LLM) providers behind a common interface. The core of this abstraction lies in `ProviderFactory`, implemented in [`aisuite/provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/provider.py), which handles automatic discovery and instantiation of provider-specific implementations located in the `aisuite/providers/` directory.

## How Provider Discovery Works in aisuite

The discovery mechanism relies on strict file naming conventions and dynamic Python imports. This design eliminates the need for manual registration of new providers.

### File-Based Registration Convention

Every provider implementation follows a rigid naming pattern. Each provider lives in a separate file named `<key>_provider.py` (e.g., [`openai_provider.py`](https://github.com/andrewyng/aisuite/blob/main/openai_provider.py), [`google_provider.py`](https://github.com/andrewyng/aisuite/blob/main/google_provider.py)) and defines a class named `<Key>Provider` (e.g., `OpenaiProvider`, `GoogleProvider`). 

To add support for a new LLM service, you only need to create a new file in `aisuite/providers/` that follows this pattern. No changes to `ProviderFactory` or any registry are required.

### Scanning the Providers Directory

The `ProviderFactory` uses the `PROVIDERS_DIR` constant to locate the `providers` subdirectory. When `get_supported_providers()` is called, it scans this directory for all files ending with [`_provider.py`](https://github.com/andrewyng/aisuite/blob/main/_provider.py), strips the suffix to extract the provider key, and returns a set of available keys. This method is decorated with `@functools.cache` to ensure repeated calls are inexpensive.

## Key Components of the ProviderFactory

The factory implementation in [`aisuite/provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/provider.py) contains three critical components that enable dynamic loading.

### Provider Abstract Base Class

The `Provider` class defines the minimal API contract that every concrete implementation must satisfy. All providers must implement the `chat_completions_create` method to ensure a uniform interface across OpenAI, Google, Anthropic, and other services.

### Dynamic Import via create_provider

The `ProviderFactory.create_provider(key, config)` method performs dynamic loading using Python's `importlib` module:

1. It constructs the expected module name as `f"{key}_provider"` and class name as `f"{key.capitalize()}Provider"`
2. Uses `importlib.import_module(f"aisuite.providers.{module_name}")` to load the module
3. Retrieves the class via `getattr(module, class_name)`
4. Instantiates the provider with the supplied configuration dictionary

If the module cannot be imported, the factory raises a clear `ImportError` and suggests calling `ProviderFactory.get_supported_providers()` to list valid keys.

### Cached Provider Enumeration

The `get_supported_providers()` method provides runtime introspection of available backends. By caching the directory scan results, it ensures that UI components (like dropdown menus) can quickly enumerate supported providers without filesystem overhead.

## Practical Implementation Examples

### Creating a Provider Instance

To instantiate a specific provider, pass the provider key and configuration dictionary to the factory:

```python
from aisuite.provider import ProviderFactory

config = {
    "api_key": "sk-...",
    "model": "gpt-4o-mini",
}

# Dynamically loads aisuite/providers/openai_provider.py

openai_provider = ProviderFactory.create_provider("openai", config)

# Use the common interface

response = openai_provider.chat_completions_create(
    model="gpt-4o-mini",
    messages=[{"role": "user", "content": "Hello world"}],
)
print(response)

```

### Listing Supported Providers

You can query which providers are available before attempting instantiation:

```python
from aisuite.provider import ProviderFactory

available = ProviderFactory.get_supported_providers()
print("Supported providers:", sorted(available))

# Output: ['anthropic', 'aws', 'azure', 'google', 'openai', ...]

```

### Dynamic Provider Selection

Implement runtime provider selection with validation:

```python
def get_provider(key: str, cfg: dict):
    if key not in ProviderFactory.get_supported_providers():
        raise ValueError(f"Unsupported provider: {key}")
    return ProviderFactory.create_provider(key, cfg)

provider = get_provider("google", {"api_key": "..."})

```

## Extending aisuite with Custom Providers

The factory's use of standard Python import mechanics means you can extend aisuite without modifying the core library. Any third-party module that respects the naming scheme (`<key>_provider.py` with `<Key>Provider` class) can be dropped into the `aisuite/providers/` directory. The factory will automatically discover and load it on the next instantiation request.

This extensibility makes aisuite suitable for enterprise environments where custom internal LLM endpoints need to integrate with the same interface used for commercial providers like OpenAI and Anthropic.

## Summary

- **File-based discovery**: Providers are automatically discovered via the `<key>_provider.py` naming convention in `aisuite/providers/`
- **Dynamic imports**: `ProviderFactory.create_provider()` uses `importlib.import_module` and `getattr` to load classes at runtime
- **Strict naming**: Each provider file must contain a class named `<Key>Provider` (e.g., `OpenaiProvider` in [`openai_provider.py`](https://github.com/andrewyng/aisuite/blob/main/openai_provider.py))
- **Cached enumeration**: `get_supported_providers()` scans the directory once and caches results using `functools.cache`
- **Zero-registration**: Adding new providers requires only creating a file; no registry updates needed

## Frequently Asked Questions

### How does ProviderFactory handle missing or invalid provider keys?

If you pass an invalid key to `ProviderFactory.create_provider()`, the method attempts to import a non-existent module, catches the failure, and raises an `ImportError` with a message suggesting you call `ProviderFactory.get_supported_providers()` to see valid options.

### Where are the concrete provider implementations located?

Concrete implementations reside in individual files within the `aisuite/providers/` directory. For example, OpenAI support is implemented in [`aisuite/providers/openai_provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/providers/openai_provider.py), Google in [`aisuite/providers/google_provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/providers/google_provider.py), and Anthropic in [`aisuite/providers/anthropic_provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/providers/anthropic_provider.py).

### Can I add a custom provider without modifying the aisuite source code?

Yes. As long as you follow the naming convention (`<key>_provider.py` with a `<Key>Provider` class) and place the file in the `aisuite/providers/` directory, `ProviderFactory` will automatically discover and load it. The factory uses standard Python import mechanics, so any module following this pattern is eligible for dynamic loading.

### What is the performance impact of provider discovery?

Minimal. The `get_supported_providers()` method uses `@functools.cache` to memoize the directory scan results. After the first call, subsequent invocations return the cached set instantly, making it suitable for high-frequency operations like populating UI dropdowns.