Spaces:
Sleeping
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.
π Live Demo Β· π Report Sample Β· π¨βπ» Portfolio
π Table of Contents
π€ 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):
- console.groq.com β Sign up β API Keys β Create
- Copy:
gsk_...
Tavily β Web Search β Required
Real-time web search for agents:
- app.tavily.com β Sign up β Dashboard
- Copy:
tvly-... - Free: 1,000 searches/month
Google Gemini β Fallback LLM (optional)
Only needed if no Groq key:
- aistudio.google.com β Get API Key
- Copy:
AIzaSy...
LangSmith β Tracing (optional but recommended)
See every node execution, LLM call, and retry as a visual timeline:
- smith.langchain.com β Settings β API Keys β Create
- Copy:
lsv2_...
βοΈ Installation & Setup
Prerequisites: Python 3.11+, Git
# 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:
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)
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
git add .
git commit -m "Initial ResearchPilot AI upload"
git push origin main
Step 2 β Create a Hugging Face Space
- Go to huggingface.co/spaces
- Click Create new Space
- Set:
- Space name:
ResearchPilot-AI - License: MIT
- SDK: Docker β important, not Streamlit
- Visibility: Public
- Space name:
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:
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 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:
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 Β· Groq Β· Google Gemini Β· Tavily Β· Plotly Β· Streamlit Β· ReportLab Β· LangSmith
π¨βπ» Connect With Me
π Portfolio β’ πΌ LinkedIn β’ π GitHub
If this helped you learn something, give it a β on GitHub!
Built by Vishal Lazrus during AI Internship at Infosys, June 2026