This document describes the current code structure, runtime flow, and the new provider-switch path between the local LLM and the Gemini API.
The application is a Retrieval-Augmented Generation system for IIT Bhilai content.
It has three main layers:
- Backend retrieval and orchestration in Python.
- Chroma-based document and cache storage.
- Next.js chat UI with a provider switch.
The current implementation supports:
- Local LLM via Ollama.
- Gemini API via
langchain-google-genai. - Exact and semantic caching.
- Tool-based retrieval plus vector fallback.
- Automatic embedding namespaces so different embedding models use different Chroma collections.
- The frontend sends a question to
/api/chat. - The Next.js route forwards the request to the FastAPI backend.
- The backend resolves the requested provider and model.
- The orchestrator checks cache layers scoped to that provider/model.
- If no cache hit is found, it queries the registered tools.
- If tools return nothing, it falls back to direct vector search.
- The selected LLM generates the final answer from the retrieved context.
- The response is cached again for the same provider/model scope.
This module centralizes configuration.
Key responsibilities:
- Loads YAML and environment variables.
- Normalizes provider aliases:
local->ollamagoogle->gemini
- Resolves LLM configuration per request.
- Resolves embedding configuration.
Important environment variables:
LLM_PROVIDERGEMINI_MODELOLLAMA_MODELOPENAI_MODELEMBEDDING_PROVIDERGEMINI_EMBEDDING_MODELOLLAMA_EMBEDDING_MODELOPENAI_EMBEDDING_MODELGOOGLE_API_KEYOPENAI_API_KEYCHROMA_PERSIST_DIRECTORY
This module creates model instances.
Supported LLM providers:
geminiopenaiollama
Supported embedding providers:
geminiopenaiollama
The factory now imports provider packages lazily so the app can start even if a provider is not installed, as long as that provider is not selected.
This is the active orchestrator used by the FastAPI app.
It now handles:
- Provider-aware LLM selection.
- Tool registry retrieval.
- Direct vector fallback.
- Exact cache scoped by provider and model.
- Semantic cache stored in a separate Chroma collection.
Cache behavior:
- Exact cache uses an in-memory
OrderedDictwith TTL and max size. - Semantic cache stores cached question-answer pairs in a dedicated provider/model-specific Chroma collection.
- Cache entries include
llm_providerandllm_modelmetadata so local and Gemini answers do not mix.
This wrapper manages the document Chroma collection.
It now supports filtered similarity search with scores, which is required for provider-scoped semantic cache lookups.
It also derives a stable embedding namespace from the embedding provider and model, so a new embedding model gets its own Chroma collection automatically.
If the new collection is empty, the wrapper bootstraps it from the PDFs shipped with the repo, which currently means backend/courses_study.pdf.
FastAPI endpoints:
GET /chatGET /statsGET /healthGET /providersGET /cache/statsDELETE /cache/{question}DELETE /cache/all
The /chat endpoint accepts:
questionprovidermodeluse_cache
This is the main chat UI.
It now includes:
- A provider toggle for
localandgemini. - Live backend stats loading.
- Requests that pass the selected provider/model through to the backend.
- Message metadata showing the provider and cache layer.
This route proxies chat requests to the backend.
It forwards:
questionprovidermodeluse_cache
This route proxies backend stats so the UI can load backend state without hardcoding backend-specific logic in the page.
The global styles were updated to:
- Support the provider switch UI.
- Improve responsive layout behavior.
- Use a stronger visual hierarchy.
- Provide a more intentional background and surface system.
The switch is runtime-based, not restart-based.
Use the frontend toggle to switch between:
Local LLMfor Ollama.Gemini APIfor Google-hosted generation.
The selected provider is sent with each request, so the backend can choose the correct LLM instance without restarting the process.
The embedding store is separate from the generation model. The backend automatically builds a provider/model-specific embedding namespace, so switching from Gemini embeddings to Ollama embeddings creates a different Chroma collection instead of reusing incompatible vectors.
The cache is now scoped to provider and model.
That means:
- A local Ollama answer will not be returned for a Gemini request.
- A Gemini response will not pollute the local cache path.
- Semantic cache entries are stored separately from document embeddings.
- New embedding models automatically get their own collection and bootstrap from the source PDFs when available.
This is important because mixing answer caches across providers can return stale or incompatible completions.
backend/src/core/config_loader.pybackend/src/core/llm_factory.pybackend/src/core/orchestrator_with_cache.pybackend/src/ingestion/vector_store_wrapper.pybackend/src/api/app.pybackend/requirements.txtfrontend/src/app/page.tsxfrontend/src/app/api/chat/route.tsfrontend/src/app/api/stats/route.tsfrontend/src/app/layout.tsxfrontend/src/app/globals.css
- The project currently uses the cached orchestrator path in the API app.
- The local provider assumes Ollama is available at
http://localhost:11434unless overridden. - Gemini still requires a valid Google API key.
- If the backend stats fail to load, the frontend still works, but the system panel will show fallback values until the backend is reachable.