Atlas RAG is a generic, relation-aware retrieval-augmented generation (RAG) API. It discovers PostgreSQL schemas and relationships, synchronizes safe row context into local Qdrant vectors, and answers questions through /api/ask.
- Python 3.11+
- FastAPI and Uvicorn
- SQLAlchemy 2.x with asyncpg
- Alembic migrations
- Pydantic Settings for
.envconfiguration - Structlog JSON logging
- Pytest, Ruff, and mypy
- PostgreSQL 16 (your local PostgreSQL/pgAdmin installation)
- Qdrant running locally at
http://localhost:6333
PowerShell:
py -3.11 -m venv .venv
.\.venv\Scripts\Activate.ps1
Copy-Item .env.example .env
python -m pip install --upgrade pip
python -m pip install -r requirements.txt
alembic upgrade head
uvicorn app.main:app --reload --host 0.0.0.0 --port 8080The commands above assume PostgreSQL and Qdrant are already running. This project does not require Docker. With the repository Makefile, the equivalent development sequence is:
make install
make migrate
make devThe first endpoint is http://localhost:8080/api/health. It reports application status, PostgreSQL connectivity, and whether configured API keys can be read without returning secret values. http://localhost:8080/api/ready is the Kubernetes-style readiness check and only succeeds when PostgreSQL is reachable.
The .env.example file is the configuration contract. Copy it to .env and set values for the environment. .env is ignored by Git.
For a complete PostgreSQL walkthrough from startup to /api/ask, see PostgreSQL quick start.
Qdrant is a separate local service. No Docker is required. On another Windows computer:
-
Download the Windows Qdrant binary from the official Qdrant releases page.
-
Extract
qdrant.exeinto a folder such asC:\qdrant. -
Start it from PowerShell:
cd C:\qdrant .\qdrant.exeAtlas then uses
http://localhost:6333by default. You can verify it withcurl.exe http://localhost:6333/healthz.
The Qdrant Windows binary may not include a browser dashboard. For a separate local management interface, use the official Qdrant Web UI repository and follow its installation instructions. Point the UI at http://localhost:6333; the UI commonly runs on port 3000. Atlas itself only requires the Qdrant API and does not require the Web UI.
Management endpoints require the application header:
x-app-id: customer-support-appThe first POST /api/applications call is the bootstrap exception: it can omit x-app-id and uses the request body's app_id. GET /api/applications is an Atlas RAG control-plane registry endpoint and does not require x-app-id. Knowledge-base and data-source requests remain application-scoped and require the header.
Applications own knowledge bases, and knowledge bases own data sources. Phase 1 stores source metadata and validated connection configuration only; it does not store raw files. Data source configuration secrets are redacted from responses.
Available resources:
/api/applications
/api/knowledge-bases
/api/data-sources
/api/data-sources/{id}/test-connection
The initial source types are postgresql, rest_api, external_file_service, and development-only local_staging. Raw files remain owned by external services such as the NestJS media worker. Atlas RAG may later download a short-lived signed URL or temporarily process a file from the local staging directory.
Phase 2 supports local staging ingestion for UTF-8 text, Markdown, JSON, CSV, PDF, DOCX, XLSX, XLSM, and XLS. Put development-only files under .runtime/ingestion, create a local_staging data source with a path such as . or customer-support, and call:
POST /api/data-sources/{id}/ingest
GET /api/ingestion-jobs
GET /api/ingestion-jobs/{id}
GET /api/documents
All ingestion endpoints require x-app-id. Raw files are read from the temporary staging directory and removed after processing. The database stores document metadata, checksums, processing status, and extracted text only. PostgreSQL, REST, and external file service sources currently support connection testing; their ingestion adapters will be added in a later phase.
Phase 3 adds internal services for PostgreSQL sources. Schema discovery reads non-system schemas, tables, views, columns, primary keys, and foreign-key relationships. The read-only executor accepts only one SELECT or WITH statement, rejects mutation and locking clauses, applies a row limit, and runs inside a read-only transaction with a statement timeout. These services are intentionally not exposed as public endpoints yet; they are the foundation for the later AI question-answering flow.
Phase 4 adds manual test endpoints for embedding rows returned by a safe PostgreSQL query:
POST /api/data-sources/{id}/embeddings
POST /api/data-sources/{id}/embeddings/search
Both require x-app-id. The first endpoint accepts a read-only SELECT or WITH query, converts each returned row to text, generates embeddings using the configured provider fallback, and stores vectors in Qdrant. The second embeds a search phrase and ranks rows with Qdrant cosine search.
The current default embedding setup is local sentence-transformers (all-MiniLM-L6-v2). It does not consume an API quota. Cohere can remain as a configured fallback. Qdrant stores vectors and PostgreSQL stores chunk text, source metadata, and relationship metadata; Qdrant does not generate embeddings.
/api/ask searches Qdrant for semantic candidates, then combines them with BM25 lexical ranking from PostgreSQL. This keeps exact values such as names, table fields, URLs, and identifiers from being lost when a semantic match is broad. It does not contain application-specific table names or domain rules.
An optional open-source CrossEncoder reranker can improve the final ordering. Enable it in .env after running make install:
RERANKER_ENABLED=true
RERANKER_MODEL=cross-encoder/ms-marco-MiniLM-L6-v2
The model downloads from Hugging Face the first time it is used. It is optional: if it is disabled or unavailable, Atlas keeps the hybrid retrieval result.
To discover and embed all matching tables for a PostgreSQL data source, use the no-body sync endpoint:
POST /api/data-sources/{id}/sync
It requires x-app-id and scans non-system tables by default. Each row is represented as a chunk, sensitive-looking columns such as passwords, tokens, and API keys are excluded, and only new or changed rows are embedded. Rows missing from a later sync are soft-deleted from the Atlas index. The source database is accessed read-only and is never mutated.
Optional data-source configuration values are include_schemas, exclude_tables, exclude_columns, and sync_max_rows_per_table (maximum 1000). The migration for sync state is applied by alembic upgrade head.
Qdrant must be running before synchronizing or asking questions. By default Atlas connects to http://localhost:6333; configure QDRANT_URL, QDRANT_API_KEY (for Qdrant Cloud), and QDRANT_COLLECTION as needed. PostgreSQL keeps chunk text and relation metadata, while Qdrant stores only vectors.
By default, every synchronized PostgreSQL record includes records reached through declared foreign keys in the text used for embeddings. Atlas follows inbound and outbound relationships across the selected tables and stores the connected record keys for relation-aware /api/ask retrieval; no application-specific table names or rules are used. Set sync_relationship_context to false to opt out. sync_relationship_depth defaults to 2 (maximum 3), while sync_related_rows_per_relation (default 3, maximum 10) and sync_max_related_records (default 20, maximum 50) bound the context size.
For now, call this endpoint after a successful update in the source application. A webhook or outbox event is the best first automation; scheduled polling or CDC can be added later when near-real-time synchronization is needed. Creating a data source does not automatically start a potentially expensive sync.
The question-answering endpoint:
POST /api/ask
Example body:
{
"knowledge_base_id": "your-knowledge-base-id",
"question": "Who are the academic personnel?",
"top_k": 5
}The request requires x-app-id. Atlas embeds the question, searches Qdrant for semantic candidates, combines those results with PostgreSQL lexical ranking, expands related records through foreign-key relationships, and sends bounded context to the configured LLM provider. The response includes the generated answer and evidence.
After each answer, Atlas stores the question embedding and the generated answer in a separate Qdrant QA-memory collection. A later similar question retrieves a small amount of prior Q&A as optional context, while the LLM still generates a fresh response from the current question and source evidence. Prior answers are never returned directly, and low-similarity memories are ignored. Configure QA_MEMORY_MIN_SCORE and QA_MAX_MEMORY_CHARS as needed.
Supported hosted LLM providers are groq and openrouter:
LLM_PROVIDER=groq
# or
LLM_PROVIDER=openrouterGroq and OpenRouter are API services with provider/model quotas. Ollama is not enabled as a provider yet; it is a planned optional local LLM integration. When added, it will affect only answer generation—not the existing local embeddings or Qdrant vectors.
Not currently included: multi-turn conversation memory, agents, automatic SQL generation, write operations against source databases, and raw-file retrieval through /api/ask.
For development prompt inspection only, set LLM_LOG_PROMPTS=true in .env. Atlas will emit the final messages sent to Groq as structured logs. Do not enable it in production because prompts may contain indexed source data and personal information.
.\.venv\Scripts\Activate.ps1
pytest
ruff check .
ruff format --check .
mypy appThe application is split by responsibility so future ingestion, processing, embedding, retrieval, LLM, connector, and worker code can evolve independently. Database access uses SQLAlchemy's async engine and session factory, while Alembic owns schema changes. Settings are loaded once from environment variables using Pydantic Settings. Structured JSON logs make events suitable for container log collection. Dependencies remain limited to the HTTP layer, configuration, database, migrations, logging, and development quality tools.