Skip to content

BRIC-13: Add classical RAG pathway with multi-query + LLM-as-judge#15

Draft
Kaiohz wants to merge 2 commits intomainfrom
BRIC-13/classical-rag
Draft

BRIC-13: Add classical RAG pathway with multi-query + LLM-as-judge#15
Kaiohz wants to merge 2 commits intomainfrom
BRIC-13/classical-rag

Conversation

@Kaiohz
Copy link
Copy Markdown
Collaborator

@Kaiohz Kaiohz commented Apr 13, 2026

Jira

BRIC-13

Summary

Adds a classical RAG pathway alongside the existing graph-based LightRAG, using:

  • Kreuzberg for document parsing + chunking
  • langchain-postgres (PGVectorStore) for storing chunks + embeddings (one PG table per working_dir)
  • langchain-openai (ChatOpenAI via OpenRouter) for multi-query generation + LLM-as-judge scoring

Query pipeline

  1. LLM generates N query variations
  2. Similarity search for each variation via PGVectorStore, deduplicated by chunk_id
  3. LLM-as-judge scores each chunk 0-10 (concurrent with semaphore)
  4. Chunks below CLASSICAL_RELEVANCE_THRESHOLD (default 5.0) are filtered out

Changes

  • Domain ports: VectorStorePort, LLMPort + SearchResult dataclass
  • Adapters: LangchainPgvectorAdapter (PG), LangchainOpenaiAdapter (ChatOpenAI)
  • Use cases: ClassicalIndexFileUseCase, ClassicalIndexFolderUseCase, ClassicalQueryUseCase
  • REST: POST /api/v1/classical/file/index, /folder/index (202), /query (200)
  • MCP: Server RAGAnythingClassical at /classical/mcp with 3 tools
  • Config: ClassicalRAGConfig (chunk size/overlap, num variations, relevance threshold, table prefix, LLM temperature)
  • Security: Path traversal protection, temp file cleanup, RuntimeError guards
  • Pre-existing fixes: SonarQube S3776 (lightrag_adapter cognitive complexity), S1192 (indexing_result duplicate literal), Dockerfile.db merged RUN instructions
  • Vuln fixes: cryptography 46.0.7, lightrag-hku 1.4.14, pypdf 6.10.0

Tests

  • Unit tests: 351 passing (91% coverage)
  • Integration tests (QA): 32/32 passing
  • SonarQube: 0 open issues on branch
  • Trivy: 3/4 MEDIUM CVEs fixed, 1 flagged (transformers requires 5.0.0rc3 breaking RC)
  • API health check: OK after container rebuild
  • MCP classical server: 3 tools listed correctly

- Add VectorStorePort and LLMPort domain interfaces
- Add LangchainPgvectorAdapter (PGVectorStore, one table per working_dir)
- Add LangchainOpenaiAdapter (ChatOpenAI via OpenRouter)
- Add ClassicalIndexFileUseCase, ClassicalIndexFolderUseCase, ClassicalQueryUseCase
- Add REST endpoints: /api/v1/classical/file/index, /folder/index, /query
- Add MCP server RAGAnythingClassical at /classical/mcp with 3 tools
- Multi-query generation + concurrent LLM judge scoring + relevance filtering
- Path traversal protection, temp file cleanup, graceful degradation
- 351 tests passing (91% coverage), SonarQube clean on branch
- Fix pre-existing SonarQube issues: S3776 in lightrag_adapter, S1192 in indexing_result
- Upgrade vulnerable deps: cryptography 46.0.7, lightrag-hku 1.4.14, pypdf 6.10.0
- Update Dockerfile.db (merge RUN instructions)
- Update README and .env.example with classical RAG documentation
Copy link
Copy Markdown
Collaborator Author

@Kaiohz Kaiohz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Review: BRIC-13 Classical RAG with multi-query + LLM-as-judge — Score 7/10

✅ Points positifs

  1. Architecture hexagonale respectée : 2 nouveaux ports (VectorStorePort, LLMPort) + 2 adapters (LangchainPgvectorAdapter, LangchainOpenaiAdapter). Use cases bien séparés des adapters.

  2. Pipeline classique complète : Multi-query generation, deduplication by chunk_id, LLM-as-judge scoring (0-10), relevance threshold filtering. C'est un vrai RAG "serious" qui va au-dela du simple retrieval.

  3. Isolation par projet : Table PGVector par working_dir avec nom {prefix}{sha256(working_dir)[:16]}. Pas de cross-contamination.

  4. 3e serveur MCP : RAGAnythingClassical avec 3 tools (classical_index_file, classical_index_folder, classical_query). Coherent avec l'architecture existante.

  5. REST + MCP dual exposure : Meme pattern que les endpoints existants (REST routes + MCP tools en parallele).

  6. Background indexing : asyncio.create_task avec _background_tasks set + discard callback. Meme pattern que l'indexing LightRAG.

  7. Config propre : ClassicalRAGConfig avec 6 env vars, defaults sensibles. 503 si init fail (missing API key).

  8. Tests : 351 unit tests (91% coverage), 32/32 QA integration. SonarQube 0 issues.

  9. Dockerfile.db optimise : RUN instructions merged (SonarQube S3776 fix). Moins de layers.

  10. README maj : Architecture diagram updated, Classical RAG section with comparison table LightRAG vs Classical.

⚠️ Points d'attention

  1. pgvector version downgrade : pgvector>=0.4.2 change a pgvector>=0.3.6,<0.4.0. C'est necessaire pour langchain-postgres mais ca peut casser le LightRAG existant qui utilisait 0.4.x. Verifier que les features pgvector 0.4 utilisees par LightRAG sont backward-compatible avec 0.3.x.

  2. langchain-* dependencies : 3 nouvelles deps majeures (langchain-postgres, langchain-core, langchain-openai). C'est un shift significatif vers l'ecosysteme LangChain. Verifier :

    • Taille du docker image (langchain-core est lourd)
    • Pas de conflit de versions avec les deps existantes
    • Impact sur le startup time
  3. LLM cost per query : Chaque query classique fait N+1 appels LLM (N multi-query generations + M judge scorings par chunk). Pour 3 variations + 10 chunks = 3 + 10 = 13 LLM calls par query. Pas de caching ni rate limiting visible. Budget OpenRouter a surveiller.

  4. _classical_helpers.py : Fichier helper prive dans use_cases/. Le nom validate_path suggere de la validation mais il est different de _validate_prefix deja existant dans file_routes.py et mcp_file_tools.py. 3 fonctions de validation differentes pour 3 contexts = risque d'inconsistance.

  5. Ruff ignore ARG001, ARG002 : Ajout de 2 regles ignorees. Si c'est pour eviter les false positives sur les unused arguments dans les callbacks/adapters, OK. Mais ca peut aussi masquer de vrais bugs (arguments oublies).

  6. Table naming : sha256 truncation : {prefix}{sha256(working_dir)[:16]} = 16 chars du hash. Collision probability low mais non-zero pour beaucoup de projets. Documenter le risque.

  7. No Alembic migration : Les tables PGVector sont creees dynamiquement par langchain-postgres (auto-create). Pas de migration Alembic. Si le schema change en prod, pas de migration path.

🔴 Risques

  1. Pas de test d'integration cross-pipeline : Que se passe-t-il si un meme working_dir est indexe en LightRAG ET Classical ? Les deux pipelines partagent la meme DB. Pas de test pour verifier l'isolation.

  2. Concurrent judge scoring avec semaphore mais pas de timeout visible. Si l'LLM API est lente/down, les queries peuvent bloquer indefiniment.

💡 Suggestions

  • Ajouter un test d'integration LightRAG + Classical sur le meme working_dir
  • Ajouter un timeout configurable pour les appels LLM (multi-query + judge)
  • Ajouter un cache LLM pour les queries identiques (eviter 13 calls par query repetitive)
  • Unifier les fonctions de validation (validate_path, _validate_prefix) en un shared util
  • Verifier le downgrade pgvector 0.4.x -> 0.3.x ne casse pas LightRAG
  • Ajouter des metriques (LLM calls count, latency, cost estimation) pour le monitoring
  • Documenter le LLM cost per query dans le README (ex: "3-13 LLM calls per query depending on config")

Review by SoluBot 🤖

Copy link
Copy Markdown
Collaborator Author

@Kaiohz Kaiohz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Code Review — BRIC-13: Classical RAG Pipeline

✅ Points positifs

Architecture hexagonale respectée :

  • Nouveaux ports propres : LlmPort, VectorStorePort dans domain/ports/
  • Adapters dans infrastructure/ implémentent les ports
  • Use cases appellent les ports, pas les adapters directement ✅
  • Séparation classical/lightrag claire et maintenir

Tests massifs (~2229 lignes) :

  • test_classical_query_use_case.py (482 lignes) — couverture des edge cases
  • test_langchain_pgvector_adapter.py (346 lignes) — adapter bien testé
  • test_mcp_classical_tools.py (353 lignes) — MCP tools couverts
  • Tous les use cases et routes ont leurs tests

Config externalisée : variables CLASSICAL_* dans .env.example

Dockerfile optimisé : moins de layers, build plus propre

README à jour avec la nouvelle architecture diagram

⚠️ Points d'attention

  1. Kreuzberg comme dépendance critique — le parsing/chunking dépend entièrement de Kreuzberg. Si Kreuzberg a un bug ou change d'API, tout le pipeline classical est impacté. Envisager un fallback ou au moins un test d'intégration Kreuzberg ?

  2. Pas de tests d'intégration — les tests unitaires sont excellents, mais on n'a pas de test qui valide le pipeline bout en bout (index → query → résultat). Un test d'intégration MinIO + PG + API serait un gros plus.

  3. Pattern classical_rag_ pour les tables PG — chaque working_dir crée une table classical_rag_{working_dir}. Vérifier que le working_dir est sanitisé pour éviter les injections SQL dans les noms de tables.

  4. LLM temperature hardcoded à 0.0 — c'est bien pour la reproductibilité, mais ça mériterait d'être configurable pour les cas où on veut de la variabilité.

Score : 8/10

Excellente PR. L'architecture est propre, les tests sont solides. Les points ci-dessus sont des améliorations, pas des bloqueurs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant