Production-ready hybrid RAG system with BGE-M3, reranking, and comprehensive evaluation
Production-ready hybrid RAG (Retrieval-Augmented Generation) system with intelligent reranking, multi-backend vector database support, and comprehensive evaluation framework.
Documents → Ingest → Vector DB (Hybrid Index) → Query → Retrieve (topK=50) →
Rerank (topN=8) → LLM Generate → Answer with Citations → Evaluate
# Clone the repository
git clone https://github.com/deadjoe/askme.git
cd askme
# Install dependencies
uv sync --dev
# Start vector database (Weaviate)
docker compose -f docker/docker-compose.yaml --profile weaviate up -d weaviate
# Start API server using startup script
./scripts/start-api.sh --skip-heavy-init --reload
# Alternative: Start API server directly
# ASKME_SKIP_HEAVY_INIT=1 uv run uvicorn askme.api.main:app --port 8080 --reload
# Ingest documents
./scripts/ingest.sh /path/to/documents --tags="project,documentation"
# Ask questions
./scripts/answer.sh "What is machine learning?"
# Retrieve documents only (for debugging/tuning)
./scripts/retrieve.sh "hybrid search techniques" --topk=100 --alpha=0.7
# Quick end-to-end smoke test (requires curl + jq)
./query_test.sh "Who created BM25?"
# Run evaluation
./scripts/evaluate.sh --suite=baseline
The ./scripts/answer.sh script supports comprehensive parameter tuning for optimal results:
| Parameter | Default | Range/Options | Description | Impact |
|---|---|---|---|---|
--topk=N |
100 | 1-100 | Number of initial retrieval candidates | Higher = better recall, slower response |
--alpha=X |
0.5 | 0.0-1.0 | Hybrid search weight (0=sparse, 1=dense) | 0.0=keyword matching, 1.0=semantic similarity |
--rrf / --no-rrf |
--rrf |
boolean | Use RRF vs alpha fusion | RRF=stable ranking, alpha=direct weighting |
--rrf-k=N |
60 | 1-200 | RRF fusion smoothing parameter | Lower=aggressive reranking, higher=conservative |
--reranker=TYPE |
bge_local |
bge_local, cohere |
Reranking model selection | Local=private, Cohere=higher quality |
--max-passages=N |
8 | 1-20 | Final passages for LLM generation | More=richer context, risk of attention dilution |
--hyde |
disabled | boolean | Enable HyDE query expansion | Better for abstract/conceptual queries |
--rag-fusion |
disabled | boolean | Multi-query generation and fusion | Better coverage for complex questions |
--debug |
disabled | boolean | Include retrieval debug information | Shows timing and score details |
--format=FORMAT |
text |
text, json, markdown |
Output format selection | Choose based on consumption needs |
--verbose |
disabled | boolean | Enable verbose logging | Detailed execution information |
--api-url=URL |
localhost:8080 |
URL | Target API base URL | Override for remote deployments |
# Dense semantic search for conceptual queries
./scripts/answer.sh "Explain machine learning principles" --alpha=0.8 --max-passages=12
# Sparse keyword search for specific terms
./scripts/answer.sh "BGE-M3 model architecture" --alpha=0.2 --topk=80
# Enhanced query with expansion techniques
./scripts/answer.sh "How does attention mechanism work?" --hyde --rag-fusion --format=markdown
# Debug mode with detailed retrieval information
./scripts/answer.sh "Vector database comparison" --debug --verbose --format=json
# High-quality reranking with cloud fallback
./scripts/answer.sh "Production RAG best practices" --reranker=cohere --max-passages=10
Configuration is managed through configs/askme.yaml with environment variable overrides. Key parameters:
# Vector backend selection
vector_backend: weaviate # weaviate | milvus | qdrant
# Hybrid search configuration
hybrid:
mode: rrf # rrf | alpha | relative_score | ranked
alpha: 0.5 # 0=sparse only, 1=dense only, 0.5=balanced
rrf_k: 60 # RRF fusion parameter
topk: 50 # Initial retrieval candidates
# Embedding model
embedding:
model: BAAI/bge-m3
dimension: 1024
normalize_embeddings: true
# Reranking
rerank:
local_model: BAAI/bge-reranker-v2-m3
local_enabled: true
cohere_enabled: false # Enable via ASKME_ENABLE_COHERE=1
top_n: 8
# Generation
generation:
provider: ollama # simple | ollama | openai
ollama_model: gpt-oss:20b
ollama_endpoint: http://localhost:11434
openai_model: gpt-4o-mini
For convenient development and deployment, use the provided startup and shutdown scripts:
# Start API server with custom configuration
./scripts/start-api.sh --port 8080 --ollama-model qwen3:30b-a3b --vector-backend milvus
# Start with Cohere reranking enabled
./scripts/start-api.sh --enable-cohere # Requires COHERE_API_KEY env var
# Quick development start (skip heavy initialization)
./scripts/start-api.sh --skip-heavy-init --reload
# Show configuration without starting
./scripts/start-api.sh --dry-run
# Stop API server
./scripts/stop-api.sh
# Force stop all related processes
./scripts/stop-api.sh --all --force
All configuration can be overridden using environment variables with the ASKME_ prefix:
| Variable | Default | Description |
|---|---|---|
ASKME_VECTOR_BACKEND |
weaviate |
Vector database backend (weaviate/milvus/qdrant) |
ASKME_ENABLE_OLLAMA |
false |
Enable local Ollama LLM generation |
ASKME_ENABLE_COHERE |
false |
Enable Cohere reranking service |
ASKME_SKIP_HEAVY_INIT |
false |
Skip heavy service initialization |
ASKME_LOG_LEVEL |
INFO |
Log level (DEBUG/INFO/WARNING/ERROR) |
| Variable | Default | Description |
|---|---|---|
ASKME_DATABASE__HOST |
localhost |
Database host address |
ASKME_DATABASE__PORT |
19530 |
Database port |
ASKME_DATABASE__MILVUS__HOST |
localhost |
Milvus host address |
ASKME_DATABASE__MILVUS__PORT |
19530 |
Milvus port |
ASKME_DATABASE__MILVUS__USERNAME |
"" |
Milvus username |
ASKME_DATABASE__MILVUS__PASSWORD |
"" |
Milvus password |
ASKME_DATABASE__MILVUS__SECURE |
false |
Milvus secure connection |
ASKME_DATABASE__MILVUS__COLLECTION_NAME |
askme_hybrid |
Milvus collection name |
ASKME_DATABASE__WEAVIATE__URL |
http://localhost:8081 |
Weaviate connection URL |
ASKME_DATABASE__WEAVIATE__API_KEY |
"" |
Weaviate API key |
ASKME_DATABASE__WEAVIATE__CLASS_NAME |
AskmeDocument |
Weaviate class name |
ASKME_DATABASE__QDRANT__URL |
http://localhost:6333 |
Qdrant connection URL |
ASKME_DATABASE__QDRANT__API_KEY |
"" |
Qdrant API key |
ASKME_DATABASE__QDRANT__COLLECTION_NAME |
askme |
Qdrant collection name |
| Variable | Default | Description |
|---|---|---|
ASKME_GENERATION__PROVIDER |
simple |
LLM provider (simple/ollama/openai) |
ASKME_GENERATION__OLLAMA_MODEL |
llama3.1:latest |
Ollama model name |
ASKME_GENERATION__OLLAMA_ENDPOINT |
http://localhost:11434 |
Ollama endpoint URL |
ASKME_GENERATION__MODEL_NAME |
gpt-4 |
Default model name |
ASKME_GENERATION__MAX_TOKENS |
1500 |
Maximum generation tokens |
ASKME_GENERATION__TEMPERATURE |
0.1 |
Generation temperature |
ASKME_GENERATION__TOP_P |
0.9 |
Top-p sampling parameter |
ASKME_GENERATION__OPENAI_MODEL |
gpt-4o-mini |
OpenAI model name |
ASKME_GENERATION__OPENAI_BASE_URL |
https://api.openai.com/v1 |
OpenAI API endpoint |
ASKME_GENERATION__OPENAI_API_KEY_ENV |
OPENAI_API_KEY |
OpenAI API key env var name |
| Variable | Default | Description |
|---|---|---|
ASKME_EMBEDDING__MODEL |
BAAI/bge-m3 |
Embedding model name |
ASKME_EMBEDDING__DIMENSION |
1024 |
Embedding dimension |
ASKME_EMBEDDING__BATCH_SIZE |
32 |
Embedding batch size |
ASKME_EMBEDDING__MAX_LENGTH |
8192 |
Maximum input length |
ASKME_EMBEDDING__NORMALIZE_EMBEDDINGS |
true |
Normalize embeddings |
ASKME_EMBEDDING__USE_FP16 |
true |
Use FP16 precision |
| Variable | Default | Description |
|---|---|---|
ASKME_HYBRID__MODE |
rrf |
Hybrid search mode (rrf/alpha/relative_score/ranked) |
ASKME_HYBRID__ALPHA |
0.5 |
Alpha fusion parameter (0=sparse, 1=dense) |
ASKME_HYBRID__RRF_K |
60 |
RRF fusion parameter |
ASKME_HYBRID__TOPK |
50 |
Initial retrieval candidates |
ASKME_HYBRID__DENSE_WEIGHT |
1.0 |
Dense search weight |
ASKME_HYBRID__SPARSE_WEIGHT |
1.0 |
Sparse search weight |
| Variable | Default | Description |
|---|---|---|
ASKME_RERANK__LOCAL_MODEL |
BAAI/bge-reranker-v2-m3 |
Local reranking model |
ASKME_RERANK__LOCAL_ENABLED |
true |
Enable local reranking |
ASKME_RERANK__LOCAL_BATCH_SIZE |
16 |
Local reranking batch size |
ASKME_RERANK__COHERE_ENABLED |
false |
Enable Cohere reranking |
ASKME_RERANK__COHERE_MODEL |
rerank-3.5-turbo |
Cohere model name |
ASKME_RERANK__TOP_N |
8 |
Final reranked passages |
| Variable | Default | Description |
|---|---|---|
ASKME_API__HOST |
0.0.0.0 |
API server host |
ASKME_API__PORT |
8080 |
API server port |
ASKME_API__WORKERS |
1 |
Number of worker processes |
ASKME_API__RELOAD |
false |
Enable hot reload |
ASKME_API__ACCESS_LOG |
true |
Enable access logging |
| Variable | Default | Description |
|---|---|---|
OPENAI_BASE_URL |
- | OpenAI-compatible API endpoint |
OPENAI_API_KEY |
- | OpenAI API key |
COHERE_API_KEY |
- | Cohere API key (required for Cohere reranking) |
ASKME_RAGAS_LLM_MODEL |
- | Override LLM model for Ragas evaluation |
ASKME_RAGAS_EMBED_MODEL |
BAAI/bge-m3 |
Override embedding model for Ragas |
| Variable | Default | Description |
|---|---|---|
ASKME_PERFORMANCE__BATCH__EMBEDDING_BATCH_SIZE |
32 |
Embedding batch size |
ASKME_PERFORMANCE__BATCH__RERANK_BATCH_SIZE |
16 |
Reranking batch size |
ASKME_PERFORMANCE__TIMEOUTS__RETRIEVAL_TIMEOUT |
15 |
Retrieval timeout (seconds) |
ASKME_PERFORMANCE__TIMEOUTS__RERANK_TIMEOUT |
30 |
Reranking timeout (seconds) |
ASKME_PERFORMANCE__TIMEOUTS__GENERATION_TIMEOUT |
60 |
Generation timeout (seconds) |
| Variable | Default | Description |
|---|---|---|
ASKME_SKIP_HEAVY_INIT |
false |
Skip heavy service initialization |
ASKME_OLLAMA_READ_TIMEOUT |
120 |
Ollama read timeout (seconds) |
ASKME_OLLAMA_THINKING |
false |
Enable Ollama thinking mode |
TOKENIZERS_PARALLELISM |
- | Control tokenizers parallelism |
GET /health/ - Basic health checkGET /health/ready - Readiness check for orchestrationGET /health/live - Liveness check for orchestrationPOST /ingest/ - Universal document ingestion (file/directory)POST /ingest/file - Single file ingestionPOST /ingest/directory - Directory ingestion with recursionGET /ingest/status/{task_id} - Task status monitoringGET /ingest/stats - Global ingestion statisticsPOST /query/ - Hybrid search + reranking + generation pipelinePOST /query/retrieve - Retrieval-only endpoint for debuggingGET /query/similar/{doc_id} - Similar document discoveryPOST /query/explain - Retrieval explanation (debugging)POST /eval/run - Execute evaluation pipeline with TruLens + RagasGET /eval/runs/{run_id} - Retrieve evaluation resultsPOST /eval/compare - A/B test comparison between runsGET /eval/runs - List recent evaluation runsDELETE /eval/runs/{run_id} - Delete evaluation runGET /eval/metrics - Available evaluation metrics./scripts/evaluate.sh provides a unified CLI for starting suites, overriding retrieval parameters (--alpha, --topk, --topn), and choosing output formats (text, json, table).embedding_service is available, adding groundedness, context precision/recall, and answer relevance without leaving the host.ASKME_RAGAS_LLM_MODEL, OPENAI_BASE_URL, or standard OpenAI keys as needed.ASKME_TRULENS_LLM_MODEL, enabling fully offline evaluation when paired with Ollama.ASKME_RAGAS_EMBED_MODEL to swap in alternative embedding backends for evaluation-only workloads without touching production retrieval settings.curl -X POST "http://localhost:8080/query/" \
-H "Content-Type: application/json" \
-d '{
"q": "What is machine learning?",
"topk": 50,
"alpha": 0.5,
"use_rrf": true,
"reranker": "bge_local",
"max_passages": 8,
"include_debug": true
}'
# Full stack with Milvus (recommended)
docker compose -f docker/docker-compose.yaml up -d
# Alternative vector databases
docker compose -f docker/docker-compose.yaml --profile weaviate up -d
docker compose -f docker/docker-compose.yaml --profile qdrant up -d
# With monitoring
docker compose -f docker/docker-compose.yaml --profile monitoring up -d
# Install development dependencies
uv sync --dev
# Install pre-commit hooks
uv run pre-commit install
# Run tests with coverage
uv run pytest --cov=askme --cov-report=term --cov-report=html
# Code formatting and type checking
uv run black askme tests && uv run isort askme tests
uv run mypy askme
The project includes comprehensive test coverage with pytest:
# Run all tests
uv run pytest -ra
# Run specific test categories
uv run pytest -m "unit and not slow"
uv run pytest -m integration
uv run pytest -m "slow"
# Run with coverage reporting
uv run pytest --cov=askme --cov-report=html
Test Markers:
unit: Unit tests for individual componentsintegration: Cross-component integration testsslow: Time-intensive tests (model loading, evaluation)The project maintains high code quality standards:
# Comprehensive baseline evaluation
./scripts/evaluate.sh --suite=baseline
# Quick evaluation for CI/CD
./scripts/evaluate.sh --suite=quick --sample-size=3
# Custom dataset evaluation
./scripts/evaluate.sh --dataset="/path/to/qa_dataset.jsonl" --metrics="faithfulness,context_precision"
# Parameter tuning evaluation
./scripts/evaluate.sh --suite=baseline --alpha=0.3 --topk=75 --topn=10
TruLens RAG Triad:
Ragas Metrics:
We welcome contributions to the askme project! Please follow these guidelines:
git checkout -b feature/amazing-featureBefore submitting a PR, ensure:
# All tests pass
uv run pytest
# Code formatting
uv run black askme tests && uv run isort askme tests
# Type checking
uv run mypy askme
# Security check
uv run bandit -r askme
# Basic evaluation passes
./scripts/evaluate.sh --suite=quick
Milvus Container Startup Issues
docker run --name weaviate -p 8081:8080 -p 8082:50051 -d \
cr.weaviate.io/semitechnologies/weaviate:1.24.1 \
--host 0.0.0.0 --port 8080 --scheme http
configs/askme.yaml to use vector_backend: weaviateScript Command Syntax
--param=value format for script parameters:# Correct
./scripts/retrieve.sh "query" --topk=25 --alpha=0.7
# Incorrect
./scripts/retrieve.sh "query" --topk 25 --alpha 0.7
Slow Retrieval Performance
Poor Reranking Quality
Memory Issues
configs/askme.yamlASKME_SKIP_HEAVY_INIT=1 for developmentEvaluation Failures
This project is licensed under the Apache License 2.0 - see the LICENSE file for details.