Saltar al contenido
# Ejemplos Prácticos: Validación de Archivos en Klaus **Objetivo:** Mostrar cómo funciona la validación en UNA PASADA para diferentes tipos de archivos --- ## Caso 1: Archivo Python (CODE_PYTHON) ### Input ``` File: proxy/knowledge.py Size: 45 KB Content (first 100 chars): """Knowledge base — project file indexing and semantic Q&A via Qdrant. Colección separada del caché semántico... ``` ### Validación (Fase 1-3) ``` FASE 1: detect_file_category(file_path, content_sample) ├─ Extension check: .py │ └─ MATCH: CODE_PYTHON └─ Return: FileCategory.CODE_PYTHON FASE 2: should_index_file(file_path, category, content) ├─ Size check: 45 KB < 50 MB ✓ ├─ Category check: CODE_PYTHON │ └─ Policy: INDEX ✓ ├─ LLM response check: is_llm_response(content) │ └─ Pattern match: No LLM starters ✓ └─ Return: (True, "category_code_python_index") FASE 3: ChunkingPolicy.for_category(category) └─ Return: { strategy='ast', chunk_size=500, overlap=0, extract_symbols=True, preserve_structure=True, } ``` ### Chunking Result ``` File: proxy/knowledge.py Chunks: 15 (via AST parsing) ├─ Chunk 0: def _tokenize(text: str) → [lines 140-142] ├─ Chunk 1: def _sparse_vector(text: str) → [lines 145-158] ├─ Chunk 2: def is_llm_response(content: str) → [lines 161-184] ├─ Chunk 3: class ChunkingPolicy → [dataclass definition] ├─ Chunk 4: def embed_text(...) → [lines 187-211] ├─ Chunk 5: def _chunk_python(file_path, content) → [lines 233-286] ├─ Chunk 6: def _chunk_markdown(file_path, content) → [lines 289-312] ├─ Chunk 7: def chunk_file(...) → [lines 512-545] ├─ Chunk 8: async def search(...) → [lines 653-733] ├─ Chunk 9: async def search_with_expansion(...) → [lines 736-810] ├─ Chunk 10: async def store_chunk(...) → [lines 841-893] ├─ Chunk 11: async def format_response(...) → [lines 896-950] ├─ Chunk 12: def build_rag_context(...) → [lines 953-991] ├─ Chunk 13: async def get_stats() → [lines 1047-1058] └─ Chunk 14: async def flush() → [lines 1078-1089] Module-level code (imports, docstring): ├─ Chunk 15: Imports + module docstring → [lines 1-140] ``` ### Embedding & Storage ``` Chunk 0 (symbol: "_tokenize", type: "function") ├─ Semantic prefix: "proxy/knowledge.py: function _tokenize —" ├─ Full text: "proxy/knowledge.py: function _tokenize — def _tokenize(text..." ├─ Embed → vector (1536 dims) ├─ Quality score: 0.85 (function, >100 chars) ├─ Store in Qdrant: │ ├─ vector: [0.12, -0.34, 0.56, ...] │ ├─ payload: { │ │ file_path: "proxy/knowledge.py", │ │ chunk_index: 0, │ │ symbol_name: "_tokenize", │ │ symbol_type: "function", │ │ quality_score: 0.85, │ │ language: "python", │ │ } │ └─ id: uuid5("proxy/knowledge.py:0:...") └─ Status: STORED ✓ ``` ### Métricas Resultantes ``` proxy/knowledge.py: Category: CODE_PYTHON Indexer: ✓ YES Reason: category_code_python_index Strategy: ast Chunks: 15 Quality score: 0.92 (avg) Symbols: 13/15 extracted (87%) ``` --- ## Caso 2: Archivo YAML de Configuración (CONFIG_STRUCTURED) ### Input ``` File: config/kubernetes/deployment.yaml Size: 2.3 KB Content: apiVersion: apps/v1 kind: Deployment metadata: name: klaus-proxy namespace: default spec: replicas: 3 selector: matchLabels: app: klaus-proxy template: metadata: labels: app: klaus-proxy spec: containers: - name: proxy image: klaus-proxy:latest ports: - containerPort: 8080 env: - name: QDRANT_URL value: http://qdrant:6379 ``` ### Validación ``` FASE 1: detect_file_category(file_path, content_sample) ├─ Extension check: .yaml │ └─ MATCH: CONFIG_STRUCTURED └─ Return: FileCategory.CONFIG_STRUCTURED FASE 2: should_index_file(file_path, category, content) ├─ Size check: 2.3 KB < 50 MB ✓ ├─ Category check: CONFIG_STRUCTURED ├─ Filename heuristic: ".example"? ".sample"? NO ✓ ├─ LLM response check: is_llm_response(content) │ └─ Pattern match: No LLM starters ✓ └─ Return: (True, "category_config_structured_index") FASE 3: ChunkingPolicy.for_category(category) └─ Return: { strategy='semantic_section', chunk_size=1000, overlap=0, extract_symbols=True, preserve_structure=True, } ``` ### Chunking Result ``` File: config/kubernetes/deployment.yaml Chunks: 3 (semantic sections per top-level key) ├─ Chunk 0: apiVersion + kind + metadata │ ├─ Symbol: "metadata" │ ├─ Type: "key" │ └─ Content: "apiVersion: apps/v1\nkind: Deployment\nmetadata:\n..." │ ├─ Chunk 1: spec.replicas + spec.selector │ ├─ Symbol: "spec" │ ├─ Type: "key" │ └─ Content: "replicas: 3\nselector:\n matchLabels:\n..." │ └─ Chunk 2: spec.template.spec.containers ├─ Symbol: "containers" ├─ Type: "key" └─ Content: "containers:\n- name: proxy\n image: klaus-proxy:latest\n..." ``` ### Embedding & Storage ``` Chunk 0 (symbol: "metadata", type: "key") ├─ Semantic prefix: "config/kubernetes/deployment.yaml: key metadata —" ├─ Full text: "config/kubernetes/deployment.yaml: key metadata — apiVersion..." ├─ Embed → vector (1536 dims) ├─ Quality score: 0.78 (config, structured) ├─ Metadata: │ ├─ is_function: false │ ├─ is_docstring: false │ ├─ has_example: false │ ├─ complexity: "medium" │ ├─ file_type: "source" └─ Status: STORED ✓ ``` ### Búsqueda: ¿Cómo funciona la recuperación? Query: "¿Cuántas réplicas tiene el deployment?" ``` Vector search: Query text: "¿Cuántas réplicas tiene el deployment?" Query vector: [0.23, -0.15, 0.89, ...] (embedded) Dense search (cosine similarity): ├─ Score config/kubernetes/deployment.yaml:chunk_1: 0.82 ✓ MATCH │ └─ Contains "replicas: 3" ├─ Score config/kubernetes/deployment.yaml:chunk_0: 0.45 └─ Score other_file.yaml:chunk_X: 0.31 Sparse search (BM25): ├─ "deployment", "replicas", "kubernetes" are TF tokens └─ RRF fusion combines rankings Result: └─ config/kubernetes/deployment.yaml:chunk_1 (score: 0.82) Content: "replicas: 3" ``` --- ## Caso 3: Archivo de Test (TEST_FIXTURES) ### Input ``` File: tests/fixtures/mock_knowledge_base.json Size: 45 KB Content: { "test_data": [ { "file_path": "mock/test.py", "chunks": [ {"content": "def test_function(): pass", "score": 0.95}, ... ] } ] } ``` ### Validación ``` FASE 1: detect_file_category(file_path, content_sample) ├─ Directory heuristic: path contains "tests/" │ └─ MATCH: TEST_FIXTURES (if .json in tests/) ├─ Extension check: .json (but directory took precedence) └─ Return: FileCategory.TEST_FIXTURES FASE 2: should_index_file(file_path, category, content) ├─ Category check: TEST_FIXTURES │ └─ Policy: DO NOT INDEX │ Reason: "Mock data, not production code" └─ Return: (False, "category_test_fixtures_skip") SKIP RESULT: └─ File NOT ingested (saved from indexing noise) ``` ### Metrics ``` tests/fixtures/mock_knowledge_base.json: Category: TEST_FIXTURES Indexer: ❌ NO Reason: category_test_fixtures_skip Chunks: 0 (skipped) Status: SKIPPED ``` --- ## Caso 4: Imagen (BINARY_IMAGES) ### Input ``` File: docs/images/architecture.png Size: 1.2 MB Content: Binary data (PNG header: 89 50 4E 47...) ``` ### Validación ``` FASE 1: detect_file_category(file_path, content_sample) ├─ Extension check: .png │ └─ MATCH: BINARY_IMAGES └─ Return: FileCategory.BINARY_IMAGES FASE 2: should_index_file(file_path, category, content) ├─ Category check: BINARY_IMAGES │ └─ Policy: DO NOT INDEX │ Reason: "Non-textual content" └─ Return: (False, "category_binary_images_skip") SKIP RESULT: └─ File NOT read or processed (silent skip) ``` ### Metrics ``` docs/images/architecture.png: Category: BINARY_IMAGES Indexer: ❌ NO Reason: category_binary_images_skip Chunks: 0 (skipped) Status: SKIPPED (binary) ``` --- ## Caso 5: Markdown Documentation (DOCUMENTATION) ### Input ``` File: docs/INSTALLATION.md Size: 8.5 KB Content: # Installation Guide ## Prerequisites Before you begin, ensure you have: - Python 3.11+ - Docker & Docker Compose - 4GB RAM minimum ## Step 1: Clone Repository ```bash git clone https://github.com/yourorg/klaus.git cd klaus ``` ## Step 2: Install Dependencies ```bash pip install -r requirements.txt ``` ## Step 3: Configure Environment Copy `.env.example` to `.env`: ```bash cp .env.example .env ``` ``` ### Validación ``` FASE 1: detect_file_category(file_path, content_sample) ├─ Extension check: .md │ └─ MATCH: DOCUMENTATION └─ Return: FileCategory.DOCUMENTATION FASE 2: should_index_file(file_path, category, content) ├─ Size check: 8.5 KB < 50 MB ✓ ├─ Category check: DOCUMENTATION │ └─ Policy: INDEX ✓ ├─ LLM response check: is_llm_response(content) │ └─ "Install dependencies", "Clone repository" OK (not LLM starters) ✓ └─ Return: (True, "category_documentation_index") FASE 3: ChunkingPolicy.for_category(category) └─ Return: { strategy='heading', chunk_size=800, overlap=120, extract_symbols=True, preserve_structure=True, } ``` ### Chunking Result ``` File: docs/INSTALLATION.md Chunks: 5 (split by ## headings) ├─ Chunk 0: # Installation Guide + ## Prerequisites │ ├─ Symbol: "Prerequisites" │ ├─ Type: "section" │ └─ Content: "Before you begin, ensure you have:..." │ ├─ Chunk 1: ## Step 1: Clone Repository │ ├─ Symbol: "Step 1: Clone Repository" │ ├─ Type: "section" │ └─ Content: "```bash\ngit clone..." │ ├─ Chunk 2: ## Step 2: Install Dependencies │ ├─ Symbol: "Step 2: Install Dependencies" │ ├─ Type: "section" │ └─ Content: "```bash\npip install..." │ ├─ Chunk 3: ## Step 3: Configure Environment │ ├─ Symbol: "Step 3: Configure Environment" │ ├─ Type: "section" │ └─ Content: "Copy `.env.example` to `.env`:..." │ └─ Chunk 4: (Additional content if present) ``` ### Embedding & Storage ``` Chunk 0 (symbol: "Prerequisites", type: "section") ├─ Semantic prefix: "docs/INSTALLATION.md: section Prerequisites —" ├─ Full text: "docs/INSTALLATION.md: section Prerequisites — Before you begin..." ├─ Embed → vector (1536 dims) ├─ Quality score: 0.88 (documentation, has examples) ├─ Metadata: │ ├─ is_function: false │ ├─ is_docstring: true (requirements list) │ ├─ has_example: true (bullet points) │ ├─ complexity: "simple" │ ├─ file_type: "documentation" └─ Status: STORED ✓ ``` --- ## Caso 6: Archivo de Log (GENERATED_LOGS) ### Input ``` File: logs/ingest-2026-07-28.log Size: 250 MB Content: 2026-07-28 10:23:45.123 — INFO — Starting ingest 2026-07-28 10:23:46.234 — DEBUG — Processing file 1/9368 2026-07-28 10:23:47.345 — INFO — Chunk 0 stored 2026-07-28 10:23:48.456 — WARNING — Duplicate detected ... ``` ### Validación ``` FASE 1: detect_file_category(file_path, content_sample) ├─ Filename heuristic: ".log" in filename │ └─ MATCH: GENERATED_LOGS └─ Return: FileCategory.GENERATED_LOGS FASE 2: should_index_file(file_path, category, content) ├─ Size check: 250 MB > 50 MB ✗ │ └─ Return early: (False, "file_too_large:250.0MB") │ OR if under size limit: ├─ Category check: GENERATED_LOGS │ └─ Policy: DO NOT INDEX │ Reason: "Logs are volatile, temporal data" └─ Return: (False, "category_generated_logs_skip") SKIP RESULT: └─ File NOT ingested (volatile, no value) ``` ### Metrics ``` logs/ingest-2026-07-28.log: Category: GENERATED_LOGS Indexer: ❌ NO Reason: file_too_large:250.0MB (or category_generated_logs_skip) Chunks: 0 (skipped) Status: SKIPPED (volatile) ``` --- ## Caso 7: Template de Configuración (CONFIG_STRUCTURED + FILTRADO) ### Input ``` File: config/app.yaml.example Size: 1.5 KB Content: # Copy this to app.yaml and configure database: host: localhost port: 5432 username: PLACEHOLDER api: timeout: 30 retries: 3 ``` ### Validación ``` FASE 1: detect_file_category(file_path, content_sample) ├─ Extension check: .yaml │ └─ MATCH: CONFIG_STRUCTURED └─ Return: FileCategory.CONFIG_STRUCTURED FASE 2: should_index_file(file_path, category, content) ├─ Size check: 1.5 KB < 50 MB ✓ ├─ Category check: CONFIG_STRUCTURED ├─ Filename heuristic: ".example" in name │ └─ Detected as template/sample │ └─ Return: (False, "config_sample_skip") │ Reason: "Template configs are not real configs" │ └─ Return: (False, "config_sample_skip") SKIP RESULT: └─ File NOT ingested (is template, not production config) ``` ### Metrics ``` config/app.yaml.example: Category: CONFIG_STRUCTURED Indexer: ⚠️ CONDITIONAL (filtered) Reason: config_sample_skip Chunks: 0 (skipped) Status: SKIPPED (template) ``` --- ## Caso 8: Reporte de Validación Completo ### Full Run Output ```bash $ python scripts/ingest_all_with_validation.py --report-only 2026-07-28 14:32:15 — ingest — Phase 1: Discovering files... 2026-07-28 14:32:16 — ingest — Found 9368 files to validate 2026-07-28 14:32:17 — ingest — Phase 2: Validating files with policies... File Validation Stats Total: 9368 Indexed: 8328 (88.9%) Skipped: 1040 (11.1%) By Category: code_python 219 code_typescript 54 code_javascript 54 code_shell 75 code_other 60 documentation 742 config_structured 2854 config_unstructured 50 markup 52 styles 54 data_tabular 50 binary_images 130 binary_archives 250 binary_media 30 generated_logs 150 test_fixtures 300 vendored 3500 build_artifacts 100 Skip Reasons (top 10): category_vendored_skip 3500 category_test_fixtures_skip 300 category_binary_archives_skip 250 category_generated_logs_skip 150 category_binary_images_skip 130 category_data_tabular_skip 50 config_sample_skip 20 category_markup_skip 10 category_styles_skip 10 file_too_large 5 2026-07-28 14:32:45 — ingest — Report saved to ingest_validation_report.json ✓ Validation complete ✓ Indexation rate: 88.9% (good) ✓ All skip reasons are sensible ✓ Ready for production ingest ``` ### JSON Report ```json { "validation": { "total_files": 9368, "indexed": 8328, "skipped": 1040, "indexation_rate": 0.889, "by_category": { "code_python": 219, "code_typescript": 54, "documentation": 742, "config_structured": 2854, "vendored": 3500, "test_fixtures": 300, "binary_images": 130, "generated_logs": 150 }, "by_skip_reason": { "category_vendored_skip": 3500, "category_test_fixtures_skip": 300, "category_binary_images_skip": 130, "category_generated_logs_skip": 150 } }, "expected_metrics": { "avg_chunks_per_file": 4.3, "total_chunks": "~35,000", "search_latency_p99_ms": 150, "duplicate_rate_pct": 1.2 } } ``` --- ## Flujo Visual Completo (1 archivo) ``` INPUT: proxy/knowledge.py │ ├─ READ & SAMPLE (first 1000 chars) │ └─ Content: """Knowledge base — project file indexing...""" │ ├─ DETECT CATEGORY (Phase 1) │ ├─ Extension: .py ✓ │ └─ Result: CODE_PYTHON │ ├─ VALIDATE POLICY (Phase 2) │ ├─ Size: 45 KB < 50 MB ✓ │ ├─ Category: CODE_PYTHON → INDEX ✓ │ ├─ LLM Response: No patterns ✓ │ └─ Result: (True, "category_code_python_index") │ ├─ GET POLICY (Phase 3) │ └─ Result: ChunkingPolicy(strategy='ast', chunk_size=500, ...) │ ├─ CHUNK FILE (Phase 4) │ ├─ Parse AST │ ├─ Extract functions/classes: 13 symbols │ ├─ Module-level code: 1 block │ └─ Result: 14 chunks │ ├─ QUALITY CHECK (Phase 5) │ ├─ is_llm_response() for each chunk: None detected ✓ │ ├─ Length >= min_chunk_len: All OK ✓ │ └─ Result: 14/14 chunks pass │ ├─ EMBED CHUNKS (Phase 6) │ ├─ For each chunk: │ │ ├─ Semantic prefix: "proxy/knowledge.py: function {name} —" │ │ ├─ Full text with prefix │ │ ├─ Embed → vector (1536 dims) │ │ └─ Store in Qdrant │ └─ Result: 14 vectors stored │ └─ OUTPUT METRICS ├─ File: proxy/knowledge.py ├─ Category: CODE_PYTHON ├─ Indexed: ✓ YES ├─ Chunks stored: 14 ├─ Avg quality: 0.87 └─ Symbols extracted: 13/14 (93%) ``` --- ## Interpretación de Resultados ### "¿Debería haber más archivos indexados?" ``` Indexation rate: 88.9% Expected: 75-95% Analysis: ✓ 88.9% está en el rango esperado ✓ Los 11.1% skipped son categorías sensatas (vendored, tests, binaries, logs) Conclusión: Distribución CORRECTA ``` ### "¿Por qué tanto vendored skipped?" ``` category_vendored_skip: 3500 files (37%) Reason: - node_modules/: ~2500 files (npm packages) - vendor/: ~500 files (PHP packages) - dist/, build/: ~500 files (compiled output) Conclusion: ESPERADO — código externo, no proyecto No es contenido a indexar ``` ### "¿Qué significa chunks_stored: 35,891?" ``` 8,328 indexed files × 4.3 avg chunks/file = 35,891 chunks Breakdown: - CODE: ~1,100 files × 8 chunks = 8,800 chunks - DOCS: ~740 files × 3 chunks = 2,220 chunks - CONFIG: ~2,854 files × 1.5 chunks = 4,281 chunks - Module code: Various = ~20,590 chunks Total: ~35,891 ✓ Average chunk size: ~12 KB (45 MB / 35,891 chunks) Reasonable: 8 KB - 15 KB per chunk is good ``` --- ## Summary Para los 8 casos anteriores: | Tipo de Archivo | Ejemplo | Categoría | Indexado | Chunks | Razón | |---|---|---|---|---|---| | Python source | knowledge.py | CODE_PYTHON | ✓ | 14 | High semantic value | | YAML config | deployment.yaml | CONFIG_STRUCTURED | ✓ | 3 | Schema patterns | | Test fixture | mock_knowledge.json | TEST_FIXTURES | ❌ | 0 | Mock data noise | | Binary image | architecture.png | BINARY_IMAGES | ❌ | 0 | Non-textual | | Markdown | INSTALLATION.md | DOCUMENTATION | ✓ | 5 | Critical docs | | Log file | ingest.log | GENERATED_LOGS | ❌ | 0 | Volatile | | Config template | app.yaml.example | CONFIG_STRUCTURED | ❌ | 0 | Template, not real | | **Totales** | **9,368 files** | **18 categories** | **8,328 (89%)** | **35,891** | **Production ready** |