Skip to main content

ragless

File-based retrieval for RAG, with no vector database.

ragless indexes a folder of text files (or in-memory strings) and lets you search them with BM25 keyword search, fuzzy string matching, and optional local semantic embeddings -- combined with Reciprocal Rank Fusion. Everything lives on disk as plain files (or in memory): no Postgres/pgvector, no Pinecone/Weaviate/Chroma server, nothing to run.

from ragless import Retriever

r = Retriever("./docs")
for hit in r.search("how do I configure retries", mode="hybrid"):
    print(f"{hit.path}:{hit.start_line}-{hit.end_line}  score={hit.score:.3f}")
    print(hit.text)

Install

pip install ragless                # BM25 + fuzzy (no heavy deps)
pip install 'ragless[semantic]'    # + local embeddings and cross-encoder rerank

Quickstart

from ragless import Retriever

# Index a directory of files.
r = Retriever("./docs")
results = r.search("installation steps", mode="hybrid", top_k=5)

# Or index in-memory text directly -- no files required.
r = Retriever(
    [
        "ragless indexes folders of text files for retrieval.",
        "BM25, fuzzy matching, and semantic search are combined with RRF.",
    ]
)
results = r.search("how are results combined?")

for hit in results:
    print(hit.path, hit.start_line, hit.end_line, hit.score)
    print(hit.text)

Search modes

r.search("query", mode="hybrid")  # fuse every configured engine (default)
r.search("query", mode="bm25")  # keyword search only
r.search("query", mode="fuzzy")  # fuzzy string matching only
r.search("query", mode="semantic")  # embeddings only (requires the extra)

Semantic search and caching

from ragless import Retriever

r = Retriever(
    "./docs",
    engines=["bm25", "fuzzy", "semantic"],
    cache_dir="./.ragless_cache",  # embeddings cached here as .npy/.json
)
r.search("query", mode="hybrid")

Embeddings are cached per source file, keyed by the file's mtime/size and the embedder's name. Editing one file only re-embeds that file's chunks on the next run; untouched files are loaded straight from the cache.

Cross-encoder rerank

r.search("query", mode="hybrid", rerank=True)

Reranking takes the top fused candidates and rescoring them with a small local cross-encoder (also via fastembed, under the semantic extra) for higher precision at the top of the list.

Filters

# Only chunks whose metadata says category="guide"
r.search("query", filters={"category": "guide"})

# Only chunks from markdown files
r.search("query", path_filter="*.md")

# Per-document metadata, assigned when building the index
r = Retriever(
    "./docs",
    metadata=lambda path: {"category": "guide"} if path and "guide" in path else {},
)

Pluggable components

Chunkers, retrievers, and embedders are all swappable:

from ragless import Retriever, Chunker, BaseRetriever
from ragless.chunking import LineChunker

r = Retriever("./docs", chunker=LineChunker(lines_per_chunk=60, overlap=10))

# Bring your own retriever/embedder implementation:
r = Retriever("./docs", engines={"bm25": MyRetriever(), "fuzzy": FuzzyRetriever()})

Implement ragless.chunking.Chunker, ragless.retrievers.base.BaseRetriever, or ragless.embedders.base.Embedder to plug in your own.

Why

Most "RAG" tutorials reach for a vector database before checking whether they need one. For a folder of a few thousand files, plain keyword search (BM25), fuzzy matching, and a small local embedding model get you most of the way there, with:

  • No server to run, no API keys, no network calls (semantic search runs a small model locally via fastembed).
  • No ingestion pipeline: point it at a directory and it chunks and indexes on construction.
  • Caching as plain sidecar files (.npy + .json) next to your index, not a database you have to back up and migrate.
  • Every result keeps the file path and line range it came from.
ragless vector DB (Pinecone/Chroma/pgvector)
Infra none a running database/service
Setup Retriever("./docs") provision, configure, ingest
Keyword search built in (BM25) usually bolted on separately
Fuzzy/typo tolerance built in usually absent
Good for a few thousand files, local tools, CLIs, CI large, constantly-changing, multi-tenant corpora
Cold start instant needs the service up and reachable

If you need to search tens of millions of chunks with concurrent writers across a fleet of machines, use a vector database. If you need to search the docs folder sitting next to your code, ragless is simpler.

How it works

  1. Load -- read files from a directory (or accept raw in-memory strings). Binary files and undecodable text are skipped automatically.
  2. Chunk -- split each document into overlapping line-based windows, keeping the file path and 1-indexed start_line/end_line for every chunk (ragless.chunking.LineChunker, pluggable).
  3. Index -- each configured engine builds its own index over the chunks:
    • BM25Retriever: classic Okapi BM25 over tokenized text (NumPy).
    • FuzzyRetriever: rapidfuzz string similarity.
    • SemanticRetriever: dense embeddings (fastembed) with cosine similarity (NumPy), cached to disk as .npy/.json sidecar files.
  4. Search -- query every configured engine, fuse their rankings with Reciprocal Rank Fusion, apply metadata/path filters, and optionally rerank the top candidates with a cross-encoder.

Status

0.1.0 -- the API may still shift. Feedback and issues welcome.

License

MIT

Metadata

Release files for ragless 0.1.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for ragless 0.1.0
File Size Uploaded Provenance Actions
ragless-0.1.0.tar.gz 28.7 kB With provenance Details for ragless-0.1.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for ragless 0.1.0
File Interpreter ABI Platform Actions
ragless-0.1.0-py3-none-any.whl Python 3 none any Details for ragless-0.1.0-py3-none-any.whl

Total release size: 49.8 kB

Release files / ragless-0.1.0.tar.gz

Download URL ragless-0.1.0.tar.gz
Size 28.7 kB
Tags Source
SHA-256 checksum
How to use checksums
8b6f9a00d0cd6114b63c84c4df0c8227541e7782708f476ad1de2d549da547c6
BLAKE2b-256 checksum
How to use checksums
8176c910f2339d857b7a2696590130f7a5c6acf5a4f1b52b8d4cffab55cdb67d
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 12, 2026.

Transparency log

Release files / ragless-0.1.0-py3-none-any.whl

Download URL ragless-0.1.0-py3-none-any.whl
Size 21.1 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2efb766f4acf0e5cc808ba04cafd44803155de41ae39aadd70727c9dc4b20d6f
BLAKE2b-256 checksum
How to use checksums
1d2f083c1b703483b30c77bc42eadd40bb0a2783a81f5d1dee28da3912310b20
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 12, 2026.

Transparency log

Security for ragless 0.1.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

Both files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for ragless-0.1.0.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Nov 12, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files Full provenance

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page