Skip to main content

Lazy Imports & Fast Startup

PraisonAI Agents v0.5.0+ uses lazy imports to dramatically reduce startup time and memory usage. Heavy dependencies like litellm, requests, and chromadb are only loaded when actually needed.
The user imports PraisonAI and starts an agent instantly; heavy libraries load only on first use.

How It Works

Quick Start

1

Import without heavy deps

2

Verify lazy loading

Performance Benefits

How It Works

Lazy Module Loading

Core modules are loaded on-demand using Python’s __getattr__ mechanism:

Heavy Dependencies

The following dependencies are NOT loaded at import time:
  • litellm - Only loaded when LLM calls are made
  • requests - Only loaded when HTTP calls are needed
  • chromadb - Only loaded when vector stores are used
  • mem0 - Only loaded when memory features are used

Wrapper CLI Lazy Loading

The praisonai CLI and praisonai.run(...) used to eagerly import the framework adapter tree (praisonaiagents.frameworks.*) on every invocation, wasting the ~420 ms deferral that agent.py already had. As of PR #4821 the agents_generator module is fully lazy — framework adapters load only when a framework is actually selected.
  • Runtime access goes through the lazy _get_default_adapter_registry(); framework-adapter imports live under TYPE_CHECKING, so importing praisonai.agents_generator never loads the framework tree.

Training & Vision Module Lazy Loading

Modules affected: praisonai.train.llm.trainer (the TrainModel class) and praisonai.upload_vision (the UploadVisionModel class) now use lazy loading to defer heavy ML dependencies. These modules use a _lazy_import_*_deps() helper called from __init__, mirroring train.py / train_vision.py patterns. Dependencies deferred:
  • torch - CUDA/GPU computation framework
  • transformers (TextStreamer, TrainingArguments) - Hugging Face transformers
  • unsloth (FastLanguageModel, FastVisionModel, is_bfloat16_supported, standardize_sharegpt, get_chat_template) - Fast training optimization
  • trl (SFTTrainer) - Transformer Reinforcement Learning
  • datasets (load_dataset, concatenate_datasets) - Dataset loading utilities
  • psutil (virtual_memory) - System memory monitoring
Impact: Importing praisonai.upload_vision or praisonai.train.llm.trainer is now near-instant; CUDA / ~2 GB of ML libs only load when you instantiate UploadVisionModel(...) or TrainModel(...).
ImportError messages now include install hints:
  • Vision upload: pip install torch unsloth
  • Training: pip install torch transformers unsloth datasets trl psutil

Verifying Lazy Imports

You can verify lazy imports are working:

Configuration

Lazy imports are enabled by default. You can check the configuration:

Shared lazy cache for optional-dep loading

praisonai._lazy_cache is the single source of truth for thread-safe optional-dependency loading — lazy_get(key, factory) returns a memoised value (including memoised exceptions), and lazy_reset(key) clears it.
As of PR #4861, all three lazy-model factories in praisonai/auto.py (team, workflow, job workflow) route through the shared lazy_get, so exception caching and lazy_reset behave identically across them — no more ad-hoc _models_cache with divergent semantics. A broken pydantic install now fails fast and identically for every factory, and lazy_reset clears all three caches at once.

Transient vs structural failures

LazyCache(retry_cooldown: float = 30.0) splits cached loader failures by type, so a one-off environment blip no longer poisons the cache for the whole process lifetime. A transient failure is timestamped when cached. Inside the cool-down window get(key, loader) re-raises the cached error; once the cool-down expires the next get retries the loader, and a success clears the cached failure. reset(key) clears both the value cache and the failure timestamp; reset() with no key clears everything. Use a scoped instance for multi-tenant callers instead of sharing the module-level singleton.
The cool-down mirrors the one PraisonAIDB._init_stores already uses for the same failure mode. It closes a real failure: a long-lived process (praisonai serve) that hit a transient OSError on first litellm load previously returned the cached error for the entire process lifetime — every subsequent request in every tenant. With the cool-down, the process recovers automatically once the underlying condition clears. See PR #4948 (fixes #4945).

Best Practices

Defer optional modules until a feature is invoked — keeps CLI and server startup fast.
Use pip install praisonaiagents[memory] rather than pulling every optional dependency upfront.
Track cold import duration to catch accidental module-level heavy imports in PRs.
Use the lite package when you bring your own LLM client and need minimal footprint.
Construct a scoped LazyCache instance per tenant so a reset in one tenant does not stomp another, and tune retry_cooldown to how quickly transient failures are expected to clear.

Measuring Performance

Use the built-in benchmarks to measure import time:

Performance Benchmarks

Import time and memory metrics

Lite Package

Minimal BYO-LLM subpackage