Arquitectura
Las notas entran por un observador y una cola de tareas; las preguntas vuelven como citas con rangos de líneas. Cada recuadro nombra el archivo que lo implementa.
En una pantalla estrecha, lee la tabla de cada parte en lugar de los dibujos.
Los dos flujos
Recuperación, citas y evaluación solo necesitan Postgres y Ollama para los embeddings. Un modelo de lenguaje añade la respuesta escrita en ask. Corre con Docker Compose o de forma nativa con unidades systemd; la GPU se usa por Vulkan cuando existe /dev/dri y nunca es obligatoria. Los mensajes del programa, como No evidence found for that query., se quedan en inglés porque son la salida literal. Fuente: core/README.md, core/docs/running.md.
Los componentes que hay detrás
El mismo sistema, agrupado por capa. Se lee de arriba abajo: cada capa llama a la de abajo, y la fila del final la usan todas. Cada recuadro es un archivo o un paquete dentro de core/src/knowman/.
La flecha de la izquierda va de la capa que llama a la capa de la que depende. Configuración, control de acceso y registro van al final porque todas las capas de arriba los leen. Fuente: core/src/knowman/, core/README.md, core/docs/running.md.
Cada parte
Los nombres de la columna Parte están traducidos. Los nombres de la columna Código son los archivos y ajustes reales.
| Parte | Código | Estado | Qué hace |
|---|---|---|---|
| Notas (.md) | carpeta CORPUS_PATH | real | Tu carpeta Markdown. La indexación nunca la modifica; solo el agente escribe en ella. |
| Observador | watcher.py | real | Convierte cada archivo .md añadido, editado o borrado en una tarea. |
| Cola de tareas | store.py | real | Las tareas son filas en Postgres: ingest_path y delete_path, con estado pending, processing, done o failed. |
| Procesador | worker.py | real | Toma una tarea a la vez y la ejecuta; una tarea fallida queda registrada, no se reintenta en silencio. |
| Fragmentador | chunking.py, ingest.py | real | Corta en líneas vacías conservando el rango de líneas de cada fragmento; ingest.py calcula los embeddings y guarda los fragmentos. |
| Embeddings | embeddings/base.py, embeddings/ollama.py | real | Ollama convierte cada fragmento en un vector (modelo en EMBEDDINGS_MODEL). Una interfaz, una implementación. |
| Postgres + pgvector | store.py | real | Guarda fragmentos, tareas, corridas de eval y trazas. Índice HNSW cosine sobre la columna embedding. |
| Embed consulta | retrieval.py | real | Convierte la pregunta en un vector con el mismo modelo. |
| Fragmentos cercanos | store.py | real | Devuelve los k fragmentos más cercanos (k por defecto viene de RETRIEVAL_DEFAULT_K). |
| Filtro de distancia | retrieval.py | real | Descarta los fragmentos que están más lejos que RETRIEVAL_MAX_DISTANCE. Un resultado vacío es el negativo explícito. |
| Citas | retrieval.py | real | Cada cita lleva ruta, línea inicial, línea final, texto y distancia. |
| Formato | formatting.py | real | Escribe una cita como path:Lstart-Lend más su pasaje, y un resultado vacío como "No evidence found for that query." |
| Respuesta del LLM | ask.py, llm/*.py | opcional | Solo cuando LLM_PROVIDER está definido (Ollama, Claude, OpenAI o Grok) y hay evidencia. search y eval nunca lo necesitan. |
| Prompts | prompts/ask_v1.txt | opcional | La plantilla con la que se redacta la respuesta; PROMPT_VERSION elige el archivo, así que un texto nuevo es un archivo nuevo, no un cambio de código. |
| Evaluación | eval.py, evaldata/dataset.json | real | Puntúa un dataset etiquetado contra la recuperación; ningún modelo juzga a otro modelo. |
| Agente | agent.py | opcional | knowman write: un agente LangGraph sobre Ollama que puede buscar en las notas y escribir una nueva. |
| CLI | cli.py | real | db-init, ingest, search, ask, eval, worker, watch, mcp, write. |
| API HTTP | api.py | real | Search, ask, eval, tareas de indexación, estado; API_TOKEN y límite de tasa opcionales. |
| Control de acceso | access.py | real | La comprobación del token y el contador de peticiones por minuto detrás de esas dos opciones. Ambas están apagadas si no se definen, y ninguna sabe qué hacen search o ask. |
| Servidor MCP | mcp_server.py | real | Dos herramientas de solo lectura por stdio: search y ask. |
| Panel | dashboard.py | real | Una página en /dashboard: índice contra disco, cola de tareas, última evaluación, actividad reciente. |
| Configuración | config.py | real | Un único objeto Settings leído del entorno y de .env; cada módulo se lo pide en vez de parsear variables. |
| Registro | logging_setup.py | real | Logs JSON en stdout, un registro por línea, para que los contenedores y las unidades systemd registren la misma forma. |