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 (
InMemoryArmStoreis 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)
| File | Size | Uploaded | |
|---|---|---|---|
| recsys_candidates-0.1.0.tar.gz | 25.4 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| 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 logRelease 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