This is the architectural reference. For install/run instructions see README.md.
The spine of ragzero is a hard-gated answering pipeline. Every query passes through
these stages in RAGPipeline.answer() (src/ragzero/rag/pipeline.py); each stage emits
a tracer event for observability.
| # | Stage | Where it lives |
|---|---|---|
| 1 | Ingest + normalize — parse files, dedup by content hash, version stably | ragzero/rag/ingest.py |
| 2 | Chunk — split docs into overlapping windows (pluggable strategy) | ragzero/rag/chunkers/ |
| 3 | Hybrid retrieve — dense (vector) + sparse (BM25) with RRF fusion | ragzero/rag/retrieval.py |
| 4 | Confidence score — per-chunk and aggregate scoring | ragzero/rag/confidence.py |
| 5 | Early-refuse gate — refuse before generation if confidence is too low | pipeline.py (fallback.early event) |
| 6 | Constrained generation — LLM call locked to retrieved context | ragzero/rag/generation.py |
| 7 | Citation extraction — pull citations out of the model's response | generation.py + ConstrainedGenerator |
| 8 | Final fallback gate — refuse if citations missing or evidence insufficient | ragzero/rag/fallback.py |
| 9 | Cache — store final answer keyed by query (skipped when filters present) | ragzero/rag/cache.py |
| 10 | Trace + finalize — emit observability events, return Answer |
ragzero/rag/observability.py |
These stages are the contract. Everything below is an extension point — pluggable without touching the spine.
Each registry maps a string id → constructor. Pick which implementation to use via YAML config or the API; defaults work without configuration.
mock,anthropic,openai,azure_openai,gemini,openrouter- Settable via
POST /api/session/llm
hash,sentence_transformers,openai,azure_openai,voyage,gemini,openrouter- Settable via
POST /api/session/embedder
in_memory,faiss,qdrant,pinecone,weaviate,chroma,pgvector,azure_ai_search- Settable via
POST /api/session/vector_store - Each implements
add,search(query_vector, k, filters=None),size,clear
fixed_size,sentence,paragraph,markdown_header,token,recursive,per_row- Settable via
POST /api/session/chunkeror thepipeline.chunker_strategyYAML key - New strategy = add a class with
.chunk(doc) -> list[Chunk]+ register it
- Unified format:
[{field, op, value}]with opseq/ne/gt/gte/lt/lte/in/not_in/contains pipeline.answer(query, filters=[...])plumbs them through- Backends with native support translate; others use over-fetch + in-process post-filter
- Chroma has native
where-clause translation (vector_stores_external.py::_filters_to_chroma_where)
- Optional. Built-in fields (
source,doc_type,content_hash,created_at, ...) auto-populated - Custom fields settable via
POST /api/schema CAPABILITY_MATRIXdocuments which vector stores support which flags
- Format detection + type inference for CSV / JSON-array / JSONL
POST /api/ingest/structured/previewreturns inferred schemaPOST /api/ingest/structured/commitindexes each row as one Document with theper_rowchunker
simple,graph,agentic,multilingual- Each strategy reads filters from
ctx.options["filters"]and forwards topipeline.answer()orretriever.search()directly
SessionState (ragzero/rag/sessions.py) is the per-user request scope:
- Provider configs (LLM / embedder / vector store)
- Pipeline overrides
- Per-session
Ingestor(so content-hash dedup doesn't leak across users and resets on Clear) metadata_schema,chunker_strategy,chunker_settings- Cached
RAGPipeline(rebuilt when provider changes; sources auto-re-ingested)
Switching providers no longer wipes state.sources — the pipeline rebuilds on next query
and re-ingests stored sources into the new backend transparently. clear_sources does
purge the active store (calling each backend's clear()).
- Implement
VectorStoreinragzero/rag/backends/vector_stores_external.py(add, search, size, clear).search(query_vector, k, filters=None)is optional; without it the retriever falls back to over-fetch + post-filter. - Register a constructor in
ragzero/rag/config.py::VECTOR_STORES. - Add a
ProviderSpectoragzero/rag/providers.py::VECTOR_STORE_PROVIDERSso the UI catalog picks it up. - (Optional) Add a row to
schema.py::CAPABILITY_MATRIXso the UI knows which flags to honor.
- Implement
ChunkerLike(just.chunk(doc) -> list[Chunk]) inragzero/rag/chunkers/<your_strategy>.py. - Register a constructor in
ragzero/rag/chunkers/__init__.py::CHUNKERSand add achunker_catalogentry so the UI /GET /api/chunkersknows about it.
- Implement the interface in
ragzero/rag/backends/llms.py/embedders.py. - Register in
ragzero/rag/config.py::LLMSorEMBEDDERS. - Add a
ProviderSpectoragzero/rag/providers.py::LLM_PROVIDERS/EMBEDDER_PROVIDERS.