# How Does the ProviderFactory Dynamically Load Providers in aisuite?

> Discover how aisuite's ProviderFactory dynamically loads providers using importlib and naming conventions. Achieve plug-and-play extensibility effortlessly.

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

---

**The `ProviderFactory` in [`aisuite/provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/provider.py) uses a convention-based naming scheme and `importlib` to lazily load provider modules by converting a provider key like "openai" into a module name `openai_provider` and class name `OpenaiProvider`, enabling plug-and-play extensibility without registry updates.**

The **aisuite** library by Andrew Ng provides a unified interface for multiple LLM providers through a dynamic loading mechanism. At its core, the **ProviderFactory** implements convention-based discovery that eliminates hardcoded registries. This architecture allows developers to add new AI providers simply by creating a file that follows the established naming pattern, without modifying the factory code.

## Convention-Based Naming Strategy

The factory relies on a strict naming convention to locate provider implementations. When `create_provider` receives a key like `"anthropic"` or `"gemini"`, it transforms this string into two specific identifiers:

- **Module name**: The provider key is suffixed with `_provider`, producing filenames like [`openai_provider.py`](https://github.com/andrewyng/aisuite/blob/main/openai_provider.py) or [`anthropic_provider.py`](https://github.com/andrewyng/aisuite/blob/main/anthropic_provider.py).
- **Class name**: The key is title-cased and suffixed with `Provider`, resulting in class names like `OpenaiProvider` or `AnthropicProvider`.

This transformation logic is implemented in [`aisuite/provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/provider.py) within the `create_provider` method (lines 99-104). By enforcing this convention, aisuite ensures that every provider module exposes a predictable interface without requiring explicit configuration files or registration decorators.

## Dynamic Module Loading with importlib

Rather than importing all providers at startup, the factory uses **lazy loading** through Python's `importlib` module. When instantiation is requested, the factory constructs the full module path `aisuite.providers.<provider_key>_provider` and attempts to import it dynamically using `importlib.import_module`.

If the module does not exist, the factory raises a clear `ImportError` directing developers to check available providers. This error handling occurs in lines 107-112 of [`aisuite/provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/provider.py). This approach keeps memory usage low and startup times fast, as only the providers actually used in a session are loaded into memory.

## Provider Instantiation and Configuration

After successfully importing the module, the factory uses `getattr` to retrieve the provider class from the module namespace. It then instantiates the class by passing the entire configuration dictionary directly to the constructor.

This process, found in lines 115-117 of [`aisuite/provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/provider.py), means that security credentials, API endpoints, and model parameters flow directly from the user's configuration into the provider instance without intermediate processing. The configuration dictionary typically contains keys like `api_key`, `model`, and provider-specific options.

## Runtime Discovery of Available Providers

Beyond instantiation, the factory provides introspection capabilities through the `get_supported_providers` method. This utility scans the `aisuite/providers` directory using `Path.glob` to find all files matching the pattern `*_provider.py`.

Located in lines 119-124 of [`aisuite/provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/provider.py), this method strips the [`_provider.py`](https://github.com/andrewyng/aisuite/blob/main/_provider.py) suffix from filenames to return a set of available provider keys (e.g., `{"openai", "anthropic", "gemini"}`). The results are cached to prevent repeated filesystem operations, making this suitable for frequent calls during application initialization.

## Integration with the aisuite Client

The **aisuite** client in [`aisuite/client.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/client.py) serves as the primary consumer of the factory. When users specify a provider in their requests, the client delegates to `ProviderFactory.create_provider`, abstracting away the import mechanics entirely.

This integration creates a truly plug-and-play architecture. Developers can extend aisuite by dropping a new [`custom_provider.py`](https://github.com/andrewyng/aisuite/blob/main/custom_provider.py) file into the providers directory, following the naming convention, and the factory automatically recognizes and loads it without any modifications to the core library code.

## Practical Implementation Examples

The following examples demonstrate how to interact with the dynamic loading system in application code:

```python
from aisuite.provider import ProviderFactory

# 1️⃣ List all providers that are currently available

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

# → e.g. {'openai', 'anthropic', 'gemini', ...}

```

```python

# 2️⃣ Create a provider instance (synchronously)

cfg = {"api_key": "sk‑my‑secret‑key", "model": "gpt-4"}
openai = ProviderFactory.create_provider("openai", cfg)
response = openai.chat_completions_create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Hello!"}]
)
print(response)

```

```python

# 3️⃣ Create a provider instance (async)

# The same factory method is used; the provider class decides

# whether to expose native async methods.

async_openai = ProviderFactory.create_provider("openai", cfg)
resp = await async_openai.achat_completions_create(
    model="gpt-4",
    messages=[{"role": "user", "content": "Async hello!"}]
)
print(resp)

```

## Summary

- **ProviderFactory** lives in [`aisuite/provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/provider.py) and handles all provider discovery and instantiation.
- **Convention-based naming** maps provider keys like `"openai"` to module [`openai_provider.py`](https://github.com/andrewyng/aisuite/blob/main/openai_provider.py) and class `OpenaiProvider`.
- **Lazy loading** via `importlib.import_module` imports providers only when requested, with clear `ImportError` handling for missing providers (lines 107-112).
- **Automatic discovery** through `get_supported_providers` scans for `*_provider.py` files in `aisuite/providers/` and caches the results.
- **Zero-registration architecture** allows new providers to be added by simply creating a properly named file in the providers directory.

## Frequently Asked Questions

### What naming convention must provider modules follow in aisuite?

Provider modules must reside in the `aisuite/providers` directory and follow the pattern `<provider_key>_provider.py`. The class inside must be named `<ProviderKey>Provider` (title-cased key plus "Provider"). For example, a provider with key `"anthropic"` requires a file named [`anthropic_provider.py`](https://github.com/andrewyng/aisuite/blob/main/anthropic_provider.py) containing a class named `AnthropicProvider`.

### How does the ProviderFactory handle invalid or unsupported provider keys?

If `create_provider` receives a key that does not correspond to an existing module, the factory raises an `ImportError` with a descriptive message pointing to the list of supported providers. This check occurs during the dynamic import phase in [`aisuite/provider.py`](https://github.com/andrewyng/aisuite/blob/main/aisuite/provider.py) lines 107-112, ensuring fail-fast behavior with clear debugging information.

### Where are provider modules physically located in the aisuite codebase?

All provider implementations live in the `aisuite/providers/` package directory. Each provider is a separate Python file (e.g., [`openai_provider.py`](https://github.com/andrewyng/aisuite/blob/main/openai_provider.py), [`anthropic_provider.py`](https://github.com/andrewyng/aisuite/blob/main/anthropic_provider.py)). The factory specifically imports from this package using `importlib.import_module(f"aisuite.providers.{module_name}")`.

### Does ProviderFactory support asynchronous provider instantiation?

The factory itself is agnostic to sync versus async operations; it simply instantiates the provider class. Whether the returned instance supports async methods depends on the specific provider implementation. Most providers in aisuite expose both synchronous methods like `chat_completions_create` and asynchronous variants like `achat_completions_create`, but the factory handles both identically during instantiation.