How Does the ProviderFactory Dynamically Load Providers in aisuite?

The ProviderFactory in 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 or 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 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. 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, 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, this method strips the _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 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 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:

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', ...}

# 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)

# 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 and handles all provider discovery and instantiation.
  • Convention-based naming maps provider keys like "openai" to module 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 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 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, 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.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →