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 ? It will become hidden in your post, but will still be visible via the comment's permalink. as well , this person and/or
toolsutilitiessecurity toolsactualizaciembeddingsproduccilangchainpgvector