Mercury

Conversational shopping that keeps up when you change your mind.

Inspiration

Shopping rarely begins with a perfect search query.

You might start with “I’m looking for a jacket,” realise it needs to be waterproof, then decide you would rather have something lighter. A useful assistant should follow that conversation without forgetting the requirements you still care about.

That is what we wanted to build with Mercury: a shopping assistant that remembers your current preferences, asks worthwhile questions, and helps you explore beyond the first set of suggestions.

The challenge brought together two familiar shopping experiences—knowing exactly what you want and figuring it out as you browse. We approached both with structured conversational memory, lexical search, adaptive shortlists, and guarded paging.

Everything runs locally, and we can inspect how the assistant reached each recommendation.


What it does

Mercury searches a catalog of 50,000 products and returns up to ten ranked recommendations per turn.

As the conversation develops, it tracks:

  • What you are shopping for: the product category and intended use.
  • What matters: requirements and softer preferences.
  • What to avoid: exclusions and incompatible features.
  • What has changed: corrections, alternatives, and preferences you no longer have.

For example, you could ask for a black leather bag with an adjustable strap, switch to blue canvas, then decide that color does not matter. Mercury updates those preferences while retaining the bag category and adjustable-strap requirement.

Saying “no preference” matters too. It tells Mercury to stop pursuing that attribute instead of treating it as an unanswered question.

The shortlist changes with the conversation. Strong evidence can lead to a few focused recommendations. Greater uncertainty—or fewer turns remaining—can lead to more options. When a useful question could narrow the search, Mercury can ask it while keeping the shortlist focused.

If preferences remain unchanged and the leading candidates keep repeating, guarded paging brings forward highly ranked products the shopper has not seen. A change of intent resets that exploration so the strongest matches for the revised request can be considered again.

The default pipeline requires no hosted model, external search service, API key, or GPU. There are no model API charges, although hardware and operating costs still apply.


How we built it

We built Mercury in Python and separated the pipeline into stages with clear responsibilities:

Conversation → Structured evidence → Lexical retrieval → Constraint-aware ranking → Clarification and adaptive shortlist → Guarded paging → Validated response

1. Remember what changed

Each message can add a requirement, replace a preference, exclude something, introduce alternatives, or remove a constraint.

A deterministic parser turns those messages into structured evidence. Each piece records its source turn, making it possible to trace the current search state back to the conversation.

We also separate feedback about the recommendations from product requirements. “Those options aren’t right” is feedback about the shortlist; it should not become a collection of keywords in the next product search.

2. Search from several angles

Mercury uses SQLite FTS5 with field-weighted BM25. This rewards relevant text matches, gives distinctive words more influence, and lets us weigh different listing fields differently.

We combine several search routes:

Search route What it contributes
Broad keywords Products containing the shopper’s terms
Phrases Matches for distinctive wording
Categories Products of the requested type
Multiple constraints Combinations of stated requirements

We merge these results using weighted reciprocal-rank fusion, which gives products credit for ranking highly across the search lists.

A separate exact-constraint index, derived from the catalog, supplies additional candidates that match stated requirements.

The backend can load a validated, prebuilt SQLite index or build an in-memory index. Processed product features are cached to avoid repeatedly interpreting the same metadata.

3. Rank with the requirements in mind

“I need a waterproof jacket” calls for a different approach from “I’m exploring jackets.” Mercury uses transparent Buying and Browsing policies to adjust the emphasis on requirements and discovery.

Category relevance comes first. A shoe should not become a strong answer to a bag search just because both listings mention canvas and adjustable straps. Known category mismatches are excluded; unknown categories remain available as a fallback.

Within those category tiers, ranking considers contradictions, exact requirement matches, phrase evidence, and where that evidence appears in the listing. Review and price signals come later.

Two distinctions proved especially useful:

  • Missing is different from contradictory. An unspecified material does not prove that a product violates a cotton requirement.
  • The product component matters. A leather upper and a leather lining are different requirements, even though both contain “leather.”

After ranking, Mercury retains up to 100 candidates for clarification and exploration.

4. Ask questions that help

A follow-up question earns its place when the answer could distinguish the remaining products.

Mercury examines the candidate pool and combines information gain with a heuristic estimate of how answerable a question is. Repeated questions receive less weight.

Early open-ended prompts also give shoppers room to mention details that do not fit neatly into color, material, or size.

The shortlist policy considers ranking confidence, requirement coverage, the value of another answer, and the turns remaining. That lets Mercury move between a focused shortlist and a broader selection as the conversation develops.

5. Explore without losing the shopper’s intent

A product can be in the candidate pool and still never reach the shopper.

When preferences are unchanged and the same products remain in the top-ten candidate set, guarded paging favors unseen products from the existing ranked context. It does not change retrieval scores.

Three safeguards keep that exploration consistent:

  • Preserve the shortlist size chosen for the turn.
  • Do not increase known constraint violations just to show something new.
  • Reset exposure when preferences change, allowing newly relevant products to return to the top.

For example, after exploring polyester shirts, “Actually, I need cotton” should bring the strongest cotton matches back into consideration.

An identical request retry is handled separately: Mercury returns the cached response without advancing the page.

Tools, libraries, and data

Area What we used
Development Python, a local virtual environment, Git, and command-line evaluation scripts
Runtime SQLite FTS5 through sqlite3 and Python’s standard library
Verification Python’s unittest, Ruff, and the competition’s local evaluator
Diagnostics HTML and JSON conversation replays
Interface The competition’s Python Agent interface, including reset and respond

Earlier experiments used NumPy, SciPy, scikit-learn, PyTorch, Hugging Face Transformers, and Sentence Transformers. Those dependencies remain available for the experimental pipelines, but neural reranking and vector inference are not part of the current default.

Our main dataset is the competition’s frozen catalog, derived from the Clothing, Shoes and Jewelry category of Amazon Reviews 2023, published by McAuley Lab at UCSD. Development also used 200 public sessions, locally generated synthetic conversations, and authored regression cases.

The runtime uses text and structured metadata, including categories, features, details, prices, and aggregate ratings. Our indexes and diagnostic replays are derived assets. Organizer-private evaluation labels and product imagery are not used by the runtime.


Challenges we ran into

Knowing how much a correction should replace

Changing a material should not erase the product category. Adding an alternative should not reject the original option. Removing a preference should not require a replacement.

These messages can sound similar, but they need different updates to the conversation state.

Telling similar listings apart

Many catalog entries share most of their wording. A rare phrase—or the field containing it—can be more useful than broad semantic similarity.

We explored neural and vector approaches, then selected a default built around lexical evidence and deterministic ranking.

Handling incomplete information

A missing material, an explicitly incompatible material, and a matching word in the wrong product category should lead to different decisions.

That pushed us toward category safeguards, explicit contradiction handling, and conservative treatment of unreliable prices.

Balancing exploration with relevance

Repeating a shortlist wastes opportunities to show other candidates. Advancing blindly can skip the best answer after a correction.

Paging therefore had to stay connected to the shopper’s current intent.

Being honest about the results

Public and synthetic sessions helped us develop the system, but they cannot tell us exactly how real shoppers will behave.

We recorded source hashes, configurations, comparisons, and dataset exposure so each result remains attached to the version that produced it.


Accomplishments that we're proud of

We built a working pipeline that follows changing preferences, runs locally without model inference, and exposes its decisions for inspection.

It can explore beyond its first recommendations while preserving the safeguards around the shopper’s requirements.

In a recorded frozen evaluation of the lexical-search-plus-guarded-paging version:

Public development metric Result
Target products found 200 / 200
Mean reciprocal rank (MRR) 0.965
Average turns 2.11
TechnicalScore 0.967

MRR measures how highly the target appeared in the recommendations. TechnicalScore is the competition’s combined performance measure.

These are public development results, not evidence of real-shopper performance.


What we learned

Finding good candidates is only part of conversational search. The assistant also has to remember corrections, ask useful questions, and decide which products to show. A mistake in any of those steps can keep the right product out of view.

The catalog should guide the choice of tools. Exact phrases and structured attributes carry substantial information in this dataset. A carefully designed lexical system can use that information while keeping the runtime straightforward to operate.

Retrieval and presentation need separate attention. We found that a product could already be in the candidate pool but remain invisible because the same shortlist kept appearing. Paging helps, but we still need to check relevance, intent changes, and whether exploration pushes the target into a worse position.


What's next for Mercury

Test with real shoppers

People may ignore suggestions, reject only part of a list, or change direction without saying “actually” or “correction.”

We want to understand those interactions before treating a continued conversation as rejection in a real storefront.

Support more ways of asking

We want to improve multilingual support and paraphrase handling. Any optional language model would need to respect explicit requirements and preserve an offline fallback.

Work with larger, changing catalogs

The next engineering steps include incremental indexing, updated inventory and prices, and measured limits for concurrency and memory use.

Measure whether the experience is useful

Longer term, we want to know whether Mercury saves people time, produces relevant suggestions, and leaves them satisfied with the search—not just whether it recovers an exact product.

Any persistent personalisation should remain opt-in, with clear ways for shoppers to inspect or delete what is remembered.

Demo vid: https://youtu.be/e7WyMUkOal4

+ 223 more
Share this project:

Updates