Inspiration
Online shopping is easy when a customer already knows the exact product category, but real shoppers often describe what they want conversationally: “something for outdoor work,” “make that a leather belt,” or “I’m flexible on colour.”
For TikTok TechJam Track 4, we built an agent that must identify a hidden target product from a frozen 50,000-item clothing catalog within ten turns. We wanted to explore whether a lightweight, deterministic system could handle changing intent, ambiguity, and limited user attention without depending on a large language model at runtime.
What we built
Our system is an offline conversational shopping copilot with five main stages:
- It detects whether the customer is buying with a specific requirement or browsing more openly.
- It maintains typed dialogue state for categories, materials, colours, budgets, features, and other constraints.
- It routes each conversation through catalog-derived retrieval and lexical search.
- It ranks candidates using popularity, BM25 text matching, exact phrase agreement, structured facets, and a small interpretable linear reranker.
- It decides whether to recommend products immediately or ask a high-value clarification question.
The dialogue state supports incremental constraints, corrections, intent overrides, recency decay, and product-level restarts. When a request is too broad, the agent estimates the candidate pool size and proactively asks a structured question rather than presenting an unhelpful list.
The agent also learns during operation which types of questions a customer tends to answer. Bounded profile memory can influence tie-breaking and future question selection without overwhelming the explicit preferences stated in the current conversation.
The default runtime uses only Python’s standard library. It makes no network calls, requires no API key, uses no GPU or vector database, and consumes zero prompt or completion tokens during evaluation. An optional LLM ranking stage exists for experimentation, but it is disabled by default because the measured linear reranker was more reliable for this task.
How we built it
The catalog is loaded into memory and indexed once. Retrieval combines exact category matching, catalog-mined word-to-shelf associations, an inverted lexical index, and BM25 scoring. The ranking pipeline is intentionally interpretable so that every behavior can be measured and tested independently.
The linear reranker was trained offline using development sessions 1–100 and evaluated separately on held-out sessions 101–200. The repository includes the evaluator, regression tests, adversarial tests, latency checks, ranking benchmarks, and experiment artifacts needed to reproduce the results.
On the public evaluation set, the current agent achieved a TechnicalScore of 0.916125, HR@10 of 1.000, MRR of 0.773417, and mean time to conversion of 1.795 turns.
What we learned
Our biggest lesson was that retrieval and ranking are different problems. On the official sessions, the target product was already present in the candidate pool from the first turn, so the remaining gains came mostly from ordering, confidence-based recommendation width, and dialogue strategy.
We also found that popularity is a powerful prior in this dataset, but relying on it too heavily harms long-tail products. This led us to keep popularity as one interpretable signal among several rather than allowing it to dominate the system.
Another important lesson was that stronger models are not automatically better. We tested an optional LLM semantic ranking stage, but it did not outperform the lightweight linear reranker on held-out data. Keeping the simpler approach gave us deterministic behavior, lower operational cost, and easier testing.
Challenges
The hardest challenges were handling customers who changed their minds, distinguishing a category correction from an ordinary product constraint, and resolving near-duplicate catalog shelves with almost identical product text. We also had to account for simulator artifacts while avoiding solutions that would only optimize the public benchmark.
To address these issues, we created separate public, held-out, shadow, adversarial, and ranking-focused evaluations. Failed experiments were retained in the repository rather than hidden, making the final system easier to understand and reproduce.
Given more time, we would validate the agent with real shoppers, improve category disambiguation using signals outside the catalog text, and address missing price metadata for budget-based requests.
Built With
- amazon
- bm25
- conversational-ai
- dialogue-systems
- git
- github
- in-memory-search
- information-retrieval
- machine-learning
- natural-language-processing
- offline-ai
- python
- python-standard-library
- ranking
- recommender-systems
- reviews
- search
- unittest
- visual-studio-code
Log in or sign up for Devpost to join the conversation.