Skip to main content

Set up retrieval-augmented generation from your own text in one call. Pass your documents and a model, and get a RAG-backed LLM.

Project description

swiftrag

CI PyPI version Python versions License: MIT

swiftrag sets up a retrieval-augmented generation (RAG) pipeline from your own text in one call. You pass your documents and a model, and it handles the chunking, embedding, vector search, retrieval, and prompt building.

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 is the whole API. You bring documents (a string, a list of strings, or dicts) and a model spec, and swiftrag does the rest.

What you get

  • One call to a working RAG pipeline, with no extra glue code.
  • A small core that depends only on numpy, so it installs quickly.
  • Search that normalizes embeddings once and runs as a single BLAS matrix multiply, with top-k selection via argpartition instead of a full sort. Embedding requests are batched and run concurrently, chunking is token-aware, and there is an optional FAISS backend for large corpora.
  • Offline operation by default. With no API key it uses a built-in hashing embedder and an extractive answerer, so the pipeline runs in tests, CI, and demos.
  • Support for OpenAI, Anthropic, local sentence-transformers, or any callable or object you pass in.
  • An MIT license.

Install

pip install swiftrag                 # core (numpy only), works offline
pip install "swiftrag[openai]"       # OpenAI embeddings and 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 "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, readable citations

Documents can be a string, a 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 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 and generation is parallelized.
responses = rag.query_many(["q1?", "q2?", "q3?"], max_workers=8)

# Async API for non-blocking use, for example in a web server:
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

On ingest, each document is chunked (token-aware), embedded in batches, normalized, and stored in the vector index. On a query, the question is embedded, compared to the index with a cosine similarity matrix multiply, reduced to the top-k chunks with argpartition, and passed as context to the LLM, which returns the 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.1.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.1-py3-none-any.whl (22.8 kB view details)

Uploaded Python 3

File details

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

File metadata

  • Download URL: swiftrag-0.1.1.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.1.tar.gz
Algorithm Hash digest
SHA256 d5507d8df8d0469d4c65fbf3b42bbfb3fc0e4f15f31a066a3cd57556341a6296
MD5 61616930b6b118a608239ab8066a7139
BLAKE2b-256 ace66db1b70fff9e7952510016edd0b878372c72f830391aa5c539ffcae2ca90

See more details on using hashes here.

File details

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

File metadata

  • Download URL: swiftrag-0.1.1-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.1-py3-none-any.whl
Algorithm Hash digest
SHA256 26c68be16c640b77291a79bafd91ef3b40a901c2e554cd7a782296f3654f9115
MD5 9538d03bd3dbcf0f7898f37439e63565
BLAKE2b-256 d304a2ed6733db7b7309dd52f6b4b6c428b9ef90445195e56a18fd1a05718128

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