PTENES
MÓDULO 3.2

🤖 IA aplicada a datos

Ventana de contexto, RAG, bases de datos vectoriales y búsqueda semántica. Desde pgvector hasta Weaviate, Milvus, Qdrant, Redis, Chroma y Azure AI Search.

7
Temas
70
Minutos
Avan
Avanzado
🧪
Práctica
1

🧠 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.

2

🔎 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
3

🐘 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 solo probes clú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.

4

🌊 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
5

⚡ 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.

6

🎯 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
7

🧪 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.

✅ Lista de verificación del módulo 3.2

← Volver a la Ruta Volver al inicio