BRIC-13: Add classical RAG pathway with multi-query + LLM-as-judge#15
BRIC-13: Add classical RAG pathway with multi-query + LLM-as-judge#15
Conversation
- 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
Kaiohz
left a comment
There was a problem hiding this comment.
🟡 Review: BRIC-13 Classical RAG with multi-query + LLM-as-judge — Score 7/10
✅ Points positifs
-
Architecture hexagonale respectée : 2 nouveaux ports (
VectorStorePort,LLMPort) + 2 adapters (LangchainPgvectorAdapter,LangchainOpenaiAdapter). Use cases bien séparés des adapters. -
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.
-
Isolation par projet : Table PGVector par
working_diravec nom{prefix}{sha256(working_dir)[:16]}. Pas de cross-contamination. -
3e serveur MCP :
RAGAnythingClassicalavec 3 tools (classical_index_file,classical_index_folder,classical_query). Coherent avec l'architecture existante. -
REST + MCP dual exposure : Meme pattern que les endpoints existants (REST routes + MCP tools en parallele).
-
Background indexing :
asyncio.create_taskavec_background_tasksset + discard callback. Meme pattern que l'indexing LightRAG. -
Config propre :
ClassicalRAGConfigavec 6 env vars, defaults sensibles. 503 si init fail (missing API key). -
Tests : 351 unit tests (91% coverage), 32/32 QA integration. SonarQube 0 issues.
-
Dockerfile.db optimise : RUN instructions merged (SonarQube S3776 fix). Moins de layers.
-
README maj : Architecture diagram updated, Classical RAG section with comparison table LightRAG vs Classical.
⚠️ Points d'attention
-
pgvectorversion downgrade :pgvector>=0.4.2change apgvector>=0.3.6,<0.4.0. C'est necessaire pourlangchain-postgresmais 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. -
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
-
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.
-
_classical_helpers.py: Fichier helper prive dansuse_cases/. Le nomvalidate_pathsuggere de la validation mais il est different de_validate_prefixdeja existant dansfile_routes.pyetmcp_file_tools.py. 3 fonctions de validation differentes pour 3 contexts = risque d'inconsistance. -
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). -
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. -
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
-
Pas de test d'integration cross-pipeline : Que se passe-t-il si un meme
working_direst indexe en LightRAG ET Classical ? Les deux pipelines partagent la meme DB. Pas de test pour verifier l'isolation. -
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 🤖
Kaiohz
left a comment
There was a problem hiding this comment.
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
-
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 ?
-
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.
-
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.
-
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.
Jira
BRIC-13
Summary
Adds a classical RAG pathway alongside the existing graph-based LightRAG, using:
Query pipeline
CLASSICAL_RELEVANCE_THRESHOLD(default 5.0) are filtered outChanges
VectorStorePort,LLMPort+SearchResultdataclassLangchainPgvectorAdapter(PG),LangchainOpenaiAdapter(ChatOpenAI)ClassicalIndexFileUseCase,ClassicalIndexFolderUseCase,ClassicalQueryUseCasePOST /api/v1/classical/file/index,/folder/index(202),/query(200)RAGAnythingClassicalat/classical/mcpwith 3 toolsClassicalRAGConfig(chunk size/overlap, num variations, relevance threshold, table prefix, LLM temperature)Tests