---
title: "Architecture"
manual: "TYPO3 LLM Extension"
version: "0.35"
permalink: "https://docs.typo3.org/permalink/netresearch/nr-llm:architecture@0.35"
source: "Architecture/Index.rst"
modified: "2026-09-16T22:09:16+00:00"
---

# Architecture

This section describes the architectural design of the TYPO3 LLM extension.

![Consuming extensions call the nr-llm service layer, which resolves a Configuration to a Model to a Provider and reaches the LLM API through the middleware pipeline.](../Images/diagram-architecture-overview.svg)

-   [Three-tier configuration architecture](https://docs.typo3.org/permalink/netresearch/nr-llm:three-tier-configuration-architecture@0.35)
-   [Service layer](https://docs.typo3.org/permalink/netresearch/nr-llm:service-layer@0.35)
-   [Security](https://docs.typo3.org/permalink/netresearch/nr-llm:security@0.35)

## Three-tier configuration architecture

The extension uses a three-level hierarchical architecture separating concerns:

```
┌─────────────────────────────────────────────────────────────────────────┐
│ CONFIGURATION (Use-Case Specific)                                        │
│ "blog-summarizer", "product-description", "support-translator"          │
│                                                                          │
│ Fields: system_prompt, temperature, max_tokens, use_case_type           │
│ References: model_uid → Model                                            │
└──────────────────────────────────┬──────────────────────────────────────┘
                                   │ N:1
┌──────────────────────────────────▼──────────────────────────────────────┐
│ MODEL (Available Models)                                                 │
│ "gpt-5", "claude-sonnet-4-5", "llama-70b", "text-embedding-3-large"     │
│                                                                          │
│ Fields: model_id, context_length, capabilities, pricing                 │
│ References: provider_uid → Provider                                      │
└──────────────────────────────────┬──────────────────────────────────────┘
                                   │ N:1
┌──────────────────────────────────▼──────────────────────────────────────┐
│ PROVIDER (API Connections)                                               │
│ "openai-prod", "openai-dev", "local-ollama", "azure-openai-eu"          │
│                                                                          │
│ Fields: endpoint_url, api_key (encrypted), adapter_type, timeout        │
└─────────────────────────────────────────────────────────────────────────┘

```

The same architecture expressed as PlantUML (for rendering with
external tools):

**Three-tier configuration architecture (PlantUML source)**

```text
@startuml
skinparam rectangle {
    BackgroundColor<<config>> #E8F5E9
    BackgroundColor<<model>>  #E3F2FD
    BackgroundColor<<provider>> #FFF3E0
}

rectangle "**CONFIGURATION**\n(Use-Case Specific)" <<config>> as C {
    note right
        blog-summarizer
        product-description
        support-translator
    end note
}

rectangle "**MODEL**\n(Available Models)" <<model>> as M {
    note right
        gpt-5, claude-sonnet-4-5
        llama-70b
        text-embedding-3-large
    end note
}

rectangle "**PROVIDER**\n(API Connections)" <<provider>> as P {
    note right
        openai-prod, openai-dev
        local-ollama
        azure-openai-eu
    end note
}

C -down-> M : "N:1\nmodel_uid"
M -down-> P : "N:1\nprovider_uid"
@enduml
```

### Benefits

-   **Multiple API keys per provider type**:
    Separate production and development accounts.
-   **Custom endpoints**: Azure OpenAI, Ollama, vLLM, local models.
-   **Reusable model definitions**: Centralized capabilities and pricing.
-   **Clear separation of concerns**: Connection vs capability vs use-case.

### Provider layer

Represents a specific API connection with credentials.

Database table: `tx_nrllm_provider`

| Field | Type | Description |
| --- | --- | --- |
| identifier | string | Unique slug (e.g., `openai-prod`, `ollama-local`) |
| name | string | Display name (e.g., `OpenAI Production`) |
| adapter_type | string | Protocol: `openai`, `anthropic`, `gemini`, `ollama`, etc. |
| endpoint_url | string | Custom endpoint (empty = default) |
| api_key | string | nr-vault identifier (UUID) for the encrypted key |
| organization_id | string | Optional organization ID (OpenAI) |
| timeout | int | Request timeout in seconds |
| max_retries | int | Retry count on failure |
| options | JSON | Additional adapter-specific options |

**Key design points:**

-   One provider = one API key = one billing relationship.
-   Same adapter type can have multiple providers (prod/dev accounts).
-   Adapter type determines the protocol/client class used.
-   API keys are stored as nr-vault identifiers (UUIDs); the raw key never
    touches nr-llm's tables.

### Model layer

Represents a specific model available through a provider.

Database table: `tx_nrllm_model`

| Field | Type | Description |
| --- | --- | --- |
| identifier | string | Unique slug (e.g., `gpt-5.3-instant`, `claude-sonnet-4-6`) |
| name | string | Display name (e.g., `GPT-5.3 Instant (128K)`) |
| provider_uid | int | Foreign key to Provider |
| model_id | string | API model identifier (e.g., `gpt-5.3-instant`, `claude-sonnet-4-6`) |
| context_length | int | Token limit (e.g., 128000) |
| max_output_tokens | int | Output limit (e.g., 16384) |
| capabilities | CSV | Supported features: `chat,vision,streaming,tools` |
| cost_input | int | Cents per 1M input tokens |
| cost_output | int | Cents per 1M output tokens |
| is_default | bool | Default model for this provider |

**Key design points:**

-   Models belong to exactly one provider.
-   Capabilities define what the model can do.
-   Pricing stored as integers (cents/1M tokens) to avoid float issues.
-   Same logical model can exist multiple times (different providers).

### Configuration layer

Represents a specific use case with model and prompt settings.

Database table: `tx_nrllm_configuration`

| Field | Type | Description |
| --- | --- | --- |
| identifier | string | Unique slug (e.g., `blog-summarizer`) |
| name | string | Display name (e.g., `Blog Post Summarizer`) |
| model_uid | int | Foreign key to Model |
| system_prompt | text | System message for the model |
| temperature | float | Creativity: 0.0 - 2.0 |
| max_tokens | int | Response length limit |
| top_p | float | Nucleus sampling |
| presence_penalty | float | Topic diversity |
| frequency_penalty | float | Word repetition penalty |
| use_case_type | string | `chat`, `completion`, `embedding`, `translation` |

**Key design points:**

-   Configurations reference models, not providers directly.
-   All LLM parameters are tunable per use case.
-   Same model can be used by multiple configurations.

## Service layer

The extension follows a layered service architecture:

```
┌─────────────────────────────────────────┐
│         Your Application Code           │
└────────────────┬────────────────────────┘
                 │
┌────────────────▼────────────────────────┐
│         Feature Services                │
│  (Completion, Embedding, Vision, etc.)  │
└────────────────┬────────────────────────┘
                 │
┌────────────────▼────────────────────────┐
│         LlmServiceManager               │
│    (Provider selection & routing)       │
└────────────────┬────────────────────────┘
                 │
┌────────────────▼────────────────────────┐
│       ProviderAdapterRegistry           │
│    (Maps adapters to database providers)│
└────────────────┬────────────────────────┘
                 │
┌────────────────▼────────────────────────┐
│       Provider Adapters                 │
│  (OpenAI, Claude, Gemini, Ollama, etc.) │
└─────────────────────────────────────────┘

```

### Feature services

High-level services for common AI tasks:

-   `CompletionService`: Text generation with
    format control (JSON, Markdown).
-   `EmbeddingService`: Text-to-vector conversion with caching.
-   `VisionService`: Image analysis for alt-text, titles, descriptions.
-   `TranslationService`: Language translation with glossaries.

### Provider adapters

The extension includes adapters for multiple LLM providers:

-   **OpenAI** (`OpenAiProvider`): GPT-5.x series, o-series reasoning models.
-   **Anthropic** (`ClaudeProvider`):
    Claude Opus 4.5, Claude Sonnet 4.5,
    Claude Haiku 4.5.
-   **Google** (`GeminiProvider`):
    Gemini 3 Pro, Gemini 3 Flash,
    Gemini 2.5 series.
-   **Ollama** (`OllamaProvider`): Local model deployment.
-   **OpenRouter** (`OpenRouterProvider`): Multi-model routing.
-   **Mistral** (`MistralProvider`): Mistral models.
-   **Groq** (`GroqProvider`): Fast inference.

## Security

### API key encryption

API keys are never stored as plaintext in nr-llm's own tables. Each provider
record holds a vault identifier (UUID) issued by the [nr-vault](https://github.com/netresearch/t3x-nr-vault) extension, which performs
envelope encryption with audited access.

-   The database stores only the vault UUID, never a raw key.
-   Retrieval and injection into outbound requests go through nr-vault's
    secure, SSRF-guarded HTTP client.
-   Key rotation is handled by nr-vault.

For the historical sodium-based design that this replaced, see [ADR-012: API key encryption at application level](https://docs.typo3.org/permalink/netresearch/nr-llm:adr-012@0.35).

### Supported adapter types

| Adapter Type | PHP Class | Default Endpoint |
| --- | --- | --- |
| openai | `OpenAiProvider` | [https://api.openai.com/v1](https://api.openai.com/v1) |
| anthropic | `ClaudeProvider` | [https://api.anthropic.com/v1](https://api.anthropic.com/v1) |
| gemini | `GeminiProvider` | [https://generativelanguage.googleapis.com/v1beta](https://generativelanguage.googleapis.com/v1beta) |
| ollama | `OllamaProvider` | [http://localhost:11434](http://localhost:11434) |
| openrouter | `OpenRouterProvider` | [https://openrouter.ai/api/v1](https://openrouter.ai/api/v1) |
| mistral | `MistralProvider` | [https://api.mistral.ai/v1](https://api.mistral.ai/v1) |
| groq | `GroqProvider` | [https://api.groq.com/openai/v1](https://api.groq.com/openai/v1) |
| azure_openai | `OpenAiProvider` | (custom Azure endpoint) |
| custom | `OpenAiProvider` | (custom endpoint) |
