Para los 9586 fragmentos de este proyecto, producto escalar de matriz numpy + pickle BM25 es suficiente. El retraso de búsqueda es inferior a 100 ms y el uso de memoria es de aproximadamente 29 MB (incrustación de 14 MB + índice BM25 de 7,1 MB + corpus de tokenización de 7,6 MB). Pero cuando amplías:
| Número de trozos | Tamaño de incrustación (384d) | tiempo de búsqueda del producto escalar | problema |
|---|---|---|---|
| 10K | 14MB | <100 ms | no existe |
| 100K | 140MB | ~500ms | Comienza la presión de la memoria |
| 1M | 1,4GB | ~5 segundos | Limitaciones de memoria, tolerancia a la latencia. |
| 10M | 14GB | imposibilidad | No es posible con numpy |
Enfoque de cambio mínimo. Mejora el rendimiento manteniendo la estructura del código actual:
| componente | hoy | cambiar |
|---|---|---|
| búsqueda vectorial | producto escalar numeroso | FAISS IndexFlatIP (exacto, pero optimizado) |
| BM25 | pepinillo rango-bm25 | Igual (en memoria posible hasta 50K) |
| metadatos | archivo JSONL | SQLite (chunks.db) |
| Crear incrustaciones | Transformador de oraciones de PyTorch | Conversión ONNX (script de conversión preparado: convert_to_onnx.py) |
Nota de términos:
# FAISS 적용 예시 (embed.py 변경 부분만)
import faiss
# 빌드 시
index = faiss.IndexFlatIP(384) # Inner Product = cosine (정규화 후)
index.add(embeddings)
faiss.write_index(index, "data/faiss.index")
# 검색 시
index = faiss.read_index("data/faiss.index")
scores, indices = index.search(query_embedding, top_k) # GPU도 가능
Presentamos la búsqueda aproximada (ANN). Sacrificando un poco de precisión y ganando mucha velocidad:
| componente | Opción A (autohospedado) | Opción B (Administrada) |
|---|---|---|
| búsqueda vectorial | FAISS IndexIVFFlat (basado en clúster) |
Qdrant (Docker) |
| BM25 | Búsqueda elástica (Docker) | OpenSearch sin servidor |
| metadatos | PostgreSQL | Supabase (PostgreSQL + API REST) |
| Crear incrustaciones | Procesamiento por lotes en servidores GPU | OpenAI text-embedding-3-small API |
| reclasificador | reranker bge local | API de cambio de rango de Cohere |
# FAISS IVF 적용 (100K+ 청크에 효과적)
nlist = 100 # 클러스터 수 (sqrt(N) 정도)
quantizer = faiss.IndexFlatIP(384)
index = faiss.IndexIVFFlat(quantizer, 384, nlist, faiss.METRIC_INNER_PRODUCT)
index.train(embeddings) # 클러스터 학습
index.add(embeddings)
index.nprobe = 10 # 검색 시 탐색할 클러스터 수 (정확도↔속도 트레이드오프)
Base de datos vectorial dedicada + clúster de motor de búsqueda:
| componente | opciones | característica |
|---|---|---|
| búsqueda vectorial | Piña | Totalmente administrado, sin servidor y escalable automáticamente |
| Weaviate | Búsqueda híbrida integrada (BM25+consulta única densa) | |
| Qdrant | Alto rendimiento basado en Rust, autohospedaje/nube | |
| pgvector + PostgreSQL | Agregar búsqueda vectorial a RDB existente | |
| Búsqueda de palabras clave | Clúster de búsqueda elástica | BM25 + análisis morfológico incorporado (nori/ik) |
| incrustar | Servicio API (OpenAI/Cohere) | No se requiere GPU local, los costos se cobran por token |
| Orquestación | LangChain/LlamaIndex | Buscar → Reranking → Configuración automática de la cadena LLM |
El paraphrase-multilingual-MiniLM-L12-v2 actual (384 dimensiones) es liviano pero tiene menor precisión que los últimos modelos:
| modelo | dimensión | tamaño | característica | el tamaño correcto |
|---|---|---|---|---|
| MiniLM-L12-v2 (actual) | 384 | 120 megas | Ejecutar localmente, más de 50 idiomas | ~50K |
bge-m3 (BAAI) |
1024 | 2,2 GB | Dense+Sparse+ColBERT 3 en 1, potencia multilingüe | 50K ~ 500K |
multilingual-e5-large-instruct |
1024 | 2,2 GB | Optimizado para consultas dirigidas | 50K ~ 500K |
text-embedding-3-small (OpenAI) |
1536 | API | API de bajo costo, excelente multilingüe | 100K+ |
embed-multilingual-v3 (Coherir) |
1024 | API | Más de 100 idiomas, búsqueda especial | 100K+ |
Área de influencia al ser reemplazado:
embed.py + ajustar el tamaño del loteembeddings.npy Regenerar (cambiar dimensión → aumentar el tamaño del archivo)search.py (el producto escalar numpy no tiene dimensiones)| método | mérito | desventaja | situación adecuada |
|---|---|---|---|
| Reconstrucción completa | Sencillo y consistente | A medida que aumenta la escala, aumenta el tiempo. | <50.000 fragmentos, una vez al día |
| suma incremental | Rápido (procesa sólo cambios) | Gestión compleja de eliminación/edición | 50K~500K, se requiere tiempo real |
| Reconstrucción incremental + cíclica | Tiempo real + calidad | Gestión de dos sistemas. | 500K+, Producción |
Para este proyecto, una reconstrucción completa es suficiente en 9586 fragmentos, ya que una reconstrucción completa tarda entre 3 y 5 minutos. Sin embargo, más allá de los 100.000 fragmentos, la indexación incremental se vuelve esencial.
Actualmente, todo el sistema opera localmente. Al expandir esto a un servicio externo o compartirlo con un equipo, organice qué opciones están disponibles en cada paso.
| opciones | explicación | ambiente adecuado |
|---|---|---|
| Visualización del sistema de archivos | Detección de cambio de directorio con watchdog/inotify → reprocesamiento automático |
local, pequeño |
| Git webhooks | Reconstrucción automática desde CI/CD cuando se envía el repositorio de documentos | Documentación técnica, IaC |
| Sincronización de API de Confluence/Notion | Detectar páginas modificadas con REST API → Procesamiento incremental | ambiente corporativo |
| Eventos S3 + Lambda | Fragmentación + incrustación con Lambda al cargar documentos en S3 | Entorno AWS, sin servidor |
| No estructurado.io | PDF/DOCX/PPTX/HTML → Conversión automática a texto estructurado | Varios formatos de archivo |
| opciones | explicación | ambiente adecuado |
|---|---|---|
| Implementación directa (actual) | chunk.py: 512 caracteres, respeta los límites de los párrafos |
Cuando se requiere control personalizado de dominio |
| Divisor de texto LangChain | RecursiveCharacterTextSplitter: reconocimiento de encabezados de rebajas, preservación de bloques de código |
Inicio universal y rápido |
| LlamaIndex SentenceSplitter | Respete los límites de las oraciones, extraiga metadatos automáticamente | universal |
| No estructurado.io | Análisis automático de la estructura del documento seguido de fragmentación basada en elementos (separando título, cuerpo, tabla y títulos de imagen) | documento no estructurado |
| fragmentación semántica | Dividir en el punto donde el significado cambia según la similitud incorporada | texto largo sin estructura |
| opciones | gastos | demora | ambiente adecuado |
|---|---|---|---|
| Transformer de sentencia local (actual) | gratis | Lote 3-5 minutos | Desarrollo local, <100K |
| ONNX local (script de conversión preparado) | gratis | Implementación ~2 minutos | Local, CPU optimizada |
| Servidor GPU | costo de instancia | Implementación ~30 segundos | 100K+, reconstrucciones frecuentes |
| API de integración de OpenAI | 0,02 USD/1 millón de tokens | tiempo real | Carga de producción y gestión↓ |
| API de inserción de Cohere | 0,10 $/1 millón de fichas | Tiempo real | Especialización Multilingüe |
| Titán de roca amazónica | 0,02 USD/1 millón de tokens | tiempo real | entorno AWS |
| opciones | BM25 | Denso | híbrido | ambiente adecuado |
|---|---|---|---|---|
| Basado en archivos (actualmente) | pepinillo rango-bm25 (2 archivos: bm25_index + tokenized_corpus) | numpy.npy | suma manual | Locales, <50 000 |
| FAISS + Búsqueda elástica | búsqueda elástica | FAISS | Lógica de suma separada | Autohospedaje, 50K~1M |
| Weaviate | BM25 incorporado | HNSW incorporado | Automáticamente con parámetros alpha |
Todo en uno, 50K~10M |
| Qdrant | (se requiere ES por separado) | HNSW incorporado | Integración rápida | Búsqueda de vectores de alto rendimiento |
| Piña | (Se requiere por separado) | decoración de interiores | Soporte escaso+denso | Totalmente gestionado, escalable |
| pgvector + PostgreSQL | pg_trgm/FTS | pgvector | Suma con consulta SQL | Utilizar RDB existente |
| opciones | gastos | actuación | ambiente adecuado |
|---|---|---|---|
| bge-reranker-v2-m3 (actual) | gratis | 40 candidatos/500 ms | Local, multilingüe |
| Cohere Rerank | $2/1KBúsqueda | 40 candidatos/200 ms | Producción, basada en API |
| Jina Reranker | Gratis ~ Pagado | 40 candidatos/300 ms | Multilingüe, API/local |
| ColBERT v2 | gratis | Coincidencia de unidades de token | Documentos largos, cotejo preciso |
| Reclasificación basada en LLM | costo simbólico | Lento pero extremadamente preciso | Búsquedas de bajo volumen y alto valor |
Datos efectivos gestionados con RAG:
| tipo de datos | Bondad de ajuste de RAG | razón |
|---|---|---|
| Plan de servicio | altura | Cambia con frecuencia, requiere versiones y se comparte entre equipos. |
| Documentación API | muy alto | Se requiere una coincidencia precisa de términos, diferencias por versión |
| Guía de incorporación | altura | Responder a diversas preguntas de nuevos empleados. |
| Manual de respuesta a fallos | muy alto | La búsqueda rápida es esencial en situaciones de emergencia |
| Pautas de revisión de código | medio | Para el código en sí, la búsqueda IDE es más adecuada |
| actas | llanura | No estructurado, requiere estructuración después de extraer solo decisiones. |
| Notas diarias | muy bajo | Manejo de vencimientos de corta duración basado en TTL |
┌──────────────────────────────────────────────────┐
│ 데이터 소스 │
│ Confluence │ Notion │ Google Docs │ Git (MD) │
└──────┬───────────┬────────────┬──────────────────┘
│ │ │
▼ ▼ ▼
┌──────────────────────────────────────────────────┐
│ 수집 + 정제 레이어 │
│ - API 동기화 (변경분 감지) │
│ - HTML→Markdown 변환 │
│ - 메타데이터 추출 (작성자, 수정일, 라벨, 버전) │
│ - 이전 버전 아카이브 (검색 대상에서 제외) │
│ - 구조 정규화 (헤딩 레벨 통일, 섹션 구분선 삽입) │
└──────────────────┬───────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ 청킹 + 인덱싱 │
│ - 헤딩 기반 청킹 (## 단위로 분할) │
│ - 메타데이터 보존 (문서 제목, 스페이스, 태그) │
│ - 증분 인덱싱 (변경분만 재처리) │
│ - 하이브리드 인덱스 (BM25 + Dense) │
└──────────────────┬───────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────┐
│ 검색 + 활용 │
│ - Slack/Teams 봇: "결제 API 타임아웃 몇 초?" │
│ - AI Agent: 기획서 기반 코드 생성 │
│ - 온보딩 봇: 신규 입사자 질문 대응 │
│ - 장애 대응: 에러 메시지로 해결 방법 검색 │
└──────────────────────────────────────────────────┘
Aunque el proyecto y el entorno corporativo tienen la misma estructura, los requisitos operativos son diferentes:
1. Permisos de acceso (ACL)
Los derechos de acceso son diferentes para cada documento. Los ingenieros no deberían poder buscar documentos de recursos humanos.
→ Agregue el campo access_group a los metadatos fragmentados, filtrando al buscar
2. Registro de auditoría
Debe realizar un seguimiento de quién buscó qué.
→ Registro de consulta de búsqueda + resultados devueltos + ID de usuario
3. Enmascaramiento de PII (información personal)
La información personal incluida en el plan no debe ser expuesta como resultado de RAG.
→ Detección de PII antes de fragmentación + canalización de enmascaramiento agregada
4. Multiinquilino
Corpus independiente para cada equipo o corpus compartido + corpus dedicado para cada estructura de equipo.
→ Separe el corpus por espacio de nombres, filtre el espacio de nombres al buscar