# Environment Variables Required for Each Service in the Production Agentic RAG Course

> Discover the essential environment variables needed for each service in the production Agentic RAG course. Learn how Pydantic settings manage your configurations effectively.

- Repository: [jamwithai/production-agentic-rag-course](https://github.com/jamwithai/production-agentic-rag-course)
- Tags: how-to-guide
- Published: 2026-03-23

---

**The system uses Pydantic settings classes in [`src/config.py`](https://github.com/jamwithai/production-agentic-rag-course/blob/main/src/config.py) that load configuration from environment variables using double‑underscore delimiters (e.g., `ARXIV__BASE_URL`), where each service defines its own required variables and optional defaults.**

The `jamwithai/production-agentic-rag-course` repository implements a modular RAG pipeline where every component—from PDF parsing to vector search—reads its configuration through a centralized hierarchy defined in **[`src/config.py`](https://github.com/jamwithai/production-agentic-rag-course/blob/main/src/config.py)**. Understanding which **environment variables** each service expects is essential for deploying the application in development, staging, or production environments.

## How Configuration Works in [`src/config.py`](https://github.com/jamwithai/production-agentic-rag-course/blob/main/src/config.py)

At the core of the application lies a `BaseConfigSettings` class that leverages Pydantic’s `SettingsConfigDict` to load values from a **`.env`** file or the process environment. According to the source code, the loader applies three critical rules:

* **`env_nested_delimiter="__"`** – flattens nested fields with a double‑underscore separator.
* **`env_prefix`** – each service appends its own prefix (e.g., `ARXIV__`, `OPENSEARCH__`).
* **Case‑insensitive parsing** – variable names can be written in any casing.

When the application boots, the `get_settings()` singleton (bottom of [`src/config.py`](https://github.com/jamwithai/production-agentic-rag-course/blob/main/src/config.py)) aggregates every sub‑settings class into a single `Settings` object, making all **environment variables required for each service** available via attributes like `settings.arxiv` or `settings.opensearch`.

## Global Environment Variables

The top‑level settings class (lines 62‑73 in [`src/config.py`](https://github.com/jamwithai/production-agentic-rag-course/blob/main/src/config.py)) defines variables with no prefix. These apply to the FastAPI application core, database connections, and default LLM endpoints.

| Variable | Default Value | Description |
|----------|---------------|-------------|
| `APP_VERSION` | `0.1.0` | Application version string. |
| `DEBUG` | `True` | Enable FastAPI debug mode. |
| `ENVIRONMENT` | — | Deployment context: `development`, `staging`, or `production`. |
| `SERVICE_NAME` | `rag-api` | Service identifier used in logging and tracing. |
| `POSTGRES_DATABASE_URL` | `postgresql://rag_user:rag_password@localhost:5432/rag_db` | PostgreSQL connection string. |
| `POSTGRES_ECHO_SQL` | — | Boolean to echo SQL statements for debugging. |
| `POSTGRES_POOL_SIZE` | — | Connection pool size. |
| `POSTGRES_MAX_OVERFLOW` | — | Maximum overflow connections beyond pool size. |
| `OLLAMA_HOST` | `http://localhost:11434` | Base URL for the local Ollama service. |
| `OLLAMA_MODEL` | `llama3.2:1b` | Default model tag for text generation. |
| `OLLAMA_TIMEOUT` | — | Request timeout in seconds. |
| `JINA_API_KEY` | — | **Required** API key for Jina AI embeddings. |

## Service‑Specific Environment Variables

Each module defines a dedicated Pydantic class that maps environment variables to strongly‑typed attributes using the double‑underscore convention.

### Arxiv Service (`ARXIV__`)

Defined in the `ArxivSettings` class (lines 22‑41), these variables control paper fetching, PDF caching, and download concurrency.

- `ARXIV__BASE_URL` – Base URL for the arXiv API.
- `ARXIV__PDF_CACHE_DIR` – Directory path for downloaded PDF storage.
- `ARXIV__RATE_LIMIT_DELAY` – Seconds to wait between API calls.
- `ARXIV__TIMEOUT_SECONDS` – HTTP request timeout.
- `ARXIV__MAX_RESULTS` – Maximum papers returned per query.
- `ARXIV__SEARCH_CATEGORY` – Default arXiv category (e.g., `cs.AI`).
- `ARXIV__DOWNLOAD_MAX_RETRIES` – Retry attempts for failed PDF downloads.
- `ARXIV__DOWNLOAD_RETRY_DELAY_BASE` – Base delay for exponential back‑off.
- `ARXIV__MAX_CONCURRENT_DOWNLOADS` – Download concurrency limit.
- `ARXIV__MAX_CONCURRENT_PARSING` – PDF parsing concurrency limit.
- `ARXIV__NAMESPACES` *(optional)* – Custom XML namespaces.

### PDF Parser Service (`PDF_PARSER__`)

The `PDFParserSettings` class (lines 55‑68) governs document ingestion limits and OCR behavior.

- `PDF_PARSER__MAX_PAGES` – Maximum pages to process per PDF.
- `PDF_PARSER__MAX_FILE_SIZE_MB` – Upper file‑size limit for uploads.
- `PDF_PARSER__DO_OCR` – Boolean flag to enable OCR for scanned pages.
- `PDF_PARSER__DO_TABLE_STRUCTURE` – Boolean to preserve table structures.

### Chunking Service (`CHUNKING__`)

Configured via `ChunkingSettings` (lines 70‑83), these variables tune text segmentation strategies.

- `CHUNKING__CHUNK_SIZE` – Target word count per chunk.
- `CHUNKING__OVERLAP_SIZE` – Word overlap between consecutive chunks.
- `CHUNKING__MIN_CHUNK_SIZE` – Minimum words required for a valid chunk.
- `CHUNKING__SECTION_BASED` – Boolean to use document headings as chunk boundaries.

### OpenSearch Service (`OPENSEARCH__`)

The `OpenSearchSettings` class (lines 85‑106) manages vector and full‑text indexing parameters.

- `OPENSEARCH__HOST` – OpenSearch server URL.
- `OPENSEARCH__INDEX_NAME` – Primary index for document storage.
- `OPENSEARCH__CHUNK_INDEX_SUFFIX` – Suffix appended to create the chunk index (`{index_name}-{suffix}`).
- `OPENSEARCH__MAX_TEXT_SIZE` – Maximum text size permitted per document.
- `OPENSEARCH__VECTOR_DIMENSION` – Embedding dimensionality (e.g., **1024** for Jina).
- `OPENSEARCH__VECTOR_SPACE_TYPE` – Similarity metric: `cosinesimil`, `l2`, or `innerproduct`.
- `OPENSEARCH__RRF_PIPELINE_NAME` – Reciprocal Rank Fusion pipeline for hybrid search.
- `OPENSEARCH__HYBRID_SEARCH_SIZE_MULTIPLIER` – Multiplier for k‑nearest‑neighbour retrieval recall.

### Langfuse Observability (`LANGFUSE__`)

Tracing and monitoring are controlled by `LangfuseSettings` (lines 108‑126).

- `LANGFUSE__PUBLIC_KEY` – Public API key for authentication.
- `LANGFUSE__SECRET_KEY` – Secret API key.
- `LANGFUSE__HOST` – Langfuse server URL.
- `LANGFUSE__ENABLED` – Boolean to toggle tracing on or off.
- `LANGFUSE__FLUSH_AT` – Event count threshold for flushing traces.
- `LANGFUSE__FLUSH_INTERVAL` – Flush interval in seconds.
- `LANGFUSE__MAX_RETRIES` – API retry attempts.
- `LANGFUSE__TIMEOUT` – Request timeout in seconds.
- `LANGFUSE__DEBUG` – Enable verbose debug logging.

### Redis Caching (`REDIS__`)

The `RedisSettings` class (lines 128‑147) configures connection pooling and cache TTL.

- `REDIS__HOST` – Redis host (default: `localhost`).
- `REDIS__PORT` – Redis port (default: `6379`).
- `REDIS__PASSWORD` – Authentication password (optional).
- `REDIS__DB` – Database index (default: `0`).
- `REDIS__DECODE_RESPONSES` – Return Python objects instead of bytes.
- `REDIS__SOCKET_TIMEOUT` – Socket read timeout.
- `REDIS__SOCKET_CONNECT_TIMEOUT` – Connection establishment timeout.
- `REDIS__TTL_HOURS` – Cache time‑to‑live in hours.

### Telegram Bot (`TELEGRAM__`)

Finally, `TelegramSettings` (lines 149‑160) handles bot integration.

- `TELEGRAM__BOT_TOKEN` – Token obtained from BotFather.
- `TELEGRAM__ENABLED` – Boolean to enable or disable the Telegram interface.

## Accessing Settings in Application Code

Individual services import the singleton via `get_settings()` and extract their specific configuration objects. The example below illustrates how the **Arxiv** and **Redis** clients receive their respective **environment variables**:

```python
from src.config import get_settings

settings = get_settings()

# Arxiv service receives ARXIV__* variables

arxiv_client = ArxivClient(settings=settings.arxiv)

# Redis service receives REDIS__* variables

redis_cache = RedisClient(settings=settings.redis)

```

Each component therefore receives a fully‑populated, type‑checked configuration object that reflects the current environment.

## Summary

- **Hierarchical loading**: Variables are parsed in [`src/config.py`](https://github.com/jamwithai/production-agentic-rag-course/blob/main/src/config.py) using `env_nested_delimiter="__"` and service‑specific `env_prefix` values.
- **Global defaults**: `APP_VERSION`, `DEBUG`, `POSTGRES_DATABASE_URL`, and `OLLAMA_HOST` configure the core API and database.
- **Service prefixes**: Use `ARXIV__`, `PDF_PARSER__`, `CHUNKING__`, `OPENSEARCH__`, `LANGFUSE__`, `REDIS__`, and `TELEGRAM__` to scope variables per module.
- **Critical secrets**: `JINA_API_KEY`, `LANGFUSE__SECRET_KEY`, and `TELEGRAM__BOT_TOKEN` are sensitive values that should be injected via secrets management, not committed to code.
- **Runtime access**: Call `get_settings()` once and pass sub‑settings (e.g., `settings.opensearch`) to service constructors for type‑safe configuration.

## Frequently Asked Questions

### How does the double‑underscore delimiter work in environment variables?

The `env_nested_delimiter="__"` setting in [`src/config.py`](https://github.com/jamwithai/production-agentic-rag-course/blob/main/src/config.py) tells Pydantic to treat double underscores as nested field separators. For example, `ARXIV__MAX_RESULTS=50` maps to the `max_results` attribute inside the `arxiv` settings object. This convention allows flat environment files to represent structured configuration hierarchies.

### Which environment variables are strictly required to start the application?

While most variables have sensible defaults, **`JINA_API_KEY`** is mandatory for embedding generation, and **`POSTGRES_DATABASE_URL`** must point to a reachable database unless you rely on the local default `postgresql://rag_user:rag_password@localhost:5432/rag_db`. Services like Langfuse, Telegram, and Redis can be disabled via `LANGFUSE__ENABLED`, `TELEGRAM__ENABLED`, or by omitting their hosts if not used.

### Can I change the OpenSearch vector dimension for different embedding models?

Yes. Set `OPENSEARCH__VECTOR_DIMENSION` to match your embedding model’s output size. The codebase defaults to **1024** for Jina embeddings, but if you switch to a model with 768 or 1536 dimensions, update this variable before index creation to prevent dimension mismatch errors.

### What is the best way to override settings in a production deployment?

Create a `.env` file at the project root or export variables directly in the host environment. The `BaseConfigSettings` class reads from the environment first, ensuring that production secrets (such as `LANGFUSE__SECRET_KEY` or `TELEGRAM__BOT_TOKEN`) override any development defaults defined in [`src/config.py`](https://github.com/jamwithai/production-agentic-rag-course/blob/main/src/config.py).