opik-optimizer 0.7.2__tar.gz → 0.7.4__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. {opik_optimizer-0.7.2/src/opik_optimizer.egg-info → opik_optimizer-0.7.4}/PKG-INFO +30 -28
  2. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/README.md +27 -27
  3. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/setup.py +6 -1
  4. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/__init__.py +2 -0
  5. opik_optimizer-0.7.4/src/opik_optimizer/_throttle.py +43 -0
  6. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/base_optimizer.py +1 -80
  7. opik_optimizer-0.7.4/src/opik_optimizer/data/hotpot-500.json +2502 -0
  8. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/demo/datasets.py +15 -32
  9. opik_optimizer-0.7.4/src/opik_optimizer/evolutionary_optimizer/__init__.py +1 -0
  10. opik_optimizer-0.7.4/src/opik_optimizer/evolutionary_optimizer/evolutionary_optimizer.py +1447 -0
  11. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/few_shot_bayesian_optimizer/few_shot_bayesian_optimizer.py +7 -7
  12. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/meta_prompt_optimizer.py +3 -0
  13. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/mipro_optimizer/_lm.py +2 -2
  14. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4/src/opik_optimizer.egg-info}/PKG-INFO +30 -28
  15. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer.egg-info/SOURCES.txt +3 -0
  16. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer.egg-info/requires.txt +2 -0
  17. opik_optimizer-0.7.2/src/opik_optimizer/_throttle.py +0 -43
  18. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/LICENSE +0 -0
  19. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/setup.cfg +0 -0
  20. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/cache_config.py +0 -0
  21. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/demo/__init__.py +0 -0
  22. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/demo/cache.py +0 -0
  23. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/few_shot_bayesian_optimizer/__init__.py +0 -0
  24. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/few_shot_bayesian_optimizer/prompt_parameter.py +0 -0
  25. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/few_shot_bayesian_optimizer/prompt_templates.py +0 -0
  26. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/integrations/__init__.py +0 -0
  27. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/logging_config.py +0 -0
  28. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/mipro_optimizer/__init__.py +0 -0
  29. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/mipro_optimizer/_mipro_optimizer_v2.py +0 -0
  30. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/mipro_optimizer/mipro_optimizer.py +0 -0
  31. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/mipro_optimizer/utils.py +0 -0
  32. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/optimization_config/__init__.py +0 -0
  33. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/optimization_config/configs.py +0 -0
  34. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/optimization_config/mappers.py +0 -0
  35. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/optimization_result.py +0 -0
  36. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/task_evaluator.py +0 -0
  37. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer/utils.py +0 -0
  38. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer.egg-info/dependency_links.txt +0 -0
  39. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/src/opik_optimizer.egg-info/top_level.txt +0 -0
  40. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/tests/test_base_optimizer.py +0 -0
  41. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/tests/test_example.py +0 -0
  42. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/tests/test_few_shot_bayesian_optimizer.py +0 -0
  43. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/tests/test_mappers.py +0 -0
  44. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/tests/test_optimization_dsl.py +0 -0
  45. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/tests/test_optimization_result.py +0 -0
  46. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/tests/test_task_evaluator.py +0 -0
  47. {opik_optimizer-0.7.2 → opik_optimizer-0.7.4}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: opik_optimizer
3
- Version: 0.7.2
3
+ Version: 0.7.4
4
4
  Summary: Agent optimization with Opik
5
5
  Home-page: https://github.com/comet-ml/opik
6
6
  Author: Comet ML
@@ -21,6 +21,8 @@ Requires-Dist: optuna
21
21
  Requires-Dist: pydantic
22
22
  Requires-Dist: pandas
23
23
  Requires-Dist: hf_xet
24
+ Requires-Dist: pyrate-limiter
25
+ Requires-Dist: deap>=1.4.3
24
26
  Provides-Extra: dev
25
27
  Requires-Dist: adalflow; extra == "dev"
26
28
  Requires-Dist: pytest; extra == "dev"
@@ -72,7 +74,7 @@ from your LLMs. You can use a variety of algorithms, including:
72
74
 
73
75
  3. Install the package:
74
76
  ```bash
75
- pip install git+https://github.com/comet-ml/opik#subdirectory=sdks/opik_optimizer
77
+ pip install opik-optimizer
76
78
  ```
77
79
 
78
80
  You'll need:
@@ -94,11 +96,10 @@ You can see how to use those below:
94
96
 
95
97
  ```python
96
98
  from opik.evaluation.metrics import LevenshteinRatio
97
- from opik_optimizer.few_shot_bayesian_optimizer import FewShotBayesianOptimizer
99
+ from opik_optimizer import FewShotBayesianOptimizer
98
100
  from opik_optimizer.demo import get_or_create_dataset
99
101
 
100
102
  from opik_optimizer import (
101
- OptimizationConfig,
102
103
  MetricConfig,
103
104
  TaskConfig,
104
105
  from_dataset_field,
@@ -111,40 +112,41 @@ hot_pot_dataset = get_or_create_dataset("hotpot-300")
111
112
  prompt_instruction = """
112
113
  Answer the question.
113
114
  """
114
-
115
- initial_prompt_no_examples = [
116
- {"role": "system", "content": prompt_instruction},
117
- {"role": "user", "content": "{{question}}"},
118
- ]
115
+ project_name = "optimize-few-shot-bayesian-hotpot"
119
116
 
120
117
  optimizer = FewShotBayesianOptimizer(
121
118
  model="gpt-4o-mini",
122
- project_name="optimize-few-shot-bayesian-hotpot",
119
+ project_name=project_name,
123
120
  min_examples=3,
124
121
  max_examples=8,
125
122
  n_threads=16,
126
123
  seed=42,
127
124
  )
128
125
 
129
- optimization_config = OptimizationConfig(
126
+ metric_config = MetricConfig(
127
+ metric=LevenshteinRatio(project_name=project_name),
128
+ inputs={
129
+ "output": from_llm_response_text(),
130
+ "reference": from_dataset_field(name="answer"),
131
+ },
132
+ )
133
+
134
+ task_config = TaskConfig(
135
+ instruction_prompt=prompt_instruction,
136
+ input_dataset_fields=["question"],
137
+ output_dataset_field="answer",
138
+ use_chat_prompt=True,
139
+ )
140
+
141
+ result = optimizer.optimize_prompt(
130
142
  dataset=hot_pot_dataset,
131
- objective=MetricConfig(
132
- metric=LevenshteinRatio(),
133
- inputs={
134
- "output": from_llm_response_text(),
135
- "reference": from_dataset_field(name="answer"),
136
- },
137
- ),
138
- task=TaskConfig(
139
- instruction_prompt=prompt_instruction,
140
- input_dataset_fields=["question"],
141
- output_dataset_field="answer",
142
- use_chat_prompt=True,
143
- ),
143
+ metric_config=metric_config,
144
+ task_config=task_config,
145
+ n_trials=10,
146
+ n_samples=150,
144
147
  )
145
148
 
146
- result = optimizer.optimize_prompt(optimization_config, n_trials=10)
147
- print(result)
149
+ result.display()
148
150
  ```
149
151
 
150
152
  More examples can be found in the `scripts` folder.
@@ -152,7 +154,7 @@ More examples can be found in the `scripts` folder.
152
154
  ## Installation
153
155
 
154
156
  ```bash
155
- pip install git+https://github.com/comet-ml/opik#subdirectory=sdks/opik_optimizer
157
+ pip install opik-optimizer
156
158
  ```
157
159
 
158
160
  ## Development
@@ -167,6 +169,6 @@ pip install -e .
167
169
 
168
170
  ## Requirements
169
171
 
170
- - Python 3.10+
172
+ - Python 3.10+ < 3.13
171
173
  - Opik API key
172
174
  - OpenAI API key (or other LLM provider)
@@ -33,7 +33,7 @@ from your LLMs. You can use a variety of algorithms, including:
33
33
 
34
34
  3. Install the package:
35
35
  ```bash
36
- pip install git+https://github.com/comet-ml/opik#subdirectory=sdks/opik_optimizer
36
+ pip install opik-optimizer
37
37
  ```
38
38
 
39
39
  You'll need:
@@ -55,11 +55,10 @@ You can see how to use those below:
55
55
 
56
56
  ```python
57
57
  from opik.evaluation.metrics import LevenshteinRatio
58
- from opik_optimizer.few_shot_bayesian_optimizer import FewShotBayesianOptimizer
58
+ from opik_optimizer import FewShotBayesianOptimizer
59
59
  from opik_optimizer.demo import get_or_create_dataset
60
60
 
61
61
  from opik_optimizer import (
62
- OptimizationConfig,
63
62
  MetricConfig,
64
63
  TaskConfig,
65
64
  from_dataset_field,
@@ -72,40 +71,41 @@ hot_pot_dataset = get_or_create_dataset("hotpot-300")
72
71
  prompt_instruction = """
73
72
  Answer the question.
74
73
  """
75
-
76
- initial_prompt_no_examples = [
77
- {"role": "system", "content": prompt_instruction},
78
- {"role": "user", "content": "{{question}}"},
79
- ]
74
+ project_name = "optimize-few-shot-bayesian-hotpot"
80
75
 
81
76
  optimizer = FewShotBayesianOptimizer(
82
77
  model="gpt-4o-mini",
83
- project_name="optimize-few-shot-bayesian-hotpot",
78
+ project_name=project_name,
84
79
  min_examples=3,
85
80
  max_examples=8,
86
81
  n_threads=16,
87
82
  seed=42,
88
83
  )
89
84
 
90
- optimization_config = OptimizationConfig(
85
+ metric_config = MetricConfig(
86
+ metric=LevenshteinRatio(project_name=project_name),
87
+ inputs={
88
+ "output": from_llm_response_text(),
89
+ "reference": from_dataset_field(name="answer"),
90
+ },
91
+ )
92
+
93
+ task_config = TaskConfig(
94
+ instruction_prompt=prompt_instruction,
95
+ input_dataset_fields=["question"],
96
+ output_dataset_field="answer",
97
+ use_chat_prompt=True,
98
+ )
99
+
100
+ result = optimizer.optimize_prompt(
91
101
  dataset=hot_pot_dataset,
92
- objective=MetricConfig(
93
- metric=LevenshteinRatio(),
94
- inputs={
95
- "output": from_llm_response_text(),
96
- "reference": from_dataset_field(name="answer"),
97
- },
98
- ),
99
- task=TaskConfig(
100
- instruction_prompt=prompt_instruction,
101
- input_dataset_fields=["question"],
102
- output_dataset_field="answer",
103
- use_chat_prompt=True,
104
- ),
102
+ metric_config=metric_config,
103
+ task_config=task_config,
104
+ n_trials=10,
105
+ n_samples=150,
105
106
  )
106
107
 
107
- result = optimizer.optimize_prompt(optimization_config, n_trials=10)
108
- print(result)
108
+ result.display()
109
109
  ```
110
110
 
111
111
  More examples can be found in the `scripts` folder.
@@ -113,7 +113,7 @@ More examples can be found in the `scripts` folder.
113
113
  ## Installation
114
114
 
115
115
  ```bash
116
- pip install git+https://github.com/comet-ml/opik#subdirectory=sdks/opik_optimizer
116
+ pip install opik-optimizer
117
117
  ```
118
118
 
119
119
  ## Development
@@ -128,6 +128,6 @@ pip install -e .
128
128
 
129
129
  ## Requirements
130
130
 
131
- - Python 3.10+
131
+ - Python 3.10+ < 3.13
132
132
  - Opik API key
133
133
  - OpenAI API key (or other LLM provider)
@@ -2,7 +2,7 @@ from setuptools import setup, find_packages
2
2
 
3
3
  setup(
4
4
  name="opik_optimizer",
5
- version="0.7.2",
5
+ version="0.7.4",
6
6
  description="Agent optimization with Opik",
7
7
  author="Comet ML",
8
8
  author_email="support@comet.com",
@@ -11,6 +11,9 @@ setup(
11
11
  url="https://github.com/comet-ml/opik",
12
12
  packages=find_packages(where="src"),
13
13
  package_dir={"": "src"},
14
+ package_data={
15
+ 'opik_optimizer': ['data/*.json'],
16
+ },
14
17
  python_requires=">=3.9,<3.13",
15
18
  install_requires=[
16
19
  "opik>=1.7.17",
@@ -22,6 +25,8 @@ setup(
22
25
  "pydantic",
23
26
  "pandas",
24
27
  "hf_xet",
28
+ "pyrate-limiter",
29
+ "deap>=1.4.3",
25
30
  ],
26
31
  # dev requirements
27
32
  extras_require={
@@ -27,12 +27,14 @@ from opik.evaluation.models.litellm import warning_filters
27
27
  warning_filters.add_warning_filters()
28
28
 
29
29
  from .optimization_result import OptimizationResult
30
+ from opik_optimizer.evolutionary_optimizer.evolutionary_optimizer import EvolutionaryOptimizer
30
31
 
31
32
  __all__ = [
32
33
  "BaseOptimizer",
33
34
  "FewShotBayesianOptimizer",
34
35
  "MetaPromptOptimizer",
35
36
  "MiproOptimizer",
37
+ "EvolutionaryOptimizer",
36
38
  "MetricConfig",
37
39
  "OptimizationConfig",
38
40
  "TaskConfig",
@@ -0,0 +1,43 @@
1
+ import functools
2
+ import pyrate_limiter
3
+ import time
4
+ import opik.config
5
+
6
+ from typing import Callable, Any
7
+
8
+
9
+ class RateLimiter:
10
+ """
11
+ Rate limiter that enforces a maximum number of calls across all threads using pyrate_limiter.
12
+ """
13
+ def __init__(self, max_calls_per_second: int):
14
+ self.max_calls_per_second = max_calls_per_second
15
+ rate = pyrate_limiter.Rate(max_calls_per_second, pyrate_limiter.Duration.SECOND)
16
+
17
+ self.limiter = pyrate_limiter.Limiter(rate, raise_when_fail=False)
18
+ self.bucket_key = "global_rate_limit"
19
+
20
+ def acquire(self) -> None:
21
+ while not self.limiter.try_acquire(self.bucket_key):
22
+ time.sleep(0.01)
23
+
24
+ def rate_limited(limiter: RateLimiter) -> Callable[[Callable], Callable]:
25
+ """Decorator to rate limit a function using the provided limiter"""
26
+
27
+ def decorator(func: Callable) -> Callable:
28
+ @functools.wraps(func)
29
+ def wrapper(*args, **kwargs) -> Any:
30
+ limiter.acquire()
31
+ return func(*args, **kwargs)
32
+ return wrapper
33
+ return decorator
34
+
35
+
36
+ def get_rate_limiter_for_current_opik_installation() -> RateLimiter:
37
+ opik_config = opik.config.OpikConfig()
38
+ max_calls_per_second = (
39
+ 10
40
+ if opik_config.is_cloud_installation
41
+ else 50
42
+ )
43
+ return RateLimiter(max_calls_per_second=max_calls_per_second)
@@ -12,7 +12,7 @@ from .cache_config import initialize_cache
12
12
  from opik.evaluation.models.litellm import opik_monitor as opik_litellm_monitor
13
13
  from .optimization_config.configs import TaskConfig, MetricConfig
14
14
 
15
- limiter = RateLimiter(max_calls_per_second=15)
15
+ limiter = RateLimiter(max_calls_per_second=8)
16
16
 
17
17
  # Don't use unsupported params:
18
18
  litellm.drop_params = True
@@ -141,85 +141,6 @@ class BaseOptimizer:
141
141
  """
142
142
  self._history.append(round_data)
143
143
 
144
- @rate_limited(limiter)
145
- def _call_model(
146
- self,
147
- prompt: str,
148
- system_prompt: Optional[str] = None,
149
- is_reasoning: bool = False,
150
- ) -> str:
151
- """Call the model to get suggestions based on the meta-prompt."""
152
- model = self.reasoning_model if is_reasoning else self.model
153
- messages = []
154
-
155
- if system_prompt:
156
- messages.append({"role": "system", "content": system_prompt})
157
- logger.debug(f"Using custom system prompt: {system_prompt[:100]}...")
158
- else:
159
- messages.append(
160
- {"role": "system", "content": "You are a helpful assistant."}
161
- )
162
-
163
- messages.append({"role": "user", "content": prompt})
164
- logger.debug(f"Calling model {model} with prompt: {prompt[:100]}...")
165
-
166
- api_params = self.model_kwargs.copy()
167
- api_params.update(
168
- {
169
- "model": model,
170
- "messages": messages,
171
- # Ensure required params like 'temperature', 'max_tokens' are present
172
- # Defaults added here for safety, though usually set in __init__ kwargs
173
- "temperature": api_params.get("temperature", 0.3),
174
- "max_tokens": api_params.get("max_tokens", 1000),
175
- }
176
- )
177
-
178
- # Attempt to add Opik monitoring if available
179
- try:
180
- # Assuming opik_litellm_monitor is imported and configured elsewhere
181
- api_params = opik_litellm_monitor.try_add_opik_monitoring_to_params(
182
- api_params
183
- )
184
- logger.debug("Opik monitoring hooks added to LiteLLM params.")
185
- except Exception as e:
186
- logger.warning(f"Could not add Opik monitoring to LiteLLM params: {e}")
187
-
188
- logger.debug(
189
- f"Final API params (excluding messages): { {k:v for k,v in api_params.items() if k != 'messages'} }"
190
- )
191
-
192
- # Increment Counter
193
- self.llm_call_counter += 1
194
- logger.debug(f"LLM Call Count: {self.llm_call_counter}")
195
-
196
- try:
197
- response = litellm.completion(**api_params)
198
- model_output = response.choices[0].message.content.strip()
199
- logger.debug(f"Model response from {model_to_use}: {model_output[:100]}...")
200
- return model_output
201
- except litellm.exceptions.RateLimitError as e:
202
- logger.error(f"LiteLLM Rate Limit Error for model {model_to_use}: {e}")
203
- # Consider adding retry logic here with tenacity
204
- raise
205
- except litellm.exceptions.APIConnectionError as e:
206
- logger.error(f"LiteLLM API Connection Error for model {model_to_use}: {e}")
207
- # Consider adding retry logic here
208
- raise
209
- except litellm.exceptions.ContextWindowExceededError as e:
210
- logger.error(
211
- f"LiteLLM Context Window Exceeded Error for model {model_to_use}. Prompt length: {len(prompt)}. Details: {e}"
212
- )
213
- raise
214
- except litellm.exceptions.APIError as e: # Catch broader API errors
215
- logger.error(f"LiteLLM API Error for model {model_to_use}: {e}")
216
- raise
217
- except Exception as e:
218
- # Catch any other unexpected errors
219
- logger.error(
220
- f"Unexpected error during model call to {model_to_use}: {type(e).__name__} - {e}"
221
- )
222
- raise
223
144
 
224
145
  def update_optimization(self, optimization, status: str) -> None:
225
146
  """