---
title: 'ResearchPilot AI '
sdk: docker
emoji: π
colorFrom: indigo
colorTo: purple
thumbnail: >-
https://cdn-uploads.huggingface.co/production/uploads/64ea5e1dc68ddc867b5ec02f/r8wTLNQPQIfsQjgazt_I5.png
short_description: ResearchPilot AI is an Autonomous Multi-Agent Research Syste
---
# π§ ResearchPilot AI
### Autonomous Multi-Agent Research System
**Give it a topic β Get a complete, evidence-backed research report with charts, citations, and PDF export.**
ResearchPilot AI runs a coordinated team of specialised AI agents β each with a focused job β orchestrated by LangGraph. It plans, routes, searches, analyses, fact-checks, visualises, writes, and self-grades, all from one query.
[](https://python.org)
[](https://langchain-ai.github.io/langgraph/)
[](https://groq.com)
[](https://streamlit.io)
[](https://plotly.com)
[](https://www.reportlab.com)
[](LICENSE)
[π Live Demo](#) Β· [π Report Sample](#) Β· [π¨βπ» Portfolio](https://vishal-lazrus-portfolio.vercel.app/)
---
## π Table of Contents
| # | Section |
|---|---|
| 1 | [What is ResearchPilot AI?](#-what-is-researchpilot-ai) |
| 2 | [What Makes It Different](#-what-makes-it-different) |
| 3 | [Architecture](#-architecture) |
| 4 | [How It Works β Real Example](#-how-it-works--real-example) |
| 5 | [Folder Structure](#-folder-structure) |
| 6 | [The Five Agents](#-the-five-agents) |
| 7 | [The Six Chart Types](#-the-six-chart-types) |
| 8 | [Getting API Keys (Free)](#-getting-api-keys-free) |
| 9 | [Installation & Setup](#-installation--setup) |
| 10 | [Running the Project](#-running-the-project) |
| 11 | [Deploy to Hugging Face Spaces](#-deploy-to-hugging-face-spaces) |
| 12 | [Concepts Covered](#-concepts-covered) |
| 13 | [Troubleshooting](#-troubleshooting) |
| 14 | [Roadmap](#-roadmap) |
| 15 | [Connect With Me](#-connect-with-me) |
---
## π€ What is ResearchPilot AI?
ResearchPilot AI is a **multi-agent AI research system** built with LangGraph. You type one query β say, *"Impact of AI on healthcare market growth"* β and it autonomously runs an 8-node pipeline:
```
Query β Plan β Route β Research + Analyse β Visualise β Write β Grade β Deliver
```
The system produces:
- β
A **structured markdown report** (Executive Summary β Key Findings β Analysis β Expert Perspective β Conclusion β References)
- π Up to **6 interactive Plotly charts** generated from real statistical data
- π A **professional academic PDF** with embedded charts and APA citations
- ποΈ A **CSV file** of the raw statistics for further analysis
> This is not a chatbot wrapper. It implements the **planner β router β workers β critic** pattern used in production agentic AI systems.
### Who is this for?
| π Students | πΌ Professionals | π§βπ» Developers |
|---|---|---|
| Research papers, literature reviews, assignment prep | Market research, competitive analysis, technology evaluation | Learn LangGraph, conditional routing, agentic design patterns |
---
## β¨ What Makes It Different
| Feature | What it does |
|---|---|
| π **Dynamic Router Agent** | One LLM call decides *per-query* which of 5 specialist agents to activate. A history question never wastes time running a Statistics agent. A finance query gets Fact Checker. Nothing runs unless it adds value. |
| π **Statistics β Charts pipeline** | The Statistics agent returns *structured JSON* (not prose) β metrics, time-series, regional breakdowns β which directly drives 6 Plotly chart types with no extra LLM calls. |
| π **Persona-driven Domain Expert** | Adopts a credentialed persona per domain ("Dr. Sarah Chen, Harvard physician" for healthcare; "Marcus Reid, ex-Goldman analyst" for finance) β sharper than a generic "you are an expert" prompt. |
| β
**Dedicated Fact Checker** | Extracts specific claims, runs independent search evidence per claim, labels each: Verified / Partially True / Disputed / Unverifiable. |
| π **Self-grading + auto-retry** | Quality Gate scores the report 0β10 against five weighted criteria. Below 7 β automatic retry with explicit feedback. Capped at 2 retries to prevent runaway cost. |
| πΌοΈ **Cover runs after scoring** | The SVG cover card is generated *last* β after Quality Gate β so it always shows the real quality score, not zero. |
| π **ReportLab academic PDF** | Flowable single-column layout, deep-blue academic headings, horizontal rule separators, charts embedded directly under their matching report section. |
---
## ποΈ Architecture
> **Exact node execution order as wired in `graph/graph_builder.py`:**
```
βββββββββββββββββββββββββββββββββββ
β USER QUERY β
ββββββββββββββββββ¬βββββββββββββββββ
β
βΌ
ββββββββββββββββββββ
β π§ PLANNER β
β β
β β’ Detects domain β
β β’ Builds 3 tasks β
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
β π ROUTER β
β β
β Single LLM call β
β β active_agents β
β list in state β
ββββββββββ¬ββββββββββ
β
βΌ
βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
β βοΈ WORKERS NODE β
β Only activated agents run β
β β
β ββββββββββββββ ββββββββββββββ ββββββββββββββββββββ β
β β πResearch β β πStats β β πDomain Expert β β
β β β β β β β β
β β 3 Tavily β β Structured β β Persona prompt β β
β β searches β β JSON β β β per domain β β
β β β LLM β β chart data β β β β
β βββββββ¬βββββββ βββββββ¬βββββββ ββββββββββ¬ββββββββββ β
β β β β β
β βββββββ΄βββββββ βββββββ΄βββββββ β β
β β β
Fact β β πRefs β β β
β β Checker β β β β β
β β Claim-by- β β APA format β β β
β β claim β β citations β β β
β βββββββ¬βββββββ βββββββ¬βββββββ β β
β β β β β
β βββββββββββββββββ΄βββββββ¬βββββββββββββ β
β Virtual File System β
β (shared dict living in state) β
βββββββββββββββββββββββββββββ¬ββββββββββββββββββββββββββββββ
β
βΌ
ββββββββββββββββββββ
β π VISUALIZATION β
β β
β Statistics JSON β
β β 6 Plotly chartsβ
β (no LLM call) β
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
β βοΈ WRITER β
β β
β Reads all 5 VFS β
β files β builds β
β final report β
ββββββββββ¬ββββββββββ
β
βΌ
ββββββββββββββββββββ
ββββββββββ€ π QUALITY GATE βββββββββββββββββββββββ
β β β β
β β LLM scores 0-10 β β
β ββββββββββ¬ββββββββββ β
β β β
β score β₯ 7 β score < 7 (max 2 retries) β
β ββββββββββ ββββββββββββββββββββββββΊ Writer
β βΌ
β ββββββββββββββββββββ
β β πΌοΈ COVER β
β β β
β β SVG card with β
β β real score baked β
β β in (runs last) β
β ββββββββββ¬ββββββββββ
β β
ββββββββββββ
β
βΌ
STREAMLIT UI
ββββββββββββββββββββββββββββββββββ
β π¬ Research β π Data&Charts β
β π Referencesβ π Report β
β β β±οΈ Trace β
ββββββββββββββββββββββββββββββββββ
MD Β· CSV Β· PDF downloads
```
---
## β‘ How It Works β Real Example
**Query typed:** `"Impact of AI on healthcare market growth: adoption rates, investment trends and future outlook"`
| Step | Node | What happens |
|---|---|---|
| 1 | **Planner** | Detects `topic_domain = "healthcare"`. Creates tasks: search clinical data, find market numbers, locate key organisations. |
| 2 | **Router** | One LLM call β `["research", "statistics", "domain_expert", "fact_checker", "citation"]`. All 5 activate because healthcare needs everything. |
| 3a | **Research** | Runs 3 Tavily searches: raw query + "latest developments 2025" + "key findings evidence". LLM synthesises into structured deep-research. Writes `research_deep.txt` to VFS. |
| 3b | **Statistics** | Searches for "$45B market size", "29% CAGR" etc. Forces LLM to return exact JSON schema (metrics array + trends array + comparisons array). Writes `statistics.txt` + `statistics_data.csv`. |
| 3c | **Domain Expert** | Persona: *"Dr. Sarah Chen, Harvard-trained physician"*. Reads `research_deep.txt`, adds clinical nuance. Writes `expert_analysis.txt`. |
| 3d | **Fact Checker** | Extracts 6 specific claims. Verifies 4 individually via fresh Tavily searches. Labels β
/β οΈ/β. Writes `fact_check.txt`. |
| 3e | **References** | Formats all sources from `raw_search.txt` into APA JSON. Writes `references.txt`. Returns structured `citations` list. |
| 4 | **Visualization** | No LLM call. Reads `structured_data` dict β builds 6 Plotly figures β stores as JSON strings in `chart_json`. |
| 5 | **Writer** | Checks each VFS key. Builds context from whichever files exist. One large LLM call produces 9-section markdown report. |
| 6 | **Quality Gate** | LLM scores the report: **7.5/10**. `should_retry()` returns `"done"`. Routes to Cover. |
| 7 | **Cover** | Now has `quality_score = 7.5`. Generates SVG card with real score baked in. |
| **End** | **UI** | 5 sections rendered. Download MD + CSV + PDF available. |
---
## π Folder Structure
```
ResearchPilot AI/ β root folder
β
βββ graph/ β LangGraph nodes (the "brain")
β βββ __init__.py
β βββ state.py β ResearchState TypedDict β shared memory
β β every node reads from and writes to
β βββ llm_factory.py β get_llm() β Groq primary, Gemini fallback
β β every node imports this, never hardcodes
β βββ planner.py β Node 1: detects domain, builds task list
β βββ router.py β Node 2: LLM β active_agents list
β βββ workers.py β Node 3: all 5 specialist agents
β β conditionally called by if "agent" in active_agents
β βββ visualization.py β Node 4: structured_data JSON β 6 Plotly charts
β β (no LLM call β pure Python/Plotly)
β βββ synthesizer.py β Node 5 (displayed as "Writer"):
β β reads VFS β one LLM call β final report
β βββ quality_gate.py β Node 6: scores report + should_retry() function
β β drives the conditional edge / retry loop
β βββ thumbnail.py β Node 7 (displayed as "Cover"):
β β runs AFTER quality_gate so score exists
β βββ graph_builder.py β Wires all 7 nodes + edges + conditional edge
β into one compiled StateGraph object
β
βββ tools/ β Utilities used by nodes (not nodes themselves)
β βββ __init__.py
β βββ search_tool.py β web_search() wraps Tavily API
β β returns plain string for LLM context
β βββ file_system.py β vfs_write() / vfs_read() helpers
β β copy-on-write to keep state immutable
β βββ pdf_generator.py β ReportLab flowable PDF
β strips duplicate References section,
β embeds charts under matching headings
β
βββ ui/
β βββ app.py β Single-page Streamlit UI (~800 lines)
β st.session_state caches results so
β download clicks don't re-run the pipeline
β
βββ .streamlit/
β βββ config.toml β Dark theme + port 7860 for HF Spaces
β
βββ Dockerfile β Production Docker image for HF Spaces
βββ main.py β Terminal test runner (no UI)
βββ app.py β HF Spaces entry point
βββ requirements.txt
βββ .env.example β API key template
βββ .gitignore β Excludes .env, __pycache__, *.pdf
βββ README.md
```
---
## π€ The Five Agents
| Agent | File | Activates when | What it produces |
|---|---|---|---|
| **Research** | `workers.py` | Always | 3-angle Tavily search + LLM synthesis β `research_deep.txt` |
| **Statistics** | `workers.py` | Topic has numbers/trends | Structured JSON (metrics + trends + comparisons) + CSV β `statistics.txt` |
| **Domain Expert** | `workers.py` | Specialised topic | Persona-primed analysis β `expert_analysis.txt` |
| **Fact Checker** | `workers.py` | Claims need verification | Per-claim Tavily verify β `fact_check.txt` |
| **References** | `workers.py` | Citations add value | APA-formatted JSON list β `references.txt` |
All agents share data through the **Virtual File System** β a `Dict[str, str]` inside LangGraph state. Zero disk I/O.
---
## π The Six Chart Types
All generated from Statistics agent JSON with zero extra LLM calls:
| # | Chart | Driven by |
|---|---|---|
| 1 | **Horizontal Bar** | `metrics` array |
| 2 | **Multi-series Area / Trend** | `trends[].data_points` |
| 3 | **Donut / Pie** | `comparisons` array |
| 4 | **Gauge** | First 0β100 metric value |
| 5 | **Bubble Scatter** | All `metrics` (size = relative value) |
| 6 | **Year-on-Year Bar** | `trends[0].data_points` |
---
## π Getting API Keys (Free)
### Groq β Primary LLM β Required
Fast open-source inference (14,400 free requests/day):
1. [console.groq.com](https://console.groq.com) β Sign up β API Keys β Create
2. Copy: `gsk_...`
### Tavily β Web Search β
Required
Real-time web search for agents:
1. [app.tavily.com](https://app.tavily.com) β Sign up β Dashboard
2. Copy: `tvly-...`
3. Free: 1,000 searches/month
### Google Gemini β Fallback LLM (optional)
Only needed if no Groq key:
1. [aistudio.google.com](https://aistudio.google.com) β Get API Key
2. Copy: `AIzaSy...`
### LangSmith β Tracing (optional but recommended)
See every node execution, LLM call, and retry as a visual timeline:
1. [smith.langchain.com](https://smith.langchain.com) β Settings β API Keys β Create
2. Copy: `lsv2_...`
---
## βοΈ Installation & Setup
**Prerequisites:** Python 3.11+, Git
```bash
# 1. Clone
git clone https://github.com/vishal815/ResearchPilot-AI.git
cd ResearchPilot-AI
# 2. Virtual environment
python -m venv .venv
# 3. Activate
# Windows:
.venv\Scripts\activate
# Mac/Linux:
source .venv/bin/activate
# 4. Install dependencies
pip install -r requirements.txt
# 5. Set up API keys
cp .env.example .env
# Now open .env and fill in your keys
```
Your `.env` file:
```env
GROQ_API_KEY=gsk_your_key_here
TAVILY_API_KEY=tvly_your_key_here
# GOOGLE_API_KEY=AIzaSy_your_key_here (optional fallback)
# LANGCHAIN_API_KEY=lsv2_your_key_here (optional tracing)
# LANGCHAIN_TRACING_V2=true
# LANGCHAIN_PROJECT=researchpilot-ai
```
---
## βΆοΈ Running the Project
### Terminal mode (test the pipeline first)
```bash
python main.py
```
Output:
```
============================================================
ResearchPilot AI
Query: Impact of AI on healthcare market growth...
============================================================
[NODE: PLANNER] Domain detected: healthcare | 3 tasks created
[NODE: ROUTER] Activated: ['research', 'statistics', 'domain_expert', 'fact_checker', 'citation']
[NODE: WORKERS] Research done | Statistics: 8 metrics, 3 trends | Expert done | FactCheck done | Refs: 8 sources
[NODE: VISUALIZATION] 6 charts generated
[NODE: WRITER] Report generated
[NODE: QUALITY_GATE] Score: 7.5/10
[NODE: COVER] SVG cover card generated
============================================================
Total time: 52.3s | Saved to output_report_v2.md
```
### Streamlit Web UI
```bash
streamlit run ui/app.py
```
Opens at `http://localhost:8501`
---
## π³ Deploy to Hugging Face Spaces
The project ships with a ready `Dockerfile` that targets port 7860 (Hugging Face's required port).
### Step 1 β Push to GitHub
```bash
git add .
git commit -m "Initial ResearchPilot AI upload"
git push origin main
```
### Step 2 β Create a Hugging Face Space
1. Go to [huggingface.co/spaces](https://huggingface.co/spaces)
2. Click **Create new Space**
3. Set:
- **Space name:** `ResearchPilot-AI`
- **License:** MIT
- **SDK:** **Docker** β important, not Streamlit
- **Visibility:** Public
### Step 3 β Add API Keys as Secrets
> β οΈ Never put real API keys in code or `Dockerfile`. Use HF Secrets β they're injected as environment variables at runtime, invisible in the repo.
Go to your Space β **Settings** β **Repository secrets** β **New secret**:
| Secret Name | Value | Required? |
|---|---|---|
| `GROQ_API_KEY` | Your Groq key (`gsk_...`) | β
Required |
| `TAVILY_API_KEY` | Your Tavily key (`tvly_...`) | β
Required |
| `LANGCHAIN_API_KEY` | Your LangSmith key (`lsv2_...`) | Optional |
| `LANGCHAIN_TRACING_V2` | `true` | Optional (with LangSmith) |
| `GOOGLE_API_KEY` | Your Gemini key | Optional fallback |
**Why secrets, not `.env`?** HF Spaces clones your repo publicly β your `.env` must never be committed (it's in `.gitignore`). Secrets are stored encrypted in HF's vault and injected at container start time.
Your `Dockerfile` already sets:
```dockerfile
ENV LANGCHAIN_PROJECT="researchpilot-ai"
```
This constant is safe to hardcode because it's not sensitive β it's just the project name in LangSmith's dashboard.
The `LANGCHAIN_TRACING_V2=true` env var activates LangSmith auto-tracing β set it as a secret alongside your `LANGCHAIN_API_KEY`. Once both are set, every run appears in your [LangSmith dashboard](https://smith.langchain.com) showing exactly which node ran, how long each LLM call took, and the full prompt/response for every agent call.
### Step 4 β Link GitHub Repo
In your Space β **Files** β **Connect to GitHub repo** β select your repo β HF auto-builds on every push.
Or push directly to the HF Space's git remote:
```bash
git remote add hf https://huggingface.co/spaces/YOUR_HF_USERNAME/ResearchPilot-AI
git push hf main
```
### Step 5 β Wait for Build
HF Spaces shows a build log. The first build takes ~3-5 minutes (downloads dependencies). After that, code-only pushes rebuild in ~60 seconds.
---
## π Concepts Covered
| Concept | Where in code | One-line description |
|---|---|---|
| **Agentic AI** | All nodes | Agents decide and act, not just reply |
| **LangGraph StateGraph** | `graph_builder.py` | Stateful multi-node orchestration with cycles |
| **Conditional Edge / Routing** | `graph_builder.py` + `quality_gate.py` | `should_retry()` returns string β LangGraph picks next node |
| **Shared State (TypedDict)** | `state.py` | One dict flows through every node β how agents "talk" |
| **Tool Use** | `search_tool.py` | Agents calling Tavily external API |
| **Virtual File System** | `file_system.py` | Dict-as-filesystem for zero-I/O context sharing |
| **Persona Priming** | `workers.py` | Named, credentialed identity β sharper domain output |
| **Structured Output Forcing** | `workers.py` | Force LLM to return exact JSON schema for deterministic chart rendering |
| **LLM-as-Judge** | `quality_gate.py` | Separate LLM call evaluates the first LLM's output |
| **Self-Correction Loop** | `quality_gate.py` | Cycle in graph capped by `retry_count` |
| **RAG** | `workers.py` | Search first β synthesise over retrieved context |
| **Flowable PDF** | `pdf_generator.py` | ReportLab auto-layout vs. manual x/y coordinate mess |
| **Streamlit Session State** | `ui/app.py` | Cache results across reruns so downloads don't re-trigger agents |
---
## π§ Troubleshooting
| Error | Cause | Fix |
|---|---|---|
| `ModuleNotFoundError` | venv not activated | `.venv\Scripts\activate` then `pip install -r requirements.txt` |
| `ImportError: cannot import name 'web_search'` | Old `search_tool.py` | Confirm file has `def web_search(query, max_results=5):` |
| Charts missing / only 1 chart | rgba color bug (old version) | Make sure you have the latest `visualization.py` |
| Cover shows `Score: 0.0` | Old graph wiring (cover before quality_gate) | Make sure you have the latest `graph_builder.py` |
| PDF has two References sections | LLM writes its own + structured list | Make sure you have latest `pdf_generator.py` with `_strip_references_section()` |
| `kaleido` error in PDF | Wrong kaleido version | `pip install kaleido==0.2.1` (pin to 0.2.1 exactly) |
| Page "resets" on download | Old `app.py` without session_state cache | Make sure you have latest `ui/app.py` |
| `429` rate limit | Hit LLM free tier | Wait 60s and retry, or switch to Gemini fallback |
---
## π£οΈ Roadmap
- [ ] AI-generated cover image via Pollinations AI (free, no key needed)
- [ ] LangGraph checkpointing for session memory across multiple queries
- [ ] Upload a PDF/document as additional research context
- [ ] Model selector in UI (Groq / Gemini / OpenRouter)
- [ ] Auto-generate PowerPoint slide deck from the report
- [ ] LangSmith evaluation dashboard integration
---
## π License
MIT License β free to use, modify, and distribute with attribution.
---
## π Acknowledgements
[LangGraph](https://langchain-ai.github.io/langgraph/) Β· [Groq](https://groq.com) Β· [Google Gemini](https://aistudio.google.com) Β· [Tavily](https://tavily.com) Β· [Plotly](https://plotly.com) Β· [Streamlit](https://streamlit.io) Β· [ReportLab](https://www.reportlab.com) Β· [LangSmith](https://smith.langchain.com)
---
## π¨βπ» Connect With Me
[π Portfolio](https://vishal-lazrus-portfolio.vercel.app/) β’
[πΌ LinkedIn](https://www.linkedin.com/in/vishal-lazrus/) β’
[π GitHub](https://github.com/vishal815)
**If this helped you learn something, give it a β on GitHub!**
*Built by Vishal Lazrus during AI Internship at Infosys, June 2026*