Athena is an open-source search agent that combines web search, intelligent scraping, BM25 retrieval, and local LLM reasoning to answer user questions with up-to-date information from the web. Unlike traditional search engines that return lists of links, Athena reads and understands web content to provide direct, well-sourced answers to your questions.
- Python 3.8+
- Ollama installed and running
- At least one LLM model pulled (e.g.,
gpt-oss:20b-cloud)
-
Clone the repository:
git clone <repository-url> cd athena
-
Install dependencies:
pip install -r requirements.txt
-
Pull an LLM model using Ollama:
ollama pull gpt-oss:20b-cloud
-
Create a
.envfile to specify the model you want to use:echo "MODEL_NAME=gpt-oss:20b-cloud" > .env
-
Ensure Ollama is running:
ollama serve
Run the application:
python run.pyEnter your question when prompted. Athena will:
- Use an LLM to break your query into 3-5 diverse search terms
- Search DuckDuckGo for all queries in parallel
- Scrape and extract content from the top pages
- Index all content using a BM25 corpus
- Retrieve the most relevant information based on your original query
- Generate an answer using the local LLM
- Display the response with source attribution
- Save the query to history
To exit, press Ctrl+C. Your conversation history will be saved automatically.
Ask Athena: What are the latest developments in quantum computing 2024?
[cyan]Analyzing query and generating search terms...[/cyan]
[dim]Queries: quantum computing breakthroughs 2024, latest quantum processor news, etc...[/dim]
[cyan]Searching...[/cyan]
[bold green]Athena:[/bold green]
Quantum computing has seen significant advances in 2024, including...
[answer continues...]
[bold yellow]Sources:[/bold yellow]
1. https://example.com/quantum-computing-2024
2. https://example.org/quantum-news
3. https://example.net/research-updates
- Query Expansion: An LLM agent analyzes the user query and generates 3-5 specialized search queries to ensure comprehensive coverage.
- Parallel Search: All generated queries are processed concurrently using
asyncio, retrieving results from DuckDuckGo.
- For each URL:
- First attempts static scraping using
requestswith proper headers - If static scraping fails (non-200 status, Cloudflare protection, etc.):
- Falls back to dynamic scraping using Selenium in headless mode
- Uses semaphores to limit concurrent requests (10 global, 2 dynamic)
- Implements timeouts to prevent hanging requests
- First attempts static scraping using
- HTML content is converted to clean text using Trafilatura
- Text is split into overlapping chunks (300 words each)
- A BM25 (Best Matching 25) index is built from all retrieved chunks, providing efficient keyword-based retrieval without the need for heavy embedding models.
- The original user query is used to retrieve the top 5 most relevant text chunks from the BM25 index
- Context + question + system prompt are formatted for the LLM
- Ollama generates a response using the model specified in
.env - Response is streamed back to the user in real-time
- Sources are deduplicated and displayed (top 5 unique URLs)
- Each query and timestamp is stored in
History/history.json - History is loaded on startup and saved on exit
To change the LLM model, simply update the MODEL_NAME value in the .env file:
MODEL_NAME=your-model-nameAdjust these values in the code:
max_resultsinseeker/search.py(default: 10)kinrun.pyretrieve_bm25 function (default: 10 chunks)chunk_sizeinrun.py(default: 300 words)
- Static scrape timeout: 8 seconds
- Dynamic scrape timeout: 15 seconds
- Global concurrency limit: 10 URLs
- Dynamic concurrency limit: 2 URLs
Key dependencies include:
ddgs: DuckDuckGo searchrequests&selenium: Web scrapingtrafilatura: HTML-to-text conversionrank-bm25: Probabilistic information retrievalollama: LLM interfacerich: Beautiful terminal output
See requirements.txt for the complete list.
Modify seeker/search.py to use different search APIs (Google, Bing, etc.) while maintaining the same return format.
Adjust scrapion/scrape.py to:
- Add more headers or cookies
- Implement different waiting strategies for dynamic content
- Add proxy support
Modify utils/model.py to work with different LLM APIs (OpenAI, Anthropic, etc.) while keeping the same interface.
Athena is designed for privacy:
- All processing happens locally on your machine
- No data is sent to external APIs (except for the initial web search)
- LLMs run locally via Ollama
- History is stored only on your local machine
- Scraped content is processed in memory and not persisted
-
"No results found"
- Check your internet connection
- Try a different query
- Verify DuckDuckGo is accessible
-
"No usable content extracted"
- The search results may be from sites that block scraping
- Try a query likely to return text-heavy results (news, Wikipedia, etc.)
-
Model loading errors
- Ensure Ollama is running:
ollama serve - Verify the model is pulled:
ollama list - Check if you have enough RAM/VRAM for the model
- Ensure Ollama is running:
-
Selenium issues
- Ensure Chrome/Chromium is installed
- Try updating selenium and webdriver-manager
This project is open source and available under the MIT License.
- Built with Ollama for local LLM inference
- Retrieval powered by rank-bm25
- Scraping powered by requests and Selenium
- Content extraction via trafilatura
- Search via DuckDuckGo Instant Answer API
- Terminal UI enhanced by Rich
Start exploring the web with Athena - your private, intelligent search agent! 🚀