hiring-radar: búsqueda híbrida que duplica el recall
La recuperación híbrida (semántica + keyword, fusionadas con RRF) lleva el recall@10 a 0.52, casi el doble que la semántica sola, con un gold set reproducible incluido en el repo.
TL;DR
- La recuperación híbrida (semántica + keyword, fusionadas con RRF) lleva el recall@10 a 0.52, casi el doble que la semántica sola (0.28).
- MRR 0.74 vs 0.28 semántica vs 0.16 exact, medido sobre un gold set incluido en el repo y reproducible.
- Más allá del search: un matcher con agente, con loop de tool-use acotado, memoria entre corridas y un servidor MCP.

Problema
Ningún search por sí solo encuentra el laburo.
Rankear los posteos de "Who is hiring" de HN es un problema de recall. La búsqueda semántica capta la intención pero se pierde términos exactos: nombres de empresas, versiones de frameworks, ubicaciones. La de keyword clava esos pero ignora el significado. Cualquiera de las dos sola deja la mitad de los posteos correctos fuera de la primera página.
Arquitectura
ingesta del thread HN → extracción de campos con LLM → chunk + embed local → pgvector HNSW + tsvector → fusión RRF → resultados rankeados
Browseá todo el corpus por exact, semantic o hybrid: el toggle de modo es la tesis en un solo control.

Decisiones clave
pgvector HNSW en lugar de exact scan
Elegí un índice HNSW aproximado sobre un scan coseno exacto. Trade-off: un poco de recall a cambio de una gran mejora de latencia, y ese recall lo recupera igual la pata de keyword del híbrido.
Fusión RRF en lugar de mezclar scores ponderados
Elegí reciprocal rank fusion en vez de tunear una mezcla ponderada de scores crudos. Trade-off: descarta la magnitud del score, pero es robusto y no necesita tuning por query entre dos escalas muy distintas.
Un gold set hecho a mano en lugar de labels sintéticos
Elegí etiquetar un gold set a mano en vez de generar los juicios de relevancia con un modelo. Trade-off, y una limitación real: es chico y de un solo anotador, así que los números son direccionales, no absolutos.
El híbrido no solo le ganó por poco al mejor método individual: les ganó a los dos en cada clase de query. Los dos retrievers fallan en inputs distintos, así que fusionarlos cubre los puntos ciegos del otro.
lo que demostró el eval
Resultados
Medido sobre un gold set hecho a mano (12 queries · 294 posteos), incluido junto al script de eval:
modo recall@10 MRR latencia prom
exact (keyword) 0.140 0.156 ~199 ms
semantic (vector) 0.276 0.283 ~351 ms
hybrid (RRF) 0.521 0.737 ~348 ms
El híbrido aproximadamente duplica el recall de la semántica y lleva el MRR a 0.74. RRF recupera los hits de términos literales (un "Rust" o "Kubernetes") que los vectores se pierden, manteniendo las coincidencias semánticas que el keyword no alcanza.
Más allá del search: un agente de matching
Un loop de tool-use acotado rankea los posteos contra tu perfil: llama a search_jobs, read_posting y recall_memory (recuerda veredictos de corridas anteriores), arma un shortlist y corta apenas toca un límite duro (24 pasos, 600k tokens o $1.00, chequeado antes de cada llamada al modelo). El texto no confiable de los posteos se spotlightea como dato, nunca como instrucciones. Las mismas tools se exponen como servidor MCP, invocables desde Claude.

Más difícil de lo esperado
Construir un eval en el que pudiera confiar. Con un gold set chico y de un solo anotador, cada métrica carga un intervalo de confianza lo bastante ancho como para engañar. Decir esa limitación con honestidad, y tratar los números como direccionales, importó más que perseguir un score más alto.