Read the full writeup →
Wine Sommelier RAGBy Jeremy Lee, WSET Level 3 · Source

The request

a bold red under $25 for a steak dinner --max-price 25

The pick, of four bottles retrieved

Misiones de Rengo Carmenère91 pts · $20 · [3]

"a juggernaut red that cries out for steak"

It passed over the Soos Creek as "a touch gentler than the bold profile you're after." The [3] points to the review the pick came from.

One recorded run, quoted in the project writeup.

Wine recommendations where every bottle comes from a review

Ask in plain English. A local hybrid retriever finds matching Wine Enthusiast reviews, a cross-encoder reranks them, and Claude recommends two or three, citing each one. If nothing fits, it says so.

What the reranker bought

Three retrieval setups, scored on the original twelve requests and on 30 more that were committed to the repo before any system ran on them. Each request has a written relevance rubric (grape or wine family, country or region, price cap, descriptor words).

RetrievernDCG@10, 12 queriesnDCG@10, 30 held out
Dense vectors only0.670.59
Dense + BM25, fused with RRF0.680.68
Dense + BM25 + cross-encoder rerank0.830.76

The cross-encoder, which reads the request and each review together, helped on both sets. BM25 fusion did little on the style-led first twelve and helped on the 30, which name more grapes and places. Retrieval takes 196 ms median on an Apple M4; a Claude CLI answer takes 8.3 s and about $0.13 API-equivalent. The write-up has per-query results and the error analysis: the two most common misses are the wrong grape or color and a price stated in the sentence, which the retriever ignores.

How a request is answered

  1. The request is embedded locally with all-MiniLM-L6-v2 and searched in Chroma, with any price, country, grape or minimum-score filters applied inside the query.
  2. A BM25 keyword index ranks the same candidates, and Reciprocal Rank Fusion merges the two lists.
  3. The cross-encoder ms-marco-MiniLM-L-6-v2 re-scores the fused shortlist.
  4. Claude gets the top reviews and a system prompt that allows recommendations only from them, each cited by [n].
Pipeline diagram: request, local embedding, hybrid retrieval with BM25, RRF and cross-encoder rerank over a 30,000-review index, Claude generation, and a cited answer naming Misiones de Rengo at 91 points and $20.
The pipeline as benchmarked.
python -m src.cli ask "elegant and mineral, great with oysters" \
    --country France --max-price 40 --min-points 90

Filters compose with any request. Retrieval runs locally at no cost; generation uses the Claude CLI, or the Anthropic API when ANTHROPIC_API_KEY is set.

Limits

The benchmark is 42 queries with rule-based relevance, so it compares the three retrievers fairly but does not give absolute quality. The default index holds the 30,000 highest-scored reviews of the 129,971 in the dataset, all from one magazine.