The Problem
This repository implements a production-grade RAG system for academic paper curation, but lacks the operational guardrails expected of production software. The codebase is functional—121 Python files, Docker support, LangGraph agentic workflows, and a Telegram bot integration—but has no automated build/test gate, no dependency lockfile, and several files with broad exception handling that would mask failures in production.
What This Does
The system evolves across seven weeks, starting with Docker/Infrastructure (Week 1) and progressing through arXiv ingestion (Week 2), BM25 keyword search (Week 3), hybrid keyword+vector search (Week 4), a local LLM + Gradio interface (Week 5), monitoring with Langfuse/Redis (Week 6), and culminating in agentic RAG with LangGraph + Telegram bot (Week 7). The Week 7 architecture is documented in static/week7_telegram_and_agentic_ai.png and static/langgraph-mermaid.png.
Execution originates at three entry points: lifespan in src/main.py:29 reaches 37 functions and is called by nothing else in the repo; start in src/services/telegram/bot.py:32 reaches 7 functions with no callers; and main in src/gradio_app.py:212 reaches 1 function called from 1 place. The typical run path flows lifespan → health_check → [network via client.get], making a single network call before any user interaction. The call graph shows get_settings is called from 16 places, list from 12, and build from 11—these are the widest-blast-radius functions any change would ripple through.
The repository contains three projects: src (89 files, 88 code files), airflow (12 files, 8 code files for arXiv ingestion DAGs), and notebooks (14 files including 7 Jupyter notebooks for the course deliverables).
How It Is Wired
Control flows through a hub-and-spoke pattern centered on src/config.py, which 23 modules depend on and which defines validate_cache_dir, validate_database_url, get_settings, BaseConfigSettings, and ArxivSettings. The dependency structure shows src/dependencies has instability 0.75 (4 importers, 12 imports), and src/main has instability 0.86 (2 importers, 12 imports)—both are high-risk touch points. The OpenSearch client at src/services/opensearch/client.py has 9 importers and 3 imports with instability 0.25, making it a relatively stable service boundary. The agentic RAG module at src/services/agents/agentic_rag has 5 importers and 9 imports with instability 0.64, indicating moderate coupling.
The internal call graph has 462 resolved call edges between repository functions. parse_pdf calls PDFParsingException 7 times; _validate_pdf calls PDFValidationError 5 times. The agentic workflow in src/services/agents/nodes/ contains decision nodes (guardrail_node, out_of_scope_node, retrieve_node) with the documented duplicated 6-line blocks and high branching density (22 branch points over 74 lines in prompts.py).
What the code touches outside itself: 37 functions make outbound network calls, 13 read/write a database, 7 read/write files, 5 call a model for inference, 1 performs cryptographic operations, and 1 runs an external command. The shortest exit path from lifespan goes through health_check to a network call via client.get.
How To Use It
Setup: The project uses pyproject.toml for dependencies and Dockerfile + compose.yml for containerization. No lockfile is committed (uv.lock exists but is not referenced in build commands). Install with uv pip install -e . or pip install -e . from the repo root.
Configuration: Environment variables are defined in .env.example (verbatim content not provided in analysis). The actual loaded file is .env.test, which the hygiene section flags as committed and requiring rotation. Required vars likely include database URLs, OpenSearch credentials, LLM keys, and cache configuration—exact names should be verified from .env.example.
Running it: Start the infrastructure with docker compose up -d (compose.yml is at root). The FastAPI server starts via src/main.py; the Gradio interface via src/gradio_app.py:212; the Telegram bot via src/services/telegram/bot.py:32. No CI configuration exists, so there is no automated test gate on push.
Notebook workflow: The Week 7 notebook notebooks/week7/week7_agentic_rag.ipynb is the primary deliverable for agentic RAG. The hardcoded path in notebooks/week4/week4_hybrid_search.ipynb (/Users/Shared/Projects/MOAI/zero_to_RAG) must be replaced with a relative path or environment variable before running on another machine.
Real-World Use
A research team wanting to build an internal knowledge base could fork this repo and customize the arXiv fetching pipeline (airflow/dags/arxiv_ingestion/) for their domain. The agentic workflow in src/services/agents/agentic_rag.py with its guardrail node (src/services/agents/nodes/guardrail_node.py) and query rewriting (src/services/agents/nodes/rewrite_query_node.py) provides a pattern for adaptive retrieval that prevents hallucination when papers are outside the system's domain. The Telegram bot (src/services/telegram/bot.py) demonstrates mobile conversational access without rebuilding the entire UI.
Code Health & Issues
The static analysis produced 21 findings across 5 kinds:
- [MEDIUM/resilience] Broad exception handling in 6 files:
src/services/opensearch/client.py,src/services/telegram/bot.py,src/db/interfaces/postgresql.py. Bareexceptclauses swallow errors indiscriminately. - [HIGH/cognitive_load] Deep nesting in 12 locations across
src/services/ollama/client.py,src/services/arxiv/client.py,src/services/langfuse/client.py. Max indentation depth 8 makes control flow hard to follow. - [MEDIUM/clarity] Hub module
src/config.pywith 23 dependents; high-blast-radius churn point. - [MEDIUM/cognitive_load] High branching density in
src/services/agents/prompts.py: 22 branch points over 74 lines. - [MEDIUM/clarity] Duplicated 6-line code blocks in
src/services/agents/nodes/out_of_scope_node.pyandsrc/services/agents/nodes/retrieve_node.py.
Beyond the measured findings: no CI/CD pipeline is configured (/.github/ absent), pyproject.toml declares dependencies without a lockfile enabling non-reproducible builds, and .env.test is committed containing credentials that should be rotated.
The Bottom Line
This is a fully functional, well-structured RAG courseware repo that teaches production patterns through a complete seven-week build path. The code is readable, the architecture evolves logically from keyword search to agentic retrieval, and Docker/Compose setup gets everything running locally. However, the absence of CI/CD, missing lockfile, and committed .env.test mean it is not production-ready without operational hardening. Teams looking to learn modern RAG patterns or prototype a domain-specific research assistant will find significant value; teams needing auditable deployments should add a CI gate, lockfile, and secret rotation before promotion.