📝(doc) fix/add documentation

This is a first step to write some useful documentation.
This commit is contained in:
Quentin BEY
2025-11-05 10:29:35 +01:00
parent 55400636b6
commit 5e497b2ccb
12 changed files with 458 additions and 43 deletions
+10
View File
@@ -141,6 +141,16 @@ You first need to create a superuser account:
$ make superuser
```
## Documentation 📚
Additional documentation is available in the `docs/` directory:
- [LLM Configuration](docs/llm-configuration.md) - Configure Large Language Models and providers
- [Environment Variables](docs/env.md) - All available environment variables
- [Installation Guide](docs/installation.md) - Deploy on a Kubernetes cluster
- [Theming](docs/theming.md) - Customize the application appearance
- [Architecture](docs/architecture.md) - Technical architecture overview
## Licence 📝
This work is released under the MIT License (see [LICENSE](https://github.com/suitenumerique/conversations/blob/main/LICENSE)).
+2 -2
View File
@@ -7,8 +7,8 @@ flowchart TD
User -- HTTP --> Front("Frontend (NextJS SPA)")
Front -- REST API --> Back("Backend (Django)")
Front -- OIDC --> Back -- OIDC ---> OIDC("Keycloak / ProConnect")
Back -- REST API --> Yserver
Back --> DB("Database (PostgreSQL)")
Back <--> Celery --> DB
Back --> Cache("Cache (Redis)")
Back ----> S3("Minio (S3)")
Back -- REST API --> LLM("LLM Providers")
```
+9 -9
View File
@@ -10,7 +10,6 @@ These are the environment variables you can set for the `conversations-backend`
|-------------------------------------------------|-----------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------|
| DJANGO_ALLOWED_HOSTS | allowed hosts | [] |
| DJANGO_SECRET_KEY | secret key | |
| DJANGO_SERVER_TO_SERVER_API_TOKENS | | [] |
| DB_ENGINE | engine to use for database connections | django.db.backends.postgresql_psycopg2 |
| DB_NAME | name of the database | conversations |
| DB_USER | user to authenticate with | dinum |
@@ -24,12 +23,11 @@ These are the environment variables you can set for the `conversations-backend`
| AWS_S3_SECRET_ACCESS_KEY | access key for s3 endpoint | |
| AWS_S3_REGION_NAME | region name for s3 endpoint | |
| AWS_STORAGE_BUCKET_NAME | bucket name for s3 endpoint | conversations-media-storage |
| ATTACHMENT_MAX_SIZE | maximum size of document in bytes | 10485760 |
| ATTACHMENT_MAX_SIZE | maximum size of document in bytes | 10485760 |
| LANGUAGE_CODE | default language | en-us |
| API_USERS_LIST_THROTTLE_RATE_SUSTAINED | throttle rate for api | 180/hour |
| API_USERS_LIST_THROTTLE_RATE_BURST | throttle rate for api on burst | 30/minute |
| SPECTACULAR_SETTINGS_ENABLE_DJANGO_DEPLOY_CHECK | | false |
| TRASHBIN_CUTOFF_DAYS | trashbin cutoff | 30 |
| DJANGO_EMAIL_BACKEND | email backend library | django.core.mail.backends.smtp.EmailBackend |
| DJANGO_EMAIL_BRAND_NAME | brand name for email | |
| DJANGO_EMAIL_HOST | host name of email | |
@@ -76,12 +74,14 @@ These are the environment variables you can set for the `conversations-backend`
| OIDC_USERINFO_FULLNAME_FIELDS | OIDC token claims to create full name | ["first_name", "last_name"] |
| OIDC_USERINFO_SHORTNAME_FIELD | OIDC token claims to create shortname | first_name |
| ALLOW_LOGOUT_GET_METHOD | Allow get logout method | true |
| AI_API_KEY | AI key to be used for AI Base url | |
| AI_BASE_URL | OpenAI compatible AI base url | |
| AI_MODEL | AI Model to use | |
| AI_AGENT_INSTRUCTION | Base instruction for the AI agent | You are a helpful assistant |
| Y_PROVIDER_API_KEY | Y provider API key | |
| Y_PROVIDER_API_BASE_URL | Y Provider url | |
| LLM_CONFIGURATION_FILE_PATH | Path to the LLM configuration JSON file. See [LLM Configuration](llm-configuration.md) for details | <BASE_DIR>/conversations/configuration/llm/default.json |
| LLM_DEFAULT_MODEL_HRID | HRID of the model used for conversations | default-model |
| LLM_SUMMARIZATION_MODEL_HRID | HRID of the model used for summarization | default-summarization-model |
| AI_API_KEY | AI API key to be used for the default provider (used in default LLM configuration, not for production use) | |
| AI_BASE_URL | OpenAI compatible AI base URL (used in default LLM configuration, not for production use) | |
| AI_MODEL | AI Model name to use (used in default LLM configuration, not for production use) | |
| AI_AGENT_INSTRUCTIONS | Base instruction for the AI agent (used in default LLM configuration, not for production use) | You are a helpful assistant. Wrap formulas... |
| AI_AGENT_TOOLS | List of enabled tools for the agent (used in default LLM configuration, not for production use) | [] |
| CONVERSION_API_ENDPOINT | Conversion API endpoint | convert-markdown |
| CONVERSION_API_CONTENT_FIELD | Conversion api content field | content |
| CONVERSION_API_TIMEOUT | Conversion api timeout | 30 |
-1
View File
@@ -9,7 +9,6 @@ backend:
DJANGO_CSRF_TRUSTED_ORIGINS: https://conversations.127.0.0.1.nip.io
DJANGO_CONFIGURATION: Feature
DJANGO_ALLOWED_HOSTS: conversations.127.0.0.1.nip.io
DJANGO_SERVER_TO_SERVER_API_TOKENS: secret-api-key
DJANGO_SECRET_KEY: AgoodOrAbadKey
DJANGO_SETTINGS_MODULE: conversations.settings
DJANGO_SUPERUSER_PASSWORD: admin
+1 -1
View File
@@ -7,7 +7,7 @@ This document is a step-by-step guide that describes how to install Conversation
- k8s cluster with an nginx-ingress controller
- an OIDC provider (if you don't have one, we provide an example)
- a PostgreSQL server (if you don't have one, we provide an example)
- a Memcached server (if you don't have one, we provide an example)
- a Redis server (if you don't have one, we provide an example)
- a S3 bucket (if you don't have one, we provide an example)
### Test cluster
+412
View File
@@ -0,0 +1,412 @@
# LLM Configuration
This document describes how to configure Large Language Models (LLMs) in Conversations via the configuration file.
## Overview
Conversations uses a JSON configuration file to define LLM models and providers. This approach allows you to:
- Configure multiple LLM models from different providers
- Switch between models without code changes
- Customize model-specific settings like temperature, max tokens, and system prompts
- Enable or disable models dynamically
The overall structure consists of two main sections: `providers` and `models`.
Settings for models, provides customization through `settings` and `profile`, which corresponds to the
Pydantic AI model settings and profile. While we currently not use those settings extensively,
they are available for future use and advanced configurations, please reach us if you face any problem using them.
## Configuration File Location
The default LLM configuration file is located at:
```
src/backend/conversations/configuration/llm/default.json
```
You can override this location by setting the `LLM_CONFIGURATION_FILE_PATH` environment variable, but be careful as
this path must be accessible by the backend application _inside the docker image_:
``` ini
LLM_CONFIGURATION_FILE_PATH=/path/to/your/llm/config.json
```
## Default Behavior
### Default Configuration
The default configuration file is useful for local development and running the test, while it can be used
in production, we suggest to create a specific one for production and replace the `settings.` values with
`environ.` one.
The default configuration file (`default.json`) includes:
1. **Two default models**:
- `default-model`: The primary conversational model used for chat interactions
- `default-summarization-model`: A specialized model for summarizing conversations
2. **One default provider**:
- `default-provider`: An OpenAI-compatible provider that uses environment variables for configuration
### Environment Variable Integration
The configuration uses dynamic value resolution with two special prefixes:
- `settings.VARIABLE_NAME`: Resolves to a Django setting value
- `environ.VARIABLE_NAME`: Resolves to an environment variable value
For example, in the default configuration:
```json
{
"model_name": "settings.AI_MODEL",
"system_prompt": "settings.AI_AGENT_INSTRUCTIONS",
"tools": "settings.AI_AGENT_TOOLS"
}
```
This allows to configure models in tests using the setting override mechanism from Django/Pytest (but might be replaced
later with a simple override of the full configuration like it's done in some tests already).
### Required Environment Variables
For the default configuration to work, you need to set these environment variables:
| Variable | Description | Example |
|-------------------------------|----------------------------------------|-----------------------------|
| `AI_API_KEY` | API key for the default provider | `sk-...` |
| `AI_BASE_URL` | Base URL for the OpenAI-compatible API | `https://api.openai.com/v1` |
| `AI_MODEL` | Model name to use | `gpt-4o-mini` |
### Optional Environment Variables
If you want to customize the agent behavior and tools, you can set these optional environment variables
(defaults are provided in the default configuration):
| Variable | Description | Default |
|-------------------------------|----------------------------------------|-------------------|
| `AI_AGENT_INSTRUCTIONS` | System prompt for the agent | see `settings.py` |
| `AI_AGENT_TOOLS` | List of enabled tools | `[]` |
| `SUMMARIZATION_SYSTEM_PROMPT` | Base prompt of the summarization agent | see `settings.py` |
### Model Selection
You can configure which models are used for specific tasks via environment variables:
| Variable | Description | Default |
|--------------------------------|------------------------------------------|-------------------------------|
| `LLM_DEFAULT_MODEL_HRID` | HRID of the model used for conversations | `default-model` |
| `LLM_SUMMARIZATION_MODEL_HRID` | HRID of the model used for summarization | `default-summarization-model` |
## Configuration Structure
The configuration file has two main sections:
### 1. Providers
Providers define the API endpoints and authentication for LLM services.
```json
{
"providers": [
{
"hrid": "unique-provider-id",
"base_url": "https://api.example.com/v1",
"api_key": "environ.API_KEY_VAR",
"kind": "openai"
}
]
}
```
**Provider Fields:**
| Field | Type | Required | Description |
|------------|--------|----------|---------------------------------------------------------|
| `hrid` | string | Yes | Unique identifier for the provider |
| `base_url` | string | Yes | API base URL (can use `settings.` or `environ.` prefix) |
| `api_key` | string | Yes | API authentication key (use `environ.` here) |
| `kind` | string | Yes | Provider type: `openai` or `mistral` |
### 2. Models
Models define the LLMs available in your application.
```json
{
"models": [
{
"hrid": "unique-model-id",
"model_name": "gpt-4o-mini",
"human_readable_name": "GPT-4o Mini",
"provider_name": "unique-provider-id",
"profile": null,
"settings": {},
"is_active": true,
"icon": null,
"system_prompt": "You are a helpful assistant",
"tools": []
}
]
}
```
**Model Fields:**
| Field | Type | Required | Description |
|-----------------------|--------------|----------|-----------------------------------------------------------------------------------------------------|
| `hrid` | string | Yes | Unique identifier for the model |
| `model_name` | string | Yes | Name of the model as recognized by the provider (can use `settings.` or `environ.` prefix) |
| `human_readable_name` | string | Yes | Display name shown to users |
| `provider_name` | string | No* | Reference to a provider's `hrid` |
| `provider` | object | No* | Inline provider definition (alternative to `provider_name`) |
| `profile` | object | No | Model-specific capabilities and settings |
| `settings` | object | No | Model inference settings (temperature, max_tokens, etc.) |
| `is_active` | boolean | Yes | Whether the model is available for use |
| `icon` | string/array | No | Base64-encoded icon or array of icon parts |
| `system_prompt` | string | Yes | Default system prompt for the model (can use `settings.` or `environ.` prefix) |
| `tools` | array | Yes | List of enabled tools for this model (can use `settings.` or `environ.` prefix for the whole array) |
| `supports_streaming` | boolean | No | Whether the model supports streaming responses |
\* Either `provider_name` or `provider` must be set, unless `model_name` is in the format `<provider>:<model>`.
## Adding New Models
### Example 1: Adding a New OpenAI Model
To add a new OpenAI model using the existing default provider:
```json
{
"models": [
// ...existing models...
{
"hrid": "gpt-4-turbo",
"model_name": "gpt-4-turbo-preview",
"human_readable_name": "GPT-4 Turbo",
"provider_name": "default-provider",
"profile": null,
"settings": {
"temperature": 0.7,
"max_tokens": 4096
},
"is_active": true,
"icon": null,
"system_prompt": "You are an expert AI assistant.",
"tools": ["web_search_brave_with_document_backend"],
"supports_streaming": true
}
],
"providers": [
// ...existing providers...
]
}
```
### Example 2: Adding a Model using Pydantic AI format
To add a model with a specific provider using the default Pydantic AI format, you don't need to define the provider separately if you use the `model_name` format `<provider>:<model>`.
1. **Add the model without provider**:
```json
{
"models": [
{
"hrid": "claude-3-opus",
"model_name": "anthropic:claude-3-opus-20240229",
"human_readable_name": "Claude 3 Opus",
"provider_name": null,
"profile": null,
"settings": {
"temperature": 0.7,
"max_tokens": 4096
},
"is_active": true,
"icon": null,
"system_prompt": "You are Claude, a helpful AI assistant.",
"tools": []
}
],
"providers": []
}
```
2**Set the environment variable**:
Pydantic AI expects the API key in an environment variable named `ANTHROPIC_API_KEY` is this example, so set it accordingly:
```ini
ANTHROPIC_API_KEY=your-api-key-here
```
### Example 3: Adding a Mistral Model
For Mistral AI models using the Etalab platform:
```json
{
"models": [
{
"hrid": "mistral-large",
"model_name": "mistral-large-latest",
"human_readable_name": "Mistral Large (Etalab)",
"provider_name": "mistral-etalab",
"profile": null,
"settings": {
"temperature": 0.5,
"max_tokens": 8192
},
"is_active": true,
"icon": null,
"system_prompt": "settings.AI_AGENT_INSTRUCTIONS",
"tools": ["web_search_brave_with_document_backend"]
}
],
"providers": [
{
"hrid": "mistral-etalab",
"base_url": "https://api.mistral.etalab.gouv.fr/",
"api_key": "environ.MISTRAL_ETALAB_API_KEY",
"kind": "mistral"
}
]
}
```
### Example 4: Using Inline Provider Definition
Instead of referencing a provider by name, you can define it inline if you use a unique configuration:
```json
{
"models": [
{
"hrid": "custom-model",
"model_name": "custom-model-v1",
"human_readable_name": "Custom Model",
"provider": {
"hrid": "custom-provider-inline",
"base_url": "https://custom-api.example.com/v1",
"api_key": "environ.CUSTOM_API_KEY",
"kind": "openai"
},
"settings": {},
"is_active": true,
"icon": null,
"system_prompt": "You are a custom assistant.",
"tools": []
}
]
}
```
## Advanced Configuration
### Model Settings
The `settings` object supports various inference parameters:
```json
{
"settings": {
"max_tokens": 4096,
"temperature": 0.7,
"top_p": 0.9,
"timeout": 60.0,
"parallel_tool_calls": true,
"seed": 42,
"presence_penalty": 0.0,
"frequency_penalty": 0.0,
"logit_bias": {},
"stop_sequences": [],
"extra_headers": {},
"extra_body": {}
}
}
```
### Model Profile
The `profile` object defines model capabilities:
```json
{
"profile": {
"supports_tools": true,
"supports_json_schema_output": true,
"supports_json_object_output": true,
"default_structured_output_mode": "json_schema",
"thinking_tags": ["<thinking>", "</thinking>"],
"ignore_streamed_leading_whitespace": true
}
}
```
### Available Tools
Tools can be specified in the `tools` array. Common tools include:
- `web_search_brave_with_document_backend`: Web search using Brave API with document processing
You can also reference the tools list from Django settings:
```json
{
"tools": "settings.AI_AGENT_TOOLS"
}
```
### Custom Icons
Icons can be provided as base64-encoded PNG images. For long strings, you can split them into an array:
```json
{
"icon": [
"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABwAAAAcCAMAAABF0y+m",
"AAAAn1BMVEUALosAKoovTZjw8vb////+9/jlPUniAAziABUAGIWbpsTwq7HhAAAA"
]
}
```
## Validation
The configuration is validated when loaded. Common validation errors include:
- **Provider not found**: A model references a `provider_name` that doesn't exist in the `providers` array
- **Missing provider**: Neither `provider_name` nor `provider` is specified, and `model_name` is not in `<provider>:<model>` format
- **Environment variable not set**: A value using `environ.` prefix references an undefined environment variable
- **Django setting not set**: A value using `settings.` prefix references an undefined Django setting
- **Invalid provider kind**: The `kind` field must be either `openai` or `mistral`
## Testing Your Configuration
After modifying the configuration file, you can test it by:
1. **Checking for syntax errors**:
```bash
python -m json.tool src/backend/conversations/configuration/llm/default.json
```
2. **Starting the application** and checking the logs for validation errors
3. **Using the Django shell** to load the configuration:
```bash
./bin/manage shell
```
```python
from django.conf import settings
models = settings.LLM_CONFIGURATIONS
models.keys() # Should show all model HRIDs
```
## Best Practices
1. **Use environment variables** for sensitive data like API keys (with `environ.` prefix)
2. **Use Django settings** for configurable values that may change between environments (with `settings.` prefix)
3. **Keep provider definitions separate** from models to avoid duplication when using multiple models from the same provider
4. **Set `is_active: false`** for models you want to keep in the configuration but temporarily disable
5. **Use descriptive `hrid` values** that clearly identify the model and provider
6. **Document custom configurations** in your deployment documentation
7. **Test configuration changes** in a development environment before deploying to production
## See Also
- [Environment Variables Documentation](env.md) - For configuring environment variables
- [Installation Guide](installation.md) - For deployment instructions
+20 -20
View File
@@ -14,15 +14,15 @@ Memory is the first bottleneck; CPU matters only when Celery or the Next.js buil
## 2. Development Environment Memory Requirements
| Service | Typical use | Rationale / source |
|-----------------------|-------------------------------|-----------------------------------------------------------------------------------------|
| PostgreSQL | **1 2 GB** | `shared_buffers` starting point ≈ 25% RAM ([postgresql.org][1]) |
| Keycloak | **≈ 1.3 GB** | 70% of limit for heap + ~300 MB non-heap ([keycloak.org][2]) |
| Redis | **≤ 256 MB** | Empty instance ≈ 3 MB; budget 256 MB to allow small datasets ([stackoverflow.com][3]) |
| MinIO | **2 GB (dev) / 32 GB (prod)** | Pre-allocates 12 GiB; docs recommend 32 GB per host for ≤ 100 Ti storage ([min.io][4]) |
| Django API (+ Celery) | **0.8 1.5 GB** | Empirical in-house metrics |
| Next.js frontend | **0.5 1 GB** | Dev build chain |
| Nginx | **< 100 MB** | Static reverse-proxy footprint |
| Service | Typical use | Rationale / source |
|------------------|-------------------------------|-----------------------------------------------------------------------------------------|
| PostgreSQL | **1 2 GB** | `shared_buffers` starting point ≈ 25% RAM ([postgresql.org][1]) |
| Keycloak | **≈ 1.3 GB** | 70% of limit for heap + ~300 MB non-heap ([keycloak.org][2]) |
| Redis | **≤ 256 MB** | Empty instance ≈ 3 MB; budget 256 MB to allow small datasets ([stackoverflow.com][3]) |
| MinIO | **2 GB (dev) / 32 GB (prod)** | Pre-allocates 12 GiB; docs recommend 32 GB per host for ≤ 100 Ti storage ([min.io][4]) |
| Django API | **0.8 1.5 GB** | Empirical in-house metrics |
| Next.js frontend | **0.5 1 GB** | Dev build chain |
| Nginx | **< 100 MB** | Static reverse-proxy footprint |
[1]: https://www.postgresql.org/docs/9.1/runtime-config-resource.html "PostgreSQL: Documentation: 9.1: Resource Consumption"
[2]: https://www.keycloak.org/high-availability/concepts-memory-and-cpu-sizing "Concepts for sizing CPU and memory resources - Keycloak"
@@ -58,7 +58,7 @@ Production deployments differ significantly from development environments. The t
| Service | Memory | Notes |
|----------------------------------|------------|----------------------------------------|
| PostgreSQL | **2 GB** | Core database |
| Django API (+ Celery) | **1.5 GB** | Backend services |
| Django API | **1.5 GB** | Backend services |
| Nginx | **100 MB** | Static files + reverse proxy |
| Redis | **256 MB** | Session storage |
| **Total (without auth/storage)** | **≈ 4 GB** | External OIDC + object storage assumed |
@@ -81,16 +81,16 @@ Production deployments differ significantly from development environments. The t
## 5. Ports (dev defaults)
| Port | Service |
|-----------|-----------------------|
| 3000 | Next.js |
| 8071 | Django |
| 8080 | Keycloak |
| 8083 | Nginx proxy |
| 9000/9001 | MinIO |
| 15432 | PostgreSQL (main) |
| 5433 | PostgreSQL (Keycloak) |
| 1081 | Maildev |
| Port | Service |
|-----------|----------------------------|
| 3000 | Next.js |
| 8071 | Django |
| 8080 | Keycloak |
| 8083 | Nginx proxy |
| 9000/9001 | MinIO |
| 15432 | PostgreSQL (main) |
| 5433 | PostgreSQL (Keycloak) |
| 1081 | Maildev (currently unused) |
## 6. Sizing Guidelines
+4 -4
View File
@@ -4,7 +4,7 @@
To use this feature, simply set the `FRONTEND_CSS_URL` environment variable to the URL of your custom CSS file. For example:
```javascript
```ini
FRONTEND_CSS_URL=http://anything/custom-style.css
```
@@ -38,7 +38,7 @@ The footer is configurable from the theme customization file.
### Settings 🔧
```shellscript
```ini
THEME_CUSTOMIZATION_FILE_PATH=<path>
```
@@ -55,10 +55,10 @@ The translations can be partially overridden from the theme customization file.
### Settings 🔧
```shellscript
```ini
THEME_CUSTOMIZATION_FILE_PATH=<path>
```
### Example of JSON
The json must follow some rules: https://github.com/suitenumerique/conversations/blob/main/src/helm/env.d/dev/configuration/theme/demo.json
The json must follow some rules: https://github.com/suitenumerique/conversations/blob/main/src/helm/env.d/dev/configuration/theme/demo.json
-1
View File
@@ -1,6 +1,5 @@
# For the CI job test-e2e
BURST_THROTTLE_RATES="200/minute"
DJANGO_SERVER_TO_SERVER_API_TOKENS=test-e2e
SUSTAINED_THROTTLE_RATES="200/hour"
# Features
-3
View File
@@ -631,9 +631,6 @@ class Base(BraveSettings, Configuration):
LLM_DEFAULT_MODEL_HRID = values.Value(
"default-model", environ_name="LLM_DEFAULT_MODEL_HRID", environ_prefix=None
)
LLM_ROUTING_MODEL_HRID = values.Value(
"default-routing-model", environ_name="LLM_ROUTING_MODEL_HRID", environ_prefix=None
)
LLM_SUMMARIZATION_MODEL_HRID = values.Value(
"default-summarization-model",
environ_name="LLM_SUMMARIZATION_MODEL_HRID",
@@ -16,7 +16,6 @@ backend:
DJANGO_CSRF_TRUSTED_ORIGINS: https://conversations.127.0.0.1.nip.io
DJANGO_CONFIGURATION: Feature
DJANGO_ALLOWED_HOSTS: conversations.127.0.0.1.nip.io
DJANGO_SERVER_TO_SERVER_API_TOKENS: secret-api-key
DJANGO_SECRET_KEY: *djangoSecretKey
DJANGO_SETTINGS_MODULE: conversations.settings
DJANGO_SUPERUSER_PASSWORD: admin
@@ -19,7 +19,6 @@ backend:
DJANGO_CSRF_TRUSTED_ORIGINS: https://conversations.127.0.0.1.nip.io
DJANGO_CONFIGURATION: Feature
DJANGO_ALLOWED_HOSTS: conversations.127.0.0.1.nip.io
DJANGO_SERVER_TO_SERVER_API_TOKENS: secret-api-key
DJANGO_SECRET_KEY: *djangoSecretKey
DJANGO_SETTINGS_MODULE: conversations.settings
DJANGO_SUPERUSER_PASSWORD: admin