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
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:
@@ -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
@@ -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
@@ -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())
|
||||
Executable
+319
@@ -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()
|
||||
@@ -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
@@ -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
@@ -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()
|
||||
Executable
+202
@@ -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())
|
||||
Reference in New Issue
Block a user