Saltar a contenido

Cifrado y vectores

Columnas cifradas

datasource(provider=env('MAIN_DATABASE_URL'), secret_key_name='SECRET_KEY')

class Usuario(Table):
    __tablename__ = 'usuario'

    id: col[int] = column(primary_key=True, autoincrement=True)
    email: col[str] = column(unique=True)
    password: col[str] = column(encrypt=True)

Cifrado Fernet con la clave que haya en la variable de entorno que nombra secret_key_name.

Es transparente en el cliente generado: se escribe y se lee en claro, y en la base de datos está cifrado.

public_sync_api.usuario.create(UsuarioCreate(email='a@x.com', password='secreto'))
usuario = public_sync_api.usuario.find(id=1)
usuario.password        # 'secreto'  ← descifrado al leer

La clave no se rota sola

Si cambias el valor de SECRET_KEY, lo ya cifrado deja de poder descifrarse. Guárdala como un secreto del despliegue, no en el repositorio.

Necesita el extra encryption en tai-sql —lo usan generate, que valida la clave antes de emitir el cliente, y feed, que cifra lo que inserta— y cryptography en el proyecto.

Una columna cifrada no se puede filtrar por su valor

En la base de datos está el texto cifrado, y dos cifrados del mismo valor no son iguales. Un find_many(password='secreto') no encontrará nada. Para autenticación, compara en tu aplicación tras leer la fila.

Columnas vectoriales

Solo en PostgreSQL, sobre pgvector.

class Post(Table):
    __tablename__ = 'post'

    id: col[bigint] = column(primary_key=True, autoincrement=True)
    contenido: col[text]

    embedding: col[vector | None] = vector_column(
        dimensions=384,                              # se deduce del encoder si se omite
        source='contenido',                          # columna de texto que se codifica al escribir
        encoder=SentenceTransformerEncoder('all-MiniLM-L6-v2'),
        metric='cosine',                             # 'cosine' | 'l2' | 'inner_product'
        threshold=0.5,                               # umbral de distancia por defecto
        index=True,                                  # índice HNSW
        description='',
    )

Con source declarado, el cliente generado codifica solo: escribes contenido y el embedding se calcula al guardar.

Los encoders

Encoder Qué usa el cliente generado en runtime Variables de entorno
SentenceTransformerEncoder langchain-huggingface —
OpenAIEncoder langchain-openai OPENAI_API_KEY
AzureOpenAIEncoder langchain-openai AZURE_OPENAI_API_KEY, AZURE_OPENAI_ENDPOINT, AZURE_OPENAI_API_VERSION
GoogleEncoder langchain-google-genai GOOGLE_API_KEY

Son descriptores de configuración: no cargan ninguna librería de ML al importar el schema; solo le dicen al generador qué código emitir. Las dependencias reales se instalan en el proyecto (tai-sql install), no en tai-sql.

Dimensiones

Cada modelo tiene las suyas, y el encoder las conoce para los modelos habituales:

Dimensiones Modelos
384 all-MiniLM-L6-v2, all-MiniLM-L12-v2, paraphrase-MiniLM-*
512 distiluse-base-multilingual-cased-v2
768 all-mpnet-base-v2, paraphrase-multilingual-mpnet-base-v2, text-embedding-004
1536 text-embedding-3-small, text-embedding-ada-002
3072 text-embedding-3-large, gemini-embedding-2-preview

Si declaras dimensions y el encoder conoce las suyas y no coinciden, el error salta al declarar el schema, no en runtime.

La métrica y el umbral

metric decide qué función de distancia se usa por defecto al buscar. Las funciones de pgvector devuelven distancia (menor = más parecido), no similitud:

Métrica Rango Lectura
cosine [0, 2] 0 = idénticos, 1 = ortogonales, 2 = opuestos. threshold=0.5 ≈ 75 % de similitud
l2 [0, ∞) 0 = idénticos. Depende de la magnitud de los vectores
inner_product — Usa el producto interno negado: menor valor = más parecido

Al usarlas

  • Las columnas vectoriales no se cargan por defecto en las consultas normales: hay que pedirlas con include_vectors=True.
  • Cada vector_column() genera su propio método de búsqueda en el DAO. Ver búsqueda vectorial.

tai-sql feed no codifica vectores

Si una columna vectorial con encoder no trae valor, el feed corta con un error. Codificar es trabajo del cliente generado, en runtime: meter las librerías de embeddings en las dependencias de la herramienta para hacer en tiempo de desarrollo lo que el cliente hace en producción sería el mundo al revés.

Necesita el extra vectors en tai-sql (lo usan push y feed) y vectors / vectors-encoding en el proyecto.