1
1
import dspy
2
+ import mlflow .dspy
2
3
from pandas import DataFrame
3
- from typing import Callable , Dict , Optional , List , Tuple , Type
4
+ from typing import Callable , Dict , Optional , List , Tuple , Type , Any , Union
4
5
5
6
from dspy .teleprompt import Teleprompter
6
7
from dspy .teleprompt .mipro_optimizer_v2 import MIPROv2
7
8
from dspy .teleprompt .bootstrap import BootstrapFewShot
8
9
from dspy import Signature , Module
9
10
10
-
11
11
from fmcore .experimental .metrics .base_metric import BaseMetric
12
12
from fmcore .experimental .prompt_tuner .base_prompt_tuner import BasePromptTuner
13
13
from fmcore .experimental .types .enums .prompt_tuner_enums import PromptTunerFramework
16
16
from fmcore .experimental .adapters .dspy_adapter import DSPyLLMAdapter
17
17
from fmcore .experimental .utils .introspection_utils import IntrospectionUtils
18
18
from fmcore .experimental .prompt_tuner .utils .dspy_utils import DSPyUtils
19
- from py_expression_eval import Parser
20
19
from asteval import Interpreter
21
20
22
21
23
-
24
-
25
22
class DSPyPromptTuner (BasePromptTuner ):
23
+ """
24
+ A prompt tuner implementation using the DSPy framework.
25
+
26
+ This class provides functionality to optimize prompts using various DSPy optimizers
27
+ such as MIPROv2 or BootstrapFewShot. It uses a student model for generating responses
28
+ and evaluates them using a configured metric to iteratively improve the prompt.
29
+
30
+ Attributes:
31
+ aliases (List[PromptTunerFramework]): Framework identifiers for this tuner.
32
+ student (dspy.LM): The student language model used for prompt optimization.
33
+ teacher (Optional[dspy.LM]): The teacher language model used in some optimization techniques.
34
+ optimizer_metric (BaseMetric): The metric used to evaluate prompt performance.
35
+ """
36
+
26
37
aliases = [PromptTunerFramework .DSPY ]
27
38
student : dspy .LM
28
39
teacher : Optional [dspy .LM ]
29
40
optimizer_metric : BaseMetric
30
41
31
42
@classmethod
32
- def _get_constructor_parameters (cls , * , config : PromptTunerConfig ) -> Dict :
43
+ def _get_constructor_parameters (cls , * , config : PromptTunerConfig ) -> Dict [str , Any ]:
44
+ """
45
+ Creates and configures the necessary components for DSPy prompt tuning.
46
+
47
+ Args:
48
+ config: Configuration containing all necessary parameters for the prompt tuner.
49
+ Must include student model config and optionally teacher model config.
50
+
51
+ Returns:
52
+ Dictionary of parameters needed to initialize the DSPyPromptTuner instance.
53
+ """
54
+ # Initialize student model and configure DSPy to use it
33
55
student_model = DSPyLLMAdapter (llm_config = config .optimzer_config .student_config )
34
56
dspy .configure (lm = student_model )
35
57
58
+ # Initialize teacher model (or use student if not specified)
36
59
if config .optimzer_config .teacher_config :
37
60
teacher_model = DSPyLLMAdapter (llm_config = config .optimzer_config .teacher_config )
38
61
else :
39
62
teacher_model = student_model
63
+
64
+ # Initialize metric for optimization
40
65
optimizer_metric = BaseMetric .of (metric_config = config .optimzer_config .metric_config )
41
66
42
67
return {
@@ -46,19 +71,33 @@ def _get_constructor_parameters(cls, *, config: PromptTunerConfig) -> Dict:
46
71
"config" : config ,
47
72
}
48
73
49
- def _create_evaluation_function (self ):
74
+ def _create_evaluation_function (self ) -> Callable :
50
75
"""
51
76
Creates an evaluation function that uses the configured metric.
52
-
77
+
78
+ The function evaluates DSPy predictions by applying the metric and interpreting
79
+ the criteria expression to determine the quality of the prediction.
80
+
53
81
Returns:
54
- Evaluation function that takes an example and prediction
82
+ A callable function that takes an example and prediction and returns a
83
+ numerical or boolean evaluation score.
55
84
"""
56
-
57
85
# Store criteria once to avoid re-fetching it in each evaluation call
58
86
criteria = self .optimizer_metric .config .metric_params ["criteria" ]
59
87
60
- def evaluate_func (example : dspy .Example , prediction : dspy .Prediction , trace = None ):
61
- # Get evaluation results
88
+ def evaluate_func (example : dspy .Example , prediction : dspy .Prediction , trace = None ) -> Union [float , bool ]:
89
+ """
90
+ Evaluates a single example-prediction pair using the configured metric.
91
+
92
+ Args:
93
+ example: The DSPy example containing input data
94
+ prediction: The model's prediction to evaluate
95
+ trace: Optional trace information from DSPy (not used)
96
+
97
+ Returns:
98
+ Evaluation score as determined by the configured criteria
99
+ """
100
+ # Get evaluation results from the metric
62
101
evaluation_response : dict = DSPyUtils .evaluate (
63
102
example = example ,
64
103
prediction = prediction ,
@@ -72,23 +111,33 @@ def evaluate_func(example: dspy.Example, prediction: dspy.Prediction, trace=None
72
111
73
112
return evaluate_func
74
113
75
-
76
-
77
114
def tune (self , data : DataFrame ) -> str :
78
115
"""
79
- Tunes a prompt using the configured DSPy optimizer.
80
-
116
+ Tunes a prompt using the configured DSPy optimizer and training data.
117
+
118
+ This method:
119
+ 1. Converts the input data to DSPy examples
120
+ 2. Creates a DSPy signature and module based on the prompt configuration
121
+ 3. Configures an evaluation function using the specified metric
122
+ 4. Applies the DSPy optimizer to generate an optimized prompt
123
+
81
124
Args:
82
- data: DataFrame containing the training data
83
- prompt_config: Configuration containing input and output fields
84
-
125
+ data: DataFrame containing the training data with input and expected output fields
126
+
85
127
Returns:
86
128
The optimized prompt as a string
129
+
130
+ Raises:
131
+ ValueError: If the optimization process fails or returns invalid results
87
132
"""
88
133
134
+ import mlflow
135
+ mlflow .dspy .autolog (log_traces = True , log_traces_from_compile = True , log_traces_from_eval = True , disable = False , silent = False )
136
+
89
137
# Convert data to DSPy examples
90
138
dspy_examples = DSPyUtils .convert_to_dspy_examples (
91
- data = data , prompt_config = self .config .prompt_config
139
+ data = data ,
140
+ prompt_config = self .config .prompt_config
92
141
)
93
142
94
143
# Create signature and module separately
@@ -108,13 +157,20 @@ def tune(self, data: DataFrame) -> str:
108
157
evaluate_func = evaluate_func ,
109
158
)
110
159
160
+ # Filter optimizer parameters to only include those accepted by the compile method
111
161
filtered_optimizer_params = IntrospectionUtils .filter_params (
112
- func = optimizer .compile , params = self .config .optimzer_config .params
162
+ func = optimizer .compile ,
163
+ params = self .config .optimzer_config .params
113
164
)
165
+
114
166
# Compile the module with the optimizer
115
167
optimized_module = optimizer .compile (
116
168
student = module ,
117
169
trainset = dspy_examples ,
118
170
requires_permission_to_run = False ,
119
171
** filtered_optimizer_params ,
120
172
)
173
+
174
+ dspy .inspect_history (optimized_module )
175
+
176
+ optimized_module .signature .prompt
0 commit comments