Skip to main content

Instant, optimized Retrieval-Augmented Generation. Pass your text + a model, get a RAG-powered LLM in one line.

Project description

swiftrag

CI PyPI version Python versions License: MIT

Instant, optimized Retrieval-Augmented Generation. Pass your text and a model — get a RAG-powered LLM in one line.

from swiftrag import RAG

rag = RAG(
    documents="The Eiffel Tower is 330 metres tall and located in Paris.",
    embedding_model="openai:text-embedding-3-small",
    llm_model="openai:gpt-4o-mini",
)

print(rag.query("How tall is the Eiffel Tower?"))
# -> "The Eiffel Tower is 330 metres tall."

That's the whole API. You bring documents (a string, a list of strings, or dicts) and a model spec; swiftrag handles chunking, embedding, vector indexing, retrieval, and prompt construction.


Why swiftrag

  • One line to a working RAG. No glue code, no framework to learn.
  • Optimized core. L2-normalized embeddings + a single BLAS matmul for search, argpartition top-k (no full sort), batched & concurrent embedding requests, token-aware chunking, and an optional FAISS backend for large corpora.
  • Tiny footprint. The core depends only on numpy. It installs in seconds.
  • Runs offline out of the box. With no API key it uses a built-in hashing embedder and an extractive answerer, so the full pipeline works in tests/CI/demos.
  • Provider-agnostic. OpenAI, Anthropic, local sentence-transformers, or any custom callable/object you plug in.
  • MIT licensed.

Install

pip install swiftrag                 # core (numpy only) — works offline
pip install "swiftrag[openai]"       # OpenAI embeddings + LLM
pip install "swiftrag[anthropic]"    # Claude LLM
pip install "swiftrag[local]"        # local sentence-transformers embeddings
pip install "swiftrag[faiss]"        # FAISS backend for big corpora
pip install "swiftrag[all]"          # everything

Usage

Pick your models with a simple "provider:model" string

# OpenAI (needs OPENAI_API_KEY)
RAG(documents=text, embedding_model="openai:text-embedding-3-small", llm_model="openai:gpt-4o-mini")

# Anthropic for generation, local embeddings (no embedding API calls)
RAG(documents=text, embedding_model="local:all-MiniLM-L6-v2", llm_model="anthropic:claude-3-5-sonnet-latest")

# Fully offline (default) — no keys required
RAG(documents=text)

Build straight from files or a folder

rag = RAG.from_files("docs/", embedding_model="openai:text-embedding-3-small")
# each file becomes a document tagged with metadata={"source": <path>}

resp = rag.query("What's our deployment process?")
print(resp.answer)
print(resp.format_sources())   # numbered, human-readable citations

Documents can be a string, list, or dicts with metadata

rag = RAG(documents=[
    "Plain string document.",
    {"text": "Document with metadata.", "metadata": {"source": "handbook", "page": 12}},
])

Query, stream, or just retrieve

resp = rag.query("What does the handbook say about refunds?")
print(resp.answer)
for s in resp.sources:
    print(s.score, s.metadata, s.text[:80])

# Token streaming
for token in rag.stream("Summarize the refund policy."):
    print(token, end="", flush=True)

# Retrieval only (no LLM call)
chunks = rag.retrieve("refunds", top_k=5)

Filter by metadata and score

# Only consider chunks whose metadata matches, and drop weak matches.
resp = rag.query(
    "What is the refund window?",
    where={"source": "handbook"},     # exact metadata match (or pass a Chunk -> bool callable)
    min_score=0.25,                    # cosine threshold; weaker chunks are ignored
    top_k=3,
)

Repeated queries reuse a cached query embedding (LRU, configurable via query_cache_size), so re-asking the same question skips the embedding call.

Add documents incrementally, save, and reload

rag = RAG().add("first batch").add("second batch")
rag.save("index.pkl")

rag = RAG.load("index.pkl", embedding_model="openai:text-embedding-3-small",
               llm_model="openai:gpt-4o-mini")

Batch and async

# Answer many questions at once — embeddings are batched, generation is parallelized.
responses = rag.query_many(["q1?", "q2?", "q3?"], max_workers=8)

# Async API (non-blocking, great for web servers):
resp = await rag.aquery("your question")
async for token in rag.astream("your question"):
    print(token, end="", flush=True)

Bring your own provider

# Any callable fn(prompt) -> str works as an LLM:
rag = RAG(documents=text, llm_model=lambda prompt: my_model.generate(prompt))

# Any object with embed_documents(list[str]) and embed_query(str) works as an embedder.

Configuration

Argument Default Description
documents None str / list[str] / list[dict] / Document(s) to index.
embedding_model "hash" "provider:model" string or a custom provider.
llm_model None (offline) "provider:model" string, callable, or provider.
chunk_size 512 Target chunk size in tokens.
chunk_overlap 64 Token overlap between chunks.
top_k 4 Chunks retrieved per query.
use_mmr False Maximal Marginal Relevance re-ranking for diverse results.
use_faiss False Use FAISS index (install swiftrag[faiss]).
min_score None Default cosine threshold for dropping weak matches.
max_context_tokens None Cap the tokens of retrieved context packed into the prompt.
dedup True Skip exact-duplicate chunks on ingest.
query_cache_size 128 LRU size for cached query embeddings (0 disables).
system_prompt grounded default System prompt for the LLM.

How it works

documents ─▶ chunk (token-aware) ─▶ embed (batched) ─▶ normalize ─▶ vector store
                                                                         │
query ─▶ embed ─▶ cosine (BLAS matmul) ─▶ top-k (argpartition) ─▶ context ─▶ LLM ─▶ answer

Development

pip install -e ".[dev]"
pytest
ruff check .

License

MIT — see LICENSE.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

swiftrag-0.1.0.tar.gz (22.2 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

swiftrag-0.1.0-py3-none-any.whl (22.8 kB view details)

Uploaded Python 3

File details

Details for the file swiftrag-0.1.0.tar.gz.

File metadata

  • Download URL: swiftrag-0.1.0.tar.gz
  • Upload date:
  • Size: 22.2 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for swiftrag-0.1.0.tar.gz
Algorithm Hash digest
SHA256 45a8a9999bcfd2b986fda60b5aac8cd9ef8473f4300b8463160fe074f00a3a3b
MD5 d6432519495a216e38852daece411f3a
BLAKE2b-256 22cee26fa8e375350931fe16f7e75fe7606c55b3c92f623c1915d375384d26ca

See more details on using hashes here.

File details

Details for the file swiftrag-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: swiftrag-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 22.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.10

File hashes

Hashes for swiftrag-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4f45addd401e68088d989ccff2374e2083b375e5ee24b62ced9e821cbdc1806d
MD5 1bc7abc7af8951d88d69d3bd6bce670a
BLAKE2b-256 2c92dd30dcc164b2031d213ea0f2674fb3d58f0deb9e24fffffefcc18466f9c6

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page