Saltar al contenido
# Runbook: Validación Diferenciada de Archivos en Klaus **Objetivo:** Implementar políticas diferenciadas para indexación de archivos (9K+ archivos, 9.5GB) **Componentes:** `proxy/file_validator.py`, `scripts/ingest_all_with_validation.py` **Documentación:** `docs/MATRIZ_POLITICAS_INDEXACION.md` --- ## I. DESCRIPCIÓN GENERAL Klaus ahora categoriza automáticamente archivos en **18 categorías semánticas** y aplica políticas diferenciadas de: - **Chunking:** Tamaño, estrategia (AST, heading, semantic sections) - **Embedding:** Prefijo semántico, modelo - **Filtrado:** Qué indexar/saltar con razones explícitas Todo se valida en **UNA PASADA** (single-pass) sin re-lectura de archivos. --- ## II. INSTALACIÓN Y SETUP ### Paso 1: Copiar archivos Los siguientes archivos ya están en el repositorio: ``` proxy/file_validator.py # Detector de categoría + políticas scripts/ingest_all_with_validation.py # Ingestor con validación docs/MATRIZ_POLITICAS_INDEXACION.md # Documentación completa docs/RUNBOOK_VALIDACION_INDEXACION.md # Este archivo ``` ### Paso 2: Verificar importación En `proxy/knowledge.py`, el ingestor ya importa `is_llm_response()`. Validar que exista: ```python # en knowledge.py, línea ~161 def is_llm_response(content: str) -> bool: """Rechaza chunks que parecen respuestas LLM, no código/docs.""" ... ``` ### Paso 3: Test rápido (sin ingestión) ```bash cd /Users/asantacana/proyectos/klaus-proxy-global # Test del validador en modo reporte (no ingestión) python scripts/ingest_all_with_validation.py --report-only # Salida esperada: # - Reporte en ingest_validation_report.json # - Logs mostrando categorización de archivos ``` --- ## III. FLUJO DE VALIDACIÓN (UNA PASADA) ### Fase 1: Descubrimiento de archivos ``` discover_files(root_path) ├─ Itera sobre directorios ├─ Salta: .git, node_modules, __pycache__, .venv, dist, build, tests, etc. └─ Retorna: lista ordenada de archivos ``` ### Fase 2: Categorización (extension + heurísticos) Para **cada archivo**: ```python category = detect_file_category(file_path, content_sample) # Retorna: FileCategory enum (18 opciones) ``` Orden de decisión: 1. **Extensión** (rápido, .py → CODE_PYTHON) 2. **Directorio** (vendored → skip, tests → test fixtures) 3. **Nombre archivo** (.log, .sample → special handling) 4. **Contenido** (JSON structure, YAML colons, etc.) — fallback ### Fase 3: Aplicación de política ```python should_index, reason = should_index_file( file_path, category, content, # Contenido completo para LLM response check max_size_mb=50 ) # Retorna: (bool, reason_string) ``` Decisiones por categoría: | Categoría | Indexar | Razón | |---|---|---| | CODE_* | ✓ SÍ | High semantic value | | DOCUMENTATION | ✓ SÍ | Context critical | | CONFIG_STRUCTURED | ✓ SÍ (filtrado) | Schema patterns, pero skip .sample | | CONFIG_UNSTRUCTURED | ❌ NO | Noise | | MARKUP | ❌ NO | Tag noise | | STYLES | ❌ NO | Low semantics | | DATA_TABULAR | ❌ NO | Bloat (>1MB) | | BINARY_* | ❌ NO | Non-textual | | LOGS | ❌ NO | Volatile | | TEST_FIXTURES | ❌ NO | Mock data noise | | VENDORED | ❌ NO | External code | | BUILD_ARTIFACTS | ❌ NO | Compiled binaries | ### Fase 4: Resolución de política de chunking ```python policy = ChunkingPolicy.for_category(category) # Retorna: {strategy, chunk_size, overlap, extract_symbols, ...} ``` Ejemplos: ```python # CODE_PYTHON policy = ChunkingPolicy( strategy='ast', # AST parsing chunk_size=500, # Max per def overlap=0, # No overlap (boundaries) extract_symbols=True, # Get func/class names ) # DOCUMENTATION policy = ChunkingPolicy( strategy='heading', # Split by ## headings chunk_size=800, # Per subsection overlap=120, # Preserve context extract_symbols=True, # Get heading as symbol ) # CONFIG_STRUCTURED policy = ChunkingPolicy( strategy='semantic_section', # Split by top-level keys chunk_size=1000, overlap=0, extract_symbols=True, # Get key path (db.connection.host) ) ``` --- ## IV. USO: TRES MODOS ### Modo 1: Validación Solamente (Reporte) **Genera reporte SIN ingestión:** ```bash python scripts/ingest_all_with_validation.py --report-only ``` **Salida:** ``` File Validation Stats Total: 1234 Indexed: 1100 (89.1%) Skipped: 134 (10.9%) By Category: code_python 234 documentation 89 config_structured 234 test_fixtures 15 vendored 100 binary_images 50 ... Skip Reasons (top 10): category_vendored_skip 100 category_test_fixtures_skip 50 config_sample_skip 20 category_data_tabular_skip 15 ... ``` **Archivo generado:** `ingest_validation_report.json` ```json { "validation": { "total_files": 1234, "indexed": 1100, "skipped": 134, "indexation_rate": 0.891, "by_category": {...}, "by_skip_reason": {...} } } ``` ### Modo 2: Ingestión Proxy Solamente (Debug) **Ingesta solo `proxy/` para testing rápido:** ```bash python scripts/ingest_all_with_validation.py --proxy-only ``` **Flujo:** 1. Descubre ~50-100 archivos en proxy/ 2. Valida cada uno con políticas 3. Ingestiona archivos aprobados 4. Reporta: chunks_stored, chunks_skipped, chunks_failed ### Modo 3: Ingestión Full (Producción) **Opción A: Flush + Re-ingestión (limpia el KB primero)** ```bash python scripts/ingest_all_with_validation.py --flush ``` **Flujo:** 1. Elimina todos los puntos en Qdrant 2. Descubre ~9K archivos 3. Valida cada uno 4. Ingestiona en paralelo (rate-limited, 0.2s entre archivos) **Opción B: Ingestión incremental (agrega a lo existente)** ```bash python scripts/ingest_all_with_validation.py ``` --- ## V. INTERPRETACIÓN DE RESULTADOS ### Reporte: Total vs. Indexation Rate ``` Total: 1234 files Indexed: 1100 (89.1%) Skipped: 134 (10.9%) ``` **Análisis:** - **89% es bueno** para proyectos reales (contienen binarios, tests, etc.) - **Si < 75%:** Revisar `by_skip_reason` (posible over-filtering) - **Si > 95%:** Posible bajo-filtering (incluir noise) ### Skip Reasons: Red Flags **Normal/Esperado:** - `category_vendored_skip` — node_modules, vendor/ - `category_test_fixtures_skip` — /tests/fixtures/ - `category_binary_images_skip` — .png, .jpg - `category_generated_logs_skip` — .log **Inesperado (revisar):** - `category_config_structured_skip` — Muchos (revisar si hay .sample templates) - `llm_response_contamination` — Muy alto (revisar si docs generadas indexadas) - `config_sample_skip` — Múltiples (normal si hay template configs) ### By Category: Distribución esperada Para un proyecto típico (9K files): ``` code_python ~219 (2%) — Small but critical code_typescript ~54 (0.6%) — High value code_javascript ~54 (0.6%) code_shell ~75 (0.8%) code_other ~60 (0.6%) documentation ~742 (8%) — Important config_structured ~2854 (30%) — Large, filtered config_unstructured ~50 (0.5%) — Skipped markup ~52 (0.5%) — Skipped styles ~54+ (0.6%) — Skipped test_fixtures ~300 (3%) — Skipped vendored ~3500 (37%) — Skipped binary_images ~130 (1.4%) — Skipped generated_logs ~100+ (1%) — Skipped build_artifacts ~50+ (0.5%) — Skipped --- TOTAL INDEXED: ~4000 (43%) TOTAL SKIPPED: ~5300 (57%) ``` **Validar:** - Code + docs + config_structured = indexed files (should be ~4K) - Everything else = skipped (should be ~5K) --- ## VI. CUSTOMIZACIÓN DE POLÍTICAS ### Cambiar umbral de tamaño máximo **Actual:** 50 MB por archivo ```python # En scripts/ingest_all_with_validation.py, función validate_file(): should_index, reason = should_index_file( rel_path, category, content, max_size_mb=50 # ← CAMBIAR AQUÍ ) ``` Recomendaciones: - **< 5MB:** Estricto (solo contenido crítico) - **5-50MB:** Balanceado (actual) - **> 50MB:** Permisivo (pero cuidado con bloat) ### Cambiar categoría de skip a index Ejemplo: Si quieres indexar CSS para búsqueda de estilos: ```python # En proxy/file_validator.py, función should_index_file(): if category == FileCategory.STYLES: # Cambiar de: # return False, "category_styles_skip" # A: return True, "category_styles_index" # Y ajustar política de chunking: FileCategory.STYLES: ChunkingPolicy( strategy='rule_group', chunk_size=200, # Conservador (pocos caracteres por regla) overlap=30, min_chunk_len=50, # Requiere reglas no-vacías extract_symbols=True, # Extraer selectores CSS preserve_structure=True, ) ``` ### Agregar nueva categoría Ejemplo: Indexar Dockerfiles ```python # 1. En proxy/file_validator.py: class FileCategory(enum.Enum): # Agregar: CODE_DOCKERFILE = "code_dockerfile" # 2. En detect_file_category(): if ext == 'dockerfile' or 'dockerfile' in path_lower: return FileCategory.CODE_DOCKERFILE # 3. En should_index_file(): if category == FileCategory.CODE_DOCKERFILE: return True, "category_code_dockerfile_index" # 4. En ChunkingPolicy.for_category(): FileCategory.CODE_DOCKERFILE: ChunkingPolicy( strategy='fixed', chunk_size=400, overlap=50, min_chunk_len=40, extract_symbols=True, # Extract FROM, RUN commands preserve_structure=False, ), ``` --- ## VII. DIAGNÓSTICO Y TROUBLESHOOTING ### Problema: Demasiados archivos skipped **Síntomas:** ``` Indexed: 500 (5%) Skipped: 9500 (95%) ``` **Causas probables:** 1. Demasiados binarios (normal si hay imágenes, videos) 2. Muchos archivos de configuración template (.sample, .example) 3. Directorio vendored no excluido correctamente **Solución:** ```bash # Ver qué está siendo skipped python scripts/ingest_all_with_validation.py --report-only # Analizar ingest_validation_report.json: cat ingest_validation_report.json | jq '.validation.by_skip_reason' | sort -k2 -nr ``` ### Problema: Chunks muy grandes o muy pequeños **Síntomas:** ``` Warning: chunk 0 in file.py is 5000 chars (expected ~500) Warning: chunk 1 in file.py is 20 chars (expected ~40 min) ``` **Análisis:** 1. Verificar archivo problemático: ```bash ls -lh <archivo problemático> ``` 2. Si muy grande: ajustar chunk_size para esa categoría 3. Si muy pequeño: aumentar min_chunk_len ### Problema: LLM contamination alta **Síntomas:** ``` Quality issue: llm_response_contamination in docs/FAQ.md Quality issue: llm_response_contamination in docs/EXAMPLES.md ``` **Causa:** Documentación generada por LLM indexada (contiene patrones de respuesta LLM) **Solución:** 1. Revisar archivos marcados en `quality_issues` del reporte 2. Editar archivos para remover patrones LLM (ej: "Aquí está...", "He utilizado...") 3. Re-ingestionar: ```bash python scripts/ingest_all_with_validation.py --flush ``` ### Problema: Búsqueda lenta después de ingestión **Síntomas:** - Latencia de búsqueda > 500ms (esperado: < 200ms) - Muchos chunks sin relevancia **Análisis:** ```python # En proxy/knowledge.py, check query latency: start = time.time() results = await search(query_vector, query_text, top_k=5) latency = (time.time() - start) * 1000 log.info(f"Search latency: {latency:.0f}ms") ``` **Soluciones:** 1. Verificar cantidad de puntos en KB: ```bash curl http://192.168.1.127:8080/knowledge/stats # Esperado: < 50K puntos para 9K archivos ``` 2. Si > 100K puntos: hay duplicados o over-chunking ```bash # Flush y re-ingest con políticas más estrictas python scripts/ingest_all_with_validation.py --flush ``` 3. Si latencia alta pero puntos normales: indexar es OK ```bash # Problema es búsqueda, no ingestión (revisa Qdrant config) ``` --- ## VIII. MÉTRICAS DE MONITOREO Después de cada ingestión, validar estas métricas: ```python # Script para generar dashboard (opcional) import json with open('ingest_validation_report.json') as f: report = json.load(f) metrics = { 'indexation_rate': report['validation']['indexation_rate'], 'total_files': report['validation']['total_files'], 'indexed_files': report['validation']['indexed'], 'skipped_files': report['validation']['skipped'], 'avg_chunks_per_file': report['ingest']['chunks_stored'] / max(1, report['validation']['indexed']), 'skip_ratio': report['validation']['skipped'] / report['validation']['total_files'], } print(f"Indexation Rate: {metrics['indexation_rate']:.1%}") print(f"Avg Chunks/File: {metrics['avg_chunks_per_file']:.1f}") print(f"Skip Ratio: {metrics['skip_ratio']:.1%}") # Alertas if metrics['indexation_rate'] < 0.75: print("⚠️ WARNING: Low indexation rate") if metrics['skip_ratio'] > 0.5: print("⚠️ WARNING: More than 50% files skipped") ``` --- ## IX. INTEGRACIÓN CON CI/CD ### GitHub Actions (ejemplo) ```yaml name: KB Validation on: push: branches: [main] paths: - 'proxy/**' - 'docs/**' - 'scripts/**' - '.github/workflows/kb-validation.yml' jobs: validate: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Set up Python uses: actions/setup-python@v4 with: python-version: '3.11' - name: Install deps run: pip install httpx pydantic - name: Run KB validation run: python scripts/ingest_all_with_validation.py --report-only - name: Upload report uses: actions/upload-artifact@v3 with: name: kb-validation-report path: ingest_validation_report.json ``` ### Manual trigger (para ingestión) ```bash # En producción, después de code review + merge: # 1. Validación solamente (sin riesgo) python scripts/ingest_all_with_validation.py --report-only # 2. Revisar reporte cat ingest_validation_report.json | jq '.validation' # 3. Si todo OK: ingestión completa python scripts/ingest_all_with_validation.py --flush ``` --- ## X. CASOS DE USO COMUNES ### Case 1: Agregar nuevo proyecto a Klaus ```bash # Proyecto ubicado en: ~/src/nuevo-proyecto/ # 1. Symlink o copy ln -s ~/src/nuevo-proyecto ./projects/nuevo-proyecto # 2. Validar (sin ingestión) python scripts/ingest_all_with_validation.py --report-only # 3. Revisar report # ¿Indexation rate > 75%? ✓ # ¿Skip reasons sensatos (binarios, tests, etc.)? ✓ # 4. Ingestionar python scripts/ingest_all_with_validation.py ``` ### Case 2: Remover ruido (re-clean KB) ```bash # Síntomas: búsqueda devuelve resultados irrelevantes # 1. Identificar categorías ruidosas python scripts/ingest_all_with_validation.py --report-only # 2. Ajustar should_index_file() para ser más estricto # Ej: skip CONFIG_UNSTRUCTURED en lugar de indexar # 3. Flush + re-ingest python scripts/ingest_all_with_validation.py --flush ``` ### Case 3: Aumentar cobertura (indexar más) ```bash # Síntomas: búsquedas específicas no encuentran respuestas # 1. Analizar qué categorías se están saltando python scripts/ingest_all_with_validation.py --report-only # ¿Muchos CONFIG_UNSTRUCTURED skipped? ¿MARKUP? # 2. Cambiar should_index_file() para indexar esa categoría # 3. Ajustar chunking policy si es necesario # 4. Test incremental (sin flush) python scripts/ingest_all_with_validation.py --proxy-only ``` --- ## XI. REFERENCIA RÁPIDA ### Comandos más comunes ```bash # Validación solamente (reporte, sin ingestión) python scripts/ingest_all_with_validation.py --report-only # Ingestión proxy/ solamente (debug) python scripts/ingest_all_with_validation.py --proxy-only # Ingestión full + flush anterior python scripts/ingest_all_with_validation.py --flush # Ingestión incremental (agrega a existente) python scripts/ingest_all_with_validation.py ``` ### Inspeccionar reporte ```bash # Ver por categoría jq '.validation.by_category | to_entries | sort_by(.value) | reverse' ingest_validation_report.json # Ver por skip reason jq '.validation.by_skip_reason | to_entries | sort_by(.value) | reverse' ingest_validation_report.json # Ver indexation rate jq '.validation.indexation_rate' ingest_validation_report.json ``` ### Check KB health ```bash # Total de puntos curl -s http://192.168.1.127:8080/knowledge/stats | jq '.points_count' # Por categoría (si está implementado) curl -s http://192.168.1.127:8080/knowledge/stats/by_category | jq '.' ``` --- ## XII. CHANGELOG ### Version 1.0 (2026-07-28) - ✓ Single-pass file categorization (18 categories) - ✓ Differentiated chunking policies per category - ✓ Automatic filtering (binaries, logs, test fixtures, vendored) - ✓ LLM response contamination detection - ✓ Validation statistics and reporting - ✓ Integration with existing ingest_all.py ### Planned for v1.1 - [ ] Per-category embedding model selection (code-aware vs general) - [ ] Dynamic threshold adjustment based on category - [ ] Dashboard for KB health metrics - [ ] Automated re-ingest on quality issues --- ## SOPORTE Si encuentras problemas: 1. **Revisar documentación principal:** `docs/MATRIZ_POLITICAS_INDEXACION.md` 2. **Inspeccionar reporte:** `ingest_validation_report.json` 3. **Ejecutar con debug:** ```python # En proxy/file_validator.py, línea ~100: log.setLevel(logging.DEBUG) ``` 4. **Contactar:** Team Klaus/Indexing