Skip to main content

recsys-candidates

Composable candidate generation for recommender systems.

Status: alpha. Feature-complete for v0.1 — vocabulary, source protocol, merge strategies, pipeline, filters, diversity, exploration. The API may move before 1.0.

Zero dependencies. Sources reach your data through a protocol, so the library never needs a database client, an ANN library, or a model.

The position it takes

Three sources return the same item:

ann         cosine similarity   0.82
popularity  interaction count   4300
recency     hours since posted  7

No weighting of those numbers means anything. Whichever has the widest range dominates the sum, and per-source min-max normalisation only hides it — it makes the top item of a bad source look exactly as good as the top item of a good one.

So the default merge compares ranks. A rank of 1 means the same thing coming out of every source. Run examples/candidates_quickstart.py and watch raw-score merging hand all ten slots to popularity while rank fusion returns {'fresh': 4, 'popular': 2, 'similar': 4} — same sources, same data.

The whole loop

from recsys_candidates import Budget, generate, max_per_key

result = generate(
    {"ann": ann_source, "popular": popularity, "fresh": recency},
    user_id,
    budget=Budget(total=50, per_source={"popular": 10}, min_per_source={"fresh": 5}),
    exclude=already_seen,
    filters=[lambda c: c.item not in blocked],
    diversity=max_per_key(lambda c: c.meta.get("author"), 2),
    timeout=0.2,
)

if result.failures:
    metrics.incr("retrieval.degraded", tags=result.failures)
if result.short:
    metrics.incr("retrieval.short")

A source is one method:

class RecentPosts:
    def fetch(self, user, k, exclude):
        return [i for i in self.by_recency if i not in exclude][:k]

Return bare ids and the pipeline stamps rank and source itself, so a source cannot mislabel itself or get its own ranks wrong.

Exploration

from recsys_candidates.exploration import epsilon_greedy

slate = epsilon_greedy(
    ranked, cold_start_pool, k=50, epsilon=0.1, rng=random.Random(seed)
)

epsilon has no default — how much of your slate you spend on learning is a product decision. Arm priors and reward attribution live in your ArmStore.

Explored items come back with meta["explored"] = True. Log it: without that flag, offline evaluation scores an explored item as though the ranker chose it.

thompson_order samples once per arm, not per candidate — the maximum of many draws is biased upward, so per-candidate sampling makes a chatty arm beat an equally good quiet one on order statistics alone.

What it will not do for you

  • Merge scores across sources without you saying you know they share a scale
  • Pick your epsilon
  • Persist bandit state (InMemoryArmStore is for tests, and says so)
  • Hide a short slate, a dead source, or a failed one — read Result

Documentation

Retrieval hazards — nine ways candidate generation degrades into something that still looks like a product.

License

Apache-2.0

Metadata

Release files for recsys-candidates 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 recsys-candidates 0.1.0
File Size Uploaded
recsys_candidates-0.1.0.tar.gz 25.4 kB Details

Built distribution (wheel)

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

Total release size: 48.3 kB

Release files / recsys_candidates-0.1.0.tar.gz

Download URL recsys_candidates-0.1.0.tar.gz
Size 25.4 kB
Tags Source
SHA-256 checksum
How to use checksums
19fb0d36f21d076f967d952d151b1d572a06905208d6e55162493c7fd7a53918
BLAKE2b-256 checksum
How to use checksums
f5736eaf27b9f81f6049fb823f390b81d694652ede8c0afe97cc96b46a7a7ead
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Aug 9, 2026.

Transparency log

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

Download URL recsys_candidates-0.1.0-py3-none-any.whl
Size 22.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
4214201381a52f694321bd7ca5fb9d0ea7c699872eab6cf55e76e3dece99d881
BLAKE2b-256 checksum
How to use checksums
c9cfd5457d26615bf9287bb3188cdacca556ed19acfa31f9dfc74a61ef274420
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

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 Aug 9, 2026.

Transparency log

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

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