Skip to content
Changelog

Rank newer documents higher with the recency reranker

September 23, 20261 min read

Agno's new RecencyReranker gives Knowledge search a sense of time, which vector search lacks. Update your travel policy, and the old version still matches questions about travel just as well, sometimes better. Your agent then quotes last year's meal limit.

RecencyReranker blends each result's relevance with an exponential decay on its timestamp:

score = (1 - weight) * relevance + weight * exp(-ln2 * age / half_life_days)

It tilts the ranking toward newer documents, and an older document that is clearly more relevant still wins. weight sets how much freshness counts, from 0.0 for relevance only to 1.0 for age only. It defaults to 0.3. half_life_days sets how fast freshness fades and defaults to 30 days.

from agno.knowledge.knowledge import Knowledge
from agno.knowledge.reranker import RecencyReranker
 
knowledge = Knowledge(
    vector_db=vector_db,
    reranker=RecencyReranker(half_life_days=365),
)
knowledge.insert(
    name="Travel expense policy 2025",
    text_content="Expense policy update: the daily travel meal limit is now 75 USD.",
    metadata={"updated_at": "2025-09-01"},
)

The query "What is the daily meal limit when travelling?" against PgVector, top 2 results, real output. Plain vector search ranks Travel expense policy 2023 first with 0.884 and the 2025 policy second with 0.862. RecencyReranker with half_life_days 365 ranks the 2025 policy first with 0.746 and the 2023 policy second with 0.642.

RecencyReranker reads each document's date from updated_at in its metadata, as an ISO-8601 string, a datetime, or epoch seconds or milliseconds. If a document has none, PgVector can supply one: build it with return_updated_at=True and it reports when each row was stored. Re-ingesting a document under the same name makes it fresh again. The option is off by default because the timestamp travels in metadata your model can see. Documents with no timestamp at all rank on relevance alone.

Two PgVector fixes came with it. Upserts now write updated_at, which only update_metadata() used to set. Keyword search now returns a normalized relevance score, so vector, keyword and hybrid search all report scores on one scale.

RecencyReranker runs on the knowledge retrieval pipeline, so it works with any vector database that returns relevance scores and timestamps. PgVector is the one it's built and tested against.

See the cookbook, and learn more about the recency reranker and reranking in the documentation.

Frequently asked questions

Set reranker=RecencyReranker() on your Knowledge. It mixes each result's relevance score with a freshness score that decays exponentially with age, so a newer document wins a close call against an older one.

From updated_at in the document's metadata, as an ISO-8601 string, a datetime, or epoch seconds or milliseconds. Failing that, PgVector built with return_updated_at=True reports when each row was stored. A document with no timestamp keeps its plain relevance score.

weight is the share of the score that comes from freshness. 0.0 ranks on relevance only, 1.0 on age only, and the default is 0.3. half_life_days is how many days it takes freshness to fall by half, 30 by default.

No. RecencyReranker only nudges newer documents up the ranking. An older document that is clearly more relevant still comes first.

Shipped around the same time