Freedam
IngenieríaParte 5 de 7 · 29 min de lecturaActualizado el

Medir una búsqueda que nadie creía rota

Una búsqueda puede perder una gran parte de sus coincidencias mientras las páginas cargan, las pruebas siguen en verde y los primeros resultados parecen razonables. Las personas no ven lo que se omitió, así que las señales habituales del producto son una prueba débil del recall.

Este es el cuarto artículo de una serie sobre cómo funciona la búsqueda dentro de freedam. El primero trató la recuperación: fabricar un documento buscable, fusionar BM25 con pgvector y garantizar el recall bajo topes. El segundo sacó el texto del problema y examinó el hash perceptual. El tercero lo devolvió y preguntó en qué idioma está el índice. Los tres citan cifras. Este trata de dónde salieron esas cifras.

Construimos un panel de sesenta casos de relevancia y lo ejecutamos a mano contra una réplica de la biblioteca de un cliente con 22.944 recursos. La primera ejecución seria encontró quince fallos estrictos (hard failures). En las ocho ejecuciones siguientes, el panel corrigió un diagnóstico verosímil, midió el costo de una corrección y dejó al descubierto un hueco en su propio conjunto de casos.

Sustituir «bastante bien» por una medición

Nadie había informado de ningún problema de búsqueda, y las personas encontraban recursos suficientes para que la biblioteca resultara bastante buena en el uso normal.

La primera ejecución seria del panel devolvió el código de salida 1: cuarenta y cinco casos superados, quince fallos estrictos, cero casos con error, en sesenta casos sobre una réplica de 22.944 recursos de un catálogo real de comercio minorista.

Ejecución 1 del panel de relevancia: sesenta casos por categoría, cuarenta y cinco que pasan y quince que fallan EJECUCIÓN 1, SESENTA CASOS, UN CORPUS REAL DE CLIENTE autocomplete color compatibility did_you_mean gtin material misspelling model negative part_number phrase scoped semantic suggestion IDENTIFICADORES EXACTOS: NIVEL DE PRODUCCIÓN La búsqueda por GTIN obtuvo recall@10 1,000, recall@50 1,000 y MRR 1,000. Los números de pieza, 0,833 en seis casos. Frases entre comillas, 1,000. Nada que corregir. Toda categoría donde la consulta es una cadena que el catálogo también guarda, literal, ya era correcta. TODO LO ESCRITO EN PALABRAS SE DEGRADÓ material recall@10 0,340, color 0,520, modelo 0,640, compatibilidad con dispositivos 0,537, cinco fallos estrictos. Los dos casos acotados a una colección fallaron. Los dos casos de autocompletado también. Verde pasa, rojo falla. 45 / 15 / 0 con error, en una búsqueda de la que nadie se había quejado.
La primera ejecución del panel, por categoría. La forma es el hallazgo: la recuperación era perfecta para las consultas que también son cadenas almacenadas y se desmoronaba con todo lo que un minorista escribiría de verdad.

Esto ocurre porque las personas suelen juzgar una búsqueda por sus primeros resultados. Si otros 178 recursos coincidentes eran accesibles es difícil de deducir desde la interfaz, y pocos usuarios revisan posiciones lo bastante profundas como para descubrir un problema de límite de candidatos. La calidad percibida dice por tanto muy poco del recall más allá de la cabeza del ranking.

Por ejemplo, el panel descubrió que galaxy a52 case devolvía doce resultados aunque 178 recursos tenían ese valor de dispositivo. La discrepancia se hizo visible en cuanto se escribió el conjunto esperado y se comparó con la ruta de producción.

Qué contiene un caso de relevancia útil

Un caso de relevancia combina una afirmación sobre el corpus con una expectativa sobre el comportamiento de la búsqueda, de modo que la ground truth (la verdad de referencia) tiene que sobrevivir a los cambios normales de la réplica.

Cada caso lleva un id, una categoría, la consulta tal como la escribiría un minorista, la ground truth y aserciones divididas en hard (estrictas) y soft (blandas). Las aserciones hard hacen fallar la ejecución; los objetivos soft se indican sin cambiar el veredicto, una limitación que se comenta en la sección sobre las pruebas de fallo del instrumento. El campo interesante es la ground truth y, en concreto, el hecho de que casi nunca es una lista de ids de recursos.

Anatomía de un caso de relevancia, con la ground truth resuelta desde la base de datos y no desde la búsqueda UN CASO id: compat-galaxya52-01 category: compatibility query: galaxy a52 case ground_truth: derived metadata_equals device = Galaxy A52/A52S hard find_all, min_results 1 soft first_relevant_in_top_k 10 EL SISTEMA EVALUADO el mismo punto de entrada que llama el buscador de la galería, paginado hasta agotarlo GROUND TRUTH se resuelve en la base de datos del tenant al ejecutar, nunca mediante la búsqueda EVALUADOR pass or hard_fail recall@10, recall@50 posición recíproca, notas LA ÚNICA REGLA La ground truth debe ser independiente de lo que se mide. 51 de los 63 casos tienen ground truth derivada, ninguno una lista de ids escrita a mano y doce afirman algo distinto de la pertenencia.
Los dos canales nunca se tocan. La ruta de búsqueda resuelve la consulta; el resolvedor resuelve la especificación directamente contra la base de datos del tenant mediante el constructor de consultas del propio modelo de recursos, de modo que las filas archivadas o eliminadas de forma lógica quedan fuera de ambos.

La mayor parte de la ground truth se deriva porque la réplica se sustituye periódicamente desde producción y los ids de los recursos no sobreviven a ese proceso. Un caso fijado a 178 identificadores daría error tras una nueva instantánea, con lo que el panel sería caro de mantener y menos probable de ejecutar.

Así que un caso derivado declara lo que significa, no lo que coincidió la última vez. Cuatro tipos de especificación cubren el panel: un campo de metadatos igual a un valor, uno que coincide con un prefijo o una subcadena, la pertenencia a una colección con nombre y una coincidencia de título a nivel de token. El resolvedor ejecuta la especificación contra la base de datos al comienzo de cada ejecución y entrega al evaluador un conjunto de ids nuevo.

El esquema también admite una ground truth curated como lista explícita de ids para los casos en que la relevancia es un juicio y no una propiedad de la base de datos. El panel actual no usa ninguna, porque esos casos requieren mantenimiento tras una nueva instantánea, y expresar una expectativa como especificación suele revelar una regla que se puede derivar.

Los nombres de colección no son únicos y las claves de metadatos lo son solo dentro de una clase de recurso, así que ambos resolvedores pueden coincidir legítimamente con varios registros. En lugar de elegir el primero y reducir en silencio el conjunto esperado, el panel marca el caso como error con el código de salida 2. Un error explícito es más fácil de corregir que un caso aprobado sobre una ground truth equivocada.

Doce casos no tienen ground truth de ids porque cubren sugerencias de «quizá quisiste decir», sugerencias, cadenas de autocompletado y consultas negativas. Como la utilidad es en parte subjetiva, cada caso de asistencia registra una justificación basada en el desplegable real capturado de la réplica y revisado por una persona.

Registrar las condiciones de cada ejecución

Dos cosas deciden si una cifra de relevancia significa algo, y ambas son propiedades del instrumento y no de la búsqueda: qué configuración la produjo y qué le hizo el tope de candidatos antes de que nadie la mirara.

Cada ejecución imprime una instantánea de la configuración antes de que se ejecute el primer caso: límites de candidatos, hybrid.rrf_k, pesos de fusión y si están activados los respaldos de erratas y de prefijos. El resultado de una errata depende de la corrección ortográfica, igual que el recall depende del límite de candidatos, así que registrar estos valores distingue un cambio de código de un cambio de configuración. Las ejecuciones 1 a 8 usaron todas hybrid.limit 1000, hybrid.rrf_k 60, pesos 1,0 y 1,0 y la corrección de erratas activada.

La instantánea mostró además prefix.enabled como null en el tenant usado en las tres primeras ejecuciones, lo que significa que no existía ninguna fila de configuración. El valor por defecto del código era true, así que la coincidencia por prefijo se ejecutaba igualmente, pero el informe dejaba claro que el comportamiento procedía de un valor por defecto y no de una decisión explícita del tenant. Ahora registramos el valor efectivo y el almacenado donde esa distinción importa.

El tope de candidatos también limita lo que un caso puede afirmar. En este tenant, una consulta con más de 1000 coincidencias verosímiles muestra 1000 por la ventana de candidatos, no porque el corpus contenga exactamente esa cantidad. Un conjunto de ground truth de 2189 recursos no puede exigir entonces la pertenencia completa por esa ruta; hacerlo crearía un fallo permanente que dificulta notar regresiones nuevas.

La protección contra la saturación: cómo find_all pasa a un recall muestreado con conjuntos de ground truth grandes ¿qué tamaño tiene la ground truth? umbral: 200 200 O MENOS: PERTENENCIA TOTAL todo recurso esperado debe aparecer en el conjunto de resultados, o el caso falla y nombra los ausentes MÁS DE 200: RECALL MUESTREADO muestra determinista de 50, ordenada por un hash de id de caso y recurso, debe sacar al menos 0,80 y el informe registra que hubo degradación LA SATURACIÓN SE ETIQUETA, NUNCA SE AFIRMA COMO CONTEO Si el resultado puede estar truncado, su total es una cota inferior. max_results se omite con una nota. AUN ASÍ, UNA AUSENCIA FALLA Un recurso con coincidencia directa que el tope dejó fuera se muestra como "not findable within candidate window" y falla igualmente. La muestra sale de un hash de id de caso e id de recurso, sin semilla global: el mismo caso saca siempre los mismos cincuenta.
Degradar la aserción es una concesión al tope. Excusar el fallo no lo es. La protección cambia cómo se formula la pregunta y se niega a cambiar la respuesta.

La saturación no excusa todas las coincidencias que faltan. El producto garantiza que un recurso cuyo título contiene la consulta siga siendo localizable sea cual sea el puesto o el tope, así que una coincidencia directa de título ausente sigue siendo un fallo. El informe lo etiqueta como not findable within candidate window, con lo que conserva tanto el veredicto como su causa probable.

Un detalle de muestreo merece copiarse. La muestra se extrae con un hash y no con un sorteo con semilla, de modo que el mismo caso saca los mismos cincuenta en cada ejecución, y un recall muestreado de 0,76 en la ejecución 1 frente a 0,76 en la ejecución 2 es una comparación real y no dos extracciones de la misma urna.

Agrupar los fallos por mecanismo

Los quince fallos abarcaban siete categorías del panel, pero se reducían a seis mecanismos de fondo.

Los quince fallos de la ejecución 1 ordenados en seis mecanismos y cuántos casos movió cada corrección QUINCE FALLOS, SEIS MECANISMOS Etiquetas de dispositivo con barra indexadas como un token galaxy a52 case, iphone 12 case, iphone x case 3 Acotado por colección tras el tope de candidatos, no antes black en una colección de 28 recursos dio 1; tan en una de 24 dio 10 2 Saturación real del tope en rangos grandes lynge 0,76, copenhagen 0,60, iphone 16 case 0,52 de recall muestreado 3 Vocabulario que el corpus no contiene vegan leather case dio 0; airtag holder halló 28 de 149 2 Corrección de erratas iphon, kickstnd 2 Basura en el desplegable SKU, nombres de archivo, copii 3 CORREGIR UNA CAUSA Un cambio de tokenización movió tres casos a la vez y no cambió nada más de lo medido. Un cambio de acotación movió dos y ningún otro caso se movió en ninguna métrica. CORREGIR UN SÍNTOMA Los cinco fallos de compatibilidad parecen un problema y son tres: tokenización, un tope real y una palabra ausente. Solo uno trata de límites de recuperación. Tres correcciones, un síntoma.
Ordenar los fallos por categoría indica dónde aparecen. Ordenarlos por mecanismo indica cuántas correcciones necesitas, que es un número distinto y mucho menor.

El primer mecanismo fue un buen ejemplo de por qué hay que inspeccionar directamente los términos del índice.

Los valores de compatibilidad de dispositivos en este catálogo tienen el aspecto de Galaxy A52/A52S y iPhone 12/12 Pro. El analizador inglés de PostgreSQL clasifica un valor unido por una barra como un único token de tipo file, así que Galaxy A52/A52S se indexa como el lexema a52/a52s y una búsqueda de a52 no puede coincidir con él. El texto estaba en el documento; una búsqueda de subcadena lo encontraba; el tsvector no lo contenía. En todo el corpus, 178 documentos contenían el texto bruto A52 y doce contenían el lexema, esos doce llegados por títulos separados por espacios.

El síntoma sugería al principio metadatos ausentes o un índice obsoleto, pero los metadatos estaban presentes y reconstruir produjo los mismos lexemas. Corregimos la normalización del vocabulario para que las etiquetas unidas por barra emitan sus segmentos junto con el valor original.

El diccionario de erratas usaba un tokenizador distinto que ya separaba por barras, así que informaba de a52 en 178 documentos mientras BM25 solo llegaba a doce. Esa discrepancia hacía del diccionario un sustituto poco fiable de los términos guardados en el índice BM25, por lo que el panel compara ahora contra la propia ruta de recuperación.

La ejecución 2 midió por separado la corrección de la tokenización y el cambio de acotación, en un diseño de cuatro puntos. galaxy a52 case pasó de 12 resultados a 178 sin ningún recurso imposible de encontrar, iphone 12 case de un recall muestreado de 0,06 a 1,00, y los dos casos acotados a una colección de 1 de 28 y 10 de 24 a la pertenencia completa. Entre el brazo sin acotación y el brazo con acotación, nada más en el panel se movió: ni un veredicto, ni un total, ni una cifra de recall, ni un MRR. La restricción de diseño de que las búsquedas sin acotar no pagan ningún costo adicional dejó de ser una afirmación y se convirtió en una medición.

Poner a prueba un diagnóstico verosímil

La corrección de la tokenización tuvo un efecto secundario. Al principio se publicó aplicando su regla a todo el documento normalizado y no solo a las etiquetas de vocabulario, de modo que separaba todos los tokens unidos por barra de cualquier origen: velocidades de obturación EXIF como 1/100, voltajes, URL, referencias a directivas de la UE como 2009/125/EC, conjunciones corrientes. Aproximadamente la mitad del corpus creció, y los documentos con una barra tenían de media 3758 caracteres frente a 917 los que no.

BM25 normaliza por la longitud del documento, así que todo documento que creció perdió un poco de puntuación en cada término que contenía y todo documento que no creció ganó posiciones gratis. Efectivamente, cinco casos empeoraron en recall@10 entre la ejecución 1 y la 2, dos de ellos de una puntuación perfecta a cero. El análisis se escribía solo: la expansión infló la longitud de los documentos, esa longitud hizo bajar la ground truth, y limitar la expansión a las etiquetas de vocabulario lo revertiría conservando la recuperación del recall.

Registramos esa predicción antes de la ejecución 3, limitamos la expansión, reconstruimos el corpus y medimos los casos afectados.

Cinco regresiones de recall atribuidas a la tokenización, cuatro de las cuales se movieron exactamente cero al corregirla RECALL@10, LOS CINCO CASOS QUE SE PREDIJO QUE LA REDUCCIÓN REVERTIRÍA caso ej. 1 ej. 3a ej. 3b model-greenland-01 0,70 0,00 0,00 misspelling-grenland-01 1,00 0,00 0,00 misspelling-iphon-01 0,70 0,00 0,00 color-clear-01 1,00 0,80 0,80 material-biodegradable 0,70 0,60 0,70 Cuatro de los cinco son idénticos hasta el decimal quince. Mismo recall@10 y @50, misma posición recíproca. Un caso se recuperó. LO QUE REALMENTE DECIDE LA CONSULTA GREENLAND puestos 1 a 11: documentos Product Video, de 155 a 493 caracteres puesto 12 en adelante: imágenes de producto, de 746 a 1280 caracteres el documento del límite no contiene ninguna barra LA ATRIBUCIÓN La expansión de barras infló la longitud. BM25 penaliza la longitud. Se degradó la ground truth. Coherente, específica, a nivel de mecanismo y escrita antes de que nadie la midiera. LA MEDICIÓN 2077 de los 2189 documentos de ground truth sí tenían una barra y estaban inflados. Quitar la inflación movió el ranking en cero posiciones. La causa: la longitud del documento.
La atribución no fue descuidada. Nombró un mecanismo real, en el subsistema correcto, y se equivocó cuatro veces de cinco. Decenas de caracteres añadidos a un documento de cientos son un error de redondeo frente a una proporción de longitud de tres a ocho veces entre el documento de un clip de video y el de una imagen de producto.

La limitación hizo exactamente lo que se había diseñado para hacer a nivel de corpus. El lexema a52 seguía coincidiendo con 178 documentos; el lexema 2009, que se filtraba desde 2009/125/EC, coincidía con cero. Y cuatro de las cinco reversiones previstas no se movieron ni un pelo.

El mecanismo real se hizo visible cuando alguien dejó de mirar tokens y empezó a mirar longitudes. La consulta greenland la ganaban once documentos Product Video de 155 a 493 caracteres, cada uno básicamente el título repetido según el peso de su campo más un poco de metadatos de códec. La primera imagen de producto, que es lo que forma la ground truth del caso, llegó al puesto 12 con 751 caracteres frente a un promedio de 1280 en la ground truth. Una proporción de longitud de tres a ocho veces decide un orden por sí sola, y el documento del límite no contenía ninguna barra, así que ninguna de las dos versiones de la expansión lo había tocado nunca.

El diagnóstico era coherente y lo bastante específico como para sobrevivir a una revisión, pero la predicción por caso lo hizo comprobable. La medición mostró que cuatro de las cinco reversiones esperadas no se produjeron, lo que reorientó la investigación hacia la longitud del documento y no hacia la expansión de tokens.

La limitación se publicó de todos modos, porque seguía siendo el cambio correcto. También costó un caso. compat-iphonexxs-01, la consulta iphone x case, pasó de un recall muestreado de 1,00 a 0,74 y de aprobado a fallo estricto, porque su conjunto de resultados se satura en el tope en todas las ejecuciones y la expansión demasiado amplia había alargado a sus competidores justo lo suficiente para admitir más recursos de iPhone X y Xs. Si quitas la contaminación, los competidores se acortan, puntúan mejor y vuelven a ocupar el espacio. El panel pasó de 48 casos superados a 47, y la contrapartida quedó anotada junto a la corrección.

El ranking dentro de una ventana con tope es casi un juego de suma cero, así que una mejora puede desplazar a otro resultado. Cuando un cambio solo muestra mejoras, comprobamos si el conjunto de casos cubre lo que bajó de posición. Las regresiones conocidas permanecen en el informe con su justificación para distinguirlas de los fallos nuevos.

El hábito útil es registrar predicciones por caso antes de la ejecución, incluidos los casos que se espera que no se muevan. La ejecución 2 acertó diez predicciones, mientras que la 3 acertó una de cinco; ambas fueron informativas porque los controles negativos revelaron si el mecanismo propuesto era correcto.

Un panel solo ve lo que cubren sus casos

La ejecución 4 fue un canario para otra función: la garantía de localización por título, que promete que un recurso cuyo título contiene la consulta se encuentra con esa consulta sea cual sea el puesto o el tope. Brazo de control con la garantía desactivada, brazo de tratamiento con ella activada, mismo corpus, misma compilación, misma configuración. Una advertencia acompaña desde aquí a cada cifra: la ejecución 4 midió una réplica nueva de producción, que a propósito no se ha vuelto a indexar desde que se publicó la corrección de la tokenización, así que su corpus es el anterior a la corrección. Ambos brazos lo comparten, que es todo lo que necesita un A/B, pero los veredictos de la ejecución 4 no son comparables caso por caso con los de la ejecución 3 aunque los totales coincidan.

El resultado fue plano en veredictos, 47 casos superados en ambos brazos, e inequívoco en métricas. El recall@10 medio bajó de 0,6667 a 0,6333, el recall@50 medio de 0,7446 a 0,7338, y tres casos empeoraron. Ningún caso mejoró en ninguna métrica de relevancia.

Por sí solo, el resultado sugería que la función reducía la relevancia sin aportar valor. Sin embargo, ninguno de los sesenta casos preguntaba si un recurso más allá del tope seguía siendo localizable por su título, que era el contrato de la función. Los casos existentes usaban ground truth derivada de metadatos, así que el panel podía medir el costo pero no el beneficio previsto.

La ejecución 4 identificó por tanto un hueco de cobertura, y la ejecución 5 añadió tres casos de localización por título.

Un panel ciego y uno que ve: la misma función medida antes y después de añadir los casos de título LA MISMA FUNCIÓN, EL MISMO CORPUS, DOS INSTRUMENTOS DISTINTOS EJEC. 4: SESENTA CASOS, SIN CASO DE TÍTULO veredictos 47 / 13 con la garantía desactivada veredictos 47 / 13 con la garantía activada 0 casos mejores, 3 casos peores Se lee así: la función cuesta relevancia y no aporta nada. EJECUCIÓN 5: SESENTA Y TRES CASOS veredictos 48 / 15 con la garantía desactivada veredictos 50 / 13 con la garantía activada 2 fallos estrictos recuperados, 0 introducidos Los mismos tres casos siguen costando recall@10. Ahora hay algo que lo compensa. LOS TRES CASOS Y POR QUÉ UNO ES UN CONTROL title-mainimage-01 banda de 3339 títulos, muy por encima del tope de 1000 candidatos recall muestreado de 0,32 a 1,00 title-product-01 banda de 2156 frente a 13.516 documentos competidores recall muestreado de 0,30 a 1,00 title-lifestyle...-01 banda de 188, bajo el tope y bajo el umbral de muestreo pasa en AMBOS brazos. El control.
Dos casos que la función debe corregir y uno que debe dejar en paz. Sin el tercero, un resultado limpio mostraría que los casos se escribieron para la respuesta, no que la garantía funciona.

El caso de control es el que parece relleno. Su banda de títulos es de 188 recursos: por debajo del tope de 1000 candidatos y por debajo del umbral de 200 recursos en el que las aserciones de pertenencia pasan a muestreo. Nunca se recorta nada, así que pasa con la garantía desactivada y con ella activada, idéntico en ambos brazos.

Un caso usa una banda de títulos por debajo del tope de candidatos y debe pasar con la función tanto desactivada como activada. Este control distingue la garantía prevista de un cambio más amplio que reordena resultados ya accesibles sin ella. Siguió en verde y sin cambios mientras los dos casos que superan el tope medían el comportamiento nuevo.

La adición permitió además al panel ver algo que los sesenta casos nunca podrían. title-product-01 devolvió 2587 resultados frente a una ground truth de 2156, es decir, 431 coincidencias que no eran de título sobrevivieron junto a una banda de más del doble del tamaño del tope. Una versión anterior de la garantía había numerado la banda y el grupo ordenado juntos, así que la banda ocupaba todas las posiciones bajo el tope, volvía a admitirse por su propia cláusula y borraba en silencio las coincidencias ordenadas que desplazaba. Esos 431 recursos son esa corrección, visibles en un corpus real.

El panel mostró también que el primer intento de rebajar las filas de la banda de títulos no tuvo ningún efecto: la ejecución 6 fue idéntica byte a byte a la 5b. El orden se había cambiado dentro de una subconsulta, pero los dos consumidores que determinan el orden visible para el usuario no lo conservaban. Aplicar la rebaja en ambos consumidores eliminó las regresiones medidas en los sesenta y tres casos, mientras los dos casos de título por encima del tope seguían pasando.

La reproducción del registro de consultas mide el cambio, no la corrección

Todo lo anterior procede de un único instrumento con un punto ciego fijo. Sus casos sondean modos de fallo que ya sospechábamos y su ground truth se deriva de metadatos, así que responde con precisión a «¿se puede encontrar lo correcto?» pero no puede responder a «¿lo notaría un usuario real?». El experimento de localización por título descrito arriba mostró por qué esa distinción importa.

El segundo instrumento reproduce consultas de producción sin ground truth. Compara dos brazos sobre el mismo corpus e informa de lo que se movió, así que mide el cambio y no la corrección: un top diez idéntico no ha cambiado pero tampoco está verificado, y un conjunto de resultados mayor contiene más recursos accesibles sin demostrar que sean relevantes.

El panel curado y la reproducción del registro responden preguntas distintas y ninguno sustituye al otro EL PANEL CURADO 63 casos, 15 categorías, ground truth derivada, resuelta desde la base de datos Responde: ¿se encuentra lo correcto? Mide recall@10, recall@50, MRR y la pertenencia estricta frente a un conjunto conocido. No responde: ¿lo notaría alguien? Sus consultas las escribimos nosotros para sondear mecanismos que ya sospechábamos. LA REPRODUCCIÓN DEL REGISTRO DE CONSULTAS 55 búsquedas reales por palabra clave, diez semanas del registro de un tenant, sin ground truth Responde: ¿algo empeoró? Compara los diez primeros y el total de cada consulta entre dos brazos. No responde: ¿algo de esto es correcto? Un top diez idéntico no ha cambiado, pero eso no equivale a verificado. LO QUE MIDIÓ LA REPRODUCCIÓN, GARANTÍA DE TÍTULO DESACTIVADA FRENTE A ACTIVADA 55 / 55 top diez idéntico 5 totales con más resultados 0 totales con menos resultados 2 sin resultados, antes y después
Ningún instrumento incluye al otro. El panel sabe cuál es la respuesta correcta y no sabe qué preguntó nadie; la reproducción sabe qué preguntó todo el mundo y no tiene ni idea de cuál es la respuesta correcta.

La fuente contenía 140 búsquedas que abarcaban 99 términos distintos a lo largo de diez semanas en un tenant de producción. Extrajimos solo el término, el recuento de apariciones, el tipo de búsqueda y el número de resultados; no incluimos identificadores de usuario ni de sesión porque la comparación no los necesitaba.

De los 99 términos distintos, 55 eran búsquedas por palabra clave y 44 eran árboles de filtros avanzados serializados. Excluimos los árboles porque los que no tienen una hoja de texto completo nunca llegan a la ruta híbrida y por tanto no podían cambiar en esta comparación. Las búsquedas restantes incluían SKU, nombres de archivo, frases de marca, descripciones, variantes de mayúsculas, una errata, un término en danés y un pegado con 79 SKU.

El top diez permaneció idéntico en las 55 búsquedas. Cinco totales crecieron, todos en consultas que ya estaban en el tope de 1000 candidatos, así que el cambio solo afectó a la accesibilidad más allá del tope: greenland pasó de 1000 a 1014, iphone a 1010, y phone y blue products a 1005. Ninguna consulta perdió resultados y las dos consultas vacías siguieron vacías.

Esto es evidencia sobre el alcance del cambio, no sobre su calidad. El panel curado se concentra deliberadamente en mecanismos sensibles, mientras que la reproducción refleja las consultas que los clientes hicieron por casualidad; los dos instrumentos responden a preguntas distintas.

Sí encontró una cosa que el panel no podía. Con la banda incorporada, el límite de candidatos indicado pasó a ser nulo en 52 de las 55 consultas mientras el indicador de truncamiento seguía activo en todas, de modo que la interfaz pasa de «puede estar truncado, límite 1000» a «puede estar truncado, profundidad no describible con un solo número». Eso es honesto, y es una decisión de texto que conviene tomar antes del despliegue y no descubrir después.

La primera pasada de latencia sugirió erróneamente que la banda de títulos hacía la búsqueda más rápida, porque los brazos se ejecutaron en secuencia y el segundo heredó cachés calientes. Al comparar ejecuciones calientes con ejecuciones calientes quedaron unos cinco milisegundos de diferencia media, con las consultas individuales más lentas entre ocho y diez milisegundos peor. Ambos brazos necesitan por tanto las mismas condiciones de caché.

El límite es la muestra. Cincuenta y cinco términos distintos de un tenant durante diez semanas, sesgados hacia búsquedas de SKU, son una ventana pequeña sobre exactamente la forma de consulta menos probable de verse afectada por lo que se prueba.

Comprobar que las comprobaciones pueden fallar

El propio instrumento también necesitaba pruebas de fallo. Encontramos cuatro comprobaciones que aparecían en la salida de las pruebas o de la monitorización pero producían la misma señal cuando el comportamiento que vigilaban estaba roto.

Un código de salida calculado que nada consumía. El ejecutor devolvía con cuidado 0 para éxito, 1 para fallos estrictos y 2 para errores de configuración. El trait que lo invocaba descartaba el entero y reaccionaba solo a una excepción lanzada, y el ejecutor estaba diseñado a propósito para no lanzar nunca, así que toda invocación real terminaba con 0 sin importar cuántos casos fallaran. Las pruebas de la propia suite pasaban, porque el entorno de pruebas toma una rama anterior que sí propaga el valor devuelto. La única ruta ejercitada era la única correcta.

Métricas que informan pero no pueden condicionar. Los objetivos soft emiten una nota que dice que el primer resultado relevante llegó en el puesto 17 frente a un objetivo de 10, y las notas no mueven un código de salida. Tras el cambio en el constructor de documentos, cinco casos perdieron relevancia en el top diez, dos de ellos de perfecta a cero, y cuatro seguían indicando pass.

Un monitor que indicaba silencio mientras moría el trabajo que vigilaba, porque filtraba solo marcadores de progreso y un fallo no produce ningún marcador. Una prueba de desempate que seguía en verde después de eliminar el desempate, porque la aserción se cumplía por razones ajenas al comportamiento que nombraba.

En cada caso existía una señal de fallo, pero la capa siguiente no la consumía según el mismo contrato.

Para cada barrera nos preguntamos ahora qué emitiría si el comportamiento vigilado se rompiera, y luego introducimos un fallo controlado y confirmamos que el resultado se pone en rojo. Los dos defectos hallados con este método fueron más fáciles de localizar que los dos descubiertos leyendo el código.

El defecto del código de salida habría hecho que las ejecuciones completas sobre la réplica indicaran éxito pese a los fallos estrictos. Los objetivos soft siguen siendo de diagnóstico y no condicionan, así que el informe ahora los etiqueta con claridad; de lo contrario, una métrica mostrada se confunde con facilidad con una garantía aplicada.

Lo que le diríamos a cualquiera que construya esto

La versión transferible, sin nuestros detalles.

  • Da por hecho que te equivocas con tu propia búsqueda hasta que un instrumento diga lo contrario. La calidad percibida no tiene resolución por debajo de los tres primeros resultados, así que un sistema puede perder la mayor parte de un conjunto de resultados y seguir pareciendo bien a todos los que lo usan. Quince fallos en sesenta casos y ni un solo ticket de soporte.
  • Expresa la ground truth como una especificación, no como una lista de ids. Un panel que muere cuando se sustituye el corpus deja de ejecutarse, y una suite que nadie ejecuta se borra en menos de un mes. Los casos curados son futuros eventos de mantenimiento; mantenlos cerca de cero.
  • Haz que el informe indique la configuración que midió e imprime los valores almacenados y no los efectivos. Una cifra de recall sin su tope de candidatos es un rumor, y la diferencia entre almacenado y efectivo te dice si alguien decidió de verdad.
  • Degrada la aserción bajo un tope, nunca el veredicto. Muestrea en lugar de afirmar la pertenencia completa, pero mantén un fallo estricto cuando falta una coincidencia directa, o el instrumento se queda ciego justo para la clase de defecto para la que se construyó.
  • Ordena los fallos por mecanismo antes de corregir ninguno. Cinco fallos en una categoría eran tres errores que necesitaban tres correcciones, y solo uno trataba de límites de recuperación. Corregir una causa mueve varios casos a la vez; corregir un caso mueve uno y rompe otro.
  • Escribe la predicción antes de la ejecución, caso por caso, incluido lo que no debería moverse, y espera una factura. Las predicciones negativas exponen un diagnóstico erróneo. El ranking es casi de suma cero dentro de un tope, así que un cambio que solo muestra mejoras suele significar que nada en tu conjunto de casos apunta a lo que desplazaste.
  • Comprueba si tu instrumento puede ver aquello por lo que le preguntas e incluye un control que deba pasar con la función desactivada. Cero mejores y tres peores fue una medición verdadera y una conclusión falsa, porque ni un solo caso ejercitaba el contrato probado. Un conjunto de casos en el que todo solo pasa con la función activada demuestra que los casos se escribieron para la respuesta.
  • Ejecuta dos instrumentos con puntos ciegos distintos y pregunta de cada barrera qué emitiría si lo que vigila se rompiera. Un panel curado conoce la respuesta correcta y no lo que preguntó nadie; un registro de consultas conoce lo que preguntó todo el mundo y no la respuesta correcta. Después rompe tus comprobaciones a propósito y confirma el rojo, porque leer solo las encuentra si ya sospechabas de ellas.

Dónde vive esto en el producto

Nada de esto es una función. Es el instrumento que decide qué funciones se publican, y su resultado solo es visible en el comportamiento de las búsquedas normales: la galería, la API REST, el SDK de TypeScript y cualquier agente de IA conectado por MCP. Las correcciones que arbitró son las descritas en el primer artículo: las garantías de recall bajo topes, la selección de candidatos y el informe de completitud que permite a un resultado truncado decirlo. El mismo tema a nivel de producto es búsqueda y descubrimiento, y el hecho de que todo se ejecute dentro de una sola instancia de PostgreSQL es lo que lo hace reproducible en una réplica, y también lo que hace práctico autoalojar freedam.

Los límites merecen decirse con tanta claridad como los resultados, porque un instrumento que se vende por encima de lo que es es exactamente el fallo del que trata este artículo. El panel se ejecuta a mano y a propósito no está en la integración continua: necesita una réplica de un corpus real de cliente, un sidecar de embeddings y unos noventa segundos por ejecución, y sus cifras no significan nada frente a ningún otro corpus. Sus consultas están solo en inglés, porque el catálogo para el que se construyó está en inglés, así que no mide nada de el comportamiento multilingüe del artículo anterior. Sus casos resuelven su ground truth de nuevo en cada ejecución y sobreviven a una nueva instantánea, pero un corpus cambiado sigue cambiando las cifras: las ejecuciones 4 a 8 midieron una réplica nueva de producción, sin reindexar desde la corrección de la tokenización, así que no son comparables caso por caso con la ejecución 3 aunque los totales coincidan.

A continuación en esta serie: caras y búsqueda de personas, donde los problemas interesantes dejan de tratar de la calidad de la recuperación y pasan a tratar de quién puede afirmar que dos caras son una misma persona.

Para desarrolladores

Sigue leyendo