Implementar búsqueda vectorial y RAG con PostgreSQL y pgvector
Volver a la ruta AI-200
AI-200Capítulo 13

Preparación para la Certificación Microsoft AI-200

Implementar búsqueda vectorial y RAG con PostgreSQL y pgvector

Almacena embeddings en Base de Datos de Azure para PostgreSQL, elige métricas de distancia e índices ANN, mantén vectores que evolucionan, crea recuperación semántica e híbrida y fundamenta respuestas RAG con citas rastreables.

Tiempo de estudio sugerido: 130 minutos • Nivel intermedio • Reescritura original completa con versión resumida de cada tema, evaluación comentada y laboratorio guiado de búsqueda vectorial

Escudo neón Microsoft Certified AI-200 con vectores PostgreSQL, índices pgvector, recuperación semántica y canalización RAG

1. Convertir un PostgreSQL existente en recuperador de IA

Imagina un sistema jurídico que ya conserva documentales y clientes en . Los abogados necesitan localizar casos, cláusulas y precedentes por su significado aunque la pregunta y la fuente usen vocabulario distinto. Guardar embeddings junto a los datos relacionales evita otro almacén vectorial y su sincronización, sin renunciar a nuevas ingestas diarias ni a consultas de baja latencia a escala.

  • Almacenar y consultar embeddings con pgvector.
  • Elegir una métrica y ejecutar búsquedas de similitud.
  • Seleccionar y ajustar índices de vecinos más cercanos aproximados.
  • Actualizar vectores y migrar modelos de embedding con seguridad.
  • Crear recuperación semántica, híbrida y RAG con citas y calidad medible.

Resumen del tema

pgvector incorpora recuperación semántica al PostgreSQL existente y reduce componentes y sincronizaciones adicionales.

2. Habilitar pgvector y diseñar esquemas vectoriales

En el servidor flexible de , agrega primero la extensión a la lista permitida del servidor, comprueba SHOW .extensions y créala en cada base que la necesite. La comunidad dice pgvector, pero el binario y el nombre SQL son vector. Normalmente se requieren permisos de administrador o pertenecer a azure_pg_admin.

CREATE EXTENSION IF NOT EXISTS vector;

CREATE TABLE knowledge_chunks (
  id BIGSERIAL PRIMARY KEY,
  source_id BIGINT NOT NULL,
  chunk_no INTEGER NOT NULL,
  title TEXT NOT NULL,
  content TEXT NOT NULL,
  category TEXT,
  token_count INTEGER,
  embedding vector(1536),
  embedding_stale BOOLEAN NOT NULL DEFAULT false,
  updated_at TIMESTAMPTZ NOT NULL DEFAULT now(),
  UNIQUE (source_id, chunk_no)
);

La dimensión de vector(n) debe coincidir exactamente con la salida del modelo. Vectores de 384, 1536 y 3072 dimensiones no comparten una columna restringida salvo transformación. Conserva junto al vector los que filtran y presentan resultados; separa textos enormes solo cuando ahorrar transferencia compense el JOIN.

Usa columnas distintas para embeddings de título y cuerpo o para modelos diferentes. INSERT, INSERT múltiple y COPY cargan vectores; cualquier cambio semántico del contenido exige regenerar su embedding.

El contenido se convierte en embedding, se almacena con metadatos PostgreSQL y se compara con el vector de consulta mediante distancia L2, coseno o producto interno.
La dimensión del esquema, la salida del modelo y el operador deben describir el mismo espacio vectorial.

Resumen del tema

Permite y crea vector por base de datos y vincula cada columna con la dimensión y finalidad de un único espacio de embeddings.

3. Elegir vector, halfvec o sparsevec

Tipos de almacenamiento de pgvector.
TipoRepresentaciónCuándo encaja
vectorFlotantes de 32 bits; unos 6 KB para 1536 dimensiones.Predeterminado para embeddings densos y equilibrio entre precisión y espacio.
halfvecFlotantes de 16 bits; cerca de la mitad del almacenamiento.Tras demostrar que la menor precisión conserva la relevancia.
sparsevecSolo valores no nulos y sus posiciones.Salidas de alta dimensión realmente dispersas.

Empieza con vector para embeddings densos. Evalúa halfvec con métricas antes de cambiarlo. HNSW sobre sparsevec admite como máximo 1000 elementos no nulos; si se supera, reduce dimensiones o elige otra estrategia.

Resumen del tema

Usa vector como opción inicial, halfvec tras validar calidad y sparsevec para representaciones genuinamente dispersas.

4. Alinear operadores de distancia con el modelo

-- Euclidean/L2: smaller means nearer
SELECT id, title, embedding <-> $1::vector AS distance
FROM knowledge_chunks ORDER BY embedding <-> $1::vector LIMIT 8;

-- Cosine distance: common for text embeddings
SELECT id, title, embedding <=> $1::vector AS distance
FROM knowledge_chunks ORDER BY embedding <=> $1::vector LIMIT 8;

-- Negative inner product: smaller means a larger dot product
SELECT id, title, embedding <#> $1::vector AS distance
FROM knowledge_chunks ORDER BY embedding <#> $1::vector LIMIT 8;
Semántica de distancias.
OperadorMétricaInterpretación
<->L2 / euclidianaDistancia recta; puede importar la magnitud.
<=>Distancia cosenoÁngulo entre vectores; común en texto semántico.
<#>Producto interno negativoProducto escalar negado para ordenar primero los valores menores.

En los tres casos, menor implica mayor cercanía. Sigue la recomendación del modelo. Los vectores normalizados pueden aprovechar producto interno, mientras que coseno es habitual para texto. Envía el vector como parámetro y no lo concatenes en SQL.

Resumen del tema

La métrica debe reflejar la geometría del modelo; pgvector ordena las tres distancias de menor a más similar.

5. Comprender búsqueda exacta, ANN, exhaustividad y DiskANN

Sin índice, PostgreSQL compara la consulta con cada fila y encuentra vecinos exactos. La exhaustividad es perfecta, pero el coste crece linealmente; suele ser razonable por debajo de unas diez mil filas y caro con millones.

ANN examina un subconjunto estructurado. La exhaustividad o recall expresa qué fracción de los vecinos exactos aparece también; muchos sistemas aceptan 95–99% a cambio de milisegundos. admite DiskANN mediante pg_diskann, con alta exhaustividad y rendimiento, escalado orientado a disco, compilación rápida, cuantificación de producto y dimensiones más altas que HNSW/IVFFlat en versiones recientes.

Resumen del tema

La búsqueda exacta maximiza exhaustividad; ANN sacrifica una parte mínima para reducir mucho la latencia y DiskANN añade una opción de gran escala.

6. Crear y ajustar IVFFlat

IVFFlat aplica k-means al crear el índice y reparte vectores en lists alrededor de centroides. La consulta localiza los centroides cercanos y examina la cantidad indicada por probes; el trabajo aproximado es (filas / lists) × probes.

  • Carga datos representativos antes del índice; una tabla vacía no produce clústeres útiles.
  • Hasta aproximadamente un millón de filas, comienza con filas / 1000 para lists; por encima, aproxima la raíz cuadrada.
  • Empieza probes cerca de sqrt(lists); aumentarlo mejora exhaustividad y eleva latencia.
  • Reconstruye si una carga grande o de otro dominio vuelve poco representativos los clústeres.

Resumen del tema

IVFFlat consume menos memoria y se crea rápido, pero depende de datos representativos y del equilibrio lists/probes.

7. Crear y ajustar HNSW

HNSW construye un grafo de proximidad multicapa. La consulta empieza en una capa superior dispersa, sigue conexiones prometedoras y desciende hasta candidatos cercanos. A diferencia de IVFFlat, admite una tabla vacía y crece con inserciones.

CREATE INDEX chunks_embedding_hnsw_idx
ON knowledge_chunks USING hnsw (embedding vector_cosine_ops)
WITH (m = 16, ef_construction = 96);

SET LOCAL hnsw.ef_search = 100;

-- Alternative after representative data exists
CREATE INDEX chunks_embedding_ivfflat_idx
ON knowledge_chunks USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);

SET LOCAL ivfflat.probes = 10;

m limita conexiones por nodo; aumentarlo puede elevar exhaustividad, memoria y tiempo de creación. ef_construction amplía candidatos durante la compilación y mejora el grafo a cambio de tiempo. ef_search amplía la exploración en consulta; súbelo solo si la exhaustividad medida lo exige.

Resumen del tema

HNSW suele ofrecer mejor relación velocidad/exhaustividad a cambio de memoria, creación lenta e inserciones moderadamente costosas.

8. Elegir el índice y comprobar su uso

Selección de índice ANN.
FactorIVFFlatHNSW
Velocidad/exhaustividadBuenaNormalmente mejor
CreaciónMás rápidaMás lenta
MemoriaMenorMayor
Tabla vacíaNo resulta útilCompatible
InsercionesRápidasModeradas

Elige HNSW cuando dominen baja latencia y alta exhaustividad y exista memoria. Elige IVFFlat cuando importen más compilación, memoria o recargas por lotes. La clase debe coincidir: vector_l2_ops con <->, vector_cosine_ops con <=> y vector_ip_ops con <#>. Si no, el índice no satisface la ordenación.

EXPLAIN (ANALYZE, VERBOSE, BUFFERS)
SELECT id, title
FROM knowledge_chunks
ORDER BY embedding <=> $1::vector
LIMIT 10;

En tablas grandes con ORDER BY de distancia y LIMIT, busca Index Scan. Seq Scan puede ser correcto en tablas pequeñas. Comprueba validez, estadísticas y LIMIT.

Búsqueda exacta, IVFFlat, HNSW y DiskANN comparados por exhaustividad, latencia, memoria, creación y mantenimiento.
La selección es una decisión medible que puede revisarse.

Resumen del tema

Elige con datos de carga, alinea clase y operador y confirma el plan real en lugar de suponer que se usa el índice.

9. Supervisar, reconstruir y recuperar espacio

pg_stat_user_indexes muestra exploraciones y tamaño; cero usos puede indicar operador incompatible o decisión del planificador. Sigue EXPLAIN ANALYZE y exhaustividad en consultas representativas. pg_stat_progress_create_index presenta fases y avance.

Latencia creciente sin igual aumento de volumen, menor calidad o un 20–30% de datos nuevos de otro dominio justifican reconstruir. Sin interrupción, crea sustituto con CREATE INDEX CONCURRENTLY, valida, quita el anterior y cambia el nombre. REINDEX es más sencillo si puede detenerse la escritura.

Estima vector como dimensiones × 4 bytes × filas, más cerca de 1,5–2 veces para HNSW o 1–1,5 para IVFFlat. MVCC deja tuplas muertas: VACUUM reutiliza espacio y VACUUM FULL devuelve más al disco, pero bloquea. Tablas muy actualizadas pueden requerir umbrales de autovacuum menores.

Resumen del tema

Estadísticas, planes, exhaustividad, sustitución simultánea y vacuum mantienen saludables las estructuras.

10. Actualizar embeddings sin bloquear contenido

Un embedding queda obsoleto cuando cambia el significado de su fuente. Para cambios ocasionales, contenido y vector pueden confirmarse juntos, aunque eso acopla escritura y servicio de embeddings. Con muchos cambios, marca filas pendientes, procesa lotes asíncronos, genera vectores por grupos y limpia la marca solo tras guardar.

-- Content writes stay fast and mark the vector as stale
UPDATE knowledge_chunks
SET content = $1, embedding_stale = true, updated_at = now()
WHERE id = $2;

-- A worker claims a bounded batch without colliding with peers
SELECT id, content
FROM knowledge_chunks
WHERE embedding_stale
ORDER BY updated_at
FOR UPDATE SKIP LOCKED
LIMIT 250;

-- The worker writes the regenerated vector
UPDATE knowledge_chunks
SET embedding = $1::vector, embedding_stale = false
WHERE id = $2;

Una regeneración completa programada corrige omisiones y homogeneiza cambios. Prioriza filas antiguas, respeta cuotas y usa transacciones limitadas—a menudo 1000–5000 filas en backfills grandes—mientras supervisas réplica, bloqueos, WAL e índices.

Resumen del tema

Usa actualización atómica para pocos cambios y marcas con workers por lotes para corpus dinámicos.

11. Migrar modelos con columnas paralelas

Vectores de modelos o dimensiones distintos no comparten espacio. Sobrescribir la columna activa mezcla semánticas. Añade una segunda columna, crea su índice, rellena por lotes, compara ambas versiones con evaluación etiquetada, cambia lecturas atómicamente y conserva la ruta anterior hasta descartar .

ALTER TABLE knowledge_chunks ADD COLUMN embedding_v2 vector(3072);

CREATE INDEX CONCURRENTLY chunks_embedding_v2_idx
ON knowledge_chunks USING hnsw (embedding_v2 vector_cosine_ops);

-- Backfill in bounded batches, compare recall and latency, then switch reads.
-- Keep the original column until the new model passes acceptance tests.

Calcula el plazo con filas, rendimiento del lote, cuotas de y reintentos. Dos columnas y dos índices requieren almacenamiento temporal adicional.

Resumen del tema

Las columnas paralelas evitan espacios mezclados, permiten comparar calidad y conservan reversión.

12. Combinar similitud, y umbrales

SELECT id, title, content, category,
       embedding <=> $1::vector AS distance
FROM knowledge_chunks
WHERE category = $2
  AND embedding <=> $1::vector < $3
ORDER BY embedding <=> $1::vector
LIMIT $4;

Índices B-tree en filtros frecuentes, incluso compuestos, reducen candidatos. Los predicados selectivos pueden favorecer índices relacionales; los amplios, el vectorial. ANALYZE y EXPLAIN ANALYZE muestran la decisión.

LIMIT devuelve N filas aunque sean irrelevantes. Un umbral fija calidad mínima y puede devolver cero. Dedúcelo de pares relevantes e irrelevantes etiquetados. Recupera título, contenido, de cita y distancia en un viaje, sin transferir texto completo si basta un resumen.

Resumen del tema

Los acotan alcance, los umbrales exigen relevancia mínima y los planes explican la combinación de accesos.

13. Resolver consultas multivectoriales e híbridas

Promedia ejemplos cuando representan un único concepto. Conserva vectores separados para requisitos independientes y combina la evidencia de cada recuperación.

La semántica puede infravalorar nombres, códigos o jerga exacta. La búsqueda de texto completo aporta clasificación léxica y un GIN acelera tsvector. La recuperación híbrida une candidatos. La fusión de rango recíproco (RRF) combina posiciones sin tratar distancia vectorial y puntuación textual como una misma escala.

WITH semantic AS (
  SELECT id, row_number() OVER (ORDER BY embedding <=> $1::vector) AS rank
  FROM knowledge_chunks ORDER BY embedding <=> $1::vector LIMIT 40
), lexical AS (
  SELECT id, row_number() OVER (
    ORDER BY ts_rank_cd(to_tsvector('simple', content), websearch_to_tsquery('simple', $2)) DESC
  ) AS rank
  FROM knowledge_chunks
  WHERE to_tsvector('simple', content) @@ websearch_to_tsquery('simple', $2)
  LIMIT 40
)
SELECT k.id, k.title,
       coalesce(1.0 / (60 + s.rank), 0) + coalesce(1.0 / (60 + l.rank), 0) AS rrf_score
FROM knowledge_chunks k
LEFT JOIN semantic s ON s.id = k.id
LEFT JOIN lexical l ON l.id = k.id
WHERE s.id IS NOT NULL OR l.id IS NOT NULL
ORDER BY rrf_score DESC LIMIT 10;

Resumen del tema

Promedia un concepto, recupera por separado conceptos distintos y usa RRF cuando importan significado y términos exactos.

14. Diseñar documentos y fragmentos para RAG

RAG vectoriza la pregunta, recupera pruebas y pide al modelo responder desde ellas. Los documentos completos suelen ser demasiado amplios; separa de origen y fragmentos consultables.

CREATE TABLE source_documents (
  id BIGSERIAL PRIMARY KEY,
  title TEXT NOT NULL,
  source_url TEXT,
  document_type TEXT,
  version INTEGER NOT NULL DEFAULT 1,
  ingested_at TIMESTAMPTZ NOT NULL DEFAULT now()
);

CREATE TABLE document_chunks (
  id BIGSERIAL PRIMARY KEY,
  document_id BIGINT NOT NULL REFERENCES source_documents(id) ON DELETE CASCADE,
  chunk_no INTEGER NOT NULL,
  section_title TEXT,
  page_number INTEGER,
  content TEXT NOT NULL,
  token_count INTEGER NOT NULL,
  embedding vector(1536),
  UNIQUE (document_id, chunk_no)
);

CREATE INDEX chunks_source_order_idx ON document_chunks(document_id, chunk_no);
Estrategias de fragmentación.
EstrategiaVentajaRiesgo / encaje
Tamaño fijo previsibles e ingesta simple.Puede cortar ideas; útil sin estructura.
Límites semánticosConserva párrafos, secciones, cláusulas o respuestas.Tamaño variable; ideal para contenido estructurado.
SolapamientoMantiene conceptos entre fronteras.Aumenta espacio y duplicados.

Guarda sección, página, offsets y para reconstruir contexto y citas. Agrupa solicitudes de embedding e inserciones. Sustituir una fuente puede borrar fragmentos en cascada; si se necesita historial, conserva versiones y filtra la activa.

Resumen del tema

Separa fuentes y fragmentos, conserva trazabilidad y decide fronteras según estructura y consultas.

15. Construir contexto, presupuesto y citas

Top-k basta para fragmentos autónomos. Texto narrativo puede necesitar vecinos del mismo documento. Expande solo allí, elimina duplicados y suma para reservar capacidad a instrucciones, pregunta y respuesta.

WITH seeds AS (
  SELECT id, document_id, chunk_no, embedding <=> $1::vector AS distance
  FROM document_chunks
  ORDER BY embedding <=> $1::vector
  LIMIT 4
), expanded AS (
  SELECT DISTINCT c.*, s.distance
  FROM seeds s
  JOIN document_chunks c ON c.document_id = s.document_id
   AND c.chunk_no BETWEEN s.chunk_no - 1 AND s.chunk_no + 1
), budgeted AS (
  SELECT e.*, d.title, d.source_url,
         sum(e.token_count) OVER (ORDER BY e.distance, e.chunk_no) AS tokens_used
  FROM expanded e JOIN source_documents d ON d.id = e.document_id
)
SELECT content, title, source_url, section_title, page_number, distance
FROM budgeted WHERE tokens_used <= 3200
ORDER BY distance, chunk_no;

Devuelve título, o ID estable, sección, página y distancia. Agrupa varios fragmentos de una fuente en una cita con varios extractos. En dominios críticos, cada afirmación debe verificarse y las coincidencias débiles requieren revisión humana.

Una canalización RAG fragmenta y vectoriza fuentes, recupera candidatos semánticos y léxicos, aplica filtros y RRF, amplía contexto dentro del presupuesto y entrega pruebas citadas al modelo.
Una respuesta RAG fiable empieza con recuperación rastreable, limitada y relevante.

Resumen del tema

Amplía contexto cuando aporte valor, impone presupuesto de y devuelve verificables.

16. Evaluar recuperación aparte de generación

Métricas principales.
MétricaPreguntaAjuste típico
Precisión¿Cuántos fragmentos devueltos son relevantes?Umbral estricto, menos fragmentos, tamaño enfocado.
Exhaustividad¿Cuántos relevantes se encontraron?Más candidatos, umbral flexible, mayor ef_search o probes.
MRR¿Qué tan alto aparece el primer relevante?Mejores embeddings, preprocesamiento, reclasificación o fusión.

Empieza con 20–50 preguntas representativas, recupera 10–20 candidatos y pide a expertos que etiqueten relevancia. Automatiza precision@k, recall@k y MRR. Fragmentos pequeños afinan precisión pero fragmentan hechos; solapamiento conserva continuidad pero duplica; una búsqueda ANN más amplia mejora exhaustividad y latencia.

Resumen del tema

Un conjunto etiquetado y métricas hacen que modelo, fragmentación, umbral e índice se ajusten con evidencia.

17. Laboratorio guiado: similitud de productos con Flask

El ejercicio original reserva unos 30 minutos para crear una aplicación web de similitud, patrón reutilizable para recomendaciones, búsqueda semántica y RAG.

  1. Prepara suscripción de con permisos, , actual, Python 3.12 o posterior y psql.
  2. Descarga el proyecto inicial y configura el script de implementación.
  3. Implementa un servidor flexible de con .
  4. Completa Flask mientras se implementa el servidor.
  5. Permite y habilita vector y crea la tabla de productos con embedding.
  6. Carga ejemplos, ejecuta similitud e inspecciona orden y distancias.
  7. Añade productos y observa cómo cambia el vecindario.
  8. Elimina recursos temporales al terminar.

Resumen del tema

El laboratorio conecta aprovisionamiento seguro, esquema pgvector, ingesta Flask y resultados reales.

18. Revisión de evaluación y lista final

  1. Para embeddings unitarios y similitud semántica, la respuesta esperada es coseno (<=>); la guía del modelo puede justificar producto interno en implementaciones optimizadas.
  2. Para cinco millones de embeddings, lotes ocasionales y sin inserciones en tiempo real, la evaluación elige IVFFlat con lists adecuadas.
  3. En HNSW, m controla el máximo de conexiones por nodo; ef_construction controla candidatos durante la creación.
  4. Para 50 000 vectores regenerados, transacciones de 1000–5000 filas afectan menos que una gigantesca.
  5. RRF equilibra clasificaciones híbridas sin multiplicar escalas incompatibles.
  • Alinea dimensión, modelo, operador y clase.
  • Mide exhaustividad y latencia antes de elegir exacta, HNSW, IVFFlat o DiskANN.
  • Supervisa planes, usos, creación, bloat y distribución.
  • Actualiza asíncronamente y migra modelos con columnas paralelas.
  • Filtra, usa umbrales y añade señal léxica cuando importen términos exactos.
  • Diseña RAG con fragmentos íntegros, límite de , citas y calidad medible.

Referencias oficiales

  1. Habilitar y usar pgvector en el servidor flexible de
  2. Optimizar el rendimiento al usar pgvector
  3. Habilitar y usar DiskANN
  4. Integrar capacidades de AI con
  5. Crear búsqueda semántica con OpenAI

Resumen del tema

La recuperación vectorial de producción combina un espacio coherente, índices verificados, actualización sostenible, filtros relacionales y pruebas RAG trazables.