Saltar al contenido
# 📚 Knowledge Base — klaude-proxy ## 🤔 ¿Qué hago? ¿Cómo lo hago? ¿Y para qué lo hago? **¿Qué hago?** Indexo los ficheros de un proyecto (documentación y código fuente) en una colección Qdrant separada llamada `klaude_knowledge`. Cuando el usuario hace una pregunta sobre el proyecto, inyecto los fragmentos más relevantes como contexto RAG en el system prompt y llamo al LLM externo para generar la respuesta con conocimiento del proyecto. **¿Cómo lo hago?** El dashboard ofrece un botón **📚 Knowledge** que abre un modal. Mediante la File System Access API del navegador, el usuario selecciona una carpeta local. El JavaScript lee los ficheros con las extensiones configuradas, los divide en *chunks* semánticos y los envía al endpoint `POST /knowledge/ingest`. El proxy embebe cada chunk con `nomic-ai/nomic-embed-text-v1.5` y lo almacena en Qdrant con su ruta de fichero y posición. En cada petición a `/v1/messages`, después de buscar en el caché semántico y antes de llamar al LLM externo, el proxy busca en `klaude_knowledge` mediante búsqueda híbrida (BM25 + dense, RRF fusion). Si hay resultados sobre el umbral (0.75 por defecto), inyecta los chunks en el system prompt como bloque de contexto RAG y llama al LLM. La respuesta lleva header `X-Cache: KNOWLEDGE-RAG`. **¿Para qué lo hago?** Para enriquecer las respuestas del LLM con conocimiento específico del proyecto. Cuando Claude Code está abierto dentro de un proyecto y el usuario pregunta sobre la arquitectura, APIs internas o configuración, el proxy incluye automáticamente los fragmentos de documentación más relevantes en el contexto — sin que el usuario tenga que copiarlos manualmente. --- ## 🗺️ Flujo de datos ```mermaid flowchart TD U[Usuario] -->|Selecciona carpeta| B[Dashboard JS\nFile System Access API] B -->|Lee ficheros .md .py .sh .yml .yaml .json| C[Chunking JS] C -->|POST /knowledge/ingest\nbatch 20 chunks| D[Endpoint FastAPI] D -->|get_embedding - nomic ONNX| E[Qdrant\nklaude_knowledge] subgraph Petición runtime R[Request /v1/messages] --> S1[Semantic Cache Search] S1 -->|score ≥0.98 directo| HIT[X-Cache: HIT] S1 -->|score ≥0.87 RAG| CRAG[Inyectar cache\nen system prompt] CRAG --> LLM_C[Anthropic API\nX-Cache: CACHE-RAG] S1 -->|MISS| S2[Knowledge Search\nhíbrida BM25+dense] S2 -->|chunks ≥0.75| KRAG[Inyectar knowledge\nen system prompt] KRAG --> LLM_K[Anthropic API\nX-Cache: KNOWLEDGE-RAG] S2 -->|MISS| LLM[Anthropic API\nX-Cache: MISS] end E --> S2 ``` --- ## ⚙️ Configuración | Variable de entorno | Default | Descripción | | --- | --- | --- | | `KNOWLEDGE_SIMILARITY_THRESHOLD` | `0.75` | Umbral de similitud coseno para KB hits | > El umbral 0.75 es deliberadamente más permisivo que el caché semántico (0.87) para maximizar el recall en documentación técnica donde el rephrase es mayor. --- ## 📂 Extensiones indexadas | Extensión | Estrategia de chunking | | --- | --- | | `.md` | Por secciones `##` (preserva contexto semántico), sub-chunks de 800 chars | | `.py` | Bloques de 500 chars con 100 overlap, split en doble newline | | `.sh` | Bloques de 500 chars con 100 overlap | | `.yml` / `.yaml` | Bloques de 500 chars con 100 overlap | | `.json` | Bloques de 500 chars con 100 overlap | ### 🚫 Directorios excluidos automáticamente (`KB_SKIP_DIRS`) `.git`, `node_modules`, `__pycache__`, `.venv`, `venv`, `dist`, `build`, `.claude`, `target`, `.mypy_cache`, `.pytest_cache`, **`tests`**, **`test`**, **`__tests__`**, **`spec`**, **`specs`** > ⚠️ **Por qué se excluye `tests/`**: Los scripts de test funcional (`test_cache_semantic*.sh`) contienen preguntas hardcodeadas como strings de `call_proxy()` y payloads JSON de API. Si se indexaran, la colección acumularía "solicitudes del agente" en lugar de documentación real. Al indexarlas, el KB intercepta las peticiones reales vía `KNOWLEDGE HIT` antes de que lleguen a Anthropic, impidiendo que las respuestas se guarden en `klaude_cache`. (Diagnóstico: [GH-78](https://github.com/Ka0s-Klaus/klaude-code-local/issues/78)) ### 🚫 Ficheros excluidos automáticamente (`KB_SKIP_FILES`) `CLAUDE.md` > ⚠️ El fichero `CLAUDE.md` contiene configuración del agente (instrucciones de sesión, contexto del proyecto para Claude Code). No es documentación del proyecto y su contenido queda obsoleto rápidamente — indexarlo contaminaría el KB con metadatos de agente en lugar de conocimiento técnico útil. --- ## 🛡️ Filtros anti-contaminación El sistema tiene **dos capas de defensa** para evitar que contenido no útil contamine `klaude_knowledge`: ```mermaid flowchart LR F[Fichero del proyecto] --> L1{Capa 1: JS\nKB_SKIP_DIRS\nKB_SKIP_FILES} L1 -->|excluido| SKIP1[❌ No se envía al proxy] L1 -->|permitido| L2{Capa 2: Python\nis_llm_response} L2 -->|chunk sospechoso| SKIP2[❌ skipped en ingest] L2 -->|chunk legítimo| STORE[✅ Indexado en Qdrant] ``` | Capa | Dónde | Qué filtra | | --- | --- | --- | | 🥇 **KB_SKIP_DIRS** | JS dashboard | Directorios de test, build, entornos virtuales | | 🥇 **KB_SKIP_FILES** | JS dashboard | Ficheros de configuración del agente (`CLAUDE.md`) | | 🥈 **`is_llm_response()`** | Python backend | Meta-respuestas LLM, frases de compactación, payloads de API hardcodeados en scripts de test | La capa JS es la defensa primaria (más eficiente — evita el RTT al proxy). La capa Python es una segunda línea que captura contenido que pudiera colarse por ficheros con extensión legítima (p.ej. un `.py` que genere payloads de test). --- ## 🔌 Endpoints API ### `POST /knowledge/ingest` Recibe chunks pre-procesados del dashboard y los embebe + almacena en Qdrant. **Body:** ```json { "chunks": [ {"content": "texto del fragmento", "file_path": "docs/arquitectura.md", "chunk_index": 0}, {"content": "...", "file_path": "proxy/main.py", "chunk_index": 1} ] } ``` **Response:** ```json {"stored": 42, "skipped": 3, "failed": 0, "total": 45} ``` > `skipped` cuenta los chunks rechazados por `is_llm_response()` — chunks que el backend detecta como meta-respuestas del LLM o payloads de scripts de test. ### `GET /knowledge/stats` ```json {"collection": "klaude_knowledge", "points_count": 312, "status": "Green"} ``` ### `DELETE /knowledge/flush` Requiere header `x-api-key`. Borra y recrea la colección `klaude_knowledge`. ```bash curl -X DELETE -H "x-api-key: test" http://192.168.1.50:8080/knowledge/flush ``` --- ## 📊 Dashboard El botón **📚 Knowledge** en el header abre un modal con: | Elemento | Descripción | | --- | --- | | 📁 Seleccionar carpeta | `<input webkitdirectory>` — Firefox, Chrome, Edge, Safari | | 🗑️ Borrar KB | Llama a DELETE /knowledge/flush | | Progress bar | Progreso de upload en batches de 20 chunks | | Status text | Feedback en tiempo real del estado de indexación | La sidebar muestra el contador de **chunks indexados** (actualización cada 5s) y el contador **KB HIT** de la sesión. Los logs live muestran `KNOWLEDGE HIT` en color **púrpura** (`#a78bfa`). --- ## 🔒 Seguridad - El endpoint `/knowledge/ingest` no requiere autenticación (solo añade datos, no los expone). - El endpoint `/knowledge/flush` requiere `x-api-key` (operación destructiva). - El proxy no expone el contenido indexado a través de ningún endpoint de listado — solo búsqueda por similitud. - Los ficheros se leen localmente en el navegador del usuario — **no se envían a ningún servicio externo**. --- ## 📁 Ficheros relacionados | Fichero | Rol | | --- | --- | | [`proxy/knowledge.py`](../proxy/knowledge.py) | Módulo: colección Qdrant, search, store, format_response, stats, flush | | [`proxy/main.py`](../proxy/main.py) | Endpoints REST + integración en /v1/messages + dashboard HTML | | [`proxy/config.py`](../proxy/config.py) | `knowledge_similarity_threshold` | | [`proxy/embeddings.py`](../proxy/embeddings.py) | `get_embedding()` — compartido con el caché semántico | | [`proxy/cache.py`](../proxy/cache.py) | `get_client()` — cliente Qdrant compartido | 🔗 Ver también: [`cache.md`](cache.md) — caché semántico (colección `klaude_cache`)