Two-deployment pattern: SaaS ↔ On-Prem через .env / home / architecture / two-deployment-pattern
architecturedeploymentsaason-prem

Two-deployment pattern

Архитектурное требование: один код базы, два режима развёртывания. Переключение через .env без изменения кода графов.

Зачем

SaaS режим — для:

On-Prem режим — для:

Не дублировать код = не дублировать баги, не страдать при обновлениях.

Принцип

Каждый модуль с внешними зависимостями имеет адаптер с двумя реализациями:

ModuleAdapter (interface)
    ├── SaaSAdapter    talks to cloud APIs (Anthropic, OpenAI, Deepgram, ...)
    └── OnPremAdapter  talks to local services (vLLM, Ollama, WhisperX, ...)

Граф (бизнес-логика) видит только interface. Переключение через .env:

# .env (SaaS)
LLM_PROVIDER=anthropic
LLM_MODEL=claude-sonnet-4-6
AUDIO_PROVIDER=deepgram

# .env (On-Prem)
LLM_PROVIDER=vllm
LLM_BASE_URL=http://localhost:8000
LLM_MODEL=qwen-2.5-72b
AUDIO_PROVIDER=whisperx

Что должно быть абстрагировано

Зависимость SaaS On-Prem
LLM Anthropic/OpenAI через LiteLLM vLLM/Ollama локально
Embeddings OpenAI/Voyage AI BGE-M3 / nomic через Ollama
Audio + diarization Deepgram API (если позволят) [WhisperX](/whisperx-stack) локально
Vector store Pinecone/Qdrant Cloud pgvector (локальный Postgres)
Observability Langfuse Cloud Langfuse self-hosted или Phoenix
File storage S3 local filesystem / MinIO

Что НЕ нужно абстрагировать

Реализация

LiteLLM делает большую часть работы для LLM-абстракции. Для остального — простые Python interfaces + factory pattern в core/adapters/.

Структура:

src/
  adapters/
    llm/          # LiteLLM wrapper + custom providers
    audio/        # WhisperX / Deepgram
    embeddings/   # ...
    vectorstore/  # pgvector default
    storage/      # local / s3
    obs/          # phoenix / langfuse
  config.py       # читает .env и инстанцирует адаптеры
  graphs/         # бизнес-логика, видит interfaces

Тестирование

Связано

Metadata
title
Two-deployment pattern: SaaS ↔ On-Prem через .env
tags
['architecture', 'deployment', 'saas', 'on-prem']
source
gemini-artifact + dima-decision-2026-06-29
created
2026-06-29