Skip to content

Latest commit

 

History

2 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

AI-Powered Research Assistant

Author: Utkrisht Sharma (utkrishs)

An AI research assistant that combines an AI agent (LangGraph), a RAG pipeline, a translation service (MCP), and a vector database (Milvus). The system is fully containerized and deployed on Google Kubernetes Engine (GKE). Users can upload academic papers, ask questions in English, Spanish, French, or Italian, and receive context-aware answers grounded in the indexed papers, along with two recommended research papers.


Table of Contents

  1. Demo
  2. System Architecture Diagram
  3. Component Details
  4. Index Algorithm Benchmarking
  5. Environment Variables
  6. How to Run the Application

Demo

Project Demo: https://drive.google.com/file/d/1bT9SAvU8ZZji8duW0Jvqjn1pnRYn960f/view?usp=sharing

Code Walkthrough: https://drive.google.com/file/d/17Nxqd4vo_jzPHlVcfJmmYk2kSOUWt-1J/view?usp=sharing

Indexing Results:


System Architecture Diagram

High-Level Architecture

The system consists of 3 separate services deployed on a GKE cluster.

Sequence Diagram

Component Interaction Summary

Source Target Protocol Purpose
User (Browser) Streamlit App HTTP (Port 8080) Upload papers, submit queries, view results
Streamlit App LangGraph Agent HTTP REST POST /invoke (Port 8000) Send upload/query requests
LangGraph AI Agent Translator MCP Server MCP over HTTP (Port 9000) Language detection & translation
LangGraph Agent Milvus Vector DB gRPC (Port 19530) Store/retrieve document embeddings
LangGraph Agent LLM Model HTTPS LLM inference & embedding generation

Data Flow Summary

┌─────────────────────────────────────────────────────────────────────────┐
│                          High Level Workflow                            │
├─────────────────────────────────────────────────────────────────────────┤
│                                                                         │
│  [Upload Path]                                                          │
│  User → Streamlit (PDF upload + domain) → Agent /invoke                 │
│       → index_node (chunk → embed → store) → Milvus                     │
│       → Response: "Indexed N chunks"                                    │
│                                                                         │
│  [Query Path]                                                           │
│  User → Streamlit (query text) → Agent /invoke                          │
│       → init_query → agent (LLM)                                        │
│       → detect_language (MCP) → translate to EN (MCP, if needed)        │
│       → search_papers (Milvus) → generate answer (Gemini LLM)           │
│       → translate back (MCP, if needed) → format_response               │
│       → Response: {answer, 2 recommended papers}                        │
|                                                                         |
└─────────────────────────────────────────────────────────────────────────┘

Component Details

1. Web Application (Streamlit)

Directory: streamlit/

The Streamlit web application serves as the frontend for the research assistant system.

Features

Feature Description
Paper Upload Upload academic papers in PDF format for RAG indexing
Domain Selection Select the paper's research domain: AI, Security, or Other
Language Support Submit queries in English, Spanish, French, or Italian
Answers Receive answers generated strictly from retrieved paper content
Paper Recommendations Get 2 relevant research papers with each answer
Language Matching Response language always matches the query language (e.g., Spanish input → Spanish output)

Streamlit UI Workflow

  1. Upload Papers (Sidebar):

    • Select one or more PDF files using the file uploader.
    • Choose the research domain from the dropdown (AI / Security / Other).
    • Click "Index Documents" to send papers to the LangGraph Agent for chunking, embedding, and storage in Milvus.
  2. Ask Questions (Main Area):

    • Type a query in the text input field (in any supported language).
    • Click "Send" to invoke the agent.
  3. View Results:

    • The answer is displayed under "Answer".
    • Two recommended research papers are listed under "Recommended Research Papers" with clickable source links.

2. AI Agent (LangGraph)

Directory: langgraph-rag/

This AI agent is the central orchestrator of the entire system, implemented using LangGraph. It coordinates between the frontend(streamlit), the translator service(MCP), and the vector database.

Agent Design Pattern

The agent uses an agentic tool-calling workflow where the LLM decides which tools to call and in what order. This is implemented via LangGraph's bind_tools mechanism.

Design choices to minimize hallucinations:

  • A strong system prompt ensures that the agent must call search_papers and base answers strictly on retrieved content.
  • The prompt instructs: "Base your answer STRICTLY on retrieved content. Do NOT hallucinate."
  • If no relevant results are found, the agent responds with: "The indexed research papers do not contain information on this topic."
  • The agent is instructed to call search_papers exactly once — preventing retry loops that could lead to inconsistent behavior and potential timeouts.
  • The format_response node guarantees a consistent output structure regardless of LLM behavior.

LangGraph State Machine

Graph Nodes

Node Type Description
_route_entry Conditional Entry Routes to index_node (if file_content present) or init_query (if question present)
index_node Processing Handles paper upload: chunks text using RecursiveCharacterTextSplitter (800/120), generates embeddings, and stores in Milvus with metadata (domain, title, source)
init_query Processing Prepares the initial HumanMessage with the research question and instructs LLM to detect language first
agent LLM The core LLM node: uses ChatGoogleGenerativeAI with bound tools (MCP + local). Decides autonomously which tool to call next
tools Tool Execution ToolNode that executes tool calls — MCP tools for translation, local search_papers tool for vector search
format_response Processing Extracts the final answer from the last AIMessage and the top 2 unique recommended papers from search_papers results

Agent Workflow for Queries

  1. Language Detection: Calls detect_language(text) via MCP server to detect the query language.
  2. Language Validation: Check if the language is supported. If it is not supported then it will return an error message immediately and ends the workflow instantly.
  3. Translation to English (if needed): Calls translate_text(text, source_lang, "en") via MCP server.
  4. Domain-Filtered Search: Calls search_papers(query, domain, top_k) to retrieve relevant chunks from the milvus vector databse with cosine similarity.
  5. Answer Generation: Uses the LLM to write an answer based strictly on retrieved content. Mentions relevant paper titles.
  6. Translation (if needed): Calls translate_text(answer, "en", target_lang) via MCP.
  7. Format Response: Extracts answer + 2 recommended paper titles/sources into a consistent JSON format.

Consistent Output Format

The agent always returns a consistent JSON structure via the /invoke endpoint:

{
  "answer": "The translated answer text based on retrieved papers...",
  "recommended_papers": [
    {"title": "Paper Title 1", "source": ""},
    {"title": "Paper Title 2", "source": ""}
  ]
}

MCP Communication Interface

The agent communicates with the Translator MCP Server via a standardized MCP (Model Context Protocol) HTTP interface:

  • Endpoint: http://<mcpserver_ip>:80/mcp
  • Protocol: JSON-RPC 2.0
  • Tools exposed by MCP: detect_language, translate_text
  • The MCP client is initialized once during app startup and tools are bound to the LLM via bind_tools.
  • Cleanup is handled via cleanup_mcp() on shutdown.

FastAPI Server (langgraph-rag/src/api/server.py)

Endpoint Method Description
/ok GET Health check — returns {"status": "ok"}
/invoke POST Main endpoint. Accepts upload or query payloads invokes the LangGraph state machine, and returns {answer, recommended_papers}

3. Translator Service (MCP)

Directory: mcp-server/

The translation service is a standardized service deployed on GKE. It uses the FastMCP framework to expose translation tools via the Model Context Protocol (MCP) over HTTP.

Translation Engine

The service uses deep-translator (GoogleTranslator) for actual translation. This provides high-quality, production-grade neural machine translation without requiring GPUs or custom models.

Supported Languages

Code Language
en English
es Spanish
fr French
it Italian

MCP Tools Exposed

Tool Parameters Return Value
detect_language(text) text: str {language_code, language_name, supported: bool}
translate_text(text, source_lang, target_lang) text: str, source_lang: str, target_lang: str {translated_text, source_lang, target_lang}

Example Tool Calls and Responses

// Input
{"text": "¿Cuáles son los avances recientes?", "source_lang": "es", "target_lang": "en"}
// Output
{"translated_text": "What are the recent advances?", "source_lang": "es", "target_lang": "en"}

Unsupported language handling:

// Input
{"text": "something", "source_lang": "zh", "target_lang": "en"}
// Output
{"error": "Unsupported source language: zh"}

4. RAG Pipeline & Vector Database (Milvus)

Terraform Directory: milvus-gke/
Benchmarking Directory: index_data/

Paper Collection

30 academic papers are indexed through the Streamlit application, organized by domain:

Domain Count Source
AI 10 Google Scholar — AI papers
Security 10 Google Scholar — Security papers
Other 10 Google Scholar — General papers

All 30 papers are uploaded through the Streamlit web application with their respective domain labels selected during upload.

Embedding & Storage

Setting Value
Embedding Model gemini-embedding-001
Chunk Size 800 characters
Chunk Overlap 120 characters
Similarity Metric Cosine Similarity (for all searches)
Collection Name research_papers
Index Type (Production) IVF_PQ (nlist=128, m=8, nbits=8)
Search Parameters nprobe=10 for IVF_PQ

Papers are indexed and embedded in their original language (primarily English for academic papers). The embeddings are stored in a single Milvus collection with domain metadata for filtering.

Domain-Filtered Retrieval

When a user submits a query, the search_papers tool performs:

  1. Cosine similarity search on the embedding vectors.
  2. Optional domain filtering via Milvus expression: domain == "AI" (or Security, Other).
  3. Returns top-k results (default: 4) with chunk content and metadata.

Auto-Scaling Configuration

Auto-scaling is configured via kubectl after Terraform deployment:

kubectl autoscale deployment milvus --min=1 --max=5 --cpu-percent=70 -n milvus
Parameter Value
Minimum Pods 1
Maximum Pods 5
Scaling Trigger CPU utilization ≥ 70%

Verify auto-scaling:

kubectl get hpa -n milvus

Index Algorithm Benchmarking

Script: index_data/benchmark.py

The benchmark compares three indexing algorithms on the same set of academic papers using cosine similarity for all similarity calculations.

Algorithms Compared

  1. HNSW
  2. IVF_PQ
  3. DiskANN

Benchmark Methodology

The benchmark script (benchmark.py) performs:

  1. Load: Reads all PDF/TXT papers from a directory.
  2. Chunk: Splits all documents (800/120). Same chunks for all index types.
  3. Embed: Generates embeddings via Gemini API with rate limiting (batch size 50, 2s delay). Embeddings are computed once and reused for all index types via PrecomputedEmbeddings.
  4. Index: For each index type (HNSW, IVF_PQ, DiskANN):
    • Creates a new Milvus collection.
    • Inserts all chunks with pre-computed embeddings.
    • Measures indexing time and collection storage size.
  5. Report: Prints a comparison table.

Analysis

Criterion Best Observation
Fastest Indexing IVF_PQ Product quantization with inverted file index is the fastest to build
Smallest Storage IVF_PQ PQ compression significantly reduces storage footprint
Highest Recall HNSW Graph-based ANN provides the best recall quality at the cost of higher memory

Environment Variables

Variable Default Where to Set Description
MILVUS_URI http://34.46.107.62:19530 Agent, Benchmark Milvus vector DB connection URI
MCP_SERVER_URL http://35.224.9.106:80/mcp Agent Translator MCP server endpoint
LANGGRAPH_API_BASE http://34.132.103.45:80 Streamlit LangGraph Agent API base URL

How to Run the Application

Step 1: Deploy Milvus on GKE (via Terraform)

Upload the milvus-gke folder to Google Cloud Shell

cd milvus-gke
terraform init
terraform apply
kubectl autoscale deployment milvus --min=1 --max=5 --cpu-percent=70 -n milvus

# Verify auto-scaling:
kubectl get hpa -n milvus

Note: Save the Milvus external IP

Step 2: Deploy Translator MCP Server

Update the MILVUS_URI as given in the milvus service endpoint

Upload the mcp-server folder to Google Cloud Shell

cd mcp-server
gcloud auth configure-docker
gcloud builds submit --tag gcr.io/<YOUR_PROJECT_ID>/mcpserver:1.0 .

Deploy to GKE (via Google Cloud Console):

  1. Go to Artifact Registry → find translator-mcp:1.0
  2. Click "Deploy to GKE"
  3. Deployment name: mcpserver
  4. Node type: User-managed nodes
  5. Expose: Port 80 to Target Port 9000
  6. Wait for green checkmark

Verify the translator service:

# Test
curl -X POST http://35.224.9.106:80/mcp \
  -H "Content-Type: application/json" \
  -H "Accept: application/json, text/event-stream" \
  -H "mcp-session-id: 41567d76ca6c4cc880226e9ee0505cff" \
  -d '{"jsonrpc":"2.0","method":"tools/call","params":{"name":"translate_text","arguments":{"text":"Hello world","source_lang":"en","target_lang":"es"}},"id":1}'

Note: Save the Translator external IP

Step 3: Deploy LangGraph Agent

Update the MILVUS_URI as given in the milvus service endpoint

Upload the mcp-server folder to Google Cloud Shell

cd langgraph-rag
gcloud builds submit --tag gcr.io/<YOUR_PROJECT_ID>/langgraph:1.0 .

Deploy to GKE (via Google Cloud Console):

  1. Go to Artifact Registry in langgraph:1.0
  2. Click "Deploy to GKE"
  3. Deployment name: langgraph
  4. Node type: User-managed nodes
  5. Environment variables (Container Details section):
    • MCP_SERVER_URL = http://<mcpserver_ip>:80/mcp
  6. Expose: Port 80 → Target Port 8000
  7. Wait for green checkmark

Verify the agent service:

curl http://<AGENT_IP>:80/ok
# Expected: {"status":"ok"}

# Test a query (English)
curl -X POST http://<AGENT_IP>:80/invoke \
  -H "Content-Type: application/json" \
  -d '{"input":{"question":"What are neural network architectures?","top_k":4}}'

Note: Save the Agent external IP

Step 4: Deploy Streamlit App

Upload the streamlit folder to Google Cloud Shell

cd streamlit
gcloud builds submit --tag gcr.io/<YOUR_PROJECT_ID>/streamlit:1.0 .

Deploy to GKE (via Google Cloud Console):

  1. Go to Artifact Registry and find streamlit:1.0
  2. Click "Deploy to GKE"
  3. Deployment name: streamlit
  4. Node type: User-managed nodes
  5. Environment variables (Container Details section): - LANGGRAPH_API_BASE = http://<langgraphservice_ip>:80
  6. Expose: Port 80 → Target Port 8080
  7. Wait for green checkmark

Access the Streamlit app: In services, click the service endpoint IP of the streamlit service to spin up the frontend and access the whole project

Step 5: Run Benchmarks

cd index_data
pip install -r requirements.txt

python benchmark.py --papers_dir ../papers

The benchmark:

  1. Loads all PDF papers from the directory.
  2. Chunks all documents (800/120 split).
  3. Embeds all chunks via Gemini API (with rate limiting).
  4. Creates separate Milvus collections for HNSW, IVF_PQ, and DiskANN.
  5. Prints a comparison table of indexing time and storage size.

About

This Project was part of the 14825 course I took at CMU.

Topics

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages