Tools
Tools: Actualización de embeddings en producción con LangChain + pgvector
2026-02-05
0 views
admin
async (si estás en async) ## await vs.adelete(ids=obsolete_ids)` Cuando tu pipeline de RAG está en producción, lo más común no es “cambiar el modelo”, sino algo más frecuente: el documento cambió (se editó, se reemplazó, se corrigió un párrafo) y necesitas actualizar los embeddings correspondientes en tu vector store. Este post describe un proceso práctico y seguro usando LangChain y PostgreSQL + pgvector. Actualizar embeddings sin downtime, minimizando costo y evitando inconsistencias: • Solo re-embeddear lo que cambió. • Mantener IDs estables para hacer upsert. • Borrar chunks obsoletos. • Proteger la lectura (retrieval) mientras ocurre la actualización. 1) Principio clave: actualizar por chunk, no por documento En producción, el documento suele partirse en chunks. Si solo cambió una sección, no tiene sentido recalcular todo. Recomendación: • Chunking determinista (misma regla de split). • Para cada chunk, guarda un content_hash (hash del texto normalizado). • Si el hash no cambia, no recalcules embedding. 2) IDs determinísticos (la base del upsert) La actualización en pgvector normalmente no es “update por contenido”; es update por ID. Ejemplo de ID estable: • "{doc_id}:{chunk_index}" (simple) • "{doc_id}:{chunk_hash_prefix}" (mejor si el chunking puede moverse) Con IDs estables, puedes enviar el mismo ID y sobrescribir el vector + metadata (“upsert”). 3) LangChain + PGVector: consideraciones de integración En el stack actual, la integración recomendada para PostgreSQL en LangChain es langchain-postgres, que requiere psycopg3 y pasar un connection object explícito.  Además, LangChain advierte que cambios de esquema pueden implicar recrear tablas y reinsertar datos; por eso conviene decidir el diseño de metadata/IDs desde el inicio.  4) Flujo de actualización (A) paso a paso Paso 1 — Construir el “diff” Para un doc_id: 1. Obtén el estado anterior (idealmente desde una tabla tuya): lista de chunk IDs + hashes. 2. Re-chunkea el documento actualizado. 3. Calcula: • to_upsert: chunks nuevos o con hash distinto. • to_delete: IDs que existían y ya no están. En producción suele ser más confiable mantener un “inventario” de chunks por documento en tablas propias (Postgres normal), en vez de depender de “listar por metadata” desde el vector store. Paso 2 — Upsert de chunks cambiados Con PGVector, agrega documentos con ids=... para que el write sea determinista. La API expone métodos para agregar y usar IDs.  `import psycopg
from langchain_postgres.vectorstores import PGVector
from langchain_core.documents import Document
from langchain_openai import OpenAIEmbeddings conn = psycopg.connect("postgresql://user:pass@host:5432/db") emb = OpenAIEmbeddings(model="text-embedding-3-small") # 1536 dims por defecto oai_citation:3‡OpenAI Platform vs = PGVector( embeddings=emb, connection=conn, collection_name="docs_v1", use_jsonb=True,
) docs = [ Document( page_content=chunk_text, metadata={ "doc_id": doc_id, "chunk_index": i, "content_hash": h, "updated_at": updated_at_iso, "embedding_model": "text-embedding-3-small", }, ) for i, (chunk_text, h) in enumerate(chunks_to_upsert)
] ids = [f"{doc_id}:{chunk_index}" for chunk_index, _ in enumerate(chunks_to_upsert)] vs.add_documents(docs, ids=ids)` Paso 3 — Borrar chunks obsoletos Borra por ID (sync o async). LangChain documenta delete/adelete por IDs.  `# sync
vs.delete(ids=obsolete_ids) 5) Lecturas consistentes durante el update (sin downtime) Patrón recomendado: “doc_version” (2 fases) Para evitar que el retrieval mezcle chunks viejos y nuevos: 1. Genera una doc_version nueva (p.ej. timestamp o número). 2. Upsertea chunks nuevos con metadata.doc_version = new_version. 3. Actualiza en una tabla de control docs_active_version(doc_id) = new_version. 4. Borra chunks de versiones anteriores (o márcalos como inactivos). En tiempo de búsqueda, filtras por doc_id y doc_version activa. La búsqueda en LangChain soporta filtros en los métodos de similarity search.  6) Dimensiones: evita sorpresas con pgvector Si cambias de modelo, revisa dimensiones. OpenAI indica por defecto: • text-embedding-3-small: 1536 • text-embedding-3-large: 3072  Y pgvector especifica límites por tipo: • vector: hasta 2000 dims • halfvec: hasta 4000 dims  Esto afecta la elección de modelo (o la necesidad de reducir dimensiones si tu proveedor lo permite). 7) Índices para rendimiento (HNSW / IVFFlat) pgvector soporta índices ANN. Para cosine con HNSW:  CREATE INDEX ON items USING hnsw (embedding vector_cosine_ops); Y con parámetros típicos:  CREATE INDEX ON items
USING hnsw (embedding vector_l2_ops)
WITH (m = 16, ef_construction = 64); Checklist de producción • Chunking determinista + content_hash. • IDs determinísticos por chunk (upsert idempotente). • “Diff” (upsert solo cambios, delete obsoletos). • Control de consistencia de lectura (doc_version). • Índice ANN (HNSW/IVFFlat) y monitoreo de latencia. • Validación de dimensiones vs tipo (vector/halfvec).  Si compartes tu patrón actual de chunking (tamaño/overlap) y volumen (chunks totales), puedo proponer: 1. un esquema mínimo de tablas para inventario de chunks/versiones, y 2. un job de actualización con transacciones y reintentos (idempotente) listo para correr en prod. Templates let you quickly answer FAQs or store snippets for re-use. Are you sure you want to hide this comment? It will become hidden in your post, but will still be visible via the comment's permalink. Hide child comments as well For further actions, you may consider blocking this person and/or reporting abuse
how-totutorialguidedev.toaiopenaipostgresql