Skip to main content

Performance Tuning

These settings control worker behavior, model inference, batch sizes, timeouts, OCR, and rate limits. Start with the symptom you are seeing, then tune the smallest matching knob.

Quick Tuning Map​

SymptomFirst AdjustmentWhy
High embedding memoryLower EMBEDDING_BATCH_SIZE or MAX_NODES_PER_TASKReduces texts held per FastEmbed call and per Celery task
Slow document ingestionAdd embedding workers before increasing embedding concurrencyEach embedding worker keeps model memory isolated
Slow classificationLower CLASSIFICATION_SELECT_TOP_K or enable MODERNBERT_PREFILTER_ENABLEDScores fewer chunks/categories with ONNX
ONNX CPU oversubscriptionKeep the Settings/.env.example thread defaults at 1, then inspect effective Compose overridesPrevents worker processes from competing for the same cores
OCR-heavy uploads are slowIncrease preprocessing capacity or raise OCR_PAGE_TEXT_THRESHOLD carefullyOCR runs in preprocessing and is CPU-heavy
Slow rerankingReduce the requested rerank prefix or disable reranking; see RerankingRequests wait for a bounded inference slot and worker inference; increasing the timeout does not bound native work
Too many protected-route 429sIncrease RATE_LIMIT, reduce request volume, or add an external limiter/capacity planRate limiting is per resolved client id for protected routes; /search and /web-search also have route-specific counters
Too many auth-failure 429sIncrease AUTH_FAILURE_RATE_LIMIT only after ruling out credential probingFailed auth attempts are rate limited per source address before client resolution

Worker Concurrency​

Production sizing is generated by just prod-up in .runtime/prod.env:

SettingProduction planner behavior
PROD_EMBEDDING_CONCURRENCYFixed at 1
PROD_PREPROCESSING_CONCURRENCY1 below the 4GB preprocessing target; otherwise 2
PROD_API_WORKERSFixed at 1

Do not casually raise embedding worker concurrency. Each prefork child can load the dense and sparse embedding models plus spaCy; add embedding replicas instead so each process keeps an isolated model copy. Publication-enabled API containers also keep one Uvicorn process per PUBLICATION_WORKER_SLOT; scale HTTP serving with separately slotted replicas, not extra processes in one slot.

The base Compose preprocessing service uses MODERNBERT_ONNX_INTRA_OP_THREADS=4 when no value is provided, while the Settings and .env.example defaults are 1. Set the value explicitly when CPU limits make the Compose default too aggressive.

Embedding and Search Knobs​

SettingDefaultWhy It Matters
MAX_NODES_PER_TASK50Number of chunks grouped into one embedding Celery task
EMBEDDING_BATCH_SIZE32Number of texts processed at once by FastEmbed
RETRIEVAL_TOP_K10Default number of Document Version Evidence Results
RERANK_TIMEOUT_SEC2.0 secondsCaller wait deadline; see timeout semantics

top_k_rerank is a request parameter (default 20), not an environment variable.

Classification and NER Knobs​

SettingDefaultWhy It Matters
CLASSIFICATION_ENABLEDtrueDisables ModernBERT classification when set to false
SPACY_NER_ENABLEDtrueDisables entity extraction when set to false
CLASSIFICATION_SELECT_TOP_K3Number of representative chunks selected via centroid + MMR
MODERNBERT_PREFILTER_ENABLEDfalseEnables lexical prefiltering before ONNX scoring
MODERNBERT_PREFILTER_TOP_K3Number of candidate categories kept by the prefilter
MODERNBERT_ONNX_NLI_MAX_TOKENS2048Maximum NLI sequence length before truncation
MODERNBERT_ONNX_INTRA_OP_THREADS1ONNX Runtime threads within a single operator
MODERNBERT_ONNX_INTER_OP_THREADS1ONNX Runtime threads across operators
Container defaults

The Settings and .env.example defaults are 1 for both ONNX thread settings. The base Compose preprocessing service falls back to 4 intra-op threads when no value is supplied; set the environment value explicitly when CPU limits make that fallback too aggressive.

OCR and Upload Knobs​

SettingDefaultWhy It Matters
MAX_FILE_SIZE_MB200Upload size limit enforced before processing starts
OCR_PAGE_TEXT_THRESHOLD80PDF pages with fewer than 80 native text characters use OCR fallback
ALLOWED_EXTENSIONSSee .env.exampleControls accepted file extensions
ALLOWED_MIME_TYPESSee .env.exampleValidates uploaded file MIME types

Office File Settings​

SettingDefaultWhy It Matters
OFFICE_LEGACY_CONVERSION_ENABLEDfalseEnables LibreOffice conversion for .ppt/.xls (legacy binary formats)
OFFICE_LEGACY_CONVERSION_TIMEOUT_SEC120Timeout per legacy Office conversion; large files may need more time
LIBREOFFICE_BINARYsofficeLibreOffice executable path
OFFICE_MAX_UNCOMPRESSED_BYTES1000000000Max decompressed size for OOXML files (zip-bomb guard)
OFFICE_MAX_COMPRESSION_RATIO200Max uncompressed:compressed ratio for OOXML files

Celery Worker Knobs​

SettingDefaultWhy It Matters
CELERY_BROKER_VISIBILITY_TIMEOUT_SEC3600 secondsVisibility timeout for broker and result-backend task delivery
CELERY_WORKER_MAX_MEMORY_PER_CHILD1572864 KBBase memory recycle threshold for worker children
CELERY_WORKER_MAX_TASKS_PER_CHILD100Global task recycle threshold
CELERY_WORKER_MAX_TASKS_PER_CHILD_EMBEDDING250Embedding worker recycle threshold
CELERY_WORKER_MAX_TASKS_PER_CHILD_PREPROCESSING500Preprocessing worker recycle threshold
CELERY_TASK_MAX_RETRIES3Maximum retry attempts for recoverable task failures
CELERY_RETRY_BACKOFF_BASE60 secondsBase delay for exponential retry backoff
CELERY_RESULT_EXPIRES86400 secondsTime Celery results remain in Redis DB /2
CELERY_EMBED_SOFT_TIME_LIMIT_SEC900Soft timeout for embedding tasks
CELERY_EMBED_TIME_LIMIT_SEC1200Hard timeout for embedding tasks

Rate-Limit Knob​

SettingDefaultWhy It Matters
RATE_LIMIT30Requests per minute per resolved client id for protected endpoints
AUTH_FAILURE_RATE_LIMIT10Failed authentication attempts per minute per source address

The built-in limiter uses a 60-second sliding window. Set RATE_LIMIT=0 to disable it. A limited request returns HTTP 429 with X-RateLimit-Limit, X-RateLimit-Remaining, and X-RateLimit-Reset headers. Production traffic across API workers shares Redis-backed counters through REDIS_URL; use a reverse proxy or edge limiter only for additional network-level protection.

The application and Compose fallbacks use RATE_LIMIT=30; the repository .env.example sets RATE_LIMIT=300 as a local-testing override. Copying that example changes the effective limit until you set the value intended for the deployment.

Status Endpoint Details​

GET /status/{job_id} can return:

  • pending
  • processing
  • completed
  • failed
  • partial_failed
  • retrying

partial_failed means some embedding tasks failed while others succeeded.

When to Leave Defaults Alone​

Keep the defaults when you are still validating correctness or running a small deployment. Most tuning should happen only after just status, logs, or benchmark results show a specific bottleneck.