rag-service/docs/OPERATIVA.md

15 KiB

Operativa del servicio RAG

Modulo: RAG Ultima actualizacion: 2026-09-24 Version: 1.6


Este documento registra los hechos operativos del servicio RAG: la configuracion vigente en EasyPanel y la salida por etapas del OCR. No contiene secretos: las credenciales reales viven unicamente en EasyPanel.

Estado verificado (2026-09-24)

  • Preflight R5 de solo lectura (2026-09-23): el contenedor RAG usa la base db_rag con el rol usr_rag. rag_schema_migrations contiene 001_knowledge_lifecycle.sql, 002_ocr_review.sql y 003_ocr_recovery_audit.sql, todos con checksums coincidentes con el commit publicado; la unica migracion pendiente es 004_ocr_quality_diagnostics.sql.
  • Despliegue R5 verificado (2026-09-23): RAG y OCR exponen version=0.2.1 y revision=0654ce5; sus etiquetas OCI coinciden. Digests: RAG sha256:9a22730406c09c6b773891d8953f451e6263bf9fb0033188f4479f0b93ec8bbf, OCR sha256:6725991d3893a4f16ae6c75f28e9dd59b051bdbc344b28d79f1292224ddceda1. 004_ocr_quality_diagnostics.sql esta aplicada; OCR esta live/ready, con cola vacia, worker/sweeper operativos y almacenamiento disponible; RAG confirma PostgreSQL, Qdrant y reconciliador sanos.
  • Candidata R5 (2026-09-23): FacturaTech v8 f4fd1502-1d4d-454f-bbfb-4c3b6820ee97 esta review_required, con activateRequested=false; no se aprobo, indexo ni activo. Tiene 25/25 paginas OCR completas, 25 imagenes durables verificadas, tres advertencias no bloqueantes en paginas 2, 20 y 21, y ningun bloqueo. La revision visual independiente y su auditoria posterior concluyen READY_FOR_APPROVAL: 34/34 entradas, sin duplicados, ausencias ni casos sin resolver. CBG04a y DSAU08 ya son exactos; deben proponerse FATo7 -> FAT07, NSAvo6 -> NSAV06 y DSAUo4 -> DSAU04. El recorte de la pagina 22 pertenece a la imagen fuente y la candidata conserva el contenido visible. La version activa 3fc78163-9cfb-4979-985c-1520a63327b0 sigue intacta.
  • Diagnostico de precision (2026-09-24): los PNG productivos verificados de las paginas 8, 15 y 16 muestran los ceros correctos, mientras ocr-result.json ya contiene las tres confusiones o/0 con confianza alta y la candidata las conserva sin cambios. Se descartan renderizado, reconstruccion y RAG como origen. El OCR queda aceptado para esta fase como servicio best-effort autonomo; la mejora de precision, la consola humana y un posible revisor visual por IA quedan diferidos. Esta aceptacion no aprueba ni activa v8.
  • KNOWLEDGE_LIFECYCLE_ENFORCED=true: el ciclo de vida del conocimiento esta activo; no queda pendiente ninguna activacion.
  • OCR_INGEST_ENABLED=true: la ingesta OCR esta habilitada en el RAG desplegado.
  • OCR_SERVICE_URL: configurada hacia el servicio privado ocr-service de la red interna.
  • OCR_INTERNAL_TOKEN: secreto compartido configurado en EasyPanel (RAG y servicio OCR); su valor nunca se documenta.
  • Volumen duradero del RAG en /data/ingestions: conserva originales y artefactos de revision.
  • Volumen transitorio del OCR en /data/jobs: cola SQLite y trabajos en curso.
  • La respuesta publica sin token de una ruta OCR protegida es 401, lo que confirma que el proceso desplegado tiene OCR habilitado. Con OCR deshabilitado, la misma ruta responderia 404 antes de autenticar.
  • El estado mostrado en EasyPanel debe contrastarse con su entorno persistido y con el entorno del contenedor en ejecucion; anteriormente la UI mostro valores distintos por variables duplicadas y desfasadas.
  • GET /health del RAG confirma PostgreSQL, Qdrant y reconciliador sanos. OCR responde internamente live=ok y ready=true, con cola vacia, worker/sweeper operativos y version/revision 0.2.1/0654ce5.
  • La migracion 003_ocr_recovery_audit.sql esta aplicada y su tabla de auditoria existe.
  • Las rutas autenticadas de revision y recuperacion devuelven errores estructurados y seguros para una candidata inexistente: 404, OCR_CANDIDATE_NOT_FOUND y accion verify_version_id.
  • La candidata OCR heredada de FacturaTech v4 fue cerrada como failed el 2026-09-20 mediante recuperacion administrativa auditada tras confirmar OCR_ARTIFACT_UNAVAILABLE. No fue indexada ni activada; la fuente conserva su version activa y no tiene candidatas OCR bloqueantes.
  • Las imagenes en ejecucion tienen digests y ambas etiquetas OCI org.opencontainers.image.revision=0654ce5: EasyPanel recibe BUILD_REVISION durante el build. La identidad de revision se verifica mediante las etiquetas, el health y los digests registrados para R5.

Version de despliegue

  • La version correcta de cada despliegue es la declarada en el fichero raiz VERSION del commit que se publica (para la entrega actual, 0.2.1). No reutilizar numeros escritos en entradas historicas de este documento.
  • Ambas imagenes publican org.opencontainers.image.version y org.opencontainers.image.revision; las respuestas de salud muestran version y revision.
  • EasyPanel debe construir ambas imagenes con la version de VERSION y con BUILD_REVISION=<commit desplegado>.
  • Por decision del usuario, RAG y OCR se despliegan juntos con OCR_INGEST_ENABLED=true; no se desactiva preventivamente ni se introduce una ventana sin ingestas por protocolo.
  • OCR_INGEST_ENABLED=false y el despliegue por etapas se reservan para responder a un fallo real cuando sus sintomas y la evidencia indiquen que aislar un servicio ayudara al diagnostico o a la recuperacion.

Lista rapida en EasyPanel

  1. Rotar las credenciales expuestas (ver seccion siguiente); la rotacion sigue pendiente.
  2. Comprobar que las variables coinciden con la tabla de configuracion actual.
  3. Mantener OCR_INGEST_ENABLED=true; cambiarlo a false solo ante un fallo real que justifique aislar el flujo OCR.
  4. Pulsar Deploy en EasyPanel despues de cada cambio principal.
  5. Verificar GET /health del RAG y las rutas internas de salud del OCR tras cada deploy.
  6. Registrar el digest de cada imagen y confirmar que version y revision coinciden con la entrega desplegada.

Accion de seguridad urgente: rotar credenciales

Credenciales reales quedaron expuestas en una conversacion de chat. Hay que rotarlas:

  • La credencial de OpenRouter (variable EMBEDDING_API_KEY; y ANSWER_API_KEY si tiene valor propio).
  • La contrasena y la URL de PostgreSQL (variable POSTGRES_URL).
  • El token administrativo del ciclo de vida (variable LIFECYCLE_ADMIN_TOKEN).

Como hacerlo:

  • Generar valores nuevos y actualizarlos unicamente en EasyPanel.
  • Este documento no afirma que la rotacion ya se haya realizado.
  • Nunca pegar valores de credenciales en chat, documentacion, historial ni ficheros versionados.

Como se despliega

  • Tras cada cambio principal (variables de entorno o codigo nuevo subido por Git), el usuario pulsa el boton Deploy de EasyPanel.
  • No existe ninguna accion automatizada documentada sobre EasyPanel: ni scripts, ni comandos de panel, ni webhooks. El deploy siempre lo dispara una persona desde el panel.
  • Verificacion minima tras cada deploy: GET /health del RAG.

Acceso remoto a VPS2

  • Entorno: VPS2 PRODUCCION.
  • Host SSH: 162.19.152.15, puerto 22, usuario debian.
  • Metodo actual: conexion SSH directa con password mediante SSH_ASKPASS temporal; nunca reenviar la contrasena por entrada estandar ni mostrarla en la salida.
  • Fuente canonica del procedimiento y de la credencial vigente: Empresa/Servidores/VPS2/Vps2_despliegue_apps/instrucciones_montado_y_despliegue_apps_vps2_easypanel.md.
  • Verificacion de acceso: 2026-09-23, conexion directa correcta como debian al host vps-4863ac0d.
  • Antes de cualquier accion remota, indicar expresamente VPS2 PRODUCCION; las comprobaciones que no contacten ese host se etiquetan LOCAL.
  • La contrasena no se copia en este repositorio, historial ni chat. Si cambia, actualizarla solo en la fuente canonica.

Configuracion actual (valores no secretos)

Valores vigentes confirmados en produccion (2026-09-17):

Variable Valor actual
NODE_ENV production
PORT 80
QDRANT_URL http://qdrant:6333
QDRANT_API_KEY vacia (sin valor)
QDRANT_COLLECTION rag_chunks
EMBEDDING_PROVIDER openrouter
EMBEDDING_MODEL qwen/qwen3-embedding-8b
EMBEDDING_BASE_URL https://openrouter.ai/api/v1
ANSWER_PROVIDER openrouter
ANSWER_MODEL openai/gpt-4.1-mini
ANSWER_BASE_URL https://openrouter.ai/api/v1
POSTGRES_SSL false
KNOWLEDGE_LIFECYCLE_ENFORCED true
INGEST_WRITES_ENABLED true
OCR_INGEST_ENABLED true
OCR_SERVICE_URL configurada hacia el servicio privado ocr-service

Notas de comportamiento (derivadas del codigo, sin secretos):

  • Si ANSWER_API_KEY no se define, el codigo reutiliza EMBEDDING_API_KEY.
  • Si POSTGRES_URL no se define, el codigo prueba DATABASE_URL.
  • Si OCR_INGEST_ENABLED no existe, el codigo tambien la toma como false; por eso debe existir explicitamente con valor true en el entorno persistido de EasyPanel.
  • Un cambio en KNOWLEDGE_LIFECYCLE_ENFORCED, INGEST_WRITES_ENABLED o OCR_INGEST_ENABLED se hace siempre en EasyPanel y se registra en este documento.

Variables con secretos

Estas variables contienen credenciales reales. Aqui solo se registran sus nombres:

Variable Estado
EMBEDDING_API_KEY Configurada en EasyPanel; nunca copiarla en documentacion.
ANSWER_API_KEY Configurada en EasyPanel; nunca copiarla en documentacion.
POSTGRES_URL Configurada en EasyPanel; nunca copiarla en documentacion.
LIFECYCLE_ADMIN_TOKEN Configurada en EasyPanel; nunca copiarla en documentacion.
OCR_INTERNAL_TOKEN Configurada en EasyPanel, compartida con el servicio OCR y enviada como Authorization: Bearer; nunca copiarla en documentacion.

Salida por etapas del OCR

El OCR es un servicio privado e independiente. El RAG solo lo llama si OCR_INGEST_ENABLED esta activo; con el flag apagado, la ingesta sigue el flujo nativo actual, sin cambios. Hoy el flag esta en true en el RAG desplegado.

Servicio OCR privado (referencia de configuracion)

  • Contenedor ocr-service, imagen Python CPU con PaddleOCR 3.4.0 y PaddlePaddle 3.2.2.
  • Una sola replica y un solo worker; limites del servicio: maximo 3 CPU y 5 GiB de RAM.
  • Modelos descargados durante el build, nunca en el arranque.
  • Solo red interna del proyecto (easypanel-ia_servicios), sin dominio publico.
  • OCR_SERVICE_URL apunta al servicio OCR interno por el puerto 8000; el valor por defecto del codigo es http://ocr-service:8000, valido para un servicio llamado ocr-service en la red interna.
  • Limites fijos (no configurables por variables): cola de 3 trabajos, concurrencia 1, render a 200 DPI, maximo 50 MiB por PDF y 100 paginas por trabajo.
  • Cada trabajo dispone de un lease y un limite total de 15 minutos. Solo se recupera una vez; la segunda interrupcion o el timeout son terminales.
  • La readiness es falsa hasta que modelo, worker, sweeper y almacenamiento estan operativos; expone conteos por estado, recuperaciones y ultima limpieza sin incluir secretos. El healthcheck de arranque concede 90 segundos.

Volumenes

Volumen Ruta Papel
Duradero del RAG /data/ingestions Originales y artefactos de revision conservados.
Transitorio del OCR /data/jobs Cola SQLite, PDFs y resultados en curso.

Limpieza transitoria del OCR

  • Las filas transitorias, el PDF y los resultados del OCR se eliminan tras la transferencia duradera al RAG, cuando el resultado es aceptado.
  • Si esa transferencia no llega, un sweeper ejecutado al arrancar y cada 15 minutos expira los trabajos a las 24 horas, hace checkpoint WAL y vacuum incremental.
  • Antes de admitir el PDF y antes de publicar cada PNG, OCR limita su uso al menor entre 10 % del filesystem y 2 GiB, reservando libre el mayor entre 10 % y 2 GiB. La presion falla cerrada como OCR_STORAGE_PRESSURE.
  • La limpieza transitoria nunca toca los artefactos duraderos del RAG ni el corpus activo.
  • La siguiente entrega de RAG incorpora un scheduler durable basado en next_attempt_at, con backoff de 2 a 15 segundos y un unico temporizador. Hasta que esa unidad se publique y despliegue, produccion conserva el seguimiento de la revision 0654ce5; el reconciliador de 300000 ms permanece activo como fallback global en ambas versiones.

Verificacion posterior al despliegue (cuando cambian ambos servicios)

  1. Publicar el codigo en Git main y desplegar juntos OCR y RAG con la version indicada en VERSION y OCR_INGEST_ENABLED=true.
  2. Verificar el OCR internamente: GET /health/live y GET /health/ready deben responder con el servicio preparado.
  3. Verificar GET /health del RAG: PostgreSQL, Qdrant y reconciliador deben estar correctos.
  4. Comprobar una ruta OCR protegida sin token. Un 401 Lifecycle admin token is required confirma que OCR esta habilitado y que la autenticacion administrativa permanece protegida; no es un error que requiera correccion.
  5. Contrastar OCR_INGEST_ENABLED=true en el entorno persistido de EasyPanel y en el proceso del contenedor si la UI no coincide con el comportamiento efectivo.
  6. Consultar con token administrativo una version inexistente en revision y recuperacion: ambas deben devolver un error estructurado 404 OCR_CANDIDATE_NOT_FOUND sin modificar datos.
  7. Confirmar que rag_schema_migrations contiene 003_ocr_recovery_audit.sql y que existe rag_ocr_recovery_audit.
  8. Revisar los digests y confirmar que las etiquetas OCI y las respuestas de salud muestran 0.2.1 y el commit desplegado, no unknown.
  9. Tras completar estas comprobaciones, crear una candidata FacturaTech no activa. No aprobar, indexar ni activar hasta presentar la evidencia al usuario y recibir autorizacion explicita.

Rollback de emergencia

  • Ante un fallo cuyos sintomas indiquen que conviene aislar OCR: poner OCR_INGEST_ENABLED=false, desplegar el RAG y conservar la version activa actual del corpus. No aplicar este paso automaticamente a fallos no relacionados.
  • El sistema es fail-closed: un fallo del OCR deja intacta la version activa anterior; no hay activacion parcial.
  • Las paginas con OCR no se activan solas; pasan por el contrato de revision en estado review_required. En la fase autonoma actual esa revision puede ejecutarla el agente; una futura consola humana reutilizara el mismo contrato.
  • Desactivar el OCR no borra el corpus activo ni exige reingesta.
  • Si se revierte a 0.2.0, la migracion aditiva 004_ocr_quality_diagnostics.sql permanece aplicada. No se eliminan sus columnas ni su fila de historial; antes de reabrir trafico se verifica que RAG y OCR 0.2.0 arrancan y pasan health con ese esquema extendido.

Limites opcionales del RAG (valores por defecto del codigo)

Variable Valor por defecto
OCR_MAX_UPLOAD_BYTES 52428800 (50 MiB)
OCR_MAX_PAGES 100
LIFECYCLE_RECONCILE_INTERVAL_MS 300000
LIFECYCLE_INDEXING_STALE_TIMEOUT_MS 1800000
QDRANT_LOGS_COLLECTION rag_eval_logs

Verificaciones habituales

  • GET /health del RAG: estado general con PostgreSQL, Qdrant y reconciliador.
  • GET /health/live y GET /health/ready del servicio OCR: solo accesibles desde la red interna del proyecto.
  • Tras cambiar cualquier variable: pulsar Deploy y verificar /health.

Reglas de uso de este documento

  • Consultarlo antes de tareas con servicios externos, credenciales, despliegues o ejecuciones recurrentes.
  • Nunca escribir secretos aqui: solo nombres de variables y donde viven (EasyPanel).
  • Si un hecho operativo deja de ser valido, actualizarlo o marcarlo como obsoleto en la misma intervencion en que se descubra.