Lazy Imports & Fast Startup
PraisonAI Agents v0.5.0+ uses lazy imports to dramatically reduce startup time and memory usage. Heavy dependencies likelitellm, requests, and chromadb are only loaded when actually needed.
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
Thepraisonai 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 underTYPE_CHECKING, so importingpraisonai.agents_generatornever 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
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(...).
- 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.
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.
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
Import at point of use
Import at point of use
Defer optional modules until a feature is invoked — keeps CLI and server startup fast.
Install extras only when needed
Install extras only when needed
Use
pip install praisonaiagents[memory] rather than pulling every optional dependency upfront.Measure import time in CI
Measure import time in CI
Track cold import duration to catch accidental module-level heavy imports in PRs.
Prefer lite for embedded use
Prefer lite for embedded use
Use the lite package when you bring your own LLM client and need minimal footprint.
Use a scoped LazyCache in multi-tenant callers
Use a scoped LazyCache in multi-tenant callers
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:Related
Performance Benchmarks
Import time and memory metrics
Lite Package
Minimal BYO-LLM subpackage

