CRTX
DocsSign in →

Introduction

CRTX is a multi-user Retrieval-Augmented Generation (RAG) platform. Teams upload their own documents, ask questions in natural language, and get answers that are grounded in — and cite — that content. Every answer is automatically scored for quality, so you can trust it and watch trends over time.

Most AI chat tools are black boxes: you can't see where an answer came from, and you can't tell when retrieval quietly failed. CRTX is built around the opposite principle — every response carries its sources, and every interaction is measured.


#What you can do with it

  • Chat with your documents. Ask anything about the files or web pages you've uploaded. Answers stream token-by-token, and the sources appear before the first token so you see grounding immediately.
  • Ingest almost anything. PDF, Word (.docx), PowerPoint (.pptx), Excel (.xlsx), CSV, plain text (.txt), Markdown (.md), and public URLs.
  • Understand multimodal PDFs. Embedded images are described by GPT-4o vision and become searchable; tables are extracted as structured Markdown; scanned PDFs fall back to page-level vision OCR.
  • See exactly where answers come from. Each answer cites the specific chunks it used, including inline rendering of figure/image sources.
  • Collaborate. Share a collection with a link and control whether recipients can only query it or also upload to it. Share individual chat transcripts with collection members.
  • Measure quality. Faithfulness and context-relevance scores are computed on every query by an LLM judge, and surfaced on an evaluation dashboard with daily trends and a "worst queries" view.
  • Tune retrieval. Swap retrieval strategies per collection, adjust chunk size, and (optionally) add a Cohere reranking layer.

#The mental model

Collection  ── owns ──►  Documents  ── produce ──►  Chunks  ── embedded into ──►  Vectors
     │                                                                              │
     │                                                                              ▼
     │                                                                       Pinecone namespace
     │                                                                        (== collection id)
     │
     ├── has ──► Chat sessions ── contain ──► Messages (with cited sources)
     ├── has ──► Config (retrieval strategy, chunk size)
     ├── has ──► Shares (links) ── grant ──► Members (query or ingest permission)
     └── accrues ──► Evals (faithfulness + relevance per query)

A collection is the central unit. Everything — documents, chat history, retrieval config, sharing, and evaluation metrics — hangs off a collection. Under the hood, each collection maps to a dedicated Pinecone namespace (the namespace is the collection id), which keeps every tenant's vectors isolated.


#How a query works, end to end

  1. You send a question (optionally within a chat session and collection).
  2. For follow-up questions, the last couple of user turns are prepended so the question embeds with its context (a bare "what about its pricing?" otherwise retrieves the wrong chunks).
  3. The question is embedded (text-embedding-3-small, 1024-dim) and used to search the collection's Pinecone namespace with the configured strategy (similarity / MMR / threshold), optionally reranked by Cohere.
  4. Retrieved chunks are stitched with their neighbours to restore context lost at chunk boundaries, then formatted into a numbered, source-labelled context block.
  5. GPT-4o generates an answer grounded in that context, streamed back over SSE. Image-derived chunks are marked [Figure/Image] so the model knows their origin.
  6. The exchange is saved to the chat session, logged (latency, tokens), and scored asynchronously for faithfulness and context relevance.

Full detail: Querying & chat and Retrieval tuning.


#Architecture at a glance

LayerTechnology
FrontendNext.js 16, React 19, TypeScript 5, Tailwind CSS v4
BackendFastAPI, Python 3.13, Uvicorn
AuthSupabase JWT (ES256, JWKS-validated); Next.js middleware for edge auth
DatabaseSupabase PostgreSQL
StorageSupabase Storage (documents + images buckets)
Vector storePinecone (per-collection namespace; chunk_type + image_url metadata)
LLM / VisionOpenAI GPT-4o (answers, image description, scanned-PDF OCR)
JudgeOpenAI GPT-4o-mini (faithfulness + relevance scoring)
EmbeddingsOpenAI text-embedding-3-small (1024-dim)
Reranking (opt-in)Cohere rerank-english-v3.0
Background jobsArq + Redis (batched upserts, tenacity retries)
RAG frameworkLangChain

The backend exposes five routers — /collections, /ingest, /query, /chat, /evals — behind JWT auth. Heavy work (document parsing, embedding, eval scoring) runs asynchronously in an Arq worker backed by Redis, keeping the API responsive. See Operations & scaling.


#Glossary

TermMeaning
CollectionThe top-level container for documents, chats, config, and sharing. Maps 1:1 to a Pinecone namespace.
DocumentA single ingested file or URL within a collection.
ChunkA slice of a document (text, table, or image description) that is embedded and stored as one vector.
Chunk typetext or image_description. Image-description chunks are GPT-4o vision output for embedded figures/scanned pages.
Vector IDDeterministic SHA-256 of (collection_id, source, chunk_index) — re-ingesting the same document upserts identical IDs, so Pinecone deduplicates naturally.
Retrieval strategyHow candidate chunks are selected: similarity, mmr, or threshold.
Top-KThe number of chunks retrieved and fed to the model as context.
RerankingOptional Cohere cross-encoder pass that reorders over-fetched candidates before trimming to Top-K.
Neighbour windowNumber of adjacent chunks stitched around each retrieved chunk to restore boundary context.
Faithfulness0.0–1.0 score: is every claim in the answer supported by the retrieved context?
Context relevance0.0–1.0 score: were the retrieved chunks actually useful for the question?
SessionA saved chat conversation within a collection.
Share / MemberA share is a link granting query or ingest access; a member is a user who accepted one.
JobA background ingestion task tracked in ingest_jobs with queued → processing → succeeded/partial/failed.

Next: Quickstart →