Vector Databases: Guía práctica para RAG en producción
Todo sobre vector databases para implementar RAG. Pinecone vs Weaviate vs Milvus.
Las bases de datos vectoriales son la infraestructura clave para sistemas RAG (Retrieval-Augmented Generation). Evaluamos Pinecone, Weaviate, Qdrant y pgvector en producción. Acá el análisis.
¿Qué es una base de datos vectorial?
Una vector database almacena embeddings (representaciones numéricas de texto, imágenes, audio) y permite buscar por similitud semántica en lugar de igualdad exacta.
# Ejemplo conceptual
query = "cómo optimizo queries en BigQuery"
query_embedding = embed(query) # [0.12, -0.34, 0.89, ...]
# Busca los documentos semánticamente más similares
results = vector_db.search(query_embedding, top_k=5)
# Devuelve documentos sobre BigQuery, SQL optimization, etc.
pgvector: empezar simple
Si ya usás PostgreSQL, pgvector es el punto de partida natural:
-- Instalar extensión
CREATE EXTENSION vector;
-- Tabla con embeddings
CREATE TABLE documents (
id SERIAL PRIMARY KEY,
content TEXT,
embedding vector(1536), -- OpenAI ada-002 dimension
metadata JSONB
);
-- Índice para búsqueda aproximada
CREATE INDEX ON documents USING ivfflat (embedding vector_cosine_ops)
WITH (lists = 100);
-- Búsqueda por similitud
SELECT content, 1 - (embedding <=> $1::vector) as similarity
FROM documents
ORDER BY embedding <=> $1::vector
LIMIT 10;
Cuándo usar pgvector: < 1M vectores, ya tenés PostgreSQL, no querés infraestructura adicional.
Pinecone: managed sin fricción
import pinecone
from openai import OpenAI
pinecone.init(api_key="...", environment="us-east-1-aws")
index = pinecone.Index("my-index")
openai_client = OpenAI()
def upsert_document(doc_id: str, text: str, metadata: dict):
response = openai_client.embeddings.create(
input=text,
model="text-embedding-ada-002"
)
embedding = response.data[0].embedding
index.upsert(vectors=[(doc_id, embedding, metadata)])
def search(query: str, top_k: int = 5, filter: dict = None) -> list:
response = openai_client.embeddings.create(
input=query,
model="text-embedding-ada-002"
)
query_embedding = response.data[0].embedding
results = index.query(
vector=query_embedding,
top_k=top_k,
filter=filter,
include_metadata=True
)
return results.matches
Cuándo usar Pinecone: > 1M vectores, querés managed service, latencia < 50ms es crítica.
Qdrant: open source y self-hosted
from qdrant_client import QdrantClient
from qdrant_client.models import Distance, VectorParams, PointStruct
client = QdrantClient(host="localhost", port=6333)
client.create_collection(
collection_name="documents",
vectors_config=VectorParams(size=1536, distance=Distance.COSINE),
)
client.upsert(
collection_name="documents",
points=[
PointStruct(
id=1,
vector=embedding,
payload={"content": text, "source": "blog"}
)
]
)
results = client.search(
collection_name="documents",
query_vector=query_embedding,
limit=5,
query_filter=Filter(must=[FieldCondition(key="source", match=MatchValue(value="blog"))])
)
Cuándo usar Qdrant: Open source, self-hosted, necesitás filtros complejos, costo es factor crítico.
Comparación
| Criterio | pgvector | Pinecone | Qdrant |
|---|---|---|---|
| Setup | Trivial | Trivial | Medio |
| Escala | < 1M | Ilimitado | > 10M |
| Latencia | 10-50ms | < 10ms | 5-20ms |
| Costo | Bajo | Alto | Muy bajo |
| Filtros | SQL completo | Limitado | Avanzado |
| Managed | Via RDS | Sí | Sí (cloud) |
Recomendación
- Empieza con pgvector si ya tenés PostgreSQL y tu dataset es < 500K documentos
- Migra a Qdrant cuando necesites más de 1M vectores y self-hosted
- Usa Pinecone si el presupuesto no es problema y querés cero operaciones
Escrito por Mariano Gobea Alcoba