In 14 years of building systems, I have watched time-series models fail the same way every time: they choke on the outliers. A sudden market crash, a Black Swan event, and the model is out of its depth, because its parameters were fixed during training. Anything it has not seen before turns into a guess. Retrieval-Augmented Forecasting (RAF) is the move away from that, and it works by giving the model an actual memory to consult.
Why static weights fail in time-series
Standard forecasting runs one way: past data goes in, weights get adjusted, a forecast comes out. Whatever the model knows is frozen at that point. Hit it with something like covariance shift and it is obsolete the moment the distribution moves. Retrieval-Augmented Forecasting adds an explicit search step, so rather than leaning entirely on internal weights, the model can ask whether anything like this has happened before.
The retrieval-augmented forecasting cycle
It is RAG for numbers. In natural language processing you retrieve documents; in time-series you retrieve patches, meaning windows of historical data. The cycle is simple to describe and fiddly to get right:
- Embedding: Turn the current situation into a dense vector.
- Similarity search: Use a library like FAISS to find the closest historical matches across millions of records.
- Contextual grounding: Pull the actual outcomes of those matches.
- Fusion: Feed the current state and the retrieved outcomes into the forecaster.
A naive implementation (do not ship this)
Most developers start by computing Euclidean distance over raw arrays. It is fine at 100 rows and it will flatten your server at 100,000.
# Naive approach using raw arrays (Slow, O(n) complexity)
import numpy as np
def get_similar_window(current_data, historical_db):
distances = [np.linalg.norm(current_data - h) for h in historical_db]
return historical_db[np.argmin(distances)]
The production approach: indexed vector search
Retrieval-Augmented Forecasting only survives production with an index behind it. Annoy and FAISS get you sub-linear search times by organizing data into trees or clusters. A dedicated vector database such as Pinecone or Qdrant goes further and lets you filter on metadata, so you can say “only retrieve patterns from the same season.”
# Efficient search using FAISS
import faiss
def bbioon_build_fast_index(embeddings):
d = embeddings.shape[1] # Dimension
index = faiss.IndexFlatIP(d) # Inner product for cosine similarity
index.add(embeddings.astype('float32'))
return index
# Querying the index takes milliseconds, even with millions of vectors
scores, ids = index.search(current_query_vec, k=5)
How to fuse retrieval with forecasting
Once the memory exists, you still have to wire it into the model. Four strategies keep showing up in recent papers, including the ICML 2025 work:
- Concatenation: Append the retrieved context to your input sequence. This is the easiest place to start with Transformers like Chronos.
- Cross-attention: Let the model’s decoder attend to the retrieved windows. Far more precise, but you have to modify the architecture.
- Mixture-of-experts (MoE): A gate decides whether to trust the base model or the retrieval-based prediction.
- Channel prompting: Treat the retrieved series as extra features in a multivariate setup.
If a retrieval pipeline like this is eating your dev hours, I can take it on. I have been working with WordPress and heavy backend logic since the 4.x days.
What retrieval actually buys you
One set of weights for every situation is on the way out. With Retrieval-Augmented Forecasting your historical database stops being dead storage and starts taking part in the prediction, as a memory the model can search when conditions get strange. If your business runs on high-stakes predictions, a vector retrieval pipeline pays for itself the first time an anomaly shows up.