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.