- Python 71.2%
- HTML 27.4%
- Dockerfile 1.4%
| chatbot | ||
| searxng | ||
| .dockerignore | ||
| .env.example | ||
| .gitignore | ||
| Caddyfile | ||
| docker-compose.yml | ||
| README.md | ||
AI Search Chatbot
A Docker Compose application with SearXNG (JSON mode) and an AI chatbot that generates search queries, retrieves results, and synthesizes answers with references.
Security Features
This application includes comprehensive security hardening:
- API Key Authentication: Timing-safe
X-API-Keyauthentication on all endpoints (disabled in dev mode) - Rate Limiting: Per-IP sliding window rate limiter with periodic cleanup
- Content Security Policy: CSP, X-Frame-Options, X-Content-Type-Options, and other security headers via Caddy
- Prompt Injection Protection: Input validation and sanitization to detect and block prompt injection attempts
- Request Timeouts: Configurable global request timeout with proper cancellation
- Sensitive Data Filtering: Logs automatically mask API keys, secrets, and other sensitive data
- Connection Pooling: Reused HTTP clients with connection pool limits to prevent resource exhaustion
- Retry Logic: Exponential backoff for SearXNG API calls
- Health Checks: Monitor all services for proper functioning
- Supply Chain Security: Pinned Docker image digests and SearXNG version
Architecture
┌─────────────┐ JSON API ┌─────────────────────────────────────────┐ OpenAI ┌──────────────┐
│ Browser │◄────────────────►│ Chatbot (FastAPI) │◄────────────►│ LLM API │
│ (localhost:8000)│ │ │ │ (any │
│ │ │ 1. Receive query │ │ OpenAI- │
│ │ │ 2. Launch 3 parallel researchers: │ │ compat.) │
│ │ │ ├─ Researcher A (technical focus) │ │ │
│ │ │ ├─ Researcher B (academic focus) │ │ │
│ │ │ └─ Researcher C (practical focus) │ │ │
│ │ │ 3. Each researcher: search → synthesize │ │ │
│ │ │ 4. Synthesizer agent: combine 3 answers │ │ │
└─────────────┘ └─────────────────────────────────────────┘ └──────────────┘
│
▼
┌──────────────────┐
│ SearXNG │
│ (localhost:8080) │
└──────────────────┘
Multi-Researcher Architecture
Each user query triggers a parallel research pipeline:
-
Three Researchers run concurrently, each with a different focus:
- Technical: Focuses on implementation details, code, architecture
- Academic: Focuses on research papers, definitions, scholarly sources
- Practical: Focuses on real-world usage, tutorials, best practices
-
Each researcher independently:
- Generates specialized search queries (via LLM)
- Searches SearXNG with their queries
- Synthesizes an answer from their results
-
Synthesizer Agent (no tools, system-prompt-only):
- Receives all three researcher answers
- Combines, reconciles, and deduplicates perspectives
- Produces one final, comprehensive answer with unified references
Quick Start
-
Configure the LLM in
.env:LLM_API_BASE=https://api.openai.com/v1 LLM_API_KEY=sk-your-key-here LLM_MODEL=gpt-4oWorks with any OpenAI-compatible endpoint (Ollama, vLLM, LM Studio, etc.):
LLM_API_BASE=http://host.docker.internal:11434/v1 LLM_API_KEY=not-needed LLM_MODEL=llama3 -
Generate a strong SearXNG secret key (required for production):
echo "SEARXNG_SECRET_KEY=$(openssl rand -hex 32)" >> .env -
Start the stack:
docker compose up --build
Security Configuration
Authentication
By default, authentication is disabled in dev mode. To enable it in production:
-
Set
CHATBOT_API_KEYin.envto a strong random value:echo "CHATBOT_API_KEY=$(openssl rand -hex 32)" >> .env -
Add the
X-API-Keyheader to your requests:curl -H "X-API-Key: your-key" -X POST http://localhost:8000/answer \ -H "Content-Type: application/json" \ -d '{"message": "What is RAG?"}'
CORS Configuration
Set ALLOWED_ORIGINS in .env to restrict cross-origin requests:
# Single origin
ALLOWED_ORIGINS=["https://example.com"]
# Multiple origins
ALLOWED_ORIGINS=["https://example.com", "https://app.example.com"]
Leave empty (ALLOWED_ORIGINS=[]) to reject all cross-origin requests.
Rate Limiting
The default rate limit is 10 requests per 60 seconds per IP. Configure in .env:
RATE_LIMIT_MAX_REQUESTS=20
RATE_LIMIT_WINDOW_SECONDS=120
Request Timeout
Set the global request timeout in .env:
REQUEST_TIMEOUT_SECONDS=60 # 60 seconds
API
POST /answer
{
"message": "What is RAG?"
}
Response:
{
"response": "RAG (Retrieval-Augmented Generation) is...",
"search_queries": ["RAG definition machine learning", "retrieval augmented generation explained"],
"references": [
{
"title": "RAG - Wikipedia",
"url": "https://en.wikipedia.org/wiki/RAG",
"content": "Retrieval-augmented generation (RAG)..."
}
]
}
Files
| File | Purpose |
|---|---|
docker-compose.yml |
Orchestrates SearXNG + chatbot |
.env |
API keys and endpoint URLs |
searxng/settings.yml |
SearXNG configuration |
searxng/limiter.toml |
Disable rate limiting (dev) |
chatbot/app.py |
FastAPI chatbot application |
chatbot/config.py |
Env-based configuration |
chatbot/Dockerfile |
Chatbot container image |
Customization
- Change search engines: Edit
searxng/settings.yml— enable/disable or add engines - Adjust result count: Edit
app.py→unique[:10]to change the number of results passed to the LLM - Tweak prompting: Edit the system messages in
app.py(generate_search_queriesandsynthesize_answer)