Model Provider Architecture#
Overview#
Introduced in v0.27.0 , the model provider architecture replaces the legacy flat tenant_llm table with a normalized three-tier hierarchy: Provider → Instance → Model. This enables multiple configured instances of the same provider (e.g., two different OpenAI API keys), multi-capability models expressed as integer bit flags, and group-based routing/load balancing across instances.
Table Hierarchy#
TenantModelProvider (one per provider per tenant)
└── TenantModelInstance (one per API key / endpoint config)
└── TenantModel (one per model name, with bit-flag capabilities)
TenantModelGroup / TenantModelGroupMapping (optional routing layer over TenantModel rows)
TenantModelProvider#
tenant_model_provider — scoped by a (tenant_id, provider_name) unique index. Maps a tenant to a named provider (e.g., "OpenAI").
TenantModelInstance#
tenant_model_instance — holds credentials and config for one concrete API configuration: api_key, instance_name, status, and a JSON extra blob (for custom base URLs etc.).
TenantModel#
tenant_model — the leaf node. Each row represents one model (e.g., gpt-4o) within an instance. Key fields:
model_name— model identifier stringprovider_id/instance_id—VARCHAR(32)UUID foreign keys (not integers)model_type— integer bit flags encoding one or more capabilities (see below)extra— JSON blob for per-model overrides (max tokens, etc.)
TenantModelGroup / TenantModelGroupMapping#
tenant_model_group + tenant_model_group_mapping — optional routing layer. A group references multiple (provider_id, instance_id, model_id) triples with per-member weight values and a strategy (default: "weighted").
Model Type Bit Flags#
TenantModel.model_type is an IntegerField where each bit represents a capability, defined in ModelTypeBinary. A single row can express multiple capabilities with bitwise OR:
| Flag | Value | Meaning |
|---|---|---|
| CHAT | 1 | Chat/completion |
| EMBEDDING | 2 | Text embedding |
| ASR | 4 | Speech-to-text |
| VISION | 8 | Image-to-text |
| RERANK | 16 | Reranking |
| TTS | 32 | Text-to-speech |
| OCR | 64 | OCR |
Utilities in api/utils/model_utils.py:
calculate_model_type(names)— converts a list of type name strings → integer flag. Handles legacy aliases:speech2text→asr,image2text→vision.get_model_type_human(flag)— decodes an integer flag back to a list of lowercase type names.
FK References in Downstream Tables#
After v0.27.0, tenant, knowledgebase, dialog, and memory carry both the legacy string *_id columns and new tenant_*_id VARCHAR(32) columns that hold tenant_model.id UUIDs :
| Table | New UUID FK columns | Legacy string column(s) |
|---|---|---|
tenant | tenant_llm_id, tenant_embd_id, tenant_asr_id, tenant_img2txt_id, tenant_rerank_id, tenant_tts_id, tenant_ocr_id | llm_id, embd_id, … |
knowledgebase | tenant_embd_id | embd_id |
dialog | tenant_llm_id, tenant_rerank_id | llm_id, rerank_id |
memory | tenant_embd_id, tenant_llm_id | embd_id, llm_id |
Service Layer#
CRUD — api/db/services/tenant_model_service.py#
Low-level Peewee queries scoped to TenantModel: filter by provider_id, instance_id, and model_type (using bitwise & checks); batch status/type updates; delete by instance.
Business Logic — api/db/joint_services/tenant_model_service.py#
High-level resolution used by API services and task executors:
get_tenant_default_model_by_type()— returns the tenant's defaulttenant_modelrow for a capability typeresolve_model_config()— resolves a model reference (UUID or compositename@instance@providerstring) into a provider config dictget_model_config_by_id()— fetches config bytenant_model.idwith tenant ownership validationensure_tenant_model_ids_for_params()— auto-populatestenant_*_idFK fields in request parameters from model name lookupssplit_model_name()— right-anchored parser for composite model name strings
Legacy tenant_llm Table#
The original tenant_llm table (composite PK on tenant_id, llm_factory, llm_name; model_type as a plain string) is retained for backward compatibility. New code should use the three-tier tables. Legacy rows in tenant_llm were migrated to the new tables by the mysql_migration.py stages .
The migrate_model_type_names() helper in db_models.py keeps the model_type strings in tenant_llm in sync by renaming speech2text → asr and image2text → vision at startup .
Migration Path#
Seven ordered stages in tools/scripts/mysql_migration.py, orchestrated by tools/scripts/run_migrations.sh, handle the full upgrade from tenant_llm to the new tables :
| Stage | What it does |
|---|---|
tenant_model_provider | Migrates tenant_llm.llm_factory → tenant_model_provider |
tenant_model_instance | Migrates tenant_llm credentials → tenant_model_instance |
tenant_model | Migrates per-model rows → tenant_model |
model_id_config | Normalizes stored model IDs to model@default@provider format |
tenant_model_seeding | Seeds tenant_model from conf/llm_factories.json |
model_type_merge | Merges rows by (provider_id, instance_id, model_name), converts string types → integer bit flags |
tenant_model_id_migration | Populates tenant_*_id UUID FK columns across tenant, knowledgebase, dialog, memory |
See the Database Migrations article for full details on running and extending the migration system.