Vector Databases
¿Qué es una Vector Database?
Una vector database almacena y permite buscar eficientemente embeddings (vectores de alta dimensionalidad). Son el componente central de cualquier pipeline RAG, permitiendo búsquedas semánticas a escala.
¿Por Qué No un DB Tradicional?
SQL: SELECT * FROM docs WHERE content LIKE '%machine learning%'
→ Solo encuentra coincidencias exactas de texto
Vector: Buscar documentos semánticamente similares a "IA y aprendizaje"
→ Encuentra docs sobre ML, deep learning, redes neuronales, etc.
→ Entiende SIGNIFICADO, no solo palabras
Principales Vector Databases
| Database | Tipo | Fortalezas | Ideal para |
|---|---|---|---|
| Pinecone | Managed SaaS | Fácil, escalable, serverless | Producción rápida |
| Weaviate | Open-source | Hybrid search, modules | Flexibilidad |
| ChromaDB | Open-source | Simple, Python-first | Prototipos, dev local |
| pgvector | Extensión PostgreSQL | Usa tu DB existente | Si ya tienes Postgres |
| Qdrant | Open-source | Rust-based, rápido | Alto rendimiento |
| Milvus | Open-source | Escala masiva | Billones de vectores |
ChromaDB (Desarrollo Local)
import chromadb
from chromadb.utils import embedding_functions
# Crear cliente
client = chromadb.PersistentClient(path="./chroma_data")
# Configurar embedding function
openai_ef = embedding_functions.OpenAIEmbeddingFunction(
api_key="sk-...",
model_name="text-embedding-3-small"
)
# Crear colección
collection = client.get_or_create_collection(
name="knowledge_base",
embedding_function=openai_ef,
metadata={"hnsw:space": "cosine"} # Métrica de distancia
)
# Indexar documentos
collection.add(
documents=[
"Python es un lenguaje de programación interpretado",
"JavaScript se ejecuta en el navegador",
"Rust es conocido por su seguridad de memoria",
],
metadatas=[
{"source": "python.md", "category": "backend"},
{"source": "js.md", "category": "frontend"},
{"source": "rust.md", "category": "systems"},
],
ids=["doc1", "doc2", "doc3"],
)
# Buscar
results = collection.query(
query_texts=["lenguaje para desarrollo web del lado del cliente"],
n_results=2,
where={"category": "frontend"}, # Filtro por metadatos
)
print(results["documents"]) # Documentos más relevantes
print(results["distances"]) # Scores de distancia
print(results["metadatas"]) # Metadatos asociados
pgvector (PostgreSQL)
-- Instalar extensión
CREATE EXTENSION vector;
-- Crear tabla con columna de vector
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT NOT NULL,
metadata JSONB DEFAULT '{}',
embedding vector(1536), -- dimensión del modelo
created_at TIMESTAMP DEFAULT NOW()
);
-- Crear índice para búsqueda eficiente
CREATE INDEX ON documents
USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
-- Insertar documento con embedding
INSERT INTO documents (content, embedding)
VALUES ('Python es genial', '[0.023, -0.041, ...]');
-- Búsqueda por similitud coseno (top 5)
SELECT content,
1 - (embedding <=> '[0.018, ...]') AS similarity
FROM documents
ORDER BY embedding <=> '[0.018, ...]'
LIMIT 5;
# Python con psycopg2
import psycopg2
import json
def search_similar(query_embedding, top_k=5):
conn = psycopg2.connect("postgresql://...")
cur = conn.cursor()
cur.execute("""
SELECT content, metadata,
1 - (embedding <=> %s::vector) AS similarity
FROM documents
ORDER BY embedding <=> %s::vector
LIMIT %s
""", (str(query_embedding), str(query_embedding), top_k))
return cur.fetchall()
Pinecone (Producción)
from pinecone import Pinecone
pc = Pinecone(api_key="...")
# Crear índice
pc.create_index(
name="knowledge-base",
dimension=1536,
metric="cosine",
spec={"serverless": {"cloud": "aws", "region": "us-east-1"}}
)
index = pc.Index("knowledge-base")
# Upsert (insertar/actualizar)
index.upsert(
vectors=[
{
"id": "doc-001",
"values": [0.023, -0.041, ...], # embedding
"metadata": {
"source": "manual.pdf",
"page": 5,
"category": "soporte",
}
},
],
namespace="production",
)
# Buscar con filtros
results = index.query(
vector=[0.018, ...],
top_k=5,
namespace="production",
filter={"category": {"$eq": "soporte"}},
include_metadata=True,
)
for match in results.matches:
print(f"Score: {match.score:.4f} | {match.metadata}")
Optimización de Vector DBs
Índices
| Tipo | Velocidad | Precisión | Memoria |
|---|---|---|---|
| Flat (Brute Force) | Lento | Exacto | Baja |
| IVF | Rápido | ~95% | Media |
| HNSW | Muy rápido | ~99% | Alta |
| PQ (Product Quantization) | Rápido | ~90% | Muy baja |
Estrategias de Namespaces
knowledge-base/
├── production/ # Datos en producción
├── staging/ # Datos de prueba
├── v2-migration/ # Nueva versión de embeddings
└── experiment-42/ # A/B test
Patrón Completo: RAG con Vector DB
class RAGPipeline:
def __init__(self, collection, llm_client):
self.collection = collection
self.llm = llm_client
def ingest(self, documents: list[dict]):
self.collection.add(
documents=[d["content"] for d in documents],
metadatas=[d.get("metadata", {}) for d in documents],
ids=[d["id"] for d in documents],
)
def query(self, question: str, top_k: int = 5) -> str:
results = self.collection.query(
query_texts=[question],
n_results=top_k,
)
context = "\n\n".join(results["documents"][0])
response = self.llm.chat.completions.create(
model="gpt-4o",
messages=[
{"role": "system", "content": f"Responde basándote en:\n{context}"},
{"role": "user", "content": question},
],
)
return response.choices[0].message.content
Resumen
Las vector databases son la infraestructura clave para RAG y búsqueda semántica. ChromaDB para desarrollo, pgvector si ya tienes Postgres, y Pinecone/Qdrant para producción a escala. Elegir el índice correcto y la estrategia de namespacing es crucial para rendimiento.