Skip to content

Folders and files

NameName
Last commit message
Last commit date

Latest commit

Β 

History

104 Commits
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 
Β 

Repository files navigation

Open Deep Research logo

Open Deep Research

License Python Docker

Official search support: DuckDuckGo Bocha

Read this in other languages: πŸ‡¨πŸ‡³ δΈ­ζ–‡ Β· πŸ‡«πŸ‡· FranΓ§ais Β· πŸ‡ͺπŸ‡Έ EspaΓ±ol

An open replication of OpenAI's Deep Research with a modern web UI β€” adapted from HuggingFace smolagents with simplified configuration for easy self-hosting.

Read more about the original implementation in the HuggingFace blog post.

This agent achieves 55% pass@1 on the GAIA validation set, compared to 67% for OpenAI's Deep Research.


Features

  • Parallel background research β€” fire off multiple research tasks simultaneously, monitor them independently, and come back to results later β€” even after closing the browser
  • Multi-agent research pipeline β€” Manager + search sub-agents with real-time streaming output
  • Modern Web UI β€” Preact-based SPA with collapsible sections, model selector, and copy support
  • Flexible model support β€” OpenAI, Anthropic, DeepSeek, Ollama, and any OpenAI-compatible provider
  • Multiple search engines β€” DuckDuckGo (free), SerpAPI, MetaSo with automatic fallback
  • Session history β€” SQLite-backed session storage with replay support
  • Three run modes β€” Live (real-time), Background (persistent), Auto-kill (one-shot)
  • Model auto-discovery β€” Detects available models from configured providers
  • Vision & media tools β€” Image QA, PDF analysis, audio transcription, YouTube transcripts
  • Production-ready β€” Docker, Gunicorn, multi-worker, health checks, configurable via JSON

Screenshots:

Web UI Input

Clean input interface with model selection

Agent Plans and Tools

Real-time display of agent reasoning, tool calls, and observations

Final Results

Highlighted final answer with collapsible sections


Parallel Background Research

Deep research tasks are slow β€” a single run can take 10–30 minutes. Most tools block the UI until the task completes, forcing you to wait.

This project takes a different approach: fire off as many research tasks as you want and let them run in the background β€” simultaneously.

β”Œβ”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”
β”‚  Question A: "What are the latest advances in LLMs?" β”‚  ← running
β”‚  Question B: "Compare top vector databases in 2025"  β”‚  ← running
β”‚  Question C: "EU AI Act compliance checklist"        β”‚  ← completed βœ“
β””β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”€β”˜
        All visible in the sidebar. Click any to inspect.

How it works:

  1. Select Background or Auto-kill run mode (the default)
  2. Submit your first research question β€” the agent starts immediately in a subprocess
  3. The UI is not locked β€” submit a second question, a third, as many as you need
  4. Each agent runs independently, persisting all its reasoning steps and results to SQLite
  5. Use the sidebar to switch between running sessions in real-time
  6. Close the browser β€” in Background mode, agents keep running on the server
  7. Return later and click any session to replay the full research trace

Run mode comparison:

Mode Multiple at once Survives browser close UI locked
Background βœ… βœ… βœ—
Auto-kill βœ… βœ— (killed on tab close) βœ—
Live βœ— βœ— βœ…

This is particularly useful for:

  • Batch research workflows where you queue several related questions and review results together
  • Long-running queries where you don't want to keep a tab open
  • Teams sharing a self-hosted instance with multiple concurrent users

Why This Project?

  • One-command Docker install, zero config to start β€” docker run -p 5080:5080 ghcr.io/extracurricular-ai/open-deep-research-with-web-ui:latest and a working web UI is up. DuckDuckGo search is built-in; one model API key is enough to begin.

  • No LiteLLM dependency β€” direct OpenAI + Anthropic SDK calls only. Removes the intermediary translation layer that LiteLLM has had repeated security advisories for. Safer for enterprise / internal deployments.

  • Air-gap-friendly, self-hostable β€” no telemetry, no external service dependencies beyond the model + search APIs you explicitly configure. Pair with Ollama / LM Studio / vLLM for fully offline operation behind any firewall.

  • Built to be forked β€” ~3K LOC Python on top of smolagents. Add a tool by dropping a file in scripts/; swap providers via scripts/model_routing.py; hook into agent step callbacks (see scripts/compaction.py). A starting point for your internal research agent, not a closed product.

  • Multi-provider search with auto-fallback β€” DDGS, Tavily, SerpAPI, MetaSo, Bocha β€” wired up out of the box. Configure as an ordered list; the agent walks the chain on empty results or rate-limit errors. Cross-regional, China-hosted, and air-gapped friendly.

  • Parallel background research β€” the most unique feature in this space. Run multiple research tasks simultaneously; each persists to SQLite. Close the browser, return hours later, results are waiting. No other open-source deep research tool supports this.

Comparison with alternatives

Feature This project nickscamara/open-deep-research gpt-researcher langchain/open_deep_research smolagents
Docker / one-command deploy βœ… Pre-built image on GHCR βœ… Dockerfile βœ… Docker Compose ❌ Manual ❌ Library only
No LiteLLM dependency βœ… Direct OpenAI + Anthropic SDKs ⚠️ AI SDK layer ⚠️ ⚠️ langchain layer βœ…
Air-gapped / internal deploy βœ… No telemetry, no external deps ⚠️ Depends on Firecrawl ⚠️ Cloud-leaning defaults ⚠️ LangGraph Studio βœ…
Multi-provider search w/ fallback βœ… DDGS + Tavily + SerpAPI + MetaSo + Bocha ❌ Firecrawl only ⚠️ Single per run ⚠️ Configurable ⚠️ DIY
Regional model providers βœ… DeepSeek first-class ⚠️ US-centric ⚠️ US-centric ⚠️ US-centric βœ…
No-build frontend βœ… Preact + htm (no build step) ❌ Next.js build required ❌ Next.js build required ❌ LangGraph Studio β€”
Free search out of the box βœ… DuckDuckGo (no key needed) ❌ Firecrawl API required ⚠️ Key recommended ⚠️ Configurable βœ…
Local model support βœ… Ollama, LM Studio ⚠️ Limited βœ… Ollama/Groq βœ… βœ…
Parallel background tasks βœ… Multiple simultaneous runs ❌ ❌ ❌ ❌
Session history / replay βœ… SQLite-backed ❌ ❌ ❌ ❌
Streaming UI βœ… SSE, 3 run modes βœ… Real-time activity βœ… WebSocket βœ… Type-safe stream ❌
Vision / image analysis βœ… PDF screenshots, visual QA ❌ ⚠️ Limited ❌ ⚠️
Audio / YouTube βœ… Transcription, speech ❌ ❌ ❌ ❌
GAIA benchmark score 55% pass@1 β€” β€” β€” 55% (original)

Quick Start

1. Clone the repository

git clone https://github.com/extracurricular-ai/open-deep-research-with-web-ui.git
cd open-deep-research-with-web-ui

2. Install system dependencies

The project requires FFmpeg for audio processing.

  • macOS: brew install ffmpeg
  • Linux: sudo apt-get install ffmpeg
  • Windows: choco install ffmpeg or download from ffmpeg.org

Verify: ffmpeg -version

3. Install Python dependencies

python3 -m venv venv
source venv/bin/activate  # On Windows: venv\Scripts\activate
pip install -e .

4. Configure

Copy the example config and add your API keys:

cp odr-config.example.json odr-config.json

Edit odr-config.json to set your model provider and API keys (see Configuration below).

5. Run

# Web UI (recommended)
python web_app.py
# Open http://localhost:5080

# CLI
python run.py --model-id "gpt-4o" "Your research question here"

Configuration

Two layers of configuration:

  1. odr-config.json β€” primary, JSON, controls everything (models, agent behavior, search providers, browser, limits, compaction). Auto-created from odr-config.example.json on first run.
  2. .env β€” optional, for secrets you'd rather keep out of JSON or for Docker deployments.

API keys in odr-config.json take precedence over .env values when both are set.

odr-config.json reference

Copy odr-config.example.json to odr-config.json and edit. The full schema:

{
  "agent": {
    "search_agent_max_steps": 20,
    "manager_agent_max_steps": 12,
    "planning_interval": 4,
    "verbosity_level": 2
  },
  "model": {
    "providers": [
      {"provider": "openai",    "api_key": "sk-...", "base_url": ""},
      {"provider": "deepseek",  "api_key": "",       "base_url": ""},
      {"provider": "anthropic", "api_key": "",       "base_url": ""}
    ],
    "default_model_id": "o1",
    "max_completion_tokens": 32768,
    "reasoning_effort": "high",
    "retry_max_attempts": 5,
    "retry_wait_seconds": 30
  },
  "search": {
    "providers": [
      {"provider": "DDGS",      "key": ""},
      {"provider": "TAVILY",    "key": ""},
      {"provider": "SERPAPI",   "key": ""},
      {"provider": "META_SOTA", "key": ""},
      {"provider": "BOCHA",     "key": ""}
    ],
    "max_results": 10
  },
  "browser": {
    "viewport_size": 5120,
    "request_timeout": 300
  },
  "limits": {
    "text_limit": 100000,
    "max_field_length": 50000
  },
  "compaction": {
    "enabled": true,
    "summarizer_model_id": null,
    "summary_threshold_tokens": 1000,
    "summary_max_tokens": 600,
    "summary_input_cap_tokens": 6000,
    "plan_keep_back": 3,
    "gap_summary_max_tokens": 500,
    "max_retries": 10
  },
  "other_keys": {"hf_token": ""},
  "models": [ /* UI dropdown β€” list of {id, name, description} */ ]
}

The UI exposes a settings panel that edits the same file. Server-side edits via the UI are gated behind CONFIG_ADMIN_PASSWORD if ENABLE_CONFIG_UI=true.

agent β€” multi-step research loop

Key Default Effect
search_agent_max_steps 20 Max ReAct steps the search sub-agent takes per task. Each step is one LLM call + one tool call (web search, browse, text inspect). Bigger = deeper research per sub-task, but each extra step accumulates ~5–30K tokens of observation in context.
manager_agent_max_steps 12 Max steps the manager takes. Each step usually delegates to a sub-agent or synthesizes results. Rarely needs raising; if you hit the cap, the question is probably better split.
planning_interval 4 Insert a "re-plan" step every N action steps. Lower = more course-correction (better when the agent loses focus); higher = fewer planning calls (cheaper, faster).
verbosity_level 2 Logger verbosity. 0 silent, 1 info, 2 debug.

model β€” LLM provider routing

Key Default Effect
providers[] OpenAI/DeepSeek/Anthropic stubs List of credentials. Each entry: {"provider": "<openai|deepseek|anthropic|...>", "api_key": "...", "base_url": ""}. The base_url field lets you point at a self-hosted or proxy endpoint that speaks the provider's wire format (e.g. Ollama's OpenAI-compatible API). The first provider matching the chosen default_model_id's routing is used.
default_model_id "o1" Which model the agent uses. Routing is automatic based on the prefix β€” see Supported Models. Override per-run with --model-id.
max_completion_tokens 32768 Output token cap before clamping. Each model has a hard ceiling (gpt-4o-mini: 16K, deepseek-chat: 8K, o1: 100K, claude-sonnet-4: 64K). The effective value passed to the API is min(this_setting, model_cap) β€” if you keep the default 32768, smaller models silently clamp to their own ceiling so you never get a 4xx for "max_tokens too large". Lowering only helps if you want shorter outputs; raising past the model cap is a no-op.
reasoning_effort "high" Only used when default_model_id is "o1". Values: "low", "medium", "high". Trade-off between latency/cost and reasoning depth.
retry_max_attempts 5 How many times to retry transient errors (HTTP 429, connection drops, partial reads). Note: this does not retry on context-overflow / 400-class errors, which are unrecoverable.
retry_wait_seconds 30 Initial backoff between retries. Doubles each attempt with jitter (exponential backoff).

search β€” search providers and result count

Key Default Effect
providers[] DDGS first, others empty Ordered fallback chain. The agent tries the first provider; if it returns no results or errors, it moves to the next. Add a key field per entry (DDGS doesn't need one). See Search Engines below for the full provider list.
max_results 10 How many search results returned per query. Each result is a title + snippet + URL (~few hundred tokens). Bigger = wider net, but more tokens in observation. Lower if you're hitting context limits and not using compaction.

browser β€” text browser tool

Key Default Effect
viewport_size 5120 Characters visible per page-view in the simulated browser. The agent uses page_up/page_down to scroll. Larger = fewer scroll calls but bigger observations. Smaller = more navigation steps but each observation is smaller.
request_timeout 300 Seconds to wait for an HTTP fetch before giving up. Slow sites or tiny VMs may need higher.

limits β€” content size guards

Key Default Effect
text_limit 100000 Max characters returned by text_inspector_tool (the file-reader for PDFs / large docs). Keeps a single inspect_file_as_text call from blowing up the agent's memory.
max_field_length 50000 Max characters per SSE event field sent to the frontend (display-side only β€” does not reduce LLM input). Lowering this just saves bandwidth between server and browser.

compaction β€” LLM-based context compaction (Layer 1 + Layer 2)

Without this, smolagents accumulates every step's raw observation forever and 20-step research runs reliably blow past model context windows. See scripts/compaction.py for the implementation.

Key Default Effect
enabled true Master switch. Set false to fall back to raw-observation behavior (faster per step, but long runs may crash on context overflow).
summarizer_model_id null null = use the agent's main model (simplest, no extra config). Override with a cheap model id (e.g. "deepseek-chat") to lower cost/latency of summarization. Currently the override path is reserved for a future PR; today the value is read but the main model is always used.
summary_threshold_tokens 1000 Layer 1: skip per-step summarization if the observation is shorter than this (in tokens, counted via tiktoken cl100k_base). Below 1000 tokens, the savings don't outweigh the LLM call cost.
summary_max_tokens 600 Layer 1: target output length of the per-step summary. The summary preserves facts, numbers, and URLs; drops navigation chrome and repetitive HTML.
summary_input_cap_tokens 6000 Layer 1: max input fed to the summarizer (head + tail trim if observation is bigger). Caps the summarizer's own context cost.
plan_keep_back 3 Layer 2: how many recent plan-gaps stay uncompacted. With planning_interval=4 and 20 search-agent steps, this fires once during a typical run (compacting the oldest gap). Lower (2 or 1) to consolidate more aggressively.
gap_summary_max_tokens 500 Layer 2: target length of each consolidated gap summary. URLs from the gap are appended verbatim.
max_retries 10 Retries for the compaction LLM call (own retry layer on top of the model's internal retrier). Mirrors Claude Code's default budget. After exhaustion, falls back to head+tail token truncation rather than crashing the run.

other_keys β€” miscellaneous tokens

Key Default Effect
hf_token "" HuggingFace token. Only required when running the GAIA benchmark (run_gaia.py) which downloads the validation dataset.

models β€” UI dropdown

A pure-display list of {id, name, description} triples for the model picker in the web UI. Editing this only affects the UI. The actual model used is whatever default_model_id (or CLI --model-id) resolves to.

Environment variables

For Docker or when you'd rather not put secrets in JSON, copy .env.example to .env:

cp .env.example .env
Variable Effect
ENABLE_CONFIG_UI If true, exposes the server-side config editing endpoint in the UI. Defaults to false.
CONFIG_ADMIN_PASSWORD Password gate for the server-side config UI. Required when ENABLE_CONFIG_UI=true.
META_SOTA_API_KEY API key for MetaSo search. Used as fallback when search.providers[].key is empty.
SERPAPI_API_KEY API key for SerpAPI search. Same fallback rule.
BOCHA_API_KEY API key for Bocha AI (博ζŸ₯) search. Same fallback rule.
TAVILY_API_KEY API key for Tavily search. Same fallback rule.
OPENAI_API_KEY OpenAI key. Used when model.providers[] openai entry has no api_key.
ANTHROPIC_API_KEY Anthropic key. Same fallback rule.
DEEPSEEK_API_KEY DeepSeek key. Same fallback rule.
HF_TOKEN HuggingFace token. Same fallback for other_keys.hf_token.
ODR_MAX_CONCURRENT Max research sessions running at once. Extra submissions are queued (FIFO) and auto-started as slots free. Defaults to 16; floor of 1, no upper limit β€” tune to your provider rate limits and memory. Enforced globally across all Gunicorn workers via SQLite.
ODR_DB_PATH Path to the SQLite session database. Defaults to odr_sessions.db next to the app.
DEBUG Enable debug logging (false by default).
LOG_LEVEL Log verbosity β€” DEBUG, INFO, WARNING, ERROR (INFO by default).

Note

Keys set in odr-config.json take precedence over .env values.

Supported Models

Supports OpenAI, Anthropic, DeepSeek, Ollama, and any OpenAI-compatible provider. Model routing is automatic from the model id prefix. Examples:

python run.py --model-id "gpt-4o" "Your question"
python run.py --model-id "o1" "Your question"
python run.py --model-id "claude-sonnet-4-6" "Your question"
python run.py --model-id "deepseek/deepseek-chat" "Your question"
python run.py --model-id "ollama/mistral" "Your question"  # local model

max_completion_tokens is automatically clamped to each model's published output ceiling (see scripts/model_routing.py for the full table). You don't need to lower the config when switching to a small-cap model.

Warning

The o1 model requires OpenAI tier-3 API access: https://help.openai.com/en/articles/10362446-api-access-to-o1-and-o3-mini

Search Engines

Engine Key Required Notes
DDGS No DuckDuckGo, free, default.
TAVILY Yes Tavily, often the best result quality for English queries.
META_SOTA Yes MetaSo, optimized for Chinese queries.
SERPAPI Yes Google results via SerpAPI.
BOCHA Yes Bocha AI (博ζŸ₯), Chinese-optimized web search.

Multiple engines can be listed in search.providers[] β€” the agent tries them in order and falls through to the next on empty results or errors.


Usage

Web UI

python web_app.py
# or with custom host/port:
python web_app.py --port 8000 --host 0.0.0.0

Open http://localhost:5080 in your browser.

Run modes (available via the split-button in the UI):

Mode Behavior
Live Stream output in real-time; session ends on disconnect
Background Agent runs persistently; reconnect anytime to view results
Auto-kill Agent runs, session is cleaned up after completion

CLI

python run.py --model-id "gpt-4o" "What are the latest advances in quantum computing?"

GAIA Benchmark

# Requires HF_TOKEN for dataset download
python run_gaia.py --model-id "o1" --run-name my-run

Deployment

Docker (Recommended)

Pre-built images are available on GitHub Container Registry:

docker pull ghcr.io/extracurricular-ai/open-deep-research-with-web-ui:latest

docker run -d \
  --env-file .env \
  -v ./odr-config.json:/app/odr-config.json \
  -p 5080:5080 \
  --name open-deep-research \
  ghcr.io/extracurricular-ai/open-deep-research-with-web-ui:latest

Docker Compose (includes volume for downloaded files):

cp .env.example .env        # configure API keys
cp odr-config.example.json odr-config.json  # configure models
docker-compose up -d
docker-compose logs -f      # follow logs
docker-compose down         # stop

Build your own image:

docker build -t open-deep-research .
docker run -d --env-file .env -p 5080:5080 open-deep-research

Warning

Never commit .env or odr-config.json with real API keys to git. Always pass secrets at runtime.

Gunicorn (Production)

pip install -e .
gunicorn -c gunicorn.conf.py web_app:app

The included gunicorn.conf.py is pre-configured with:

  • Multi-worker process management
  • 300s timeout for long-running agent tasks
  • Proper logging and error handling

Architecture

Agent Pipeline

User Question
    β”‚
    β–Ό
Manager Agent (CodeAgent / ToolCallingAgent)
    β”‚  Plans multi-step research strategy
    β”œβ”€β”€β–Ά Search Sub-Agent Γ— N
    β”‚       β”‚  Web search β†’ browse β†’ extract
    β”‚       └──▢ Tools: DuckDuckGo/SerpAPI/MetaSo, VisitWebpage,
    β”‚                   TextInspector, VisualQA, YoutubeTranscript
    β”‚
    └──▢ Final Answer synthesis

Streaming Pipeline

run.py  (step_callbacks β†’ JSON-lines on stdout)
  β”‚
  β–Ό
web_app.py  (subprocess β†’ Server-Sent Events)
  β”‚
  β–Ό
Browser  (Preact components β†’ DOM)

SSE event types:

Event Description
planning_step Agent reasoning and plan
code_running Code being executed
action_step Tool call + observation
final_answer Completed research result
error Error with details

DOM Hierarchy

#output
β”œβ”€β”€ step-container.plan-step       (manager plan)
β”œβ”€β”€ step-container                 (manager step)
β”‚   └── step-children
β”‚       β”œβ”€β”€ model-output           (reasoning)
β”‚       β”œβ”€β”€ Agent Call             (code, collapsed)
β”‚       └── sub-agent-container
β”‚           β”œβ”€β”€ step-container.plan-step  (sub-agent plan)
β”‚           β”œβ”€β”€ step-container            (sub-agent steps)
β”‚           └── sub-agent-result          (preview + collapsible)
└── final_answer                   (prominent result block)

Reproducibility (GAIA Results)

The 55% pass@1 result on GAIA was obtained with augmented data:

  • Single-page PDFs and XLS files were opened and screenshotted as .png
  • The file loader checks for a .png version of each attachment and prefers it

The augmented dataset is available at smolagents/GAIA-annotated (access granted instantly on request).


Development

pip install -e ".[dev]"   # includes testing, linting, type checking tools
python web_app.py         # starts dev server with auto-reload

The frontend is a dependency-free Preact app using htm for JSX-like templates β€” no build step required. Edit files in static/js/components/ and refresh.


License

Licensed under the Apache License 2.0 β€” the same license as smolagents.

See LICENSE for details.

Acknowledgments:

  • Original research agent implementation by HuggingFace smolagents
  • Web UI, session management, streaming architecture, and configuration system added in this fork

About

πŸ” AI-powered deep research agent with Web UI. Built on smolagents, featuring process-based architecture, MetaSo/DuckDuckGo search, and Docker deployment. Apache 2.0 licensed.

Topics

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages