Frameworks that do too much.
Every serious RAG implementation ends up with the same shape. You load documents. You chunk them. You embed them. You store them in a vector database. When a query arrives, you embed it, retrieve the top chunks, build a prompt, and call the LLM. That is the entire pipeline.
The problem is not the pipeline. The problem is what the popular frameworks bring with them: abstractions on top of abstractions, dependency graphs that pull in half of PyPI, and opinions baked so deep into the core that swapping a single provider means migrating your entire codebase.
You wanted a RAG pipeline. You got a framework lock-in problem.
"You bring the model. NexRAG handles the plumbing."
Own the shape. Not the components.
NexRAG starts from a single constraint: the core must have zero dependency on any AI SDK or framework. Not LangChain. Not LlamaIndex. Not OpenAI's SDK. The core is interfaces all the way down.
Each pipeline stage — loader, sanitizer, chunker, embedder, vector DB, retriever, reranker (optional), prompt builder, LLM, observer — is a clean abstract base class. NexRAG ships default implementations for every one of them. You can swap any by implementing the interface and declaring a dotted class path in YAML.
The YAML file is not configuration for NexRAG. It is the pipeline. Every behavior that varies between deployments — providers, models, chunk sizes, retrieval thresholds, secrets — lives there. None of it lives in your application code.
The six rules everything is built on.
Every stage is a contract. Implementation is secondary. If you implement the interface, NexRAG will wire it in.
YAML configures the pipeline. Code defines the logic. Secrets never in config files — only environment variables.
No framework dependency at core. Your application depends on NexRAG. NexRAG depends on nothing opinionated.
No hidden defaults. Every behavior is declared or documented. No magic — just interfaces, adapters, and YAML.
New components plug in without touching core. The extension point is YAML, not a pull request.
Native async/await pipeline with parallel batch embedding. Token-by-token streaming via stream_query() and astream_query() — no extra setup.
The infrastructure layer. Nothing more.
NexRAG is not a chatbot framework. It is not a research tool. It is not trying to be LangChain. It is the layer that sits between your documents and your LLM and handles everything in between — reliably, predictably, and without opinion about which model you use.
NexRAG owns the pipeline shape. You own the components. You point it at your data. You declare your providers in YAML. You call pipeline.ingest() and pipeline.query(). Everything else — deduplication, fingerprinting, batching, retries, observability — is handled.
When your requirements change, you change the YAML. When you outgrow a provider, you swap it. When you need a custom stage, you implement the interface and drop it in. The application code does not change.
v0.5.0 makes the query layer stateful. v1 is the platform.
v0.5.0 adds a pluggable query-result cache, multi-turn sessions with window / token-budget context strategies, and a client-side rate limiter — plus truly batched embedding for ingest_batch(). That builds on v0.4.0's Gemini and Pinecone providers, the production chunking suite (token, sentence-window, markdown, code, semantic, proposition) with independently-resolved nested component configs, the pluggable guardrails security layer, and full OpenTelemetry observability — metrics, traces, and logs with Prometheus pull, OTLP push, and LLM-as-judge evaluators — on top of the hybrid retrieval, reranking, and async streaming shipped earlier. What comes next is more remote vector stores and more loaders.
mode: async enables native async/await with parallel batch embedding. stream_query() and astream_query() stream tokens live — plugs directly into FastAPI SSE.CohereReranker and CrossEncoderReranker out of the box. Custom rerankers via BaseReranker.result.metrics.alpha. Retrieve large candidate sets with BM25; rerank precisely with dense. Requires nexrag[bm25].chunker.embedder / chunker.llm sub-configs resolved independently of the pipeline models (cheap model for chunking, strong model for generation).query_session() with a caller-supplied session_id. Pluggable BaseSessionStore (in-memory default, TTL, persist: false privacy mode) and window / token-budget context strategies. History is injected into the prompt; retrieval always uses the current query.BaseQueryCache with an exact-match in-memory default (LRU + TTL) and per-collection invalidation after ingest. Configure under query.cache.LLMRateLimitError(retry_after_seconds=...). Configure under query.rate_limit./metrics) and OTLP push to any collector. LLM-as-judge evaluators (faithfulness, relevance, completeness, coherence, context diversity) with per-metric model selection. Configure everything under observability: in YAML. Install nexrag[observability].