🧠 Ventana de contexto
A ventana de contexto (context window) es la cantidad máxima de tokens que un LLM puede procesar de una vez. Todo lo que entra en el prompt —instrucciones, datos, historial— compite por ese espacio. Superar la ventana significa perder información o truncar datos críticos.
🎯 Concepto: tokens y límites
Los modelos modernos varían de 8K a 2M tokens de contexto, pero más contexto no significa un mejor resultado. El modelo pierde precisión en el «medio» de ventanas muy grandes (problema de «lost in the middle»). La estrategia es colocar solo lo que es relevante.
- • Token: Unidad mínima de texto. ~1 token = ~4 caracteres en inglés, ~3 en portugués
- • Compresión: Resumir documentos largos antes de enviarlos al modelo
- • Resumen jerárquico: Resumir bloques y luego resumir los resúmenes
- • Priorización por relevancia: Usar búsqueda semántica para seleccionar los fragmentos más importantes
💡 Consejo práctico
Para las aplicaciones de datos, la regla es: no metas toda la base de datos en el prompt. Usa RAG para buscar solo los fragmentos relevantes, comprime los documentos largos y reserva al menos el 30% de la ventana para la respuesta del modelo. El costo escala con los tokens (entrada + salida). 5 fragmentos bien seleccionados superan 50 páginas completas.
🔎 RAG - Retrieval-Augmented Generation
RAG es la técnica que conecta los LLM con tus datos. En lugar de depender solo del conocimiento interno del modelo, RAG busca información relevante en tu base de datos y la inyecta en el prompt antes de generar la respuesta. Así es como los chatbots «conocen» los datos internos de la empresa.
🔄 Pipeline RAG completo
1. Fragmentación
Dividir documentos en fragmentos de ~500-1000 tokens con solapamiento
2. Embeddings
Convertir cada fragmento en un vector numérico que captura el significado semántico
3. Indexación
Almacenar vectores en una base de datos vectorial con un índice para realizar búsquedas rápidas
4. Consulta
Convertir la pregunta del usuario en un vector y buscar fragmentos similares
5. Reordenamiento
Reordenar resultados con un modelo cross-encoder para mayor precisión
6. Generación
Armar un prompt con el contexto recuperado y generar una respuesta con el LLM
# Pipeline RAG completo em Python
docs = split_into_chunks(load_corpus(), tokens=600)
vecs = embed(docs)
index = build_vector_index(vecs)
query = embed("Como normalizar tabelas?")
tops = index.search(query, k=5)
prompt = compose(system, user, context=tops)
answer = llm.generate(prompt)
📊 Números de referencia
- Tamaño típico del fragmento: 500-1000 tokens con un 10-20% de superposición
- Embeddings populares: text-embedding-3-small (1536 dims), BGE, E5
- Top-k típico: 3-10 fragmentos según el tamaño de la ventana
- El reranking mejora la precisión en 10-25% vs. búsqueda vectorial pura
🐘 pgvector en PostgreSQL
pgvector agrega el tipo VECTOR a PostgreSQL, lo que permite buscar por similitud directamente en la base de datos relacional que ya conoces. Sin infraestructura extra, sin una base de datos nueva. Ideal para hasta ~1 millón de vectores con buen rendimiento.
-- Habilitar a extensao
CREATE EXTENSION IF NOT EXISTS vector;
-- Criar tabela com coluna vetorial
CREATE TABLE doc_chunk (
id BIGSERIAL PRIMARY KEY,
content TEXT NOT NULL,
embedding VECTOR(1536)
);
-- Buscar os 5 chunks mais similares (distancia cosseno)
SELECT id, content
FROM doc_chunk
ORDER BY embedding <=> '[0.010, -0.020, ...]'::vector
LIMIT 5;
💡 Rendimiento: ivfflat y HNSW
Sin índice, pgvector hace una búsqueda exacta (seq scan). Para tablas grandes, crea un índice aproximado:
- • ivfflat: Divide vectores en
lists(clusters). En la búsqueda, consulta soloprobesclústeres cercanos. Regla:lists = sqrt(n),probes = sqrt(lists). - • HNSW: Grafo jerárquico navegable. Más rápido que ivfflat para buscar, más lento de construir. Ideal para producción con QPS alto.
- • Empieza con ivfflat y migra a HNSW cuando necesites más velocidad de búsqueda.
🎯 Operadores de distancia
<=> Coseno
El más usado. Compara la dirección de los vectores e ignora la magnitud.
<-> L2 (euclidiana)
Distancia geométrica. Sensible a la magnitud de los vectores.
<#> Producto interno
Maximiza la similitud. Se usa con vectores normalizados.
🌊 Weaviate
Weaviate y una base de datos vectorial con búsqueda híbrida nativa: combina búsqueda semántica (vectores) con búsqueda por palabras clave (BM25). Una búsqueda puramente semántica puede pasar por alto términos exactos. La búsqueda híbrida lo resuelve combinando ambos rankings.
import weaviate
client = weaviate.Client("http://localhost:8080")
# Busca semantica (nearVector)
result = client.query.get("Document", ["content", "source"]) \
.with_near_vector({"vector": query_vec}) \
.with_limit(5) \
.do()
# Busca hibrida (vetor + BM25)
result = client.query.get("Document", ["content", "source"]) \
.with_hybrid(query="normalizacao tabelas", alpha=0.5) \
.with_limit(5) \
.do()
# alpha=1.0 = puramente vetorial
# alpha=0.0 = puramente BM25
# alpha=0.5 = metade de cada
🔍 Ventajas de Weaviate
- • Búsqueda híbrida: El parámetro alpha controla el equilibrio entre semántica y BM25
- • Modules: Módulos integrados para embeddings automáticos (text2vec-openai, text2vec-cohere)
- • Multitenencia: Aísla los datos por tenant sin duplicar la infraestructura. Bueno para SaaS
- • GraphQL API: Interfaz de consulta expresiva y bien documentada
⚡ Milvus
Milvus y una base de datos vectorial de código abierto diseñada para miles de millones de vectores. Cuando pgvector ya no escala, Milvus es la opción más madura. Admite aceleración por GPU, sharding distribuido y múltiples tipos de índice.
from pymilvus import (
connections, FieldSchema, CollectionSchema,
DataType, Collection
)
# Conectar
connections.connect("default", host="localhost", port="19530")
# Definir schema
fields = [
FieldSchema(name="id", dtype=DataType.INT64,
is_primary=True, auto_id=True),
FieldSchema(name="content", dtype=DataType.VARCHAR,
max_length=2000),
FieldSchema(name="embedding", dtype=DataType.FLOAT_VECTOR,
dim=1536)
]
schema = CollectionSchema(fields, description="RAG docs")
collection = Collection("documents", schema)
# Criar indice IVF_FLAT
index_params = {
"metric_type": "COSINE",
"index_type": "IVF_FLAT",
"params": {"nlist": 256}
}
collection.create_index("embedding", index_params)
collection.load()
# Buscar
results = collection.search(
data=[query_vector],
anns_field="embedding",
param={"metric_type": "COSINE", "params": {"nprobe": 16}},
limit=5,
output_fields=["content"]
)
🎯 Cuándo Milvus brilla
Escala
Miles de millones de vectores distribuidos en un clúster. Sharding automático, réplicas de lectura.
Aceleración por GPU
Compatibilidad nativa con GPU para indexación y búsqueda. Mucho más rápido, por órdenes de magnitud.
Zilliz Cloud
Versión administrada (SaaS) de Milvus. Sin operaciones, escala bajo demanda.
🎯 Qdrant y Redis Vectorial
Qdrant almacena vectores con cargas útiles filtrables: ideal para búsquedas semánticas con filtros complejos. Redis con el módulo RediSearch agrega búsqueda vectorial a la caché que muchos ya usan en producción. Dos enfoques, dos escenarios diferentes.
# Qdrant com qdrant-client
from qdrant_client import QdrantClient
from qdrant_client.models import (
VectorParams, Distance, PointStruct
)
client = QdrantClient("localhost", port=6333)
# Criar collection com distancia cosseno
client.create_collection(
collection_name="documents",
vectors_config=VectorParams(
size=1536,
distance=Distance.COSINE
)
)
# Inserir com payload (metadados filtraveis)
client.upsert(
collection_name="documents",
points=[
PointStruct(
id=1,
vector=[0.012, -0.034, ...],
payload={
"content": "Normalizacao ate 3FN",
"source": "aula-sql",
"level": "intermediario"
}
)
]
)
# Buscar com filtro de payload
results = client.search(
collection_name="documents",
query_vector=query_vec,
query_filter={"must": [
{"key": "level", "match": {"value": "intermediario"}}
]},
limit=5
)
# Redis Vetorial com RediSearch
# Criar indice com campo vetorial HNSW
FT.CREATE idx_docs ON HASH PREFIX 1 doc:
SCHEMA
content TEXT
embedding VECTOR HNSW 6
TYPE FLOAT32
DIM 1536
DISTANCE_METRIC COSINE
# Inserir documento
HSET doc:1
content "Normalizacao ate 3FN reduz redundancia"
embedding "\x3f\x80\x00\x00..."
# Buscar KNN (5 vizinhos mais proximos)
FT.SEARCH idx_docs
"*=>[KNN 5 @embedding $vec AS score]"
PARAMS 2 vec "\x3f\x80\x00\x00..."
SORTBY score
RETURN 2 content score
DIALECT 2
Qdrant - Ideal para
- • Búsqueda semántica + filtros complejos por payload
- • Multi-tenancy nativo con aislamiento
- • Escrito en Rust, baja latencia
- • API REST y gRPC nativas
Redis Vectorial - Ideal para
- • ¿Ya usas Redis? Agrega vectores sin nueva infraestructura
- • Caché + búsqueda vectorial en la misma instancia
- • Latencia ultrabaja (in-memory)
- • TTL nativo para vectores temporales
🧪 Chroma y Azure AI Search
Chroma es la base de datos vectorial más ligera para el desarrollo local y la creación rápida de prototipos. Azure AI Search es la solución empresarial administrada de Microsoft, con SLA, integración con Azure OpenAI y búsqueda híbrida. Dev vs Enterprise.
# Chroma - banco vetorial mais simples
import chromadb
client = chromadb.Client() # In-memory, zero config
# Criar collection
collection = client.get_or_create_collection("my_docs")
# Adicionar documentos (embedding automatico)
collection.add(
documents=[
"Normalizacao ate 3FN reduz redundancia",
"Indices B-tree aceleram buscas por range",
"Transacoes ACID garantem consistencia"
],
ids=["doc1", "doc2", "doc3"],
metadatas=[
{"source": "sql-101"},
{"source": "indices"},
{"source": "transacoes"}
]
)
# Buscar por similaridade
results = collection.query(
query_texts=["como reduzir redundancia?"],
n_results=3
)
print(results["documents"])
// Azure AI Search - Indice com busca vetorial (JSON)
{
"name": "rag-index",
"fields": [
{"name": "id", "type": "Edm.String", "key": true},
{"name": "content", "type": "Edm.String",
"searchable": true},
{"name": "contentVector",
"type": "Collection(Edm.Single)",
"searchable": true,
"dimensions": 1536,
"vectorSearchProfile": "my-vector-profile"}
],
"vectorSearch": {
"algorithms": [
{"name": "my-hnsw", "kind": "hnsw",
"hnswParameters": {
"metric": "cosine", "m": 4,
"efConstruction": 400, "efSearch": 500
}}
],
"profiles": [
{"name": "my-vector-profile",
"algorithm": "my-hnsw"}
]
}
}
🎯 Cuándo usar cada uno
Chroma
Prototipado, hackatones, desarrollo local, proyectos pequeños. Sin configuración, funciona en memoria o persiste en SQLite. No se recomienda para producción con alta carga.
Azure AI Search
Producción empresarial, SLA 99.95%, integración con Azure OpenAI, skillsets para el enriquecimiento automático, reranking semántico nativo.