Skip to main content

Olis API Architecture & Backend Developer Guide

Table of Contents

  1. Architecture Overview
  2. System Components
  3. API Endpoints
  4. Authentication & Authorization
  5. RAG Pipeline Deep Dive
  6. Configuration Reference
  7. Development Guide
  8. Performance & Monitoring
  9. Deployment
  10. Troubleshooting

Architecture Overview

High-Level Architecture

The Olis API Server is a FastAPI-based RAG (Retrieval-Augmented Generation) system that provides intelligent question answering with document context.

Technology Stack


System Components

1. Application State (AppResources)

The API maintains application-wide state through the AppResources class:
Lifecycle: Initialized in lifespan() context manager, available via dependency injection.

2. Multi-Tenant Organization Manager

Hard isolation per organization:
  • Each org gets dedicated Milvus collection: {base}_orgid
  • Each org gets dedicated ES index: {base}_orgid
  • Resources cached per org to avoid reconnection overhead

3. RAG Pipeline Components

a. Hybrid Retriever

  • Vector Search (Milvus): Semantic similarity using embeddings
  • BM25 Search (Elasticsearch): Keyword/lexical matching
  • Weighted Fusion: Configurable weights (WEIGHT_VECTOR, WEIGHT_BM25)
  • Reranking: Optional BGE reranker for precision

b. Query Processor

  • Query decomposition into sub-queries (optional)
  • Query expansion and reformulation
  • Temporal filtering and date extraction

c. LLM Generator

  • Supports OpenAI (gpt-4o-mini) and Ollama (local models)
  • Configurable temperature, top-p, max tokens
  • Structured output with citations

d. Memory System

  • Session Memory: Long-term user context (10 mins TTL)
  • Thread Memory: Conversation history per thread (5 mins TTL)
  • Stored in Redis with automatic expiration

API Endpoints

Base URL

1. Health Check

Response:

2. Intent Detection

Analyze user input to detect intent before RAG pipeline execution.
Headers:
Request Body:
Response:
Use Case: Pre-filter queries, route to appropriate handlers, avoid unnecessary RAG calls.

3. RAG Query/Prediction

Main endpoint for question answering with document retrieval.
Headers:
Request Body:
Response:
Flow:
  1. Extract JWT, validate user
  2. Create or retrieve thread ID
  3. Normalize query text
  4. Run RAG pipeline (see RAG Pipeline Deep Dive)
  5. Filter results by RBAC
  6. Update session memory (background task)
  7. Return structured answer with citations

4. Document Upsert/Ingestion

Insert or update documents in the knowledge base.
Headers:
Request Body:
Response:
Processing:
  1. Validate JWT and extract org_id
  2. Get org-specific ingester (creates if needed)
  3. Chunk documents (default: 1000 chars, 150 overlap)
  4. Generate embeddings (HuggingFace model)
  5. Store in Milvus (vectors) and Elasticsearch (full-text)
  6. Apply org_id stamp for hard isolation
Supported Document Fields:
  • title: Document title
  • content: Full text content
  • metadata.source: Source system (confluence, slack, github, etc.)
  • metadata.owner_id: Document owner email
  • metadata.acl: Access control list (pipe-delimited)
  • metadata.created_at: ISO date string
  • metadata.*: Any additional metadata

5. Test Prediction (No Auth Required)

Simplified prediction endpoint for testing (auth bypass).
Request: Same as /predict Response: Same as /predict + prediction_time field ⚠️ WARNING: This endpoint bypasses JWT auth. Only enable in development!

Authentication & Authorization

JWT Authentication

Token Format: Bearer token in Authorization header
Required JWT Claims:
Configuration:
Token Validation:
  • Signature verification with JWT_SECRET
  • Expiration check (exp)
  • Issuer validation (iss)
  • Token type must be access
Error Responses:
  • 401: Missing/invalid/expired token
  • 503: JWT_SECRET not configured

Role-Based Access Control (RBAC)

Documents include ACL metadata for fine-grained access control. ACL Format (pipe-delimited keyset):
Access Rules:
  1. Deny always wins: If |deny:user@email.com| present, access blocked
  2. Owner access: If owner_id matches user email, granted
  3. Public access: If |user:_all_| present, granted to all
  4. User-specific: If |user:email@company.com| matches, granted
  5. Role-based: If |role:engineer| and user has role, granted
  6. Group-based: If |group:product| and user in group, granted
  7. Default deny: If no ACL or no match, only owner can access
Implementation:
Filtering:
  • Post-retrieval filtering: _filter_docs_by_rbac(docs, user_info)
  • Applied after retrieval, before LLM generation

RAG Pipeline Deep Dive

Pipeline Execution Flow

Step-by-Step Breakdown

1. Query Normalization

2. Retrieval Phase

Vector Retrieval (Milvus):
  • Embed query using same model as documents
  • Cosine similarity search in vector space
  • Top-K results: VECTOR_RETRIEVER_TOP_K (default: 8)
BM25 Retrieval (Elasticsearch):
  • Lexical keyword matching
  • TF-IDF scoring
  • Top-K results: BM25_RETRIEVER_TOP_K (default: 8)
Hybrid Fusion:
Performance Timing:

3. Reranking (Optional)

If USE_RERANKER=true:
  • Model: BAAI/bge-reranker-v2-m3
  • Re-score top results for precision
  • Select top RERANK_TOP_K (default: 5)

4. RBAC Filtering

5. Context Preparation

Context Structure:
  • context: Concatenated document chunks with source markers
  • sources: Dict of source documents with metadata
  • query: Current query
  • original_query: Original user query (before decomposition)
  • subqueries: List of decomposed queries (if enabled)

6. LLM Generation

Prompt Structure:
LLM Configuration:
  • Model: RAG_GENERATOR_MODEL (default: gpt-4o-mini)
  • Temperature: RAG_LLM_TEMP (default: 0.0)
  • Top-P: RAG_LLM_TOP_P (default: 0.2)
  • Max tokens: Configured via OLLAMA_NUM_PREDICT or model default

7. Post-Processing

8. Fast Path (Empty Context)

If SKIP_LLM_ON_EMPTY_CONTEXT=true and no docs retrieved:
Saves LLM cost and latency when no relevant docs found.

Query Decomposition (Advanced)

If USE_QUERY_DECOMPOSITION=true:
  1. Decompose complex query into QUERY_DECOMPOSITION_N sub-queries (default: 5)
  2. Retrieve docs for each sub-query independently
  3. Select top SUBQUERY_TOP_K docs per sub-query (default: 5)
  4. Merge and deduplicate results
  5. Reason over combined results (if SUBQUERY_REASONING_ENABLED=true)
Example:

Configuration Reference

Environment Variables

Database Configuration

LLM Configuration

Retrieval Configuration

Query Processing

Memory Configuration

Document Ingestion

Authentication

Performance


Development Guide

Local Setup

Prerequisites

  • Python 3.10+
  • Docker & Docker Compose
  • Poetry (Python dependency manager)

1. Clone Repository

2. Install Dependencies

3. Start Infrastructure Services

4. Set Environment Variables

Minimal .env:

5. Run Server

6. Verify


Testing

Integration Tests

Example Test:

Unit Tests

Load Testing


Debugging

Enable Debug Logging

Performance Logging

Agent Debugging

Custom debug logging is available via _debug_log():
Logs written to: DEBUG_LOG_PATH (default: .cursor/debug.log)

Performance & Monitoring

Performance Metrics

The RAG pipeline emits detailed performance metrics:
Key Metrics:
  • retrieval_ms: Time for hybrid retrieval
  • llm_ms: Time for LLM generation
  • total_ms: End-to-end latency
  • docs_count: Number of retrieved documents
  • context_chars: Context size sent to LLM

Optimization Tips

1. Tune Retrieval Parameters

2. Use Fast Path

3. Optimize Context Size

4. Disable Query Decomposition

5. Use Ollama for Local LLM

Caching Strategy

  • Session Memory: 10-minute TTL, stores user context
  • Thread Memory: 5-minute TTL, stores conversation history
  • Org Resources: Cached indefinitely per org_id
Redis Memory Usage:
  • Session: ~10KB per user
  • Thread: ~5KB per thread
  • Estimate: 100 concurrent users = ~1.5MB

Deployment

Docker Deployment

1. Build Image

2. Run Container

3. Docker Compose

Production Considerations

1. Security

  • Never expose /testpredict in production (bypasses auth)
  • Use strong JWT_SECRET (32+ chars, random)
  • Enable HTTPS/TLS for all connections
  • Lock down CORS: allow_origins=["https://yourdomain.com"]

2. Scaling

  • Horizontal Scaling: Run multiple API instances behind load balancer
  • Stateless Design: All state in Redis, safe to scale
  • Database Scaling:
    • Milvus: Standalone → Cluster mode
    • Elasticsearch: Single node → Cluster
    • Redis: Single instance → Redis Cluster/Sentinel

3. Monitoring

  • Health Checks: /healthz endpoint for load balancer
  • Metrics: Export performance logs to DataDog/Prometheus
  • Alerting: Monitor total_ms > 5000ms, error rates

4. Backup

  • Milvus: Regular snapshots of /var/lib/milvus
  • Elasticsearch: Snapshot and restore API
  • Redis: RDB/AOF persistence enabled

Troubleshooting

Common Issues

1. “JWT_SECRET not configured”

Symptom: All API calls return 503 Solution:

2. Milvus Connection Failed

Symptom: Server fails to start with Milvus error Check:
Solution:

3. Empty RAG Results

Symptom: All queries return empty answers Debug:
Solution:
  • Ingest documents via /upsert
  • Check ACLs match user permissions
  • Verify embeddings are generated correctly

4. Slow Query Performance

Symptom: total_ms > 5000ms Profile:
Optimize:

5. Redis Connection Errors

Symptom: “Error connecting to Redis” Check:
Solution:

API Design Patterns

Dependency Injection

FastAPI’s dependency injection provides clean resource access:

Background Tasks

Expensive operations run asynchronously:

Lifespan Context Manager

Resources initialized once at startup, cleaned up at shutdown:

Advanced Topics

Custom Prompts

Modify prompts in backend/variables/prompts.py:

Multi-Tenant Isolation

Each organization gets isolated resources:

Streaming Responses

For real-time LLM streaming:

Additional Resources


Support & Contact

For questions or issues:
Last Updated: 2026-02-10 Version: 1.0.0 Author: Olis Backend Team