Choosing and Configuring Models

Selecting and configuring models for GENIE.AI (LLM, embedding, reranker, translation) across GPU profiles.

Overview

GENIE.AI uses a multi-model architecture where different AI models serve distinct purposes across the entire framework — from document ingestion and knowledge graph construction through to retrieval, reranking, and response generation. Not every model is suitable for every role. Choosing the wrong model for a given purpose will cause silent failures — ingestion batches being skipped, labels returning garbage, or graph data not being created.

This guide explains what each model does, what capabilities it must have, what license it is released under, and provides specific recommendations for both open-source and commercial models across different hardware tiers.


Model Licensing — What You Need to Know

Every model has a license that governs how you can use it. This is your responsibility to verify before deployment. Licenses can change between model versions. The information below was accurate at the time of writing but you should always check the model card on HuggingFace for the latest terms.

License Categories

LicenseCommercial UseModificationDistributionNotable Restriction
Apache 2.0YesYesYesNone. Most permissive.
MITYesYesYesNone. Most permissive.
Gemma Terms of UseYesYesYes>700M monthly users must request permission.
Llama 3.x Community LicenseYesYesYes>700M monthly users must request license.
Mistral AI LicenseYesYesYesSome restrictions on competitive use.
OpenAI Terms of ServiceYes (paid)N/ANoUsage-based pricing. No weight access.
Anthropic Terms of ServiceYes (paid)N/ANoUsage-based pricing. No weight access.
Google Cloud TermsYes (paid)N/ANoUsage-based pricing. No weight access.

Important: If you are deploying GENIE.AI for a government, enterprise, or high-traffic public service, check whether your expected monthly active users exceed 700 million. If so, models under the Gemma and Llama community licenses require you to request a special license from Google or Meta respectively.


The Framework Pipeline: Where Models Are Used

Understanding where each model fits in the GENIE.AI pipeline helps you make informed choices:

DOCUMENT INGESTION PIPELINE:
                                                                                    
  Upload → Docling/OCR → Chunking → Guardrails → Labeling → Graph Extraction → Embedding → ArangoDB
              (GPU)       (config)    (optional)    (LLM)    (LLM + FC?)      (TEI)
                                           ↑          ↑           ↑               ↑
                                      Translation  Translation  Translation    Translation
                                      LLM (shared)  LLM (shared)  LLM (shared)  (separate vLLM)

QUERY PIPELINE:

  User Query → Translation → Embedding → Retrieval → Graph Traversal → Reranking → LLM Inference → Response
                 (vLLM)       (TEI)     (ArangoDB)   (optional)       (TEI)        (vLLM)

The Six Model Roles

GENIE.AI has six distinct AI model roles, served by two vLLM instances and two TEI instances:

#RoleDocker ServiceConfig VariableShared WithLicense Sensitivity
1Main Inference (Chat/QnA)vllmVLLM_LLM_MODEL_IDLabeling, Graph ExtractionHigh — visible to users
2Chunk Labelingvllm (same)VLLM_MODEL_IDMain Inference, Graph ExtractionLow — internal pipeline
3Graph Extractionvllm (same)VLLM_MODEL_IDMain Inference, LabelingLow — internal pipeline
4Translation & Guardrailsvllm-translation-guardrailVLLM_TRANSLATION_MODEL_IDGuardrailsMedium — user-facing
5EmbeddingsteiEMBEDDING_MODEL_IDLow — internal pipeline
6Rerankingtei_rerankerRERANKER_MODEL_IDLow — internal pipeline

Critical architecture point: Roles 1, 2, and 3 all share the same vLLM instance (the main inference server at http://vllm:8000). The model you choose for VLLM_LLM_MODEL_ID must be capable of serving all three of these roles simultaneously. Role 4 (Translation) has its own dedicated vLLM instance. In docker-compose, VLLM_MODEL_ID is derived from VLLM_LLM_MODEL_ID, so setting the latter configures all three shared roles — you only set one.


Role 1: Main Inference (Chat/QnA)

What It Does

This is the “brain” of the chatbot. It receives the user’s query along with retrieved document chunks from the RAG pipeline and generates a natural language answer. It is the most visible model in the system and has the greatest impact on answer quality.

Required Capabilities

CapabilityRequiredNotes
Chat completion APIYesMust support OpenAI-compatible /v1/chat/completions
Function callingNoNot used for inference
Context window4K+ tokensLarger is better for RAG (retrieved chunks consume context)
JSON outputNoAnswers are free-text
Multi-languageOptionalOnly needed if serving non-English queries directly

How It Is Called

The ChatQnA orchestrator sends retrieved chunks as system/user context and asks the model to answer the user’s question. The CHATQNA_SYSTEM_PROMPT environment variable controls the instruction framing.

Model Recommendations

Open Source

ModelParamsVRAM (FP16)VRAM (INT8/AWQ)LicenseStrengthsWeaknesses
Qwen 2.5 7B7B~14 GB~8 GBApache 2.0Excellent multilingual, strong reasoning, function callingLarge for constrained GPUs
Qwen 2.5 14B14B~28 GB~16 GBApache 2.0Very strong reasoning, good for complex RAGNeeds 24GB+ GPU
Llama 3.1 8B8B~16 GB~8 GBLlama 3.x CommunityGood all-round, strong instruction following, function callingWeaker on multilingual than Qwen
Llama 3.1 70B-Instruct-AWQ70B (4-bit)~40 GB~40 GBLlama 3.x CommunityEnterprise-grade qualityRequires 48GB+ GPU
Mistral 7B v0.37B~14 GB~8 GBApache 2.0Fast, efficient, good at following formatsLess capable than Llama 3.1 or Qwen
Gemma 3 12B12B~24 GB~12 GBGemma Terms of UseGood multilingual, strong for its sizeNo function calling support
Gemma 3 4B4B~8 GB~5 GBGemma Terms of UseFits on small GPUs, multilingualLimited reasoning depth
Granite 3.3 2B2B~4 GB~3 GBApache 2.0Very small footprintLimited quality for complex RAG
Granite 3.3 8B8B~16 GB~8 GBApache 2.0Good instruction followingLess capable than Qwen/Llama at same size
Phi-4-mini3.8B~8 GB~5 GBMITStrong reasoning for its sizeNewer, less community validation

Commercial (API-based)

ProviderModelLicenseNotes
OpenAIGPT-4o, GPT-4o-miniOpenAI ToS (paid)Best overall quality. Requires OpenAI-compatible proxy or code change.
AnthropicClaude 3.5 Sonnet, Claude 3 HaikuAnthropic ToS (paid)Excellent RAG performance. Requires API integration.
GoogleGemini 2.0 Flash, Gemini 1.5 ProGoogle Cloud ToS (paid)Strong multilingual. Access via Vertex AI or API.
AWSAmazon Bedrock (Claude, Titan, etc.)AWS ToS (paid)For AWS-hosted deployments.
AzureAzure OpenAI (GPT-4o, etc.)Microsoft ToS (paid)For Azure-hosted deployments.

Note on commercial models: The default GENIE.AI architecture uses local vLLM instances. To use commercial API-based models, you would need to configure VLLM_ENDPOINT to point to an OpenAI-compatible proxy that routes to the commercial API, or modify the ChatQnA orchestrator code.

Configuration

# In your .env file
VLLM_LLM_MODEL_ID=Qwen/Qwen2.5-7B-Instruct
VLLM_GPU_UTILIZATION=0.6
VLLM_MAX_MODEL_LEN=65536
VLLM_DTYPE=auto

Role 2: Chunk Labeling

What It Does

During document ingestion, the dataprep service sends each chunk of text to the LLM along with the full taxonomy (list of labels). The LLM must return a JSON response selecting 1–4 labels from the taxonomy that best match the chunk content.

Required Capabilities

CapabilityRequiredNotes
Chat completion APIYesMust support OpenAI-compatible /v1/chat/completions
Guided JSON outputYesMust support response_format={"type": "json_object"} (vLLM guided JSON decoding). Dataprep requests a strict JSON object per chunk; without guided JSON, models wrap output in markdown or return malformed JSON → per-chunk fallback (slower, lower label quality). Validated on ibm-granite/granite-4.1-8b.
Function callingNoUses response_format + prompt-based label extraction
ConsistencyYesMust return the same format on every call (DATAPREP_LLM_TEMPERATURE=0.0 is set); no dict values in arrays
Multi-languageHelpfulIf documents are in multiple languages

How It Is Called

The dataprep service sends:

  • System prompt: LABEL_SELECTOR_SYSTEM_PROMPT (configurable in .env)
  • User prompt: "Input: {chunk_text}\nLabels: {taxonomy_list}"
  • Sampling: temperature=0.0, response_format={"type": "json_object"} (guided JSON), bounded max_tokens. Chunks may be batched (DATAPREP_LLM_LABEL_BATCH_SIZE, default 4) into one call returning {"0": ["..."], "1": [...]}.

The LLM must return only a JSON object with a "labels" key (or an index→labels map when batched) containing an array of plain strings. response_format enforces valid JSON at the token level; lenient client-side parsing tolerates residual variations (null → [], bare string → [string]).

Contextual Retrieval (optional). On by default (CONTEXTUAL_RETRIEVAL_ENABLED=true); the same vLLM model (override with DATAPREP_CONTEXTUAL_MODEL; empty = reuse this labeling model) is also called once per chunk to generate a ~50-100 word document-context prefix that is prepended before embedding + labeling. It has the same guided-JSON requirement (response_format={"type":"json_object"}, returning {"context": "..."}). On any failure the chunk is stored raw — ingestion never blocks. See the Data Labelling Strategy doc (§7).

What Goes Wrong with Small Models

Models below ~7B parameters frequently fail at labeling:

  • Dict instead of string: Returns {"labels": [{"name": "Procurement"}]} instead of {"labels": ["Procurement"]}. The dict is unhashable and crashes downstream set operations.
  • Missing JSON structure: Returns conversational text like “Here are the labels: Procurement, Finance” instead of JSON.
  • Invented labels: Returns labels that don’t exist in the taxonomy (less critical — the code handles this with warnings).
  • Inconsistent format: Works on some chunks, fails on others (non-deterministic).

Model Recommendations

Open Source

ModelParamsLabeling QualityLicenseNotes
Qwen 2.5 7B7BExcellentApache 2.0Best open-source for structured output at this size.
Llama 3.1 8B8BVery GoodLlama 3.x CommunityStrong JSON formatting.
Mistral 7B v0.37BGoodApache 2.0Reliable JSON output.
Gemma 3 12B12BGoodGemma Terms of UseDecent but no function calling fallback.
Gemma 3 4B4BPoorGemma Terms of UseFrequently returns malformed JSON. Not recommended.
Granite 3.3 2B2BPoorApache 2.0Too small for reliable JSON formatting. Not recommended.
Gemma 3 1B1BUnusableGemma Terms of UseConsistently fails. Do not use.

Important: Labeling Shares the Main vLLM

Labeling uses VLLM_ENDPOINT + VLLM_MODEL_ID — the same vLLM instance as main inference. There is no separate configuration for a labeling-specific model. If your main inference model is too small for labeling (e.g., Granite 2B), consider using the embedding or bm25 labeling strategies instead (see Step 8 in the Installation Guide).

Alternative Labeling Strategies

If your LLM cannot reliably produce JSON, switch to a non-LLM strategy:

# Embedding-based labeling (recommended for production)
LABELING_STRATEGY=embedding
EMBEDDING_LABEL_THRESHOLD=0.75

# BM25 keyword matching (strict, CPU-only)
LABELING_STRATEGY=bm25
BM25_LABEL_THRESHOLD=2.0
StrategyLLM Required?QualitySpeed
llmYes (7B+ recommended)Best (understands context)Slowest
embeddingNoGood (semantic matching)Fast
bm25NoAdequate (keyword matching)Fastest

Role 3: Graph Extraction

What It Does

The dataprep service uses LangChain’s LLMGraphTransformer to extract entities (nodes) and relationships (edges) from document chunks. These are stored in ArangoDB as a knowledge graph used for graph traversal during retrieval.

Required Capabilities

CapabilityRequiredNotes
Chat completion APIYesMust support OpenAI-compatible /v1/chat/completions
Function callingStrongly recommendedWithout it, falls back to prompt-based JSON which frequently fails
JSON outputYesMust return structured entity/relationship JSON
ReasoningYesMust understand entities, types, and relationships in text

How It Is Called

The LLMGraphTransformer sends each document chunk to the LLM and expects a response containing:

  • head: entity name (string)
  • head_type: entity type (string) — e.g., “Person”, “Organization”
  • tail: related entity name (string)
  • tail_type: related entity type (string)
  • relation: relationship type (string) — e.g., “WORKS_FOR”, “LOCATED_IN”

When function calling is supported, the LLM uses structured tool schemas which guarantee correct types. Without function calling, the LLM must return this as raw JSON — and small models routinely return dicts instead of strings for the type fields, causing unhashable type: 'dict' crashes.

Model Recommendations

Open Source

ModelParamsFunction CallingGraph QualityLicenseNotes
Qwen 2.5 7B7BYesExcellentApache 2.0Best choice for graph extraction. Structured output works reliably.
Llama 3.1 8B8BYesVery GoodLlama 3.x CommunityNative function calling support.
Qwen 2.5 14B14BYesExcellentApache 2.0Higher quality entity extraction.
Llama 3.1 70B-Instruct-AWQ70B (4-bit)YesBestLlama 3.x CommunityEnterprise-grade graph quality.
Mistral 7B v0.37BPartialGoodApache 2.0Has some function calling support but less reliable.
Gemma 3 12B12BNoPoorGemma Terms of UseNo function calling. Prompt-based extraction fails frequently.
Gemma 3 4B4BNoUnusableGemma Terms of UseDo not use for graph extraction.
Granite 3.3 2B2BNoUnusableApache 2.0Do not use for graph extraction.
Gemma 3 1B1BNoUnusableGemma Terms of UseDo not use for graph extraction.

Why Function Calling Matters

When ignore_tool_usage=False (function calling supported), LangChain uses the model’s native structured output API. This guarantees that head_type, tail_type, and relation are strings.

When ignore_tool_usage=True (no function calling), LangChain parses raw JSON from the model’s text output. Small models return malformed types — dicts, arrays, or nested objects — which crash when added to Python sets.

The OPEA code sets ignore_tool_usage=True when using vLLM (line 173 of arangodb.py), because vLLM’s OpenAI-compatible API does not advertise function calling support in a way LangChain detects. This means graph extraction relies entirely on the model’s ability to return correct raw JSON.

Important: Graph Extraction Shares the Main vLLM

Graph extraction uses the same VLLM_ENDPOINT + VLLM_MODEL_ID as main inference and labeling. There is no separate configuration. The model you choose for VLLM_LLM_MODEL_ID must handle all three roles.

If Your Model Cannot Do Graph Extraction

If your main inference model lacks function calling or produces unreliable JSON, the graph extraction batches will be silently skipped (logged as WARN). Documents will still be ingested with chunks and embeddings, but without knowledge graph relationships. This means:

  • Hybrid retrieval will still work (vector + label filtering)
  • Graph traversal in the retriever will return no additional context
  • Related Documents feature will not function

Role 4: Translation & Guardrails

What It Does

This dedicated vLLM instance handles two tasks:

  1. Translation: Translates user queries, chat history, and system prompts between languages for the multi-language RAG pipeline. Uses structured chat prompts with language codes.
  2. Guardrails: The OPEA guardrails service sends content through this model for safety classification. (Currently disabled by default: GUARDRAIL_ENABLED=false)

Required Capabilities

CapabilityRequiredNotes
Chat completion APIYesOpenAI-compatible /v1/chat/completions
Function callingNoNot used
Multi-languageYesMust support the target languages
Context window2K+ tokensTranslation prompts are typically short
Instruction followingYesMust follow language code instructions precisely

How It Is Called

The ChatQnA orchestrator sends translation requests in a structured format:

Translate the following text from {source_lang} to {target_lang}:
{text}

For TranslateGemma fine-tuned models, a specific chat template with language codes is used.

Model Recommendations

ModelParamsVRAM (FP16)LanguagesLicenseNotes
Infomaniak-AI/vllm-translategemma-4b-it4B~8 GB100+Gemma Terms of UseFine-tuned specifically for translation via vLLM. Best choice.
facebook/m2m100-12B-last12B~24 GB100+MITDedicated translation model.
facebook/nllb-200-distilled-600M600M~1.5 GB200MITVery small. Used for CPU-based fallback in backend.

Open Source — General Instruction Models

ModelParamsVRAM (FP16)Translation QualityLicenseNotes
Gemma 3 4B4B~8 GBGoodGemma Terms of UseDefault in GENIE.AI. Works well for translation.
Qwen 2.5 7B7B~14 GBVery GoodApache 2.0Excellent multilingual support.
Llama 3.1 8B8B~16 GBGoodLlama 3.x CommunityGood multilingual but less than Qwen.
Gemma 3 12B12B~24 GBVery GoodGemma Terms of UseStrong multilingual capabilities.

Commercial

ProviderModelLicenseNotes
GoogleGemini 2.0 FlashGoogle Cloud ToS (paid)Excellent multilingual. Best commercial option for translation.
OpenAIGPT-4o-miniOpenAI ToS (paid)Good translation quality, low cost.
DeepLDeepL APIDeepL ToS (paid)Best-in-class translation quality. Requires separate integration.

Configuration

# In your .env file
VLLM_TRANSLATION_MODEL_ID=Infomaniak-AI/vllm-translategemma-4b-it
VLLM_TRANSLATION_GPU_UTILIZATION=0.3
VLLM_TRANSLATION_MAX_MODEL_LEN=2048
VLLM_TRANSLATION_DTYPE=auto

Language Support

The translation system supports these language codes (defined in the backend’s language maps): ar, bn, de, en, es, fr, id, man/mnk, pt, ru, st, sw, th, zh

For low-resource languages (e.g., Mandinka), the system uses Dyula as a linguistic proxy from the NLLB-200 model.


Role 5: Embeddings

What It Does

Converts document chunks and user queries into mathematical vectors (embeddings). These vectors are stored in ArangoDB and used for semantic similarity search during retrieval. The embedding model is critical for RAG accuracy — if the embeddings don’t capture meaning well, the retriever will return irrelevant results.

Required Capabilities

CapabilityRequiredNotes
TEI-compatibleYesMust run in HuggingFace Text Embeddings Inference
GPU supportYesServed via text-embeddings-router
Vector dimensionAnyStored in ArangoDB. Larger dimensions use more memory.

Model Recommendations

ModelDimensionsVRAMMultilingualLicenseNotes
BAAI/bge-base-en-v1.5768~500 MBNo (English only)MITDefault. Good quality for English.
BAAI/bge-m31024~1 GBYesMITRecommended upgrade. Supports 100+ languages, dense + sparse + ColBERT retrieval.
BAAI/bge-large-en-v1.51024~800 MBNoMITHigher quality English embeddings.
intfloat/multilingual-e5-base768~500 MBYesApache 2.0Good multilingual alternative.
intfloat/multilingual-e5-large1024~800 MBYesApache 2.0Higher quality multilingual.
sentence-transformers/all-MiniLM-L6-v2384~200 MBNoApache 2.0Very small. Use only if GPU memory is extremely constrained.

T4 Warning: Do not use BAAI/bge-reranker-v2-m3 on a Tesla T4. It uses an XLM-RoBERTa architecture that may have compatibility issues with T4-optimized TEI images and its memory footprint is too large for a shared 16GB card.

Configuration

# In your .env file
EMBEDDING_MODEL_ID=BAAI/bge-base-en-v1.5
TEI_EMBED_MODEL=BAAI/bge-base-en-v1.5

Role 6: Reranking

What It Does

After the retriever fetches candidate chunks, the reranker performs a more computationally expensive “cross-encoder” analysis to re-score each chunk against the actual user query. This is the final quality filter before chunks are sent to the LLM.

Required Capabilities

CapabilityRequiredNotes
TEI-compatibleYesMust run in HuggingFace Text Embeddings Inference
Cross-encoder architectureYesMust be a cross-encoder reranker model, not an embedding model
GPU supportYesServed via text-embeddings-router

Model Recommendations

ModelVRAMLanguageLicenseNotes
BAAI/bge-reranker-v2-m3~2 GBMultilingualMITDefault. Multilingual; enterprise GPUs (>=24 GB). Do not use on T4.
cross-encoder/ms-marco-MiniLM-L-6-v2~200 MBEnglishApache 2.0Use on T4 / constrained GPUs (English). Fast, reliable.
cross-encoder/ms-marco-MiniLM-L-12-v2~400 MBEnglishApache 2.0Higher quality, more memory.

Configuration

# In your .env file (default; multilingual, requires >=24 GB VRAM)
RERANKER_MODEL_ID=BAAI/bge-reranker-v2-m3
# T4 / constrained GPUs (English only) — override with the lighter model:
# RERANKER_MODEL_ID=cross-encoder/ms-marco-MiniLM-L-6-v2

Hardware Profiles and Model Combinations

Understanding GPU Memory Allocation

GENIE.AI runs multiple AI services on the same GPU. Each service claims a portion of VRAM, and the total must fit within your GPU’s capacity. Here is what consumes GPU memory:

ServiceTypical VRAMNotes
Main vLLM (inference)4–40 GBDepends on model size, VLLM_GPU_UTILIZATION, and VLLM_MAX_MODEL_LEN
Translation vLLM4–14 GBDepends on model size and VLLM_TRANSLATION_GPU_UTILIZATION
TEI Embedding200–1000 MBDepends on embedding model
TEI Reranker200–2000 MBDepends on reranker model
OS / CUDA overhead500–1000 MBAlways present

Key parameter: VLLM_GPU_UTILIZATION

This controls what fraction of GPU memory vLLM reserves for the model weights and KV cache. It does not control the total memory used — vLLM will use the full allocation for model weights plus KV cache for concurrent requests.

ValueEffect
0.3Only 30% of GPU reserved. Limits concurrent requests but leaves room for other services.
0.660% reserved. Good balance for enterprise GPUs with multiple services.
0.990% reserved. Maximizes throughput but leaves almost no room for other services.

Key parameter: VLLM_MAX_MODEL_LEN

This controls the maximum context window (in tokens). Higher values consume more VRAM for the KV cache, reducing the number of concurrent requests the model can handle.

ValueVRAM ImpactUse Case
2048LowSimple QnA, short documents
4096MediumStandard RAG with retrieved chunks
8192HighComplex RAG with long retrieved context
16384Very HighLong document analysis

Key parameter: VLLM_DTYPE

The weight precision directly affects model quality and VRAM usage:

ValueVRAM UsageQualityGPU Compatibility
half (float16)BaselineGoodAll GPUs
auto (usually bfloat16)Similar to halfSlightly betterAmpere+ (A100, RTX 3090+, Ada)
bfloat16Similar to halfSlightly betterAmpere+ only
fp8~50% of halfAcceptableAda+ (RTX 4060+, H100)

T4 Warning: The Tesla T4 does not support bfloat16. Always use VLLM_DTYPE=half on T4.

The GPU Memory Budgeting Process

Before choosing models, calculate your GPU memory budget:

  1. Start with total VRAM (e.g., 16 GB for T4, 48 GB for A100)
  2. Reserve 1 GB for OS/CUDA overhead
  3. Reserve ~500 MB for TEI embedding
  4. Reserve ~200 MB for TEI reranker
  5. Divide remaining memory between main vLLM and translation vLLM

Example for T4 (16 GB):

Total: 16 GB
- OS/CUDA:    1 GB
- TEI embed:  0.5 GB
- TEI rerank: 0.2 GB
- Remaining: 14.3 GB
  - Main vLLM (40%):    5.7 GB  → fits Granite 2B or Gemma 4B
  - Translation (60%):  8.6 GB  → fits Gemma 4B

Example for A100 (48 GB):

Total: 48 GB
- OS/CUDA:    1 GB
- TEI embed:  1 GB (bge-m3)
- TEI rerank: 0.2 GB
- Remaining: 45.8 GB
  - Main vLLM (60%):   27.5 GB → fits Qwen 2.5 14B
  - Translation (40%): 18.3 GB → fits Qwen 2.5 7B

Loading Models and Verifying GPU Allocation

After configuring your .env, bring up the services and monitor GPU usage:

# Step 1: Start services
docker compose up -d --build

# Step 2: Watch GPU allocation in real-time
watch nvidia-smi

What to look for in nvidia-smi:

IndicatorGoodBad
GPU memory usageClose to total VRAMVery low (models failed to load)
“No space left on device” in logsN/AModel too large for available VRAM
All services listed in ProcessesYesMissing service = model failed to load

Expected timeline:

  • TEI models (embedding, reranker): Load in 30–60 seconds
  • Translation vLLM: 2–5 minutes (model download + GPU loading)
  • Main vLLM: 3–10 minutes (model download + GPU loading)

vLLM healthcheck timeout is normal. The healthcheck often fails during initial startup because the model is still loading. Wait for the model to fully load, then run docker compose up -d again to restart any services that timed out.

# Check which services are healthy
docker compose ps

# If vllm is unhealthy, wait and retry
docker compose up -d

Testing Model Loading

After all services are up, run these verification steps:

1. Verify main inference is working:

# Check vLLM is serving the model
curl http://localhost:8000/v1/models

2. Verify embedding service:

# 7000 is the internal retriever port (dev/Compose only). In Swarm, run inside the net:
# docker exec <retriever-container> curl http://tei:80/embed -X POST ... \
curl http://localhost:7000/embed -X POST \
  -H "Content-Type: application/json" \
  -d '{"inputs": "test query"}'

3. Verify translation service:

curl http://localhost:9031/v1/models

4. Test end-to-end RAG: Log into the application and ask a question about an ingested document. If the response is coherent and references the source material, the pipeline is working correctly.


Profile A: Tesla T4 (16GB VRAM) — Entry Level

This is the most constrained profile. Multiple models must share a single 16GB GPU. The T4 uses Turing architecture (compute 7.5) which does not support bfloat16.

Hardware specs: 16 GB GDDR6, compute 7.5, CUDA 12.4 driver typical

Main vLLM (serves Inference + Labeling + Graph):

ModelVRAM UsedLabelingGraph ExtractionInference Quality
Granite 3.3 2B~4 GBPoorUnusableAdequate
Gemma 3 4B~8 GBPoorUnusableGood
Mistral 7B~14 GBGoodPoor (no FC)Good

Recommendation: Use Granite 3.3 2B for inference and switch labeling to embedding or bm25 strategy. Accept that graph extraction will not work reliably.

Translation vLLM:

ModelVRAM UsedQuality
Gemma 3 4B~8 GBGood

Total GPU allocation (T4): Main (~4-8 GB) + Translation (~8 GB) + TEI Embedding (~500 MB) + TEI Reranker (~200 MB) = ~13-17 GB. This is extremely tight on 16 GB.

# T4 Configuration
VLLM_LLM_MODEL_ID=ibm-granite/granite-3.3-2b-instruct
VLLM_GPU_UTILIZATION=0.4
VLLM_MAX_MODEL_LEN=65536
VLLM_DTYPE=half
LABELING_STRATEGY=embedding    # Do NOT use llm with 2B model

VLLM_TRANSLATION_MODEL_ID=google/gemma-3-4b-it
VLLM_TRANSLATION_GPU_UTILIZATION=0.4
VLLM_TRANSLATION_DTYPE=half
VLLM_TRANSLATION_KV_CACHE_DTYPE=fp8

EMBEDDING_MODEL_ID=BAAI/bge-base-en-v1.5
RERANKER_MODEL_ID=cross-encoder/ms-marco-MiniLM-L-6-v2

Profile B: RTX 4060 Laptop (8GB VRAM) — Development Only

Not recommended for production. Even more constrained than T4. The RTX 4060 has Ada Lovelace architecture (compute 8.9) which supports bfloat16 and fp8.

Hardware specs: 8 GB GDDR6, compute 8.9, CUDA 12.8 driver typical

Recommendation: Use Gemma 3 4B for inference with LABELING_STRATEGY=embedding. Accept that graph extraction will not work. Translation may need to use the CPU-based NLLB fallback or share the main vLLM (reducing available VRAM further).

VLLM_LLM_MODEL_ID=google/gemma-3-4b-it
VLLM_GPU_UTILIZATION=0.30
VLLM_MAX_MODEL_LEN=65536
VLLM_DTYPE=half
LABELING_STRATEGY=embedding

VLLM_TRANSLATION_MODEL_ID=google/gemma-3-4b-it
VLLM_TRANSLATION_GPU_UTILIZATION=0.35
VLLM_TRANSLATION_MAX_MODEL_LEN=2048
VLLM_TRANSLATION_DTYPE=half

EMBEDDING_MODEL_ID=BAAI/bge-base-en-v1.5
RERANKER_MODEL_ID=cross-encoder/ms-marco-MiniLM-L-6-v2

Profile C: RTX 6000 Ada / A40 / L40S / A100 (48GB VRAM) — Enterprise

This profile has room for high-quality models across all roles. These GPUs support bfloat16.

Hardware specs: 48 GB GDDR6 (RTX 6000 Ada) / 48 GB HBM2e (A100), compute 8.9 (Ada) / 8.0 (Ampere)

Main vLLM (serves Inference + Labeling + Graph):

ModelVRAM UsedLabelingGraph ExtractionInference Quality
Qwen 2.5 7B~14 GBExcellentExcellentVery Good
Llama 3.1 8B~16 GBVery GoodVery GoodVery Good
Qwen 2.5 14B~28 GBExcellentExcellentExcellent
Llama 3.1 70B-Instruct-AWQ~40 GBExcellentExcellentBest

Recommendation: Use Qwen 2.5 7B or Llama 3.1 8B as the best balance of quality, capability, and VRAM. Both support function calling and reliably produce structured JSON for labeling and graph extraction. For maximum quality, use Llama 3.1 70B-Instruct-AWQ if the GPU supports 48GB+.

Translation vLLM:

ModelVRAM UsedQuality
Infomaniak-AI/vllm-translategemma-4b-it~8 GBExcellent
Qwen 2.5 7B~14 GBVery Good
# Enterprise Configuration (Recommended)
VLLM_LLM_MODEL_ID=Qwen/Qwen2.5-7B-Instruct
VLLM_GPU_UTILIZATION=0.6
VLLM_MAX_MODEL_LEN=65536
VLLM_DTYPE=auto
LABELING_STRATEGY=llm    # LLM strategy works well with 7B+ models

VLLM_TRANSLATION_MODEL_ID=Infomaniak-AI/vllm-translategemma-4b-it
VLLM_TRANSLATION_GPU_UTILIZATION=0.3
VLLM_TRANSLATION_MAX_MODEL_LEN=2048
VLLM_TRANSLATION_DTYPE=auto

EMBEDDING_MODEL_ID=BAAI/bge-m3          # Multilingual upgrade
RERANKER_MODEL_ID=BAAI/bge-reranker-v2-m3   # Multilingual reranker (enterprise GPU)

Profile D: Multi-GPU / Separate Nodes

If you have multiple GPUs or separate servers, you can dedicate resources more effectively:

Option 1: Two GPUs, single node (e.g., 2x A100 48GB)

# GPU 1: Main inference + labeling + graph extraction
VLLM_LLM_MODEL_ID=meta-llama/Meta-Llama-3.1-70B-Instruct-AWQ
VLLM_GPU_UTILIZATION=0.9
NVIDIA_VISIBLE_DEVICES=0

# GPU 2: Translation + embeddings + reranking
VLLM_TRANSLATION_MODEL_ID=Infomaniak-AI/vllm-translategemma-4b-it
VLLM_TRANSLATION_GPU_UTILIZATION=0.5
NVIDIA_VISIBLE_DEVICES=1

Option 2: Separate servers (recommended for production)

ServerGPURoleModel
GPU Server48GB+Main inference, labeling, graphLlama 3.1 70B-AWQ or Qwen 2.5 14B
GPU Server16GB+Translation, embeddings, rerankingTranslateGemma 4B + bge-m3
App ServerCPU onlyBackend, frontend, Kong, ArangoDBN/A

Other Notable Hardware

GPUVRAMComputebfloat16Notes
RTX 309024 GB8.6YesGood budget option for development.
RTX 409024 GB8.9YesExcellent single-GPU for all roles.
H100 SXM80 GB9.0YesBest performance. Overkill for most deployments.
L424 GB8.9YesGood server GPU, similar to RTX 4090.
A10G24 GB8.6YesAWS GPU instance option.

Decision Matrix: Which Model Should I Choose?

For Main Inference + Labeling + Graph Extraction (shared vLLM)

Do you have 48GB+ VRAM?
├── YES → Use Qwen 2.5 7B or Llama 3.1 8B
│         (or Llama 3.1 70B-AWQ for maximum quality)
└── NO
    ├── Do you have 24GB+ VRAM?
    │   ├── YES → Use Qwen 2.5 7B or Llama 3.1 8B (INT8/AWQ)
    │   └── NO
    │       ├── Do you have 16GB VRAM?
    │       │   ├── YES → Use Mistral 7B with LABELING_STRATEGY=embedding
    │       │   │         (graph extraction will be unreliable)
    │       │   └── NO
    │       │       └── Use Gemma 3 4B with LABELING_STRATEGY=embedding
    │       │           (graph extraction will NOT work)

For Translation (dedicated vLLM)

Do you need high-quality translation for many languages?
├── YES → Use Infomaniak-AI/vllm-translategemma-4b-it
└── NO
    └── Use Gemma 3 4B (default, adequate for most use cases)

Key Environment Variables Reference

Main Inference (Roles 1, 2, 3)

VariableDefaultPurpose
VLLM_LLM_MODEL_IDmeta-llama/Meta-Llama-3.1-8B-InstructMain chat model (recommended: ibm-granite/granite-4.1-8b)
VLLM_MODEL_ID(alias of above)Used by dataprep for labeling & graph
VLLM_ENDPOINThttp://vllm:8000Main vLLM endpoint
VLLM_GPU_UTILIZATION0.6GPU memory fraction
VLLM_MAX_MODEL_LEN65536Max context window
VLLM_DTYPEautoWeight precision (half/auto/bfloat16)

Translation (Role 4)

VariableDefaultPurpose
VLLM_TRANSLATION_MODEL_IDgoogle/gemma-3-4b-itTranslation model
VLLM_TRANSLATION_ENDPOINThttp://vllm-translation-guardrail:9031Translation endpoint
VLLM_TRANSLATION_GPU_UTILIZATION0.3GPU memory fraction
VLLM_TRANSLATION_MAX_MODEL_LEN2048Max context window
VLLM_TRANSLATION_DTYPEautoWeight precision

Labeling Configuration

VariableDefaultPurpose
LABELING_STRATEGYllmStrategy: llm, embedding, or bm25
LABEL_SELECTOR_SYSTEM_PROMPT(built-in)System prompt for LLM labeling
EMBEDDING_LABEL_THRESHOLD0.75Threshold for embedding strategy
BM25_LABEL_THRESHOLD2.00Threshold for BM25 strategy

Embeddings & Reranking (Roles 5, 6)

VariableDefaultPurpose
EMBEDDING_MODEL_IDBAAI/bge-base-en-v1.5Embedding model
TEI_EMBED_MODEL(must match above)TEI embedding model
RERANKER_MODEL_IDBAAI/bge-reranker-v2-m3Reranking model (use MiniLM on T4)

Document Extraction (Non-LLM AI)

VariableDefaultPurpose
CONTENT_EXTRACTION_METHODdoclingExtraction engine: docling or opea
DOCLING_DEVICEcudaDocling device: cuda or cpu

OCR Models (Pre-downloaded, not configured)

ModelPurposeSizeLicense
EasyOCR CRAFT (craft_mlt_25k)Text detection in images/PDFs~100 MBApache 2.0
EasyOCR English (english_g2)Text recognition (English)~10 MBApache 2.0

These models are downloaded at build time (see the Dockerfile) and stored inside the container. They do not require GPU allocation — EasyOCR can run on CPU if needed, but GPU (DOCLING_DEVICE=cuda) is much faster for PDF processing.


Non-AI Components Worth Understanding

While this guide focuses on LLM and model selection, the following non-AI components are critical to the framework’s performance and should be understood:

ComponentPurposeWhy It Matters
ArangoDBGraph + vector databaseStores documents, embeddings, knowledge graph. Performance directly affects retrieval latency.
Kong API GatewayRoutes and secures trafficAll user requests pass through Kong. Misconfiguration blocks the entire application.
RedisCaching layerCaches translation results. Reduces load on translation vLLM.
DoclingPDF/document extractionConverts PDFs, DOCX, etc. into text chunks. Quality of extraction directly affects RAG quality.
NginxReverse proxy / SSL terminationExternal entry point. CSP and CORS must be configured correctly.
Node.js BackendBusiness logicHandles auth, sessions, document management, and orchestrates OPEA services.

Common Pitfalls

1. Using a 1B-2B model for everything

Small models (Gemma 1B, Granite 2B) cannot reliably produce structured JSON. Using them for labeling or graph extraction will cause silent failures — batches skipped, garbage labels, empty graphs.

2. Assuming all models work for graph extraction

Graph extraction requires either function calling support or extremely reliable JSON formatting. Most models below 7B fail at this. If your model lacks function calling, graph batches will be skipped with unhashable type: 'dict' warnings.

3. Not accounting for shared VRAM

The main vLLM, translation vLLM, embedding TEI, and reranking TEI all run on the same GPU (in single-node deployments). A 7B model at FP16 uses ~14 GB. On a 16 GB T4, that leaves almost nothing for translation and embeddings.

4. Ignoring the labeling strategy option

If your LLM cannot do labeling reliably, switch to LABELING_STRATEGY=embedding. This uses the embedding model (which is much more reliable) for semantic label matching instead of the LLM.

5. Using the wrong dtype for your GPU

  • T4 (Turing): Does not support bfloat16. Use half (float16).
  • Ampere+ (A100, RTX 3090+, RTX 6000 Ada): Supports bfloat16. Use auto or bfloat16.
  • RTX 4060 (Ada Lovelace): Supports bfloat16. Use auto.

6. PyTorch CUDA version mismatch

When building the dataprep Docker image, pip install torch without an explicit index URL pulls the latest PyTorch (currently CUDA 13.0). If your host driver is CUDA 12.8, this makes CUDA unavailable inside the container. To fix this, add a TORCH_CUDA_VERSION build ARG to the Dockerfile and pass the correct value from docker-compose. See the Dockerfile comments for details.