Shortlisting
Three-Stage Candidate Shortlisting
Retrieve-then-rerank paradigm: cheap vector search builds a 2K pool, expensive cross-encoding narrows to K, and BM25 lexically reorders. Cheapest operation runs first.
Pipeline Stages
| Stage | Model | Pool | Weight |
|---|---|---|---|
| Stage 1: HNSW Vector Retrieval | all-mpnet-base-v2 ONNX INT8 | All → 2K | 0.20 |
| Stage 2: Cross-Encoder Re-ranking | ms-marco-MiniLM-L12-v2 ONNX INT8 | 2K → K | 0.65 |
| Stage 3: BM25 Lexical Scoring | BM25 (raw_full_text) | K → K | 0.15 |
Stage Details
Stage 1: HNSW Vector Retrieval
Four Qdrant gRPC searches with has_id() filter. COSINE distance, m=16, ef_construct=200, ef=128. Recall@10 = 0.93.
Stage 2: Cross-Encoder Re-ranking
Batched [4 × max_len] input tensor. One session.run() processes all four fields. ~3x faster vs sequential. 134MB → 34MB INT8.
Stage 3: BM25 Lexical Scoring
k₁=1.2, b=0.75. Recovers exact matches for version numbers, cert codes, tool names that embeddings smooth over.
Score Blend
score(u) = 0.65 · c_n(u) + 0.20 · v_n(u) + 0.15 · b_n(u)All scores min-max normalised within top-K pool. Neutral 0.5 when all candidates are tied.
Retrieval Quality
| Metric | Whole-Doc | Section-Wise | Gain |
|---|---|---|---|
| Precision@5 | 0.72 | 0.81 | +12.5% |
| Precision@10 | 0.68 | 0.76 | +11.4% |
| Recall@10 | 0.74 | 0.83 | +12.2% |
| NDCG@10 | 0.71 | 0.79 | +11.3% |
| MRR | 0.76 | 0.84 | +10.5% |
Internal benchmark on 500 candidates, 50 job descriptions.