chore: import upstream snapshot with attribution
OSV-Scanner (Scheduled) / scan-scheduled (push) Failing after 0s
Create Release / test-gate (push) Has been cancelled
Create Release / release-gate (push) Has been cancelled
Create Release / ci-gate (push) Has been cancelled
Create Release / version-check (push) Has been cancelled
Create Release / e2e-test-gate (push) Has been cancelled
Create Release / responsive-test-gate (push) Has been cancelled
Create Release / compat-test-gate (push) Has been cancelled
Create Release / compose-integration-gate (push) Has been cancelled
Create Release / vulture-gate (push) Has been cancelled
Create Release / build (push) Has been cancelled
Create Release / provenance (push) Has been cancelled
Create Release / prerelease-docker (push) Has been cancelled
Create Release / publish-docker (push) Has been cancelled
Create Release / create-release (push) Has been cancelled
Create Release / cleanup-changelog (push) Has been cancelled
Create Release / trigger-pypi (push) Has been cancelled
Create Release / monitor-pypi (push) Has been cancelled
Create Release / Clean up orphan prerelease tags and signatures (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-form] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-metrics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [research-workflow] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-core] (push) Has been cancelled
CodeQL Advanced / Analyze (javascript-typescript) (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [history-news] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [library] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [link-analytics] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-core] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [chat-lifecycle] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [error-benchmark] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [settings-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) (push) Has been cancelled
Docker Tests (Consolidated) / Accessibility Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Unit Tests (push) Has been cancelled
Docker Tests (Consolidated) / LLM Example Tests (push) Has been cancelled
Docker Tests (Consolidated) / Production Image Smoke Test (push) Has been cancelled
Docker Tests (Consolidated) / Infrastructure Tests (push) Has been cancelled
OSSF Scorecard / OSSF Security Scorecard Analysis (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [mobile] (push) Has been cancelled
Backwards Compatibility / Verify Encryption Constants (push) Has been cancelled
Backwards Compatibility / PyPI Version Compatibility (push) Has been cancelled
Backwards Compatibility / Database Migration Tests (push) Has been cancelled
CodeQL Advanced / Analyze (python) (push) Has been cancelled
Docker Tests (Consolidated) / detect-changes (push) Has been cancelled
Docker Tests (Consolidated) / Build Test Image (push) Has been cancelled
Docker Tests (Consolidated) / All Pytest Tests + Coverage (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [accessibility] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [api-crud] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-login] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-pages] (push) Has been cancelled
Docker Tests (Consolidated) / UI Tests (Puppeteer) [auth-register] (push) Has been cancelled

This commit is contained in:
wehub-resource-sync
2026-07-13 13:08:55 +08:00
commit 7a0da7932b
2985 changed files with 1049377 additions and 0 deletions
+124
View File
@@ -0,0 +1,124 @@
# Optimization Tools for Local Deep Research
This directory contains scripts for optimizing Local Deep Research's parameters.
## Parameter Optimization
Optimization helps find the best settings for different use cases:
- **Balanced**: Optimizes for a good balance of speed and quality
- **Speed-focused**: Prioritizes faster responses
- **Quality-focused**: Prioritizes more accurate, comprehensive answers
- **Efficiency**: Balances quality, speed, and resource usage
## Available Scripts
### Main Optimization Runner
`run_optimization.py` provides a command-line interface for running different types of optimization:
```bash
python run_optimization.py "What are the latest developments in fusion energy?" --mode quality --trials 20
```
Options:
- `query`: The research query to use for optimization
- `--output-dir`: Directory to save results (default: "optimization_results")
- `--search-tool`: Search tool to use (default: "searxng")
- `--model`: Model name for the LLM (e.g., 'claude-3-sonnet-20240229')
- `--provider`: Provider for the LLM (e.g., 'anthropic', 'openai', 'openai_endpoint')
- `--endpoint-url`: Custom endpoint URL (e.g., 'https://openrouter.ai/api/v1' for OpenRouter)
- `--api-key`: API key for the LLM provider
- `--temperature`: Temperature for the LLM (default: 0.7)
- `--trials`: Number of parameter combinations to try (default: 30)
- `--mode`: Optimization mode ("balanced", "speed", "quality", "efficiency")
- `--weights`: Custom weights as JSON string, e.g., '{"quality": 0.7, "speed": 0.3}'
### Example Scripts
- `example_optimization.py`: Full example with all optimization modes
- `example_quick_optimization.py`: Simplified example for quick testing
- `gemini_optimization.py`: Example using Gemini 2.0 Flash via OpenRouter
- `llm_multi_benchmark.py`: Example with multi-benchmark optimization and custom LLM settings
### Utility Scripts
- `update_llm_config.py`: Update LLM configuration in the database
```bash
python update_llm_config.py --model "google/gemini-2.0-flash" --provider "openai_endpoint" --endpoint "https://openrouter.ai/api/v1" --api-key "your-api-key"
```
- `run_gemini_benchmark.py`: Run benchmarks with Gemini 2.0 Flash via OpenRouter
```bash
python run_gemini_benchmark.py --api-key "your-api-key" --examples 10
```
**Important**: Always update the LLM configuration in the database before running benchmarks or optimization to ensure consistent behavior. The utility scripts above help you do this.
## How Optimization Works
The optimization process:
1. Defines a parameter space to explore (iterations, questions per iteration, search strategy, etc.)
2. Runs multiple trials with different parameter combinations
3. Evaluates each combination using benchmarks
4. Uses Optuna to efficiently search for the best parameters
5. Returns the optimal parameters and stores detailed results
## Example Parameter Space
Optimization explores parameters such as:
- `iterations`: Number of search iterations
- `questions_per_iteration`: Number of questions to generate per iteration
- `search_strategy`: Search strategy to use ("standard", "rapid", "iterdrag", etc.)
- `max_results`: Maximum number of search results to consider
- Other system-specific parameters
## Using Custom LLM Models
The optimization tools support different LLM providers and models:
### Via OpenRouter
To use models like Gemini or other models via OpenRouter:
```bash
python run_optimization.py "Research query" --model "google/gemini-2.0-flash-001" --provider "openai_endpoint" --endpoint-url "https://openrouter.ai/api/v1" --api-key "your-openrouter-api-key"
```
Or use the dedicated example:
```bash
python gemini_optimization.py --api-key "your-openrouter-api-key"
```
### Direct Provider Access
To use models directly from providers like Anthropic or OpenAI:
```bash
python run_optimization.py "Research query" --model "claude-3-sonnet-20240229" --provider "anthropic" --api-key "your-anthropic-api-key"
```
Or for OpenAI:
```bash
python run_optimization.py "Research query" --model "gpt-4-turbo" --provider "openai" --api-key "your-openai-api-key"
```
## Using Optimization Results
After running optimization, you can use the resulting parameters by updating your configuration:
```python
from local_deep_research.api import quick_summary
results = quick_summary(
query="What are the latest developments in fusion energy?",
iterations=best_params["iterations"],
questions_per_iteration=best_params["questions_per_iteration"],
search_strategy=best_params["search_strategy"],
# Other optimized parameters
# You can also use custom LLM configuration:
model_name="your-model",
provider="your-provider"
)
```
+115
View File
@@ -0,0 +1,115 @@
#!/usr/bin/env python
"""
Parameter Optimization Using BrowseComp Benchmark for Local Deep Research.
This script demonstrates optimizing research parameters using the BrowseComp benchmark
for higher quality evaluation.
Usage:
# Install dependencies with PDM
cd /path/to/local-deep-research
pdm install
# Run the script with PDM
pdm run python examples/optimization/browsecomp_optimization.py
"""
import json
import sys
from datetime import datetime
from pathlib import Path
from local_deep_research.benchmarks.optimization import optimize_parameters
# Add the src directory to the Python path
project_root = str(Path(__file__).parent.parent.parent.resolve())
sys.path.insert(0, str(Path(project_root) / "src"))
def main():
# Create timestamp for unique output directory
from datetime import timezone
timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
output_dir = str(
Path("examples")
/ "optimization"
/ "results"
/ f"browsecomp_opt_{timestamp}"
)
Path(output_dir).mkdir(parents=True, exist_ok=True)
print(
f"Starting BrowseComp optimization - results will be saved to {output_dir}"
)
# Define a simple parameter space for demonstration
param_space = {
"iterations": {
"type": "int",
"low": 1,
"high": 3,
"step": 1,
},
"questions_per_iteration": {
"type": "int",
"low": 1,
"high": 3,
"step": 1,
},
"search_strategy": {
"type": "categorical",
"choices": ["rapid", "standard", "parallel"],
},
}
# Run optimization with BrowseComp benchmark
# Using a small number of trials and examples for demonstration
print("\n=== Running balanced optimization with BrowseComp benchmark ===")
balanced_params, balanced_score = optimize_parameters(
query="Climate change effects on biodiversity",
param_space=param_space,
output_dir=output_dir,
n_trials=3, # Small number for demo purposes
search_tool="searxng",
benchmark_weights={
"browsecomp": 1.0
}, # Specify BrowseComp benchmark only
)
print(f"Best balanced parameters: {balanced_params}")
print(f"Best balanced score: {balanced_score:.4f}")
# Save optimization results
summary = {
"timestamp": timestamp,
"benchmark_weights": {"browsecomp": 1.0},
"balanced": {
"parameters": balanced_params,
"score": float(balanced_score),
},
}
with open(
Path(output_dir) / "browsecomp_optimization_summary.json",
"w",
encoding="utf-8",
) as f:
json.dump(summary, f, indent=2)
print(
f"\nDemo complete! Results saved to {output_dir}/browsecomp_optimization_summary.json"
)
print(f"Recommended parameters for BrowseComp: {balanced_params}")
print(
"\nNote: For actual optimizations, we recommend increasing n_trials to at least 20."
)
print(
"This demo runs with minimal trials to demonstrate the functionality quickly."
)
if __name__ == "__main__":
main()
@@ -0,0 +1,194 @@
"""
Example of multi-benchmark optimization using weighted benchmarks.
This script demonstrates how to use the optimization system with both
SimpleQA and BrowseComp benchmarks with custom weights.
"""
import os
import sys
from datetime import datetime
from pathlib import Path
from typing import Any, Dict
# Print current directory and python path for debugging
print(f"Current directory: {os.getcwd()}")
print(f"Python path: {sys.path}")
# Add appropriate paths
sys.path.insert(0, str(Path(__file__).parent.parent.resolve()))
try:
# Try to import from the local module structure
from src.local_deep_research.benchmarks.optimization.optuna_optimizer import (
optimize_for_quality,
optimize_for_speed,
optimize_parameters,
)
print("Successfully imported using src.local_deep_research path")
except ImportError:
print("First import attempt failed, trying with direct import...")
try:
# Try to import directly
from local_deep_research.benchmarks.optimization.optuna_optimizer import (
optimize_for_quality,
optimize_for_speed,
optimize_parameters,
)
print("Successfully imported using local_deep_research path")
except ImportError as e:
print(f"Import error: {e}")
print("Creating simulation functions for demonstration only...")
# Create simulation functions if imports fail
def optimize_parameters(*args, **kwargs):
benchmark_weights = kwargs.get(
"benchmark_weights", {"simpleqa": 1.0}
)
print(
f"SIMULATION: optimize_parameters called with benchmark_weights={benchmark_weights}"
)
# Return different results based on the benchmark weights
if (
"browsecomp" in benchmark_weights
and benchmark_weights["browsecomp"] >= 1.0
):
# BrowseComp only
return {
"iterations": 4,
"questions_per_iteration": 5,
"search_strategy": "parallel",
}, 0.78
if (
"browsecomp" in benchmark_weights
and benchmark_weights["browsecomp"] > 0
):
# Mixed weights
return {
"iterations": 2,
"questions_per_iteration": 2,
"search_strategy": "iterdrag",
}, 0.81
# SimpleQA only (default)
return {
"iterations": 3,
"questions_per_iteration": 2,
"search_strategy": "standard",
}, 0.75
def optimize_for_quality(*args, **kwargs):
benchmark_weights = kwargs.get(
"benchmark_weights", {"simpleqa": 1.0}
)
print(
f"SIMULATION: optimize_for_quality called with benchmark_weights={benchmark_weights}"
)
return {
"iterations": 4,
"questions_per_iteration": 1,
"search_strategy": "iterdrag",
}, 0.85
def optimize_for_speed(*args, **kwargs):
benchmark_weights = kwargs.get(
"benchmark_weights", {"simpleqa": 1.0}
)
print(
f"SIMULATION: optimize_for_speed called with benchmark_weights={benchmark_weights}"
)
return {
"iterations": 2,
"questions_per_iteration": 2,
"search_strategy": "rapid",
}, 0.67
# Loguru automatically handles logging configuration
def print_optimization_results(params: Dict[str, Any], score: float):
"""Print optimization results in a nicely formatted way."""
print("\n" + "=" * 50)
print(" OPTIMIZATION RESULTS ")
print("=" * 50)
print(f"SCORE: {score:.4f}")
print("\nBest Parameters:")
for param, value in params.items():
print(f" {param}: {value}")
print("=" * 50 + "\n")
def main():
"""Run the multi-benchmark optimization examples."""
# Create a timestamp-based directory for results
from datetime import timezone
timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
output_dir = f"optimization_demo_{timestamp}"
os.makedirs(output_dir, exist_ok=True)
# Research query for optimization examples
query = "Recent advancements in renewable energy"
# Example 1: SimpleQA only (default)
print("\n🔍 Running optimization with SimpleQA benchmark only...")
params1, score1 = optimize_parameters(
query=query,
n_trials=3, # Using a small number for quick demonstration
output_dir=str(Path(output_dir) / "simpleqa_only"),
)
print_optimization_results(params1, score1)
# Example 2: BrowseComp only
print("\n🔍 Running optimization with BrowseComp benchmark only...")
params2, score2 = optimize_parameters(
query=query,
n_trials=3, # Using a small number for quick demonstration
output_dir=str(Path(output_dir) / "browsecomp_only"),
benchmark_weights={"browsecomp": 1.0},
)
print_optimization_results(params2, score2)
# Example 3: 60/40 weighted combination (SimpleQA/BrowseComp)
print("\n🔍 Running optimization with 60% SimpleQA and 40% BrowseComp...")
params3, score3 = optimize_parameters(
query=query,
n_trials=5, # Using a small number for quick demonstration
output_dir=str(Path(output_dir) / "weighted_combination"),
benchmark_weights={
"simpleqa": 0.6, # 60% weight for SimpleQA
"browsecomp": 0.4, # 40% weight for BrowseComp
},
)
print_optimization_results(params3, score3)
# Example 4: Quality-focused with both benchmarks
print("\n🔍 Running quality-focused optimization with both benchmarks...")
params4, score4 = optimize_for_quality(
query=query,
n_trials=3,
output_dir=str(Path(output_dir) / "quality_focused"),
benchmark_weights={"simpleqa": 0.6, "browsecomp": 0.4},
)
print_optimization_results(params4, score4)
# Example 5: Speed-focused with both benchmarks
print("\n🔍 Running speed-focused optimization with both benchmarks...")
params5, score5 = optimize_for_speed(
query=query,
n_trials=3,
output_dir=str(Path(output_dir) / "speed_focused"),
benchmark_weights={"simpleqa": 0.5, "browsecomp": 0.5},
)
print_optimization_results(params5, score5)
print(f"\nAll optimization results saved to: {output_dir}")
print("View the results directory for detailed logs and visualizations.")
if __name__ == "__main__":
main()
@@ -0,0 +1,95 @@
# example_optimization.py - Quick Demo Version
"""
Full parameter optimization example for Local Deep Research.
This script demonstrates the full parameter optimization functionality.
Usage:
# Install dependencies with PDM
cd /path/to/local-deep-research
pdm install
# Run the script with PDM
pdm run python examples/optimization/example_optimization.py
"""
import json
from datetime import datetime, UTC
from pathlib import Path
# Import the optimization functionality
from local_deep_research.benchmarks.optimization import (
optimize_parameters,
)
# Loguru automatically handles logging configuration
def main():
# Create timestamp for unique output directory
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
output_dir = str(
Path("examples")
/ "optimization"
/ "results"
/ f"optimization_results_{timestamp}"
)
Path(output_dir).mkdir(parents=True, exist_ok=True)
print(
f"Starting quick optimization demo - results will be saved to {output_dir}"
)
# Demo with just a single simple optimization
print("\n=== Running quick demo optimization ===")
# Create a very simple parameter set to test
param_space = {
"iterations": {
"type": "int",
"low": 1,
"high": 2,
"step": 1,
},
"questions_per_iteration": {
"type": "int",
"low": 1,
"high": 2,
"step": 1,
},
"search_strategy": {
"type": "categorical",
"choices": ["rapid"], # Just use the fastest strategy
},
}
balanced_params, balanced_score = optimize_parameters(
query="SimpleQA quick demo", # Task descriptor
search_tool="searxng", # Using SearXNG
n_trials=2, # Just 2 trials for quick demo
output_dir=str(Path(output_dir) / "demo"),
param_space=param_space, # Limited parameter space
metric_weights={"quality": 0.5, "speed": 0.5},
)
print(f"Best parameters: {balanced_params}")
print(f"Best score: {balanced_score:.4f}")
# Save demo results to a summary file
summary = {
"timestamp": timestamp,
"demo": {"parameters": balanced_params, "score": balanced_score},
}
with open(
Path(output_dir) / "optimization_summary.json", "w", encoding="utf-8"
) as f:
json.dump(summary, f, indent=2)
print(f"\nDemo complete! Results saved to {output_dir}")
print(f"Recommended parameters: {balanced_params}")
if __name__ == "__main__":
main()
@@ -0,0 +1,282 @@
# example_quick_optimization.py - Simplified Demo
"""
Simplified parameter optimization demo for Local Deep Research.
This script demonstrates basic parameter optimization with simulated results.
Usage:
# Install dependencies with PDM
cd /path/to/local-deep-research
pdm install
# Run the script with PDM
pdm run python examples/optimization/example_quick_optimization.py
"""
import json
import random
import time
from datetime import datetime, UTC
from pathlib import Path
from typing import Any, Dict, Tuple
from loguru import logger
# Loguru automatically handles logging configuration
def simulate_optimization(
param_space: Dict[str, Any],
n_trials: int = 5,
metric_weights: Dict[str, float] = None,
) -> Tuple[Dict[str, Any], float]:
"""
Simulate an optimization process without actually running benchmarks.
This is just for demonstration purposes.
Args:
param_space: Dictionary defining parameter search spaces
n_trials: Number of simulated trials
metric_weights: Weights for quality vs speed metrics
Returns:
Tuple of (best_parameters, best_score)
"""
if metric_weights is None:
metric_weights = {"quality": 0.5, "speed": 0.5}
logger.info(f"Starting simulated optimization with {n_trials} trials")
logger.info(f"Parameter space: {param_space}")
logger.info(f"Metric weights: {metric_weights}")
# Generate random trials
best_score = 0.0
best_params = {}
for i in range(n_trials):
# Generate random parameters
params = {}
for param_name, param_config in param_space.items():
if param_config.get("type") == "int":
params[param_name] = random.randint(
param_config.get("low", 1), param_config.get("high", 5)
)
elif param_config.get("type") == "categorical":
params[param_name] = random.choice(
param_config.get("choices", ["standard"])
)
logger.info(f"Trial {i}: Testing parameters: {params}")
# Simulate execution delay
time.sleep(1)
# Simulate metrics calculation
quality_score = random.uniform(0.5, 0.9) # Random quality score
speed_score = 1.0 - (
params.get("iterations", 1) * 0.1
) # More iterations = slower
# Calculate weighted score
combined_score = quality_score * metric_weights.get(
"quality", 0.5
) + speed_score * metric_weights.get("speed", 0.5)
logger.info(
f"Trial {i}: Quality: {quality_score:.2f}, Speed: {speed_score:.2f}, Score: {combined_score:.2f}"
)
# Update best parameters if this trial is better
if combined_score > best_score:
best_score = combined_score
best_params = params.copy()
logger.info(
f"New best parameters found: {best_params} with score: {best_score:.2f}"
)
return best_params, best_score
def optimize_for_speed(
param_space: Dict[str, Any] = None, n_trials: int = 3
) -> Tuple[Dict[str, Any], float]:
"""
Simulate speed-focused optimization.
Args:
param_space: Parameter space definition (optional)
n_trials: Number of trials
Returns:
Tuple of (best_parameters, best_score)
"""
if param_space is None:
param_space = {
"iterations": {
"type": "int",
"low": 1,
"high": 3,
},
"questions_per_iteration": {
"type": "int",
"low": 1,
"high": 3,
},
"search_strategy": {
"type": "categorical",
"choices": ["rapid", "parallel"],
},
}
# Speed-focused weights
metric_weights = {
"speed": 0.8,
"quality": 0.2,
}
return simulate_optimization(
param_space=param_space,
n_trials=n_trials,
metric_weights=metric_weights,
)
def optimize_for_quality(
param_space: Dict[str, Any] = None, n_trials: int = 3
) -> Tuple[Dict[str, Any], float]:
"""
Simulate quality-focused optimization.
Args:
param_space: Parameter space definition (optional)
n_trials: Number of trials
Returns:
Tuple of (best_parameters, best_score)
"""
if param_space is None:
param_space = {
"iterations": {
"type": "int",
"low": 1,
"high": 5,
},
"questions_per_iteration": {
"type": "int",
"low": 1,
"high": 5,
},
"search_strategy": {
"type": "categorical",
"choices": ["standard", "iterdrag", "source_based"],
},
}
# Quality-focused weights
metric_weights = {
"quality": 0.9,
"speed": 0.1,
}
return simulate_optimization(
param_space=param_space,
n_trials=n_trials,
metric_weights=metric_weights,
)
def main():
# Create timestamp for unique output directory
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
output_dir = str(
Path("examples")
/ "optimization"
/ "results"
/ f"optimization_demo_{timestamp}"
)
Path(output_dir).mkdir(parents=True, exist_ok=True)
print(
f"Starting quick optimization demo - results will be saved to {output_dir}"
)
# Create a simple parameter space for demonstration
param_space = {
"iterations": {
"type": "int",
"low": 1,
"high": 3,
},
"questions_per_iteration": {
"type": "int",
"low": 1,
"high": 3,
},
"search_strategy": {
"type": "categorical",
"choices": ["rapid", "standard", "iterdrag"],
},
}
# Run a balanced optimization
print("\n=== Running balanced optimization simulation ===")
balanced_params, balanced_score = simulate_optimization(
param_space=param_space,
n_trials=4,
metric_weights={"quality": 0.6, "speed": 0.4},
)
print(f"Best balanced parameters: {balanced_params}")
print(f"Best balanced score: {balanced_score:.4f}")
# Run a speed optimization
print("\n=== Running speed-focused optimization simulation ===")
speed_params, speed_score = optimize_for_speed(n_trials=3)
print(f"Best speed parameters: {speed_params}")
print(f"Best speed score: {speed_score:.4f}")
# Run a quality optimization
print("\n=== Running quality-focused optimization simulation ===")
quality_params, quality_score = optimize_for_quality(n_trials=3)
print(f"Best quality parameters: {quality_params}")
print(f"Best quality score: {quality_score:.4f}")
# Save results
summary = {
"timestamp": timestamp,
"balanced": {
"parameters": balanced_params,
"score": float(balanced_score),
},
"speed": {"parameters": speed_params, "score": float(speed_score)},
"quality": {
"parameters": quality_params,
"score": float(quality_score),
},
}
with open(
Path(output_dir) / "optimization_summary.json", "w", encoding="utf-8"
) as f:
json.dump(summary, f, indent=2)
print(
f"\nDemo complete! Results saved to {output_dir}/optimization_summary.json"
)
print("\nRecommended parameters:")
print(f"- For balanced performance: {balanced_params}")
print(f"- For speed: {speed_params}")
print(f"- For quality: {quality_params}")
print(
"\nNote: This is a simulation for demonstration purposes only. Real optimization"
)
print(
"would run actual benchmarks with these parameters to evaluate performance."
)
if __name__ == "__main__":
main()
@@ -0,0 +1,215 @@
#!/usr/bin/env python
"""
Optimization Example with Gemini 2.0 Flash via OpenRouter.
This script demonstrates how to run parameter optimization using the Gemini 2.0 Flash
model via OpenRouter.
Usage:
# Install dependencies with PDM
cd /path/to/local-deep-research
pdm install
# Set your OpenRouter API key
export OPENAI_ENDPOINT_API_KEY="your_openrouter_api_key"
# Run the script with PDM
pdm run python examples/optimization/gemini_optimization.py
"""
import argparse
import json
import os
import sys
from datetime import datetime, timezone
from pathlib import Path
from loguru import logger
# Import the optimization functionality
from local_deep_research.benchmarks.optimization import (
optimize_for_quality,
optimize_for_speed,
optimize_parameters,
)
def setup_gemini_config(api_key=None):
"""
Create a configuration for using Gemini via OpenRouter.
Args:
api_key: OpenRouter API key. If None, will try to get from environment.
Returns:
Dictionary with Gemini configuration.
"""
# Get API key from argument or environment
if not api_key:
api_key = os.environ.get("OPENAI_ENDPOINT_API_KEY")
if not api_key:
api_key = os.environ.get("LDR_LLM__OPENAI_ENDPOINT_API_KEY")
if not api_key:
logger.error("No API key found. Please provide an OpenRouter API key.")
return None
return {
"model_name": "google/gemini-2.0-flash-001", # OpenRouter format for Gemini
"provider": "openai_endpoint", # Use OpenRouter as endpoint
"openai_endpoint_url": "https://openrouter.ai/api/v1",
"api_key": api_key,
}
def main():
# Parse arguments
parser = argparse.ArgumentParser(
description="Run optimization with Gemini 2.0 Flash via OpenRouter"
)
parser.add_argument(
"--api-key",
help="OpenRouter API key. If not provided, will try to use from environment.",
)
parser.add_argument(
"--mode",
choices=["balanced", "speed", "quality"],
default="balanced",
help="Optimization mode (default: balanced)",
)
parser.add_argument(
"--trials",
type=int,
default=3,
help="Number of optimization trials (default: 3)",
)
parser.add_argument(
"--output-dir",
default=None,
help="Directory to save results (default: auto-generated)",
)
args = parser.parse_args()
# Set up Gemini configuration
gemini_config = setup_gemini_config(args.api_key)
if not gemini_config:
return 1
# Create timestamp for unique output directory
timestamp = datetime.now(timezone.utc).strftime("%Y%m%d_%H%M%S")
if args.output_dir:
output_dir = args.output_dir
else:
output_dir = str(
Path("examples")
/ "optimization"
/ "results"
/ f"gemini_opt_{timestamp}"
)
Path(output_dir).mkdir(parents=True, exist_ok=True)
print(
f"Starting optimization with Gemini 2.0 Flash - results will be saved to {output_dir}"
)
print(
f"Using model: {gemini_config['model_name']} via {gemini_config['provider']}"
)
# Set environment variables to ensure proper API access
os.environ["OPENAI_ENDPOINT_API_KEY"] = gemini_config["api_key"]
os.environ["LDR_LLM__OPENAI_ENDPOINT_API_KEY"] = gemini_config["api_key"]
os.environ["OPENAI_ENDPOINT_URL"] = gemini_config["openai_endpoint_url"]
os.environ["LDR_LLM__OPENAI_ENDPOINT_URL"] = gemini_config[
"openai_endpoint_url"
]
os.environ["LDR_LLM__PROVIDER"] = gemini_config["provider"]
os.environ["LDR_LLM__MODEL"] = gemini_config["model_name"]
# Create a very simple parameter space for quick demonstration
param_space = {
"iterations": {
"type": "int",
"low": 1,
"high": 2,
"step": 1,
},
"questions_per_iteration": {
"type": "int",
"low": 1,
"high": 2,
"step": 1,
},
"search_strategy": {
"type": "categorical",
"choices": ["rapid", "source_based"], # Limited choices for speed
},
}
# Run optimization based on selected mode
query = "Recent developments in fusion energy research"
try:
if args.mode == "speed":
print("\n=== Running speed-focused optimization with Gemini ===")
best_params, best_score = optimize_for_speed(
query=query,
param_space=param_space,
n_trials=args.trials,
model_name=gemini_config["model_name"],
provider=gemini_config["provider"],
output_dir=output_dir,
)
elif args.mode == "quality":
print("\n=== Running quality-focused optimization with Gemini ===")
best_params, best_score = optimize_for_quality(
query=query,
param_space=param_space,
n_trials=args.trials,
model_name=gemini_config["model_name"],
provider=gemini_config["provider"],
output_dir=output_dir,
)
else: # balanced
print("\n=== Running balanced optimization with Gemini ===")
best_params, best_score = optimize_parameters(
query=query,
param_space=param_space,
n_trials=args.trials,
model_name=gemini_config["model_name"],
provider=gemini_config["provider"],
output_dir=output_dir,
metric_weights={"quality": 0.5, "speed": 0.5},
)
print(f"Best parameters: {best_params}")
print(f"Best score: {best_score:.4f}")
# Save summary to JSON
summary = {
"timestamp": timestamp,
"mode": args.mode,
"model": gemini_config["model_name"],
"provider": gemini_config["provider"],
"best_parameters": best_params,
"best_score": float(best_score),
}
with open(
Path(output_dir) / "gemini_optimization_summary.json",
"w",
encoding="utf-8",
) as f:
json.dump(summary, f, indent=2)
print(f"\nOptimization complete! Results saved to {output_dir}")
print(f"Recommended parameters for {args.mode} mode: {best_params}")
except Exception:
logger.exception("Error during optimization")
return 1
return 0
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,255 @@
#!/usr/bin/env python
"""
Custom LLM multi-benchmark optimization example for Local Deep Research.
This script demonstrates how to run multi-benchmark optimization with custom LLM models.
Usage:
# Run from project root with PDM
cd /path/to/local-deep-research
pdm run python examples/optimization/llm_multi_benchmark.py --model "your-model" --provider "your-provider"
"""
import argparse
import os
import sys
from datetime import datetime, UTC
from pathlib import Path
from typing import Any, Dict, Optional
from loguru import logger
# Import benchmark optimization functions
from local_deep_research.benchmarks.optimization.api import optimize_parameters
def setup_llm_config(
model: Optional[str] = None,
provider: Optional[str] = None,
endpoint_url: Optional[str] = None,
api_key: Optional[str] = None,
temperature: float = 0.7,
) -> Dict[str, Any]:
"""
Set up LLM configuration for benchmarks and optimization.
Args:
model: LLM model name
provider: LLM provider
endpoint_url: Custom endpoint URL for OpenRouter or other services
api_key: API key for the service
temperature: LLM temperature
Returns:
Dictionary with LLM configuration
"""
config = {
"model_name": model,
"provider": provider,
"temperature": temperature,
}
if endpoint_url:
config["openai_endpoint_url"] = endpoint_url
os.environ["OPENAI_ENDPOINT_URL"] = endpoint_url
os.environ["LDR_LLM__OPENAI_ENDPOINT_URL"] = endpoint_url
if api_key:
# Set API key in environment
if provider == "openai" or provider == "openai_endpoint":
os.environ["OPENAI_API_KEY"] = api_key
os.environ["LDR_LLM__OPENAI_API_KEY"] = api_key
if provider == "openai_endpoint":
os.environ["OPENAI_ENDPOINT_API_KEY"] = api_key
os.environ["LDR_LLM__OPENAI_ENDPOINT_API_KEY"] = api_key
elif provider == "anthropic":
os.environ["ANTHROPIC_API_KEY"] = api_key
os.environ["LDR_LLM__ANTHROPIC_API_KEY"] = api_key
config["api_key"] = api_key
# Set model and provider in environment
if model:
os.environ["LDR_LLM__MODEL"] = model
if provider:
os.environ["LDR_LLM__PROVIDER"] = provider
return config
def main():
"""Run multi-benchmark optimization with custom LLM."""
parser = argparse.ArgumentParser(
description="Run multi-benchmark optimization with custom LLM"
)
# LLM configuration
parser.add_argument("--model", help="LLM model name")
parser.add_argument(
"--provider", help="LLM provider (openai, anthropic, openai_endpoint)"
)
parser.add_argument(
"--endpoint-url", help="Custom endpoint URL (for OpenRouter etc.)"
)
parser.add_argument("--api-key", help="API key for the LLM provider")
parser.add_argument(
"--temperature", type=float, default=0.7, help="Temperature for LLM"
)
# Optimization parameters
parser.add_argument(
"--mode",
choices=["balanced", "speed", "quality"],
default="balanced",
help="Optimization mode",
)
parser.add_argument(
"--trials", type=int, default=3, help="Number of trials (default: 3)"
)
parser.add_argument(
"--output-dir", help="Output directory (default: auto-generated)"
)
args = parser.parse_args()
# Create timestamp-based directory for results
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
if args.output_dir:
output_dir = args.output_dir
else:
output_dir = str(
Path("examples")
/ "optimization"
/ "results"
/ f"llm_multi_benchmark_{timestamp}"
)
os.makedirs(output_dir, exist_ok=True)
print(f"Results will be saved to: {output_dir}")
# Set up LLM configuration
setup_llm_config(
model=args.model,
provider=args.provider,
endpoint_url=args.endpoint_url,
api_key=args.api_key,
temperature=args.temperature,
)
if args.model and args.provider:
print(f"Using LLM: {args.model} via {args.provider}")
else:
print("Using default LLM configuration from environment or database")
# Define a small parameter space for quick demonstration
param_space = {
"iterations": {
"type": "int",
"low": 1,
"high": 2,
"step": 1,
},
"questions_per_iteration": {
"type": "int",
"low": 1,
"high": 2,
"step": 1,
},
"search_strategy": {
"type": "categorical",
"choices": ["rapid", "source_based"], # Limited choices for speed
},
}
# Example query for running optimization
query = "Recent developments in fusion energy research"
# Define metrics weights based on mode
if args.mode == "speed":
metric_weights = {"speed": 0.8, "quality": 0.2}
elif args.mode == "quality":
metric_weights = {"quality": 0.9, "speed": 0.1}
else: # balanced
metric_weights = {"quality": 0.5, "speed": 0.5}
# Run optimization with multi-benchmark weights
print(
f"\n🔍 Running {args.mode}-focused optimization with SimpleQA and BrowseComp..."
)
try:
# Run optimization with combined benchmark weights
benchmark_weights = {
"simpleqa": 0.7,
"browsecomp": 0.3,
} # 70% SimpleQA, 30% BrowseComp
params, score = optimize_parameters(
query=query,
param_space=param_space,
output_dir=output_dir,
n_trials=args.trials,
model_name=args.model,
provider=args.provider,
openai_endpoint_url=args.endpoint_url,
temperature=args.temperature,
api_key=args.api_key,
benchmark_weights=benchmark_weights,
metric_weights=metric_weights,
search_tool="searxng",
)
print("\n" + "=" * 50)
print(f" OPTIMIZATION RESULTS - {args.mode.upper()} MODE ")
print("=" * 50)
print(f"SCORE: {score:.4f}")
print("Benchmark weights: SimpleQA 70%, BrowseComp 30%")
print(f"Metrics weights: {metric_weights}")
if args.model and args.provider:
print(f"LLM: {args.model} via {args.provider}")
print("\nBest Parameters:")
for param, value in params.items():
print(f" {param}: {value}")
print("=" * 50 + "\n")
# Save results to file
import json
with open(
Path(output_dir) / "multi_benchmark_results.json",
"w",
encoding="utf-8",
) as f:
json.dump(
{
"timestamp": timestamp,
"mode": args.mode,
"model": args.model,
"provider": args.provider,
"n_trials": args.trials,
"benchmark_weights": benchmark_weights,
"metric_weights": metric_weights,
"best_parameters": params,
"best_score": float(score),
},
f,
indent=2,
)
print(
f"Results saved to {Path(output_dir) / 'multi_benchmark_results.json'}"
)
except Exception:
logger.exception("Error running optimization")
import traceback
traceback.print_exc()
return 1
return 0
if __name__ == "__main__":
sys.exit(main())
@@ -0,0 +1,413 @@
"""
Multi-benchmark optimization simulation.
This script demonstrates how to use multi-benchmark optimization with weighted scores
without actually running real benchmarks (just simulation).
"""
import json
import random
import time
from datetime import datetime, UTC
from pathlib import Path
from typing import Any, Dict, Optional, Tuple
from loguru import logger
class BenchmarkSimulator:
"""Simulates running benchmarks without actually executing them."""
def __init__(
self, name: str, quality_bias: float = 0.7, speed_factor: float = 0.2
):
"""
Initialize benchmark simulator.
Args:
name: Name of the benchmark
quality_bias: Base quality score (will be adjusted by parameters)
speed_factor: How much iterations affect speed (higher = more sensitive)
"""
self.name = name
self.quality_bias = quality_bias
self.speed_factor = speed_factor
def evaluate(self, params: Dict[str, Any]) -> Dict[str, Any]:
"""
Simulate running a benchmark.
Args:
params: System parameters to evaluate
Returns:
Dictionary with simulated metrics
"""
# Add some randomness to make it interesting
iterations = params.get("iterations", 2)
questions = params.get("questions_per_iteration", 2)
strategy = params.get("search_strategy", "standard")
# Simulate thinking for realism
time.sleep(0.5)
# Calculate quality score based on parameters
# Different benchmark types respond differently to parameters
if self.name == "simpleqa":
# SimpleQA likes more iterations
quality_score = (
self.quality_bias + (iterations * 0.04) - random.uniform(0, 0.2)
)
# SimpleQA is fast
speed_score = 1.0 - (
iterations * questions * self.speed_factor * 0.5
)
else:
# BrowseComp likes more questions per iteration
quality_score = (
self.quality_bias + (questions * 0.05) - random.uniform(0, 0.2)
)
# BrowseComp is slower
speed_score = 1.0 - (iterations * questions * self.speed_factor)
# Strategy effects
if strategy == "rapid":
speed_score += 0.1
quality_score -= 0.05
elif strategy == "iterdrag":
quality_score += 0.1
speed_score -= 0.05
# Clamp values
quality_score = max(0.0, min(1.0, quality_score))
speed_score = max(0.0, min(1.0, speed_score))
return {
"benchmark_type": self.name,
"quality_score": quality_score,
"speed_score": speed_score,
"total_duration": iterations * questions * random.uniform(10, 20),
}
class CompositeBenchmarkSimulator:
"""Simulates running multiple benchmarks with weights."""
def __init__(self, benchmark_weights: Optional[Dict[str, float]] = None):
"""
Initialize with benchmark weights.
Args:
benchmark_weights: Dictionary mapping benchmark names to weights
Default: {"simpleqa": 1.0}
"""
self.benchmark_weights = benchmark_weights or {"simpleqa": 1.0}
# Create benchmark simulators
self.simulators = {
"simpleqa": BenchmarkSimulator(
"simpleqa", quality_bias=0.75, speed_factor=0.15
),
"browsecomp": BenchmarkSimulator(
"browsecomp", quality_bias=0.7, speed_factor=0.25
),
}
# Normalize weights
total_weight = sum(self.benchmark_weights.values())
self.normalized_weights = {
k: w / total_weight for k, w in self.benchmark_weights.items()
}
def evaluate(self, params: Dict[str, Any]) -> Dict[str, Any]:
"""
Simulate running multiple benchmarks with weights.
Args:
params: System parameters to evaluate
Returns:
Dictionary with weighted results
"""
all_results = {}
combined_quality_score = 0.0
combined_speed_score = 0.0
total_duration = 0.0
# Run each benchmark with weight > 0
for benchmark_name, weight in self.normalized_weights.items():
if weight > 0 and benchmark_name in self.simulators:
simulator = self.simulators[benchmark_name]
# Run benchmark simulation
result = simulator.evaluate(params)
# Store individual results
all_results[benchmark_name] = result
# Calculate weighted contribution
quality_score = result["quality_score"]
speed_score = result["speed_score"]
weighted_quality = quality_score * weight
weighted_speed = speed_score * weight
logger.info(
f"Benchmark {benchmark_name}: quality={quality_score:.4f}, "
f"speed={speed_score:.4f}, weight={weight:.2f}"
)
# Add to combined scores
combined_quality_score += weighted_quality
combined_speed_score += weighted_speed
total_duration += result["total_duration"]
# Return combined results
return {
"quality_score": combined_quality_score,
"speed_score": combined_speed_score,
"total_duration": total_duration,
"benchmark_results": all_results,
"benchmark_weights": self.normalized_weights,
}
class OptunaOptimizerSimulator:
"""Simulates Optuna optimizer for demonstration purposes."""
def __init__(
self,
benchmark_weights: Optional[Dict[str, float]] = None,
metric_weights: Optional[Dict[str, float]] = None,
):
"""
Initialize optimizer simulator.
Args:
benchmark_weights: Weights for different benchmarks
metric_weights: Weights for quality vs speed metrics
"""
self.benchmark_weights = benchmark_weights or {"simpleqa": 1.0}
self.metric_weights = metric_weights or {"quality": 0.6, "speed": 0.4}
self.benchmark_simulator = CompositeBenchmarkSimulator(
benchmark_weights
)
def optimize(
self, param_space: Dict[str, Any], n_trials: int = 10
) -> Tuple[Dict[str, Any], float]:
"""
Simulate optimization process.
Args:
param_space: Parameter space to explore
n_trials: Number of trials
Returns:
Tuple of best parameters and best score
"""
logger.info(f"Starting optimization with {n_trials} trials")
logger.info(f"Parameter space: {param_space}")
logger.info(f"Benchmark weights: {self.benchmark_weights}")
logger.info(f"Metric weights: {self.metric_weights}")
best_score = 0.0
best_params = {}
all_trials = []
# Run simulated trials
for i in range(n_trials):
# Generate parameters for this trial
params = {}
for param_name, param_config in param_space.items():
param_type = param_config["type"]
if param_type == "int":
params[param_name] = random.randint(
param_config["low"], param_config["high"]
)
elif param_type == "categorical":
params[param_name] = random.choice(param_config["choices"])
logger.info(
f"Trial {i + 1}/{n_trials}: Testing parameters: {params}"
)
# Simulate benchmark evaluation
result = self.benchmark_simulator.evaluate(params)
# Calculate combined score based on weights
quality_score = result["quality_score"]
speed_score = result["speed_score"]
combined_score = (
self.metric_weights.get("quality", 0.6) * quality_score
+ self.metric_weights.get("speed", 0.4) * speed_score
)
logger.info(
f"Trial {i + 1}: Quality: {quality_score:.4f}, Speed: {speed_score:.4f}, "
f"Combined: {combined_score:.4f}"
)
# Save trial information
trial_info = {
"trial_number": i + 1,
"params": params,
"quality_score": quality_score,
"speed_score": speed_score,
"combined_score": combined_score,
"benchmark_results": result["benchmark_results"],
}
all_trials.append(trial_info)
# Update best parameters if this trial is better
if combined_score > best_score:
best_score = combined_score
best_params = params.copy()
logger.info(
f"New best parameters found: {best_params} with score: {best_score:.4f}"
)
# Return the best parameters
return best_params, best_score, all_trials
def optimize_parameters(
param_space: Optional[Dict[str, Any]] = None,
n_trials: int = 10,
metric_weights: Optional[Dict[str, float]] = None,
benchmark_weights: Optional[Dict[str, float]] = None,
) -> Tuple[Dict[str, Any], float]:
"""
Simulate parameter optimization.
Args:
param_space: Parameter space to explore
n_trials: Number of trials to run
metric_weights: Weights for quality vs speed
benchmark_weights: Weights for different benchmarks
Returns:
Tuple of best parameters and best score
"""
# Default parameter space
if param_space is None:
param_space = {
"iterations": {
"type": "int",
"low": 1,
"high": 5,
},
"questions_per_iteration": {
"type": "int",
"low": 1,
"high": 5,
},
"search_strategy": {
"type": "categorical",
"choices": ["iterdrag", "standard", "rapid", "parallel"],
},
}
# Create optimizer
optimizer = OptunaOptimizerSimulator(
benchmark_weights=benchmark_weights, metric_weights=metric_weights
)
# Run optimization
return optimizer.optimize(param_space, n_trials)
def print_optimization_results(params: Dict[str, Any], score: float):
"""Print optimization results in a nicely formatted way."""
print("\n" + "=" * 50)
print(" OPTIMIZATION RESULTS ")
print("=" * 50)
print(f"SCORE: {score:.4f}")
print("\nBest Parameters:")
for param, value in params.items():
print(f" {param}: {value}")
print("=" * 50 + "\n")
def main():
"""Run the multi-benchmark optimization simulation."""
# Create a timestamp-based directory for results
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
output_dir = "optimization_sim_" + timestamp
Path(output_dir).mkdir(parents=True, exist_ok=True)
print("\n🔬 Multi-Benchmark Optimization Simulation 🔬")
print(f"Results will be saved to: {output_dir}")
# Example 1: SimpleQA only (default)
print("\n🔍 Running optimization with SimpleQA benchmark only...")
params1, score1, trials1 = optimize_parameters(
n_trials=5, benchmark_weights={"simpleqa": 1.0}
)
print_optimization_results(params1, score1)
# Example 2: BrowseComp only
print("\n🔍 Running optimization with BrowseComp benchmark only...")
params2, score2, trials2 = optimize_parameters(
n_trials=5, benchmark_weights={"browsecomp": 1.0}
)
print_optimization_results(params2, score2)
# Example 3: 60/40 weighted combination (SimpleQA/BrowseComp)
print("\n🔍 Running optimization with 60% SimpleQA and 40% BrowseComp...")
params3, score3, trials3 = optimize_parameters(
n_trials=10,
benchmark_weights={
"simpleqa": 0.6, # 60% weight for SimpleQA
"browsecomp": 0.4, # 40% weight for BrowseComp
},
)
print_optimization_results(params3, score3)
# Save results
results = {
"timestamp": timestamp,
"simpleqa_only": {
"best_params": params1,
"best_score": score1,
"trials": trials1,
},
"browsecomp_only": {
"best_params": params2,
"best_score": score2,
"trials": trials2,
},
"weighted_combination": {
"best_params": params3,
"best_score": score3,
"trials": trials3,
"weights": {"simpleqa": 0.6, "browsecomp": 0.4},
},
}
results_file = str(Path(output_dir) / "multi_benchmark_results.json")
with open(results_file, "w", encoding="utf-8") as f:
# Convert all values to serializable types
json.dump(
results,
f,
indent=2,
default=lambda o: float(o) if isinstance(o, (float, int)) else o,
)
print(f"\n✅ Simulation complete! Results saved to {results_file}")
print("\nComparison of best parameters:")
print(f"- SimpleQA only: {params1}")
print(f"- BrowseComp only: {params2}")
print(f"- 60/40 weighted: {params3}")
print("\nNote: This is a simulation for demonstration purposes only.")
print(
"Real optimization would run actual benchmarks to evaluate performance."
)
if __name__ == "__main__":
main()
@@ -0,0 +1,281 @@
#!/usr/bin/env python
"""
Multi-benchmark optimization with speed metrics demonstration.
This script shows how the multi-benchmark API can be used with speed optimization
without actually running the benchmarks (simulation only).
Usage:
# Run from project root with venv activated
cd /path/to/local-deep-research
source .venv/bin/activate
cd src
python ../examples/optimization/multi_benchmark_speed_demo.py
"""
import sys
from pathlib import Path
from typing import Any, Dict
# Add src directory to Python path
src_dir = str((Path(__file__).parent.parent / "src").resolve())
if src_dir not in sys.path:
sys.path.insert(0, src_dir)
class SimulatedBenchmarkEvaluator:
"""Simulated benchmark evaluator that doesn't run actual benchmarks."""
def __init__(self, name, quality_score=0.75, speed_score=0.65):
self.name = name
self.quality_score = quality_score
self.speed_score = speed_score
def evaluate(self, system_config, num_examples=1, output_dir=None):
"""Simulate benchmark evaluation with predefined scores."""
print(f"[SIM] Running {self.name} benchmark simulation...")
print(f"[SIM] System config: {system_config}")
# Return simulated results
return {
"quality_score": self.quality_score,
"speed_score": self.speed_score,
"component_timing": {
"search": 0.5,
"processing": 0.3,
"llm": 1.2,
"total": 2.0,
},
"resource_usage": {"memory_mb": 500, "cpu_percent": 30},
}
class SimulatedCompositeBenchmarkEvaluator:
"""Simulated composite benchmark evaluator that combines multiple benchmarks."""
def __init__(self, benchmark_weights=None):
self.benchmark_weights = benchmark_weights or {"simpleqa": 1.0}
print(
f"[SIM] Created composite evaluator with weights: {self.benchmark_weights}"
)
# Normalize weights
total = sum(self.benchmark_weights.values())
self.normalized_weights = {
k: v / total for k, v in self.benchmark_weights.items()
}
print(f"[SIM] Normalized weights: {self.normalized_weights}")
# Create evaluators with slightly different characteristics
self.evaluators = {
"simpleqa": SimulatedBenchmarkEvaluator(
"SimpleQA", quality_score=0.80, speed_score=0.70
),
"browsecomp": SimulatedBenchmarkEvaluator(
"BrowseComp", quality_score=0.85, speed_score=0.60
),
}
def evaluate(self, system_config, num_examples=1, output_dir=None):
"""Run evaluation for all benchmarks with weights."""
print(
f"[SIM] Running composite evaluation with {num_examples} examples"
)
# Run each benchmark
benchmark_results = {}
for name, evaluator in self.evaluators.items():
if name in self.benchmark_weights:
benchmark_results[name] = evaluator.evaluate(
system_config, num_examples, output_dir
)
# Calculate combined quality score
quality_score = sum(
self.normalized_weights[name] * results["quality_score"]
for name, results in benchmark_results.items()
)
# Calculate combined speed score
speed_score = sum(
self.normalized_weights[name] * results["speed_score"]
for name, results in benchmark_results.items()
)
return {
"quality_score": quality_score,
"speed_score": speed_score,
"benchmark_weights": self.benchmark_weights,
"benchmark_results": benchmark_results,
}
class SimulatedOptimizer:
"""Simulated optimizer that demonstrates the API structure without running actual optimization."""
def __init__(
self,
base_query: str = "Example query",
output_dir: str = "./results",
metric_weights: Dict[str, float] = None,
benchmark_weights: Dict[str, float] = None,
):
self.base_query = base_query
self.output_dir = output_dir
self.metric_weights = metric_weights or {"quality": 0.6, "speed": 0.4}
self.benchmark_weights = benchmark_weights or {"simpleqa": 1.0}
# Create evaluator
self.evaluator = SimulatedCompositeBenchmarkEvaluator(
self.benchmark_weights
)
print("[SIM] Created optimizer with:")
print(f"[SIM] - Metric weights: {self.metric_weights}")
print(f"[SIM] - Benchmark weights: {self.benchmark_weights}")
def optimize(self, param_space=None):
"""Simulate optimization process."""
# Simulate a few trials
print("[SIM] Running optimization with parameter space:", param_space)
print("[SIM] Using metric weights:", self.metric_weights)
# Simulate trials
trials = [
{"iterations": 1, "search_strategy": "rapid"},
{"iterations": 2, "search_strategy": "standard"},
{"iterations": 3, "search_strategy": "iterdrag"},
]
# Simulate scores based on trials and weights
trial_scores = []
for trial in trials:
# Get benchmark scores
results = self.evaluator.evaluate(trial, num_examples=1)
# Calculate combined score based on metric weights
combined_score = (
self.metric_weights.get("quality", 0) * results["quality_score"]
+ self.metric_weights.get("speed", 0) * results["speed_score"]
)
trial_scores.append((trial, combined_score))
print(f"[SIM] Trial {trial}: Score {combined_score:.4f}")
# Return best parameters and score
best_trial, best_score = max(trial_scores, key=lambda x: x[1])
print(f"[SIM] Best trial: {best_trial} with score {best_score:.4f}")
return best_trial, best_score
def optimize_for_quality(
query: str, benchmark_weights: Dict[str, float] = None
):
"""Simulate quality-focused optimization."""
print("\n🔍 Simulating quality-focused optimization...")
# Quality-focused weights: 90% quality, 10% speed
metric_weights = {"quality": 0.9, "speed": 0.1}
optimizer = SimulatedOptimizer(
base_query=query,
metric_weights=metric_weights,
benchmark_weights=benchmark_weights,
)
return optimizer.optimize()
def optimize_for_speed(query: str, benchmark_weights: Dict[str, float] = None):
"""Simulate speed-focused optimization."""
print("\n🔍 Simulating speed-focused optimization...")
# Speed-focused weights: 20% quality, 80% speed
metric_weights = {"quality": 0.2, "speed": 0.8}
optimizer = SimulatedOptimizer(
base_query=query,
metric_weights=metric_weights,
benchmark_weights=benchmark_weights,
)
return optimizer.optimize()
def optimize_for_efficiency(
query: str, benchmark_weights: Dict[str, float] = None
):
"""Simulate efficiency-focused optimization."""
print("\n🔍 Simulating efficiency-focused optimization...")
# Balanced weights: 40% quality, 30% speed, 30% resource
metric_weights = {"quality": 0.4, "speed": 0.3, "resource": 0.3}
optimizer = SimulatedOptimizer(
base_query=query,
metric_weights=metric_weights,
benchmark_weights=benchmark_weights,
)
return optimizer.optimize()
def print_optimization_results(params: Dict[str, Any], score: float):
"""Print optimization results in a nicely formatted way."""
print("\n" + "=" * 50)
print(" OPTIMIZATION RESULTS ")
print("=" * 50)
print(f"SCORE: {score:.4f}")
print("\nBest Parameters:")
for param, value in params.items():
print(f" {param}: {value}")
print("=" * 50 + "\n")
def main():
"""Run simulated multi-benchmark optimization examples."""
query = "Fusion energy research developments"
# Run 1: SimpleQA benchmark only with quality focus
print("\n🔬 DEMO: SimpleQA-only optimization (quality focus)")
params1, score1 = optimize_for_quality(
query=query, benchmark_weights={"simpleqa": 1.0}
)
print_optimization_results(params1, score1)
# Run 2: BrowseComp benchmark only with quality focus
print("\n🔬 DEMO: BrowseComp-only optimization (quality focus)")
params2, score2 = optimize_for_quality(
query=query, benchmark_weights={"browsecomp": 1.0}
)
print_optimization_results(params2, score2)
# Run 3: Combined benchmarks with quality focus
print("\n🔬 DEMO: Combined benchmarks with weights (quality focus)")
params3, score3 = optimize_for_quality(
query=query, benchmark_weights={"simpleqa": 0.6, "browsecomp": 0.4}
)
print_optimization_results(params3, score3)
# Run 4: Combined benchmarks with speed focus
print("\n🔬 DEMO: Combined benchmarks with weights (speed focus)")
params4, score4 = optimize_for_speed(
query=query, benchmark_weights={"simpleqa": 0.6, "browsecomp": 0.4}
)
print_optimization_results(params4, score4)
print("Speed metrics weighting: Quality (20%), Speed (80%)")
# Run 5: Combined benchmarks with efficiency focus
print("\n🔬 DEMO: Combined benchmarks with weights (efficiency focus)")
params5, score5 = optimize_for_efficiency(
query=query, benchmark_weights={"simpleqa": 0.6, "browsecomp": 0.4}
)
print_optimization_results(params5, score5)
print(
"Efficiency metrics weighting: Quality (40%), Speed (30%), Resource (30%)"
)
if __name__ == "__main__":
main()
+321
View File
@@ -0,0 +1,321 @@
#!/usr/bin/env python
"""
Run benchmarks with Gemini Flash via OpenRouter.
This script updates the database LLM configuration and then runs benchmarks
with Gemini Flash via OpenRouter.
Usage:
# Install dependencies with PDM
cd /path/to/local-deep-research
pdm install
# Run the script with PDM
pdm run python examples/optimization/run_gemini_benchmark.py --api-key "your-openrouter-api-key" --examples 10
"""
import argparse
import sys
import time
from datetime import datetime, UTC
from pathlib import Path
from typing import Any, Dict, List, Optional
from loguru import logger
# Add the src directory to the Python path
project_root = str(Path(__file__).parent.parent.parent.resolve())
sys.path.insert(0, str(Path(project_root) / "src"))
# Loguru automatically handles logging configuration
def setup_gemini_config(api_key: Optional[str] = None) -> Dict[str, Any]:
"""
Create a configuration for using Gemini Flash via OpenRouter.
Args:
api_key: OpenRouter API key (optional, will try to get from database if not provided)
Returns:
Dictionary with Gemini configuration
"""
# Import database utilities
from local_deep_research.utilities.db_utils import (
get_db_setting,
update_db_setting,
)
# Check if API key exists in database
if not api_key:
api_key = get_db_setting("llm.openai_endpoint.api_key")
if not api_key:
logger.error("No API key found in database and none provided")
return {}
# Create configuration
config = {
"model_name": "google/gemini-2.0-flash",
"provider": "openai_endpoint",
"endpoint_url": "https://openrouter.ai/api/v1",
"api_key": api_key,
}
# Update database with this configuration
update_db_setting("llm.model", config["model_name"])
update_db_setting("llm.provider", config["provider"])
update_db_setting("llm.openai_endpoint.url", config["endpoint_url"])
update_db_setting("llm.openai_endpoint.api_key", config["api_key"])
# Log configuration
logger.info("LLM configuration updated to use Gemini Flash via OpenRouter")
logger.info(f"Model: {config['model_name']}")
logger.info(f"Provider: {config['provider']}")
return config
def run_benchmarks(
examples: int = 5,
benchmarks: List[str] = None,
api_key: Optional[str] = None,
output_dir: Optional[str] = None,
search_iterations: int = 2,
questions_per_iteration: int = 3,
search_tool: str = "searxng",
) -> Dict[str, Any]:
"""
Run benchmarks with Gemini Flash via OpenRouter.
Args:
examples: Number of examples to evaluate for each benchmark
benchmarks: List of benchmarks to run (defaults to ["simpleqa", "browsecomp"])
api_key: OpenRouter API key
output_dir: Directory to save results
search_iterations: Number of search iterations per query
questions_per_iteration: Number of questions per iteration
search_tool: Search engine to use
Returns:
Dictionary with benchmark results
"""
# Import benchmark functions
from local_deep_research.benchmarks.benchmark_functions import (
evaluate_browsecomp,
evaluate_simpleqa,
)
# Set up Gemini configuration
gemini_config = setup_gemini_config(api_key)
if not gemini_config:
return {"error": "Failed to set up Gemini configuration"}
# Create timestamp for output
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
if not output_dir:
output_dir = str(
Path(project_root)
/ "benchmark_results"
/ f"gemini_eval_{timestamp}"
)
Path(output_dir).mkdir(parents=True, exist_ok=True)
# Set benchmark list
if not benchmarks:
benchmarks = ["simpleqa", "browsecomp"]
results = {}
# Run each benchmark
for benchmark in benchmarks:
start_time = time.time()
try:
if benchmark.lower() == "simpleqa":
logger.info(
f"Running SimpleQA benchmark with {examples} examples"
)
benchmark_results = evaluate_simpleqa(
num_examples=examples,
search_iterations=search_iterations,
questions_per_iteration=questions_per_iteration,
search_tool=search_tool,
search_model=gemini_config["model_name"],
search_provider=gemini_config["provider"],
endpoint_url=gemini_config["endpoint_url"],
output_dir=str(Path(output_dir) / "simpleqa"),
)
elif benchmark.lower() == "browsecomp":
logger.info(
f"Running BrowseComp benchmark with {examples} examples"
)
benchmark_results = evaluate_browsecomp(
num_examples=examples,
search_iterations=search_iterations,
questions_per_iteration=questions_per_iteration,
search_tool=search_tool,
search_model=gemini_config["model_name"],
search_provider=gemini_config["provider"],
endpoint_url=gemini_config["endpoint_url"],
output_dir=str(Path(output_dir) / "browsecomp"),
)
else:
logger.warning(f"Unknown benchmark: {benchmark}")
continue
duration = time.time() - start_time
# Log results
logger.info(
f"{benchmark} benchmark completed in {duration:.1f} seconds"
)
if isinstance(benchmark_results, dict):
accuracy = benchmark_results.get("accuracy", "N/A")
logger.info(f"{benchmark} accuracy: {accuracy}")
# Add to results
results[benchmark] = {
"results": benchmark_results,
"duration": duration,
}
except Exception as e:
logger.exception(f"Error running {benchmark} benchmark")
import traceback
traceback.print_exc()
results[benchmark] = {
"error": str(e),
}
# Generate summary
logger.info("=" * 50)
logger.info("BENCHMARK SUMMARY")
logger.info("=" * 50)
logger.info(f"Model: {gemini_config.get('model_name')}")
logger.info(f"Examples per benchmark: {examples}")
for benchmark, benchmark_results in results.items():
if "error" in benchmark_results:
logger.info(f"{benchmark}: ERROR - {benchmark_results['error']}")
else:
accuracy = benchmark_results.get("results", {}).get(
"accuracy", "N/A"
)
duration = benchmark_results.get("duration", 0)
logger.info(
f"{benchmark}: Accuracy = {accuracy}, Duration = {duration:.1f}s"
)
logger.info(f"Results saved to: {output_dir}")
logger.info("=" * 50)
# Save summary to a file
summary_file = str(Path(output_dir) / "benchmark_summary.json")
try:
import json
with open(summary_file, "w", encoding="utf-8") as f:
json.dump(
{
"timestamp": timestamp,
"model": gemini_config.get("model_name"),
"provider": gemini_config.get("provider"),
"examples": examples,
"benchmarks": [b for b in benchmarks],
"results": {
b: {
"accuracy": (
r.get("results", {}).get("accuracy", None)
if "error" not in r
else None
),
"duration": r.get("duration", 0)
if "error" not in r
else 0,
"error": r.get("error", None)
if "error" in r
else None,
}
for b, r in results.items()
},
},
f,
indent=2,
)
logger.info(f"Summary saved to {summary_file}")
except Exception:
logger.exception("Error saving summary")
return {
"status": "complete",
"results": results,
"output_dir": output_dir,
}
def main():
"""Main function to parse arguments and run benchmarks."""
parser = argparse.ArgumentParser(
description="Run benchmarks with Gemini Flash via OpenRouter"
)
# Benchmark configuration
parser.add_argument(
"--examples",
type=int,
default=5,
help="Number of examples for each benchmark",
)
parser.add_argument(
"--benchmarks",
nargs="+",
choices=["simpleqa", "browsecomp"],
help="Benchmarks to run (default: both)",
)
parser.add_argument(
"--search-iterations",
type=int,
default=2,
help="Number of search iterations",
)
parser.add_argument(
"--questions-per-iteration",
type=int,
default=3,
help="Questions per iteration",
)
parser.add_argument(
"--search-tool", default="searxng", help="Search tool to use"
)
# API key
parser.add_argument(
"--api-key", help="OpenRouter API key (optional if already in database)"
)
# Output directory
parser.add_argument(
"--output-dir", help="Directory to save results (optional)"
)
args = parser.parse_args()
# Run benchmarks
results = run_benchmarks(
examples=args.examples,
benchmarks=args.benchmarks,
api_key=args.api_key,
output_dir=args.output_dir,
search_iterations=args.search_iterations,
questions_per_iteration=args.questions_per_iteration,
search_tool=args.search_tool,
)
return 0 if results.get("status") == "complete" else 1
if __name__ == "__main__":
sys.exit(main())
+319
View File
@@ -0,0 +1,319 @@
#!/usr/bin/env python
"""
Multi-benchmark optimization example for Local Deep Research.
This script demonstrates how to run optimization with multiple benchmark types
and custom weights between them.
Usage:
# Run from project root with venv activated
cd /path/to/local-deep-research
source .venv/bin/activate
cd src
python ../examples/optimization/run_multi_benchmark.py
"""
import os
import sys
from datetime import datetime, UTC
from pathlib import Path
from typing import Any, Dict
from loguru import logger
# Add src directory to Python path
src_dir = str((Path(__file__).parent.parent / "src").resolve())
if src_dir not in sys.path:
sys.path.insert(0, src_dir)
# Use environment variables for configuration
# The system should be configured with proper environment variables:
# - ANTHROPIC_API_KEY for Anthropic API access
# - OPENROUTER_API_KEY for OpenRouter API access (if used)
# - LDR_DATA_DIR for data directory location (if needed)
data_dir = os.environ.get("LDR_DATA_DIR", str(Path(src_dir) / "data"))
# Import benchmark optimization functions
try:
from local_deep_research.benchmarks.optimization.api import (
optimize_parameters,
)
print("Successfully imported optimization API")
except ImportError as e:
print(f"Error importing optimization API: {e}")
print("Current sys.path:", sys.path)
sys.exit(1)
def print_optimization_results(params: Dict[str, Any], score: float):
"""Print optimization results in a nicely formatted way."""
print("\n" + "=" * 50)
print(" OPTIMIZATION RESULTS ")
print("=" * 50)
print(f"SCORE: {score:.4f}")
print("\nBest Parameters:")
for param, value in params.items():
print(f" {param}: {value}")
print("=" * 50 + "\n")
def main():
"""Run multi-benchmark optimization examples."""
# Create a timestamp-based directory for results
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
# Put results in the data directory for easier access
if Path(data_dir).is_dir():
output_dir = str(
Path(data_dir)
/ "optimization_results"
/ f"multi_benchmark_{timestamp}"
)
else:
output_dir = str(
Path("optimization_results") / f"multi_benchmark_{timestamp}"
)
os.makedirs(output_dir, exist_ok=True)
print(f"Results will be saved to: {output_dir}")
print("\n🔬 Multi-Benchmark Optimization Example 🔬")
print("Results will be saved to: " + output_dir)
# Define a very small parameter space for testing
tiny_param_space = {
"iterations": {
"type": "int",
"low": 1,
"high": 3,
"step": 1,
},
"questions_per_iteration": {
"type": "int",
"low": 1,
"high": 3,
"step": 1,
},
"search_strategy": {
"type": "categorical",
"choices": ["iterdrag", "rapid", "parallel"],
},
}
# Example query for running optimization
query = "Recent developments in fusion energy research"
# Very small parameter space for quick testing
tiny_param_space = {
"iterations": {
"type": "int",
"low": 1,
"high": 2,
"step": 1,
},
"questions_per_iteration": {
"type": "int",
"low": 1,
"high": 2,
"step": 1,
},
"search_strategy": {
"type": "categorical",
"choices": ["rapid"],
},
}
# Run 1: SimpleQA benchmark only with minimal trials
print("\n🔍 Running SimpleQA-only optimization (minimal test)...")
try:
# Use very minimal settings for testing
mini_system_config = {
"iterations": 1,
"questions_per_iteration": 1,
"search_strategy": "rapid",
"max_results": 2, # Very few results
"search_tool": "wikipedia", # Fast search engine
"timeout": 5, # Extremely short timeout to speed up demo
}
# Import the evaluator directly for faster testing
from local_deep_research.benchmarks.evaluators import (
CompositeBenchmarkEvaluator,
)
print("Creating benchmark evaluator with SimpleQA only")
evaluator = CompositeBenchmarkEvaluator({"simpleqa": 1.0})
print("Running single benchmark evaluation (no optimization)...")
quality_results = evaluator.evaluate(
system_config=mini_system_config,
num_examples=1, # Use just 1 example for speed
output_dir=str(Path(output_dir) / "simpleqa_test"),
)
print("Benchmark evaluation complete!")
print(f"Quality score: {quality_results.get('quality_score', 0.0):.4f}")
print(
"Benchmark weights used:",
quality_results.get("benchmark_weights", {}),
)
print(
"Individual benchmark results:",
list(quality_results.get("benchmark_results", {}).keys()),
)
# Also run the Optuna optimizer with minimal settings
print("\nRunning minimal Optuna optimization...")
params1, score1 = optimize_parameters(
query=query,
param_space=tiny_param_space, # Use tiny param space
output_dir=str(Path(output_dir) / "simpleqa_only"),
n_trials=1, # Just one trial for testing
benchmark_weights={"simpleqa": 1.0}, # SimpleQA only
timeout=5, # Limit to 5 seconds
)
print_optimization_results(params1, score1)
except Exception as e:
logger.exception("Error running SimpleQA optimization")
print(f"Error: {e}")
# Run 2: BrowseComp benchmark only (minimal test)
print("\n🔍 Running BrowseComp-only benchmark (minimal test)...")
try:
print("Creating benchmark evaluator with BrowseComp only")
browsecomp_evaluator = CompositeBenchmarkEvaluator({"browsecomp": 1.0})
print("Running single BrowseComp evaluation (no optimization)...")
bc_results = browsecomp_evaluator.evaluate(
system_config=mini_system_config,
num_examples=1, # Just 1 example for speed
output_dir=str(Path(output_dir) / "browsecomp_test"),
)
print("BrowseComp evaluation complete!")
print(f"Quality score: {bc_results.get('quality_score', 0.0):.4f}")
print(
"Benchmark weights used:", bc_results.get("benchmark_weights", {})
)
print(
"Individual benchmark results:",
list(bc_results.get("benchmark_results", {}).keys()),
)
except Exception as e:
logger.exception("Error running BrowseComp evaluation")
print(f"Error: {e}")
# Run 3: Combined benchmark with weights (minimal test)
print(
"\n🔍 Running combined benchmarks with weights (60% SimpleQA, 40% BrowseComp)..."
)
try:
print("Creating composite benchmark evaluator with weights")
composite_evaluator = CompositeBenchmarkEvaluator(
{"simpleqa": 0.6, "browsecomp": 0.4}
)
print("Running combined benchmark evaluation (no optimization)...")
combo_results = composite_evaluator.evaluate(
system_config=mini_system_config,
num_examples=1, # Just 1 example for speed
output_dir=str(Path(output_dir) / "combined_test"),
)
print("Combined benchmark evaluation complete!")
print(f"Quality score: {combo_results.get('quality_score', 0.0):.4f}")
print(
"Benchmark weights used:",
combo_results.get("benchmark_weights", {}),
)
print(
"Individual benchmark results:",
list(combo_results.get("benchmark_results", {}).keys()),
)
except Exception as e:
logger.exception("Error running combined benchmark evaluation")
print(f"Error: {e}")
# Run 4: Combined benchmark with speed optimization
print("\n🔍 Running combined benchmarks with speed optimization...")
try:
# Import the necessary function
from local_deep_research.benchmarks.optimization.api import (
optimize_for_speed,
)
print("Running speed optimization with multi-benchmark weights...")
# Very minimal run with just 1 trial for demonstration
params_speed, score_speed = optimize_for_speed(
query=query,
output_dir=str(Path(output_dir) / "speed_optimization"),
n_trials=1, # Just one trial for testing
benchmark_weights={"simpleqa": 0.6, "browsecomp": 0.4},
timeout=5, # Limit to 5 seconds
)
print("Speed optimization with multi-benchmark complete!")
print_optimization_results(params_speed, score_speed)
print("Speed metrics weighting: Quality (20%), Speed (80%)")
except Exception as e:
logger.exception(
"Error running speed optimization with multi-benchmark"
)
print(f"Error: {e}")
# Run 5: Combined benchmark with efficiency optimization (balancing quality, speed and resources)
print("\n🔍 Running combined benchmarks with efficiency optimization...")
try:
# Import the necessary function
from local_deep_research.benchmarks.optimization.api import (
optimize_for_efficiency,
)
print("Running efficiency optimization with multi-benchmark weights...")
# Very minimal run with just 1 trial for demonstration
params_efficiency, score_efficiency = optimize_for_efficiency(
query=query,
output_dir=str(Path(output_dir) / "efficiency_optimization"),
n_trials=1, # Just one trial for testing
benchmark_weights={"simpleqa": 0.6, "browsecomp": 0.4},
timeout=5, # Limit to 5 seconds
)
print("Efficiency optimization with multi-benchmark complete!")
print_optimization_results(params_efficiency, score_efficiency)
print(
"Efficiency metrics combine quality (40%), speed (30%), and resource usage (30%)"
)
except Exception as e:
logger.exception(
"Error running efficiency optimization with multi-benchmark"
)
print(f"Error: {e}")
print("\nSkipping full optimization runs for time constraints.")
print("The system fully supports:")
print(
" 1. BrowseComp-only optimization with benchmark_weights={'browsecomp': 1.0}"
)
print(
" 2. Combined benchmarks with weights benchmark_weights={'simpleqa': 0.6, 'browsecomp': 0.4}"
)
print(
" 3. Speed optimization with benchmark_weights using optimize_for_speed()"
)
print(
" 4. Efficiency optimization with benchmark_weights using optimize_for_efficiency()"
)
print("\nThese would use the same API as demonstrated above.")
print(f"\nAll optimization runs completed. Results saved to {output_dir}")
print("Note: For serious optimization runs, increase n_trials to 20+")
if __name__ == "__main__":
main()
+198
View File
@@ -0,0 +1,198 @@
#!/usr/bin/env python
"""
Parameter Optimization Runner for Local Deep Research.
This script provides a convenient way to run hyperparameter optimization.
Usage:
# Install dependencies with PDM
cd /path/to/local-deep-research
pdm install
# Run the script with PDM
pdm run python examples/optimization/run_optimization.py --help
"""
import argparse
import json
import os
import sys
from datetime import datetime, UTC
from pathlib import Path
# Import the optimization functionality
from local_deep_research.benchmarks.optimization import (
optimize_for_efficiency,
optimize_for_quality,
optimize_for_speed,
optimize_parameters,
)
def main():
"""Run parameter optimization with command-line arguments."""
parser = argparse.ArgumentParser(
description="Run parameter optimization for Local Deep Research"
)
parser.add_argument("query", help="Research query to optimize for")
parser.add_argument(
"--output-dir",
default=str(Path("examples") / "optimization" / "results"),
help="Directory to save results",
)
parser.add_argument(
"--search-tool", default="searxng", help="Search tool to use"
)
# LLM configuration options
parser.add_argument(
"--model",
help="Model name for the LLM (e.g., 'claude-3-sonnet-20240229')",
)
parser.add_argument(
"--provider",
help="Provider for the LLM (e.g., 'anthropic', 'openai', 'openai_endpoint')",
)
parser.add_argument(
"--endpoint-url",
help="Custom endpoint URL (e.g., 'https://openrouter.ai/api/v1')",
)
parser.add_argument("--api-key", help="API key for the LLM provider")
parser.add_argument(
"--temperature",
type=float,
default=0.7,
help="Temperature for the LLM (default: 0.7)",
)
parser.add_argument(
"--trials",
type=int,
default=30,
help="Number of parameter combinations to try",
)
parser.add_argument(
"--mode",
choices=["balanced", "speed", "quality", "efficiency"],
default="balanced",
help="Optimization mode",
)
parser.add_argument(
"--weights",
help='Custom weights as JSON string, e.g., \'{"quality": 0.7, "speed": 0.3}\'',
)
args = parser.parse_args()
# Create timestamp for unique output directory
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
output_dir = str(Path(args.output_dir) / f"opt_{timestamp}")
os.makedirs(output_dir, exist_ok=True)
print(
f"Starting optimization ({args.mode} mode) - results will be saved to {output_dir}"
)
# Parse custom weights if provided
custom_weights = None
if args.weights:
try:
custom_weights = json.loads(args.weights)
except json.JSONDecodeError:
print("Error parsing weights JSON. Using default weights.")
# Set environment variables for the API key and endpoint URL if provided
if args.api_key:
os.environ["OPENAI_ENDPOINT_API_KEY"] = args.api_key
os.environ["LDR_LLM__OPENAI_ENDPOINT_API_KEY"] = args.api_key
if args.endpoint_url:
os.environ["OPENAI_ENDPOINT_URL"] = args.endpoint_url
os.environ["LDR_LLM__OPENAI_ENDPOINT_URL"] = args.endpoint_url
if args.model:
os.environ["LDR_LLM__MODEL"] = args.model
if args.provider:
os.environ["LDR_LLM__PROVIDER"] = args.provider
# Run optimization based on mode
if args.mode == "speed":
best_params, best_score = optimize_for_speed(
query=args.query,
search_tool=args.search_tool,
n_trials=args.trials,
model_name=args.model,
provider=args.provider,
openai_endpoint_url=args.endpoint_url,
temperature=args.temperature,
api_key=args.api_key,
output_dir=output_dir,
)
elif args.mode == "quality":
best_params, best_score = optimize_for_quality(
query=args.query,
search_tool=args.search_tool,
n_trials=args.trials,
model_name=args.model,
provider=args.provider,
openai_endpoint_url=args.endpoint_url,
temperature=args.temperature,
api_key=args.api_key,
output_dir=output_dir,
)
elif args.mode == "efficiency":
best_params, best_score = optimize_for_efficiency(
query=args.query,
search_tool=args.search_tool,
n_trials=args.trials,
model_name=args.model,
provider=args.provider,
openai_endpoint_url=args.endpoint_url,
temperature=args.temperature,
api_key=args.api_key,
output_dir=output_dir,
)
else: # balanced
best_params, best_score = optimize_parameters(
query=args.query,
search_tool=args.search_tool,
n_trials=args.trials,
model_name=args.model,
provider=args.provider,
openai_endpoint_url=args.endpoint_url,
temperature=args.temperature,
api_key=args.api_key,
output_dir=output_dir,
metric_weights=custom_weights,
)
print(f"\nOptimization complete! Results saved to {output_dir}")
print(f"Best parameters: {best_params}")
print(f"Best score: {best_score:.4f}")
# Save summary to a JSON file
summary = {
"timestamp": timestamp,
"query": args.query,
"mode": args.mode,
"trials": args.trials,
"search_tool": args.search_tool,
"model": args.model,
"provider": args.provider,
"temperature": args.temperature,
"best_parameters": best_params,
"best_score": best_score,
"custom_weights": custom_weights,
}
with open(
Path(output_dir) / "optimization_summary.json", "w", encoding="utf-8"
) as f:
json.dump(summary, f, indent=2)
return 0
if __name__ == "__main__":
sys.exit(main())
+300
View File
@@ -0,0 +1,300 @@
#!/usr/bin/env python
"""
Run SimpleQA and BrowseComp benchmarks in parallel with 300 examples each.
This script demonstrates running multiple benchmarks in parallel with a large number of examples.
Usage:
# Install dependencies with PDM
cd /path/to/local-deep-research
pdm install
# Run the script with PDM
pdm run python examples/optimization/run_parallel_benchmark.py
"""
import argparse
import concurrent.futures
import os
import sys
import time
from datetime import datetime, UTC
from pathlib import Path
from loguru import logger
# Add the src directory to the Python path
project_root = str(Path(__file__).parent.parent.parent.resolve())
sys.path.insert(0, str(Path(project_root) / "src"))
def run_simpleqa_benchmark(
num_examples,
output_dir,
model=None,
provider=None,
endpoint_url=None,
api_key=None,
):
"""Run SimpleQA benchmark with specified number of examples."""
from local_deep_research.benchmarks.benchmark_functions import (
evaluate_simpleqa,
)
logger.info(f"Starting SimpleQA benchmark with {num_examples} examples")
start_time = time.time()
# Run the benchmark
results = evaluate_simpleqa(
num_examples=num_examples,
search_iterations=2,
questions_per_iteration=3,
search_strategy="source_based",
search_tool="searxng",
search_model=model,
search_provider=provider,
endpoint_url=endpoint_url,
output_dir=str(Path(output_dir) / "simpleqa"),
evaluation_provider="ANTHROPIC",
evaluation_model="claude-3-7-sonnet-20250219",
)
duration = time.time() - start_time
logger.info(f"SimpleQA benchmark completed in {duration:.1f} seconds")
if results and isinstance(results, dict):
logger.info(f"SimpleQA accuracy: {results.get('accuracy', 'N/A')}")
return results
def run_browsecomp_benchmark(
num_examples,
output_dir,
model=None,
provider=None,
endpoint_url=None,
api_key=None,
):
"""Run BrowseComp benchmark with specified number of examples."""
from local_deep_research.benchmarks.benchmark_functions import (
evaluate_browsecomp,
)
logger.info(f"Starting BrowseComp benchmark with {num_examples} examples")
start_time = time.time()
# Run the benchmark
results = evaluate_browsecomp(
num_examples=num_examples,
search_iterations=3,
questions_per_iteration=3,
search_strategy="source_based",
search_tool="searxng",
search_model=model,
search_provider=provider,
endpoint_url=endpoint_url,
output_dir=str(Path(output_dir) / "browsecomp"),
evaluation_provider="ANTHROPIC",
evaluation_model="claude-3-7-sonnet-20250219",
)
duration = time.time() - start_time
logger.info(f"BrowseComp benchmark completed in {duration:.1f} seconds")
if results and isinstance(results, dict):
logger.info(f"BrowseComp accuracy: {results.get('accuracy', 'N/A')}")
return results
def setup_llm_environment(
model=None, provider=None, endpoint_url=None, api_key=None
):
"""Set up environment variables for LLM configuration."""
if model:
os.environ["LDR_LLM__MODEL"] = model
logger.info(f"Using LLM model: {model}")
if provider:
os.environ["LDR_LLM__PROVIDER"] = provider
logger.info(f"Using LLM provider: {provider}")
if endpoint_url:
os.environ["OPENAI_ENDPOINT_URL"] = endpoint_url
os.environ["LDR_LLM__OPENAI_ENDPOINT_URL"] = endpoint_url
logger.info(f"Using endpoint URL: {endpoint_url}")
if api_key:
# Set the appropriate environment variable based on provider
if provider == "openai":
os.environ["OPENAI_API_KEY"] = api_key
os.environ["LDR_LLM__OPENAI_API_KEY"] = api_key
elif provider == "openai_endpoint":
os.environ["OPENAI_ENDPOINT_API_KEY"] = api_key
os.environ["LDR_LLM__OPENAI_ENDPOINT_API_KEY"] = api_key
elif provider == "anthropic":
os.environ["ANTHROPIC_API_KEY"] = api_key
os.environ["LDR_LLM__ANTHROPIC_API_KEY"] = api_key
logger.info("API key configured")
def main():
parser = argparse.ArgumentParser(
description="Run SimpleQA and BrowseComp benchmarks in parallel"
)
parser.add_argument(
"--examples",
type=int,
default=300,
help="Number of examples for each benchmark (default: 300)",
)
# LLM configuration options
parser.add_argument(
"--model",
help="Model name for the LLM (e.g., 'claude-3-sonnet-20240229')",
)
parser.add_argument(
"--provider",
help="Provider for the LLM (e.g., 'anthropic', 'openai', 'openai_endpoint')",
)
parser.add_argument(
"--endpoint-url",
help="Custom endpoint URL (e.g., 'https://openrouter.ai/api/v1')",
)
parser.add_argument("--api-key", help="API key for the LLM provider")
args = parser.parse_args()
# Create timestamp for unique output directory
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
output_dir = str(
Path(project_root)
/ "benchmark_results"
/ f"parallel_benchmark_{timestamp}"
)
Path(output_dir).mkdir(parents=True, exist_ok=True)
# Display start information
print(f"Starting parallel benchmarks with {args.examples} examples each")
print(f"Results will be saved to: {output_dir}")
# Set up LLM environment if specified
setup_llm_environment(
model=args.model,
provider=args.provider,
endpoint_url=args.endpoint_url,
api_key=args.api_key,
)
# Start time for total execution
total_start_time = time.time()
# Run benchmarks in parallel using ThreadPoolExecutor
with concurrent.futures.ThreadPoolExecutor(max_workers=2) as executor:
# Submit both benchmark jobs
simpleqa_future = executor.submit(
run_simpleqa_benchmark,
args.examples,
output_dir,
args.model,
args.provider,
args.endpoint_url,
args.api_key,
)
browsecomp_future = executor.submit(
run_browsecomp_benchmark,
args.examples,
output_dir,
args.model,
args.provider,
args.endpoint_url,
args.api_key,
)
# Get results from both futures
try:
simpleqa_results = simpleqa_future.result()
print("SimpleQA benchmark completed successfully")
except Exception:
logger.exception("Error in SimpleQA benchmark")
simpleqa_results = None
try:
browsecomp_results = browsecomp_future.result()
print("BrowseComp benchmark completed successfully")
except Exception:
logger.exception("Error in BrowseComp benchmark")
browsecomp_results = None
# Calculate total time
total_duration = time.time() - total_start_time
# Print summary
print("\n" + "=" * 50)
print(" PARALLEL BENCHMARK SUMMARY ")
print("=" * 50)
print(f"Total duration: {total_duration:.1f} seconds")
print(f"Examples per benchmark: {args.examples}")
if simpleqa_results and isinstance(simpleqa_results, dict):
print(f"SimpleQA accuracy: {simpleqa_results.get('accuracy', 'N/A')}")
else:
print("SimpleQA: Failed or no results")
if browsecomp_results and isinstance(browsecomp_results, dict):
print(
f"BrowseComp accuracy: {browsecomp_results.get('accuracy', 'N/A')}"
)
else:
print("BrowseComp: Failed or no results")
print(f"Results saved to: {output_dir}")
print("=" * 50)
# Save summary to JSON file
try:
import json
summary = {
"timestamp": timestamp,
"examples_per_benchmark": args.examples,
"total_duration": total_duration,
"simpleqa": {
"accuracy": (
simpleqa_results.get("accuracy")
if simpleqa_results
else None
),
"completed": simpleqa_results is not None,
},
"browsecomp": {
"accuracy": (
browsecomp_results.get("accuracy")
if browsecomp_results
else None
),
"completed": browsecomp_results is not None,
},
"model": args.model,
"provider": args.provider,
}
with open(
Path(output_dir) / "parallel_benchmark_summary.json",
"w",
encoding="utf-8",
) as f:
json.dump(summary, f, indent=2)
except Exception:
logger.exception("Error saving summary")
return 0
if __name__ == "__main__":
sys.exit(main())
+592
View File
@@ -0,0 +1,592 @@
#!/usr/bin/env python3
# This script should be run from the project root directory using:
# cd /path/to/local-deep-research
# python -m examples.optimization.strategy_benchmark_plan
"""
Strategy Benchmark Plan - Comprehensive Optuna-based optimization for search strategies
This benchmark specifically focuses on comparing the iterdrag and source_based strategies
with 500 examples per experiment to ensure statistically significant results.
"""
import json
import os
import random
import sys
import time
from datetime import datetime, UTC
from pathlib import Path
from typing import Any, Dict, Tuple
from loguru import logger
# Add the src directory to the Python path before local imports
project_root = str(Path(__file__).parent.parent.parent.resolve())
sys.path.insert(0, str(Path(project_root) / "src"))
# Now we can import from the local project
from local_deep_research.benchmarks.optimization.optuna_optimizer import ( # noqa: E402
OptunaOptimizer,
)
# Logger is already imported from loguru at the top
# Number of examples to use in each benchmark experiment
NUM_EXAMPLES = 500
def progress_callback(trial_num, total_trials, data):
"""Progress callback for optimization"""
print(f"Progress: {trial_num}/{total_trials} - {data}")
def run_strategy_comparison():
"""
Run a comprehensive comparison between iterdrag and source_based strategies.
Uses a large sample size (500 examples) for statistical significance.
"""
# Verify LLM and search database settings before proceeding
try:
from local_deep_research.config.llm_config import get_llm
from local_deep_research.config.search_config import get_search
from local_deep_research.utilities.db_utils import get_db_setting
# Try to initialize LLM and search engine to check configuration
llm = get_llm()
search = get_search()
# Get relevant DB settings
try:
iterations = get_db_setting("search.iterations") or 3
questions_per_iteration = (
get_db_setting("search.questions_per_iteration") or 3
)
except Exception as e:
logger.warning(f"Error getting DB settings: {e}")
iterations = 3
questions_per_iteration = 3
logger.info("Successfully connected to database")
logger.info(f"Using LLM: {llm.__class__.__name__}")
logger.info(f"Using search engine: {search.__class__.__name__}")
logger.info(f"Default iterations from DB: {iterations}")
logger.info(
f"Default questions per iteration from DB: {questions_per_iteration}"
)
except Exception as e:
logger.exception("Error initializing LLM or search settings")
logger.info("Please check your database configuration")
return {"error": str(e)}
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
base_output_dir = f"strategy_benchmark_results_{timestamp}"
os.makedirs(base_output_dir, exist_ok=True)
# Define test query
query = "What are the latest developments in fusion energy research?"
# Track execution stats
execution_stats = {"start_time": time.time(), "experiments": []}
# Define parameter space specific to strategy comparison
strategy_param_space = {
"search_strategy": {
"type": "categorical",
"choices": ["iterdrag", "source_based"],
},
"iterations": {
"type": "int",
"low": 1,
"high": 3,
"step": 1,
},
"questions_per_iteration": {
"type": "int",
"low": 1,
"high": 5,
"step": 1,
},
"max_results": {
"type": "int",
"low": 10,
"high": 50,
"step": 10,
},
}
# Common settings for all experiments
common_settings = {
"query": query,
"n_trials": 30, # Optuna trials per experiment
"n_jobs": 1, # Run one job at a time for consistent resource measurement
"timeout": 3600, # 1 hour timeout per experiment
"progress_callback": progress_callback,
}
# ====== EXPERIMENT 1: Quality-focused optimization ======
logger.info("Starting quality-focused benchmark with 500 examples")
quality_output_dir = str(Path(base_output_dir) / "quality_focused")
Path(quality_output_dir).mkdir(parents=True, exist_ok=True)
# Create optimizer for quality
quality_optimizer = OptunaOptimizer(
base_query=query,
output_dir=quality_output_dir,
n_trials=common_settings["n_trials"],
timeout=common_settings["timeout"],
n_jobs=common_settings["n_jobs"],
progress_callback=common_settings["progress_callback"],
study_name="strategy_quality_benchmark",
optimization_metrics=["quality", "speed"],
metric_weights={"quality": 0.9, "speed": 0.1},
num_examples=NUM_EXAMPLES, # Use 500 examples for robust evaluation
)
# Run quality optimization
quality_start = time.time()
best_quality_params, best_quality_score = quality_optimizer.optimize(
strategy_param_space
)
quality_end = time.time()
quality_result = {
"experiment": "quality_focused",
"best_params": best_quality_params,
"best_score": best_quality_score,
"duration_seconds": quality_end - quality_start,
}
execution_stats["experiments"].append(quality_result)
# Log and save results
logger.info(f"Quality benchmark complete: {best_quality_params}")
logger.info(f"Best quality score: {best_quality_score}")
logger.info(f"Duration: {quality_end - quality_start} seconds")
with open(
Path(quality_output_dir) / "results.json", "w", encoding="utf-8"
) as f:
json.dump(quality_result, f, indent=2)
# ====== EXPERIMENT 2: Speed-focused optimization ======
logger.info("Starting speed-focused benchmark with 500 examples")
speed_output_dir = str(Path(base_output_dir) / "speed_focused")
Path(speed_output_dir).mkdir(parents=True, exist_ok=True)
# Create optimizer for speed
speed_optimizer = OptunaOptimizer(
base_query=query,
output_dir=speed_output_dir,
n_trials=common_settings["n_trials"],
timeout=common_settings["timeout"],
n_jobs=common_settings["n_jobs"],
progress_callback=common_settings["progress_callback"],
study_name="strategy_speed_benchmark",
optimization_metrics=["quality", "speed"],
metric_weights={"quality": 0.2, "speed": 0.8},
num_examples=NUM_EXAMPLES, # Use 500 examples for robust evaluation
)
# Run speed optimization
speed_start = time.time()
best_speed_params, best_speed_score = speed_optimizer.optimize(
strategy_param_space
)
speed_end = time.time()
speed_result = {
"experiment": "speed_focused",
"best_params": best_speed_params,
"best_score": best_speed_score,
"duration_seconds": speed_end - speed_start,
}
execution_stats["experiments"].append(speed_result)
# Log and save results
logger.info(f"Speed benchmark complete: {best_speed_params}")
logger.info(f"Best speed score: {best_speed_score}")
logger.info(f"Duration: {speed_end - speed_start} seconds")
with open(
Path(speed_output_dir) / "results.json", "w", encoding="utf-8"
) as f:
json.dump(speed_result, f, indent=2)
# ====== EXPERIMENT 3: Balanced optimization ======
logger.info("Starting balanced benchmark with 500 examples")
balanced_output_dir = str(Path(base_output_dir) / "balanced")
Path(balanced_output_dir).mkdir(parents=True, exist_ok=True)
# Create optimizer for balanced approach
balanced_optimizer = OptunaOptimizer(
base_query=query,
output_dir=balanced_output_dir,
n_trials=common_settings["n_trials"],
timeout=common_settings["timeout"],
n_jobs=common_settings["n_jobs"],
progress_callback=common_settings["progress_callback"],
study_name="strategy_balanced_benchmark",
optimization_metrics=["quality", "speed", "resource"],
metric_weights={"quality": 0.4, "speed": 0.3, "resource": 0.3},
num_examples=NUM_EXAMPLES, # Use 500 examples for robust evaluation
)
# Run balanced optimization
balanced_start = time.time()
best_balanced_params, best_balanced_score = balanced_optimizer.optimize(
strategy_param_space
)
balanced_end = time.time()
balanced_result = {
"experiment": "balanced",
"best_params": best_balanced_params,
"best_score": best_balanced_score,
"duration_seconds": balanced_end - balanced_start,
}
execution_stats["experiments"].append(balanced_result)
# Log and save results
logger.info(f"Balanced benchmark complete: {best_balanced_params}")
logger.info(f"Best balanced score: {best_balanced_score}")
logger.info(f"Duration: {balanced_end - balanced_start} seconds")
with open(
Path(balanced_output_dir) / "results.json", "w", encoding="utf-8"
) as f:
json.dump(balanced_result, f, indent=2)
# ====== EXPERIMENT 4: Multi-Benchmark (SimpleQA + BrowseComp) ======
logger.info("Starting multi-benchmark optimization with 500 examples")
multi_output_dir = str(Path(base_output_dir) / "multi_benchmark")
Path(multi_output_dir).mkdir(parents=True, exist_ok=True)
# Create optimizer with multi-benchmark weights
multi_optimizer = OptunaOptimizer(
base_query=query,
output_dir=multi_output_dir,
n_trials=common_settings["n_trials"],
timeout=common_settings["timeout"],
n_jobs=common_settings["n_jobs"],
progress_callback=common_settings["progress_callback"],
study_name="strategy_multi_benchmark",
optimization_metrics=["quality", "speed"],
metric_weights={"quality": 0.6, "speed": 0.4},
benchmark_weights={"simpleqa": 0.6, "browsecomp": 0.4},
num_examples=NUM_EXAMPLES, # Use 500 examples for robust evaluation
)
# Run multi-benchmark optimization
multi_start = time.time()
best_multi_params, best_multi_score = multi_optimizer.optimize(
strategy_param_space
)
multi_end = time.time()
multi_result = {
"experiment": "multi_benchmark",
"best_params": best_multi_params,
"best_score": best_multi_score,
"duration_seconds": multi_end - multi_start,
}
execution_stats["experiments"].append(multi_result)
# Log and save results
logger.info(f"Multi-benchmark complete: {best_multi_params}")
logger.info(f"Best multi-benchmark score: {best_multi_score}")
logger.info(f"Duration: {multi_end - multi_start} seconds")
with open(
Path(multi_output_dir) / "results.json", "w", encoding="utf-8"
) as f:
json.dump(multi_result, f, indent=2)
# ====== Save summary of all executions ======
execution_stats["total_duration"] = (
time.time() - execution_stats["start_time"]
)
execution_stats["timestamp"] = timestamp
with open(
Path(base_output_dir) / "summary.json", "w", encoding="utf-8"
) as f:
json.dump(execution_stats, f, indent=2)
# Generate summary report
generate_summary_report(base_output_dir, execution_stats)
return execution_stats
def generate_summary_report(base_dir, stats):
"""Generate a human-readable summary report of all benchmarks"""
summary_text = f"""
# Strategy Benchmark Results Summary
## Overview
- **Date:** {datetime.fromtimestamp(stats["start_time"]).strftime("%Y-%m-%d %H:%M:%S")}
- **Total Duration:** {stats["total_duration"] / 3600:.2f} hours
- **Number of Examples per Experiment:** {NUM_EXAMPLES}
## Experiment Results
"""
# Add detailed results for each experiment
for exp in stats["experiments"]:
summary_text += f"""### {exp["experiment"].replace("_", " ").title()}
- **Best Parameters:** {json.dumps(exp["best_params"], indent=2)}
- **Best Score:** {exp["best_score"]:.4f}
- **Duration:** {exp["duration_seconds"] / 60:.2f} minutes
"""
summary_text += """
## Strategy Comparison
| Metric Focus | Best Strategy | Other Parameters | Score |
|--------------|--------------|------------------|-------|
"""
for exp in stats["experiments"]:
best_strategy = exp["best_params"].get("search_strategy", "unknown")
other_params = {
k: v
for k, v in exp["best_params"].items()
if k != "search_strategy"
}
summary_text += f"| {exp['experiment'].replace('_', ' ').title()} | {best_strategy} | {other_params} | {exp['best_score']:.4f} |\n"
summary_text += """
## Analysis
This benchmark compared the performance of iterdrag and source_based strategies across different optimization goals:
- Quality-focused: Prioritizes result quality (90%) over speed (10%)
- Speed-focused: Prioritizes execution speed (80%) over quality (20%)
- Balanced: Balances quality (40%), speed (30%), and resource usage (30%)
- Multi-benchmark: Uses weighted combination of SimpleQA (60%) and BrowseComp (40%)
The results indicate which strategy is better suited for each optimization goal when using a statistically
significant sample size of 500 examples per experiment.
"""
# Write summary to file
with open(Path(base_dir) / "summary_report.md", "w", encoding="utf-8") as f:
f.write(summary_text)
def run_strategy_simulation(num_examples=10):
"""
Run a smaller simulation of the strategy benchmark with fewer examples
for testing purposes or quick comparisons.
This fallback simulation mode doesn't require actual database or LLM access,
making it useful for testing the script structure.
"""
timestamp = datetime.now(UTC).strftime("%Y%m%d_%H%M%S")
sim_output_dir = f"strategy_sim_results_{timestamp}"
os.makedirs(sim_output_dir, exist_ok=True)
# Define test query
query = "What are the latest developments in fusion energy research?"
# Define parameter space limited to strategies
strategy_param_space = {
"search_strategy": {
"type": "categorical",
"choices": ["iterdrag", "source_based"],
},
"iterations": {
"type": "int",
"low": 1,
"high": 2,
"step": 1,
},
}
try:
# Try to use real optimizer if available
logger.info("Attempting to use real optimizer...")
# Check if we can access necessary components
from local_deep_research.config.llm_config import get_llm
from local_deep_research.config.search_config import get_search
# Try to initialize LLM and search engine to check configuration
llm = get_llm()
search = get_search()
logger.info(
f"Connected to LLM ({llm.__class__.__name__}) and search ({search.__class__.__name__})"
)
# Create optimizer for simulation
sim_optimizer = OptunaOptimizer(
base_query=query,
output_dir=sim_output_dir,
n_trials=5, # Just a few trials for simulation
timeout=600, # 10 minutes timeout
n_jobs=1,
study_name="strategy_simulation",
optimization_metrics=["quality", "speed"],
metric_weights={"quality": 0.5, "speed": 0.5},
num_examples=num_examples, # Use fewer examples for simulation
)
# Run simulation
best_params, best_score = sim_optimizer.optimize(strategy_param_space)
except Exception as e:
logger.warning(f"Could not initialize real optimizer: {e!s}")
logger.warning(
"Falling back to pure simulation mode (no real benchmarks)"
)
# Simulate optimization if real system is unavailable
logger.info(
"Running purely simulated optimization (no real benchmarks)"
)
best_params, best_score = simulate_optimization(
strategy_param_space,
n_trials=5,
metric_weights={"quality": 0.5, "speed": 0.5},
)
# Log and save results
logger.info(f"Simulation complete: {best_params}")
logger.info(f"Best simulation score: {best_score}")
sim_result = {
"best_params": best_params,
"best_score": best_score,
}
with open(
Path(sim_output_dir) / "simulation_results.json", "w", encoding="utf-8"
) as f:
json.dump(sim_result, f, indent=2)
return sim_result
def simulate_optimization(
param_space: Dict[str, Any],
n_trials: int = 5,
metric_weights: Dict[str, float] = None,
) -> Tuple[Dict[str, Any], float]:
"""
Simulate an optimization process without actually running benchmarks.
This is just for demonstration/testing purposes when the real system is unavailable.
Args:
param_space: Dictionary defining parameter search spaces
n_trials: Number of simulated trials
metric_weights: Weights for quality vs speed metrics
Returns:
Tuple of (best_parameters, best_score)
"""
if metric_weights is None:
metric_weights = {"quality": 0.5, "speed": 0.5}
logger.info(f"Starting simulated optimization with {n_trials} trials")
logger.info(f"Parameter space: {param_space}")
logger.info(f"Metric weights: {metric_weights}")
# Generate random trials
best_score = 0.0
best_params = {}
for i in range(n_trials):
# Generate random parameters
params = {}
for param_name, param_config in param_space.items():
if param_config.get("type") == "int":
params[param_name] = random.randint(
param_config.get("low", 1), param_config.get("high", 5)
)
elif param_config.get("type") == "categorical":
params[param_name] = random.choice(
param_config.get("choices", ["standard"])
)
logger.info(f"Trial {i + 1}: Testing parameters: {params}")
# Simulate execution delay
time.sleep(0.5)
# Simulate metrics for different strategies
quality_score = 0.0
speed_score = 0.0
# Generate strategy-specific simulated scores
if params.get("search_strategy") == "iterdrag":
# IterDRAG typically has higher quality but lower speed
quality_score = random.uniform(0.7, 0.95)
speed_score = random.uniform(0.4, 0.7)
elif params.get("search_strategy") == "source_based":
# Source-based typically has medium quality but higher speed
quality_score = random.uniform(0.6, 0.85)
speed_score = random.uniform(0.6, 0.9)
else:
# Other strategies
quality_score = random.uniform(0.5, 0.9)
speed_score = random.uniform(0.5, 0.9)
# More iterations generally means higher quality but lower speed
iterations = params.get("iterations", 1)
quality_score += (
iterations * 0.05
) # More iterations slightly improves quality
speed_score -= (
iterations * 0.15
) # More iterations significantly reduces speed
# Normalize scores to 0-1 range
quality_score = max(0.0, min(1.0, quality_score))
speed_score = max(0.0, min(1.0, speed_score))
# Calculate weighted score based on metric weights
combined_score = quality_score * metric_weights.get(
"quality", 0.5
) + speed_score * metric_weights.get("speed", 0.5)
logger.info(
f"Trial {i + 1}: Quality: {quality_score:.2f}, Speed: {speed_score:.2f}, Score: {combined_score:.2f}"
)
# Update best parameters if this trial is better
if combined_score > best_score:
best_score = combined_score
best_params = params.copy()
logger.info(
f"New best parameters found: {best_params} with score: {best_score:.2f}"
)
return best_params, best_score
if __name__ == "__main__":
import argparse
parser = argparse.ArgumentParser(description="Run strategy benchmarks")
parser.add_argument(
"--simulate",
action="store_true",
help="Run a quick simulation instead of full benchmark",
)
parser.add_argument(
"--examples",
type=int,
default=NUM_EXAMPLES,
help=f"Number of examples to use (default: {NUM_EXAMPLES})",
)
args = parser.parse_args()
if args.simulate:
logger.info(f"Running simulation with {args.examples} examples")
run_strategy_simulation(args.examples)
else:
logger.info(f"Running full benchmark with {args.examples} examples")
NUM_EXAMPLES = args.examples # Override global constant
# Just run the benchmark function directly
run_strategy_comparison()
+202
View File
@@ -0,0 +1,202 @@
#!/usr/bin/env python
"""
Update LLM configuration in the database for benchmarks.
This script updates the LLM configuration in the database to ensure
consistent behavior when running benchmarks with different LLM models.
Usage:
# Install dependencies with PDM
cd /path/to/local-deep-research
pdm install
# Run the script with PDM
pdm run python examples/optimization/update_llm_config.py --model "google/gemini-2.0-flash" --provider "openai_endpoint" --endpoint "https://openrouter.ai/api/v1" --api-key "your-api-key"
# Or to reset to default configuration
pdm run python examples/optimization/update_llm_config.py --reset
"""
import argparse
import sys
from pathlib import Path
from typing import Optional
from loguru import logger
# Add the src directory to the Python path
project_root = str(Path(__file__).parent.parent.parent.resolve())
sys.path.insert(0, str(Path(project_root) / "src"))
def update_llm_configuration(
model_name: Optional[str] = None,
provider: Optional[str] = None,
endpoint_url: Optional[str] = None,
api_key: Optional[str] = None,
temperature: Optional[float] = None,
reset: bool = False,
) -> bool:
"""
Update LLM configuration in the database.
Args:
model_name: LLM model name to set
provider: LLM provider to set
endpoint_url: Endpoint URL for OpenRouter or similar services
api_key: API key for the provider
temperature: Temperature setting for the LLM
reset: If True, reset to default configuration
Returns:
True if successful, False otherwise
"""
# Import database utility functions
try:
from local_deep_research.utilities.db_utils import (
get_db_setting,
update_db_setting,
)
except ImportError:
logger.exception(
"Could not import database utilities. Make sure you're in the correct directory."
)
return False
# Default configuration
default_config = {
"llm.model": "gemma3:12b",
"llm.provider": "ollama",
"llm.temperature": 0.7,
"llm.max_tokens": 30000,
}
try:
if reset:
# Reset to default configuration
logger.info("Resetting LLM configuration to defaults")
for key, value in default_config.items():
update_db_setting(key, value)
logger.info(f"Reset {key} to {value}")
# Clear API keys
update_db_setting("llm.openai_endpoint.api_key", "")
update_db_setting("llm.openai_endpoint.url", "")
logger.info("LLM configuration reset to defaults")
return True
# Update model and provider if provided
if model_name:
update_db_setting("llm.model", model_name)
logger.info(f"Updated llm.model to {model_name}")
if provider:
update_db_setting("llm.provider", provider)
logger.info(f"Updated llm.provider to {provider}")
if temperature is not None:
update_db_setting("llm.temperature", temperature)
logger.info(f"Updated llm.temperature to {temperature}")
# Handle provider-specific settings
if provider == "openai_endpoint":
if endpoint_url:
update_db_setting("llm.openai_endpoint.url", endpoint_url)
logger.info(
f"Updated llm.openai_endpoint.url to {endpoint_url}"
)
if api_key:
update_db_setting("llm.openai_endpoint.api_key", api_key)
logger.info(
"Updated llm.openai_endpoint.api_key (value hidden)"
)
elif provider == "openai":
if api_key:
update_db_setting("llm.openai.api_key", api_key)
logger.info("Updated llm.openai.api_key (value hidden)")
elif provider == "anthropic":
if api_key:
update_db_setting("llm.anthropic.api_key", api_key)
logger.info("Updated llm.anthropic.api_key (value hidden)")
# Verify settings were updated
current_model = get_db_setting("llm.model")
current_provider = get_db_setting("llm.provider")
logger.info(
f"Current LLM configuration: model={current_model}, provider={current_provider}"
)
if provider == "openai_endpoint":
endpoint = get_db_setting("llm.openai_endpoint.url")
has_key = bool(get_db_setting("llm.openai_endpoint.api_key"))
logger.info(f"OpenAI Endpoint URL: {endpoint}")
logger.info(f"Has API key: {has_key}")
return True
except Exception:
logger.exception("Error updating LLM configuration")
return False
def main():
parser = argparse.ArgumentParser(
description="Update LLM configuration in the database"
)
# Configuration options
parser.add_argument("--model", help="LLM model name")
parser.add_argument(
"--provider",
help="LLM provider (e.g., 'anthropic', 'openai', 'openai_endpoint')",
)
parser.add_argument(
"--endpoint", help="Endpoint URL for OpenRouter or similar services"
)
parser.add_argument("--api-key", help="API key for the provider")
parser.add_argument(
"--temperature", type=float, help="Temperature setting for the LLM"
)
# Reset option
parser.add_argument(
"--reset", action="store_true", help="Reset to default configuration"
)
args = parser.parse_args()
# Check if any argument is provided
if not any(
[
args.model,
args.provider,
args.endpoint,
args.api_key,
args.temperature,
args.reset,
]
):
parser.print_help()
return 1
# Update LLM configuration
success = update_llm_configuration(
model_name=args.model,
provider=args.provider,
endpoint_url=args.endpoint,
api_key=args.api_key,
temperature=args.temperature,
reset=args.reset,
)
return 0 if success else 1
if __name__ == "__main__":
sys.exit(main())