From 189f858a0524b6ea2852d268175f8976a7f82fc1 Mon Sep 17 00:00:00 2001 From: Thomas D Ahle Date: Thu, 7 Mar 2024 14:24:16 -0800 Subject: [PATCH] Fixed multi-module typed signature optimizer --- dspy/functional/functional.py | 3 + dspy/primitives/module.py | 74 +- dspy/teleprompt/signature_opt_typed.py | 4 +- examples/functional/signature_opt_typed.ipynb | 861 +++++------------- intro.ipynb | 125 ++- tests/functional/test_functional.py | 4 +- tests/primitives/test_program.py | 87 +- 7 files changed, 401 insertions(+), 757 deletions(-) diff --git a/dspy/functional/functional.py b/dspy/functional/functional.py index 44f9f5a5d..d24dd4d9d 100644 --- a/dspy/functional/functional.py +++ b/dspy/functional/functional.py @@ -82,6 +82,9 @@ def __init__(self, signature, max_retries=3): def copy(self) -> "TypedPredictor": return TypedPredictor(self.signature, self.max_retries) + def __repr__(self): + return f"TypedPredictor({self.signature})" + @staticmethod def _make_example(type_) -> str: # Note: DSPy will cache this call so we only pay the first time TypedPredictor is called. diff --git a/dspy/primitives/module.py b/dspy/primitives/module.py index 90908e5c3..33690c924 100644 --- a/dspy/primitives/module.py +++ b/dspy/primitives/module.py @@ -1,4 +1,5 @@ import copy +from collections import deque from collections.abc import Generator import ujson @@ -9,45 +10,48 @@ def __init__(self): pass def named_parameters(self): - """ - Unlike PyTorch, handles (non-recursive) lists of parameters too. - """ - + """Unlike PyTorch, handles lists of parameters too.""" from dspy.predict.parameter import Parameter - visited = set() - named_parameters = [] - - def add_parameter(param_name, param_value): - if isinstance(param_value, Parameter) and id(param_value) not in visited: - visited.add(id(param_value)) - named_parameters.append((param_name, param_value)) - - for name, value in self.__dict__.items(): - if isinstance(value, Parameter): - add_parameter(name, value) + # Remove the 'self.' prefix from the names + return [(name[5:], param) for name, param in self.named_sub_modules(Parameter)] - elif isinstance(value, BaseModule): - # When a sub-module is pre-compiled, keep it frozen. - if not getattr(value, "_compiled", False): - for sub_name, param in value.named_parameters(): - add_parameter(f"{name}.{sub_name}", param) + def named_sub_modules(self, type_=None, skip_compiled=False) -> Generator[tuple[str, "BaseModule"], None, None]: + """Find all sub-modules in the module, as well as their names. - elif isinstance(value, (list, tuple)): - for idx, item in enumerate(value): - add_parameter(f"{name}[{idx}]", item) - - elif isinstance(value, dict): - for key, item in value.items(): - add_parameter(f"{name}['{key}']", item) - - return named_parameters - - def named_sub_modules(self, root_name="base") -> Generator[tuple[str, "BaseModule"], None, None]: - yield root_name, self - for name, value in self.__dict__.items(): - if isinstance(value, BaseModule): - yield from value.named_sub_modules(root_name=f"{root_name}.{name}") + Say self.children[4]['key'].sub_module is a sub-module. Then the name will be + 'children[4][key].sub_module'. But if the sub-module is accessible at different + paths, only one of the paths will be returned. + """ + if type_ is None: + type_ = BaseModule + + queue = deque([("self", self)]) + seen = {id(self)} + + def add_to_queue(name, item): + if id(item) not in seen: + seen.add(id(item)) + queue.append((name, item)) + + while queue: + name, item = queue.popleft() + if isinstance(item, type_): + yield name, item + + if isinstance(item, BaseModule): + if skip_compiled and getattr(item, "_compiled", False): + continue + for sub_name, sub_item in item.__dict__.items(): + add_to_queue(f"{name}.{sub_name}", sub_item) + + elif isinstance(item, (list, tuple)): + for i, sub_item in enumerate(item): + add_to_queue(f"{name}[{i}]", sub_item) + + elif isinstance(item, dict): + for key, sub_item in item.items(): + add_to_queue(f"{name}[{key}]", sub_item) def parameters(self): return [param for _, param in self.named_parameters()] diff --git a/dspy/teleprompt/signature_opt_typed.py b/dspy/teleprompt/signature_opt_typed.py index c86d297c1..37ae27396 100644 --- a/dspy/teleprompt/signature_opt_typed.py +++ b/dspy/teleprompt/signature_opt_typed.py @@ -272,6 +272,8 @@ def optimize_signature( pass elif strategy == "best": i = scores.index(max(scores)) + if verbose: + print(f"Best signature: {i} with score: {scores[i]}") for name, p in named_predictors: p.signature = candidates[name][i].to_signature() else: @@ -279,6 +281,6 @@ def optimize_signature( return OptimizerResult( program=module, - signatures=[{name: sigs[i].to_signature()} for name, sigs in candidates.items() for i in range(n_iterations)], + signatures=[{name: sigs[i].to_signature() for name, sigs in candidates.items()} for i in range(n_iterations)], scores=scores, ) diff --git a/examples/functional/signature_opt_typed.ipynb b/examples/functional/signature_opt_typed.ipynb index feab8d635..81bdbe77a 100644 --- a/examples/functional/signature_opt_typed.ipynb +++ b/examples/functional/signature_opt_typed.ipynb @@ -92,648 +92,23 @@ "execution_count": 5, "metadata": {}, "outputs": [], - "source": [ - "class BasicQA(dspy.Signature):\n", - " \"\"\"Answer questions with short factoid answers.\"\"\"\n", - "\n", - " question = dspy.InputField()\n", - " answer = dspy.OutputField(desc=\"often between 1 and 5 words\")" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "metadata": {}, - "outputs": [ - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Found 1 typed predictors to optimize.\n", - "Generating 6 initial signatures for base...\n", - "\n", - "================================================================================\n", - "Running eval iteration 0...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0): 100%|██████████| 50/50 [00:00<00:00, 3086.59it/s]\n", - "/Users/ahle/repos/dspy/dspy/evaluate/evaluate.py:145: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.\n", - " df = df.applymap(truncate_cell)\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0%)\n", - "\n", - "================================================================================\n", - "Running eval iteration 1...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 1 / 50 (2.0): 100%|██████████| 50/50 [00:00<00:00, 1268.65it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 1 / 50 (2.0%)\n", - "\n", - "================================================================================\n", - "Running eval iteration 2...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0): 100%|██████████| 50/50 [00:00<00:00, 1031.35it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0%)\n", - "\n", - "================================================================================\n", - "Running eval iteration 3...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0): 100%|██████████| 50/50 [00:00<00:00, 1364.88it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0%)\n", - "\n", - "================================================================================\n", - "Running eval iteration 4...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 6 / 50 (12.0): 100%|██████████| 50/50 [00:00<00:00, 892.68it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 6 / 50 (12.0%)\n", - "\n", - "================================================================================\n", - "Running eval iteration 5...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 5 / 50 (10.0): 100%|██████████| 50/50 [00:00<00:00, 1055.56it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 5 / 50 (10.0%)\n", - "\n", - "================================================================================\n", - "Running eval iteration 6...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 12 / 50 (24.0): 100%|██████████| 50/50 [00:00<00:00, 942.15it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 12 / 50 (24.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 7 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 7...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0): 100%|██████████| 50/50 [00:00<00:00, 1054.12it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 8 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 8...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0): 100%|██████████| 50/50 [00:00<00:00, 957.29it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 9 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 9...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 12 / 50 (24.0): 100%|██████████| 50/50 [00:00<00:00, 1015.95it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 12 / 50 (24.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 10 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 10...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 11 / 50 (22.0): 100%|██████████| 50/50 [00:00<00:00, 839.64it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 11 / 50 (22.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 11 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 11...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 15 / 50 (30.0): 100%|██████████| 50/50 [00:00<00:00, 833.32it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 15 / 50 (30.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 12 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 12...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 15 / 50 (30.0): 100%|██████████| 50/50 [00:00<00:00, 1105.97it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 15 / 50 (30.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 13 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 13...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0): 100%|██████████| 50/50 [00:00<00:00, 1112.59it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 14 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 14...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0): 100%|██████████| 50/50 [00:00<00:00, 1096.58it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 15 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 15...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0): 100%|██████████| 50/50 [00:00<00:00, 1092.70it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 16 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 16...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0): 100%|██████████| 50/50 [00:00<00:00, 1097.79it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 17 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 17...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0): 100%|██████████| 50/50 [00:00<00:00, 547.69it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 18 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 18...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0): 100%|██████████| 50/50 [00:00<00:00, 964.67it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 19 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 19...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 19 / 50 (38.0): 100%|██████████| 50/50 [00:00<00:00, 1014.22it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 19 / 50 (38.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 20 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 20...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0): 100%|██████████| 50/50 [00:00<00:00, 906.14it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 21 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 21...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0): 100%|██████████| 50/50 [00:00<00:00, 1017.81it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 22 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 22...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 19 / 50 (38.0): 100%|██████████| 50/50 [00:00<00:00, 1032.48it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 19 / 50 (38.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 23 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 23...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 15 / 50 (30.0): 100%|██████████| 50/50 [00:00<00:00, 726.33it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 15 / 50 (30.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 24 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 24...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 15 / 50 (30.0): 100%|██████████| 50/50 [00:00<00:00, 957.55it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 15 / 50 (30.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 25 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 25...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0): 100%|██████████| 50/50 [00:00<00:00, 1009.53it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 26 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 26...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 15 / 50 (30.0): 100%|██████████| 50/50 [00:00<00:00, 1064.53it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 15 / 50 (30.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 27 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 27...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 18 / 50 (36.0): 100%|██████████| 50/50 [00:00<00:00, 1052.90it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 18 / 50 (36.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 28 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 28...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 20 / 50 (40.0): 100%|██████████| 50/50 [00:00<00:00, 731.18it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 20 / 50 (40.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 29 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 29...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0): 100%|██████████| 50/50 [00:02<00:00, 18.61it/s]\n", - "/Users/ahle/repos/dspy/dspy/evaluate/evaluate.py:145: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.\n", - " df = df.applymap(truncate_cell)\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 16 / 50 (32.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 30 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 30...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0): 100%|██████████| 50/50 [00:02<00:00, 18.23it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 50 (34.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 31 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 31...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 19 / 50 (38.0): 100%|██████████| 50/50 [00:02<00:00, 20.82it/s]\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "Average Metric: 19 / 50 (38.0%)\n", - "Generating new signature for base...\n", - "Tested the signature, and it's not in the list of 32 to avoid.\n", - "\n", - "================================================================================\n", - "Running eval iteration 32...\n" - ] - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "Average Metric: 17 / 49 (34.7): 98%|█████████▊| 49/50 [00:14<00:00, 20.66it/s]" - ] - } - ], "source": [ "from dspy.evaluate import Evaluate\n", "from dspy.evaluate.metrics import answer_exact_match\n", - "from dspy.functional import TypedPredictor\n", + "from dspy.functional import TypedPredictor, TypedChainOfThought\n", "from dspy.teleprompt.signature_opt_typed import optimize_signature\n", "\n", - "evaluator = Evaluate(devset=devset, metric=answer_exact_match, num_threads=10, display_progress=True)\n", - "\n", + "evaluator = Evaluate(devset=devset, metric=answer_exact_match, num_threads=10, display_progress=True)\n" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "metadata": {}, + "outputs": [], + "source": [ "result = optimize_signature(\n", - " student=TypedPredictor(BasicQA),\n", + " student=TypedChainOfThought(\"question -> answer\"),\n", " evaluator=evaluator,\n", " initial_prompts=6,\n", " n_iterations=100,\n", @@ -754,22 +129,7 @@ "cell_type": "code", "execution_count": null, "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "predictor = Predict(BasicQA(question -> answer\n", - " instructions='Answer questions with short factoid answers.'\n", - " question = Field(annotation=str required=True json_schema_extra={'__dspy_field_type': 'input', 'prefix': 'Question:', 'desc': '${question}'})\n", - " answer = Field(annotation=str required=True json_schema_extra={'desc': 'often between 1 and 5 words', '__dspy_field_type': 'output', 'prefix': 'Answer:'})\n", - "))" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "result.program" ] @@ -789,16 +149,16 @@ { "data": { "text/plain": [ - "[]" + "[]" ] }, - "execution_count": 10, + "execution_count": 12, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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", + "image/png": "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Dg7iE5/4BGZmZhpfnNoB3H///WoikVC/9a1vqS+++KL6yU9+Uh0cHFSPHz/e6qW1Nddee616zz33qC+88IK6d+9e9frrr1eXL1+uzszMaI+55ZZb1LGxMXXbtm3q7t271be97W3q29/+9hauuv156qmn1JUrV6qrV69WP/3pT2u381j7w8TEhLpixQr1Yx/7mLpr1y71tddeUx955BH11Vdf1R5z5513qgMDA+qDDz6oPvvss+pv/dZvqatWrVLn5+dbuPL244477lBHRkbUhx56SD1w4ID6/e9/X+3t7VW/9rWvaY/hsa6fH//4x+qf/dmfqT/4wQ9UAOoDDzxguN/Nsb3uuuvUyy67TN25c6f6n//5n+q5556r3nTTTQ2vrSPEx5VXXqlu2rRJu14sFtUlS5aoW7dubeGqzjxOnDihAlC3b9+uqqqqTk5OqvF4XP3+97+vPebll19WAag7duxo1TLbmunpafW8885TH330UfVd73qXJj54rP3js5/9rPqOd7zD9v5SqaSOjo6qf//3f6/dNjk5qSaTSfW73/1uEEs8Y/jN3/xN9b//9/9uuO1DH/qQevPNN6uqymPtJ2bx4ebYvvTSSyoA9emnn9Ye85Of/ERVFEU9cuRIQ+s549MuuVwOe/bswfr167XbIpEI1q9fjx07drRwZWceU1NTAIDh4WEAwJ49e5DP5w3H/sILL8Ty5ct57Otk06ZN+M3f/E3DMQV4rP3k3//933H55Zfjt3/7t7Fw4UK85S1vwT//8z9r9x84cADj4+OGYz0wMIC1a9fyWHvk7W9/O7Zt24Zf/epXAIBnn30WTz75JDZs2ACAx7qZuDm2O3bswODgIC6//HLtMevXr0ckEsGuXbsaev3QDZbzm5MnT6JYLGLRokWG2xctWoRf/vKXLVrVmUepVMJtt92Gq666CpdccgkAYHx8HIlEAoODg4bHLlq0COPj4y1YZXtz//334xe/+AWefvrpqvt4rP3jtddew913343NmzfjT//0T/H000/jj/7oj5BIJLBx40bteFp9p/BYe+Nzn/sc0uk0LrzwQkSjURSLRdxxxx24+eabAYDHuom4Obbj4+NYuHCh4f5YLIbh4eGGj/8ZLz5IMGzatAkvvPACnnzyyVYv5Yzk0KFD+PSnP41HH30UqVSq1cs5oymVSrj88svxt3/7twCAt7zlLXjhhRfwjW98Axs3bmzx6s4svve97+E73/kO7rvvPlx88cXYu3cvbrvtNixZsoTH+gznjE+7LFiwANFotMr1f/z4cYyOjrZoVWcWt956Kx566CH87Gc/w7Jly7TbR0dHkcvlMDk5aXg8j7139uzZgxMnTuCtb30rYrEYYrEYtm/fjn/4h39ALBbDokWLeKx9YvHixbjooosMt73pTW/CwYMHAUA7nvxOaZw/+ZM/wec+9zl85CMfwaWXXorf+73fw+23346tW7cC4LFuJm6O7ejoKE6cOGG4v1AoYGJiouHjf8aLj0QigTVr1mDbtm3abaVSCdu2bcO6detauLL2R1VV3HrrrXjggQfw2GOPYdWqVYb716xZg3g8bjj2+/btw8GDB3nsPXLNNdfg+eefx969e7XL5Zdfjptvvln7mcfaH6666qqqkvFf/epXWLFiBQBg1apVGB0dNRzrdDqNXbt28Vh7ZG5uDpGIcRuKRqMolUoAeKybiZtju27dOkxOTmLPnj3aYx577DGUSiWsXbu2sQU0ZFdtE+6//341mUyq9957r/rSSy+pn/rUp9TBwUF1fHy81Utra37/939fHRgYUB9//HH12LFj2mVubk57zC233KIuX75cfeyxx9Tdu3er69atU9etW9fCVZ85yNUuqspj7RdPPfWUGovF1DvuuEN95ZVX1O985ztqd3e3+i//8i/aY+688051cHBQ/eEPf6g+99xz6vvf/36Wf9bBxo0b1aVLl2qltj/4wQ/UBQsWqJ/5zGe0x/BY18/09LT6zDPPqM8884wKQP3yl7+sPvPMM+qvf/1rVVXdHdvrrrtOfctb3qLu2rVLffLJJ9XzzjuPpbZe+Md//Ed1+fLlaiKRUK+88kp1586drV5S2wPA8nLPPfdoj5mfn1f/4A/+QB0aGlK7u7vVD37wg+qxY8dat+gzCLP44LH2jx/96EfqJZdcoiaTSfXCCy9U/+mf/slwf6lUUj//+c+rixYtUpPJpHrNNdeo+/bta9Fq25d0Oq1++tOfVpcvX66mUin17LPPVv/sz/5MzWaz2mN4rOvnZz/7meV39MaNG1VVdXdsT506pd50001qb2+v2t/fr3784x9Xp6enG16boqpSKzlCCCGEkCZzxns+CCGEEBIuKD4IIYQQEigUH4QQQggJFIoPQgghhAQKxQchhBBCAoXigxBCCCGBQvFBCCGEkECh+CCEEEJIoFB8EEIIISRQKD4IIYQQEigUH4QQQggJFIoPQgghhATK/w8hySi9aKQFlAAAAABJRU5ErkJggg==", "text/plain": [ "
" ] @@ -1007,6 +367,197 @@ "source": [ "gpt4.inspect_history(n=1)" ] + }, + { + "cell_type": "markdown", + "metadata": {}, + "source": [ + "# Multi-hop\n", + "Let's try a multi-hop example" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "metadata": {}, + "outputs": [], + "source": [ + "colbertv2_wiki17_abstracts = dspy.ColBERTv2(url='http://20.102.90.50:2017/wiki17_abstracts')\n", + "dspy.settings.configure(rm=colbertv2_wiki17_abstracts)\n", + "\n", + "class GenerateSearchQuery(dspy.Signature):\n", + " \"\"\"Write a simple search query that will help answer a complex question.\"\"\"\n", + "\n", + " context:list[str] = dspy.InputField(desc=\"may contain relevant facts\")\n", + " question = dspy.InputField()\n", + " query = dspy.OutputField()\n", + "\n", + "class GenerateAnswer(dspy.Signature):\n", + " \"\"\"Answer questions with short factoid answers.\"\"\"\n", + "\n", + " context:list[str] = dspy.InputField(desc=\"may contain relevant facts\")\n", + " question = dspy.InputField()\n", + " answer = dspy.OutputField(desc=\"often between 1 and 5 words\")\n", + "\n", + "from dsp.utils import deduplicate\n", + "\n", + "class SimplifiedBaleen(dspy.Module):\n", + " def __init__(self, passages_per_hop=3, max_hops=2):\n", + " super().__init__()\n", + "\n", + " self.generate_query = [dspy.TypedChainOfThought(GenerateSearchQuery) for _ in range(max_hops)]\n", + " self.retrieve = dspy.Retrieve(k=passages_per_hop)\n", + " self.generate_answer = dspy.TypedChainOfThought(GenerateAnswer)\n", + " self.max_hops = max_hops\n", + " \n", + " def forward(self, question):\n", + " context = []\n", + " \n", + " for hop in range(self.max_hops):\n", + " query = self.generate_query[hop](context=context, question=question).query\n", + " passages = self.retrieve(query).passages\n", + " context = deduplicate(context + passages)\n", + "\n", + " pred = self.generate_answer(context=context, question=question)\n", + " return dspy.Prediction(context=context, answer=pred.answer)" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Prediction(\n", + " context=['Paris (disambiguation) | Paris is the largest city and capital of France.', 'Capital (French magazine) | Capital is a monthly French economics and business magazine published in Paris, France.', 'Paris | Paris (] ) is the capital and most populous city of France, with an administrative-limits area of 105 km2 and a 2015 population of 2,229,621. The city is a commune and department, and the capital-heart of the 12,012 km2 Île-de-France \"region\" (colloquially known as the \\'Paris Region\\'), whose 12,142,802 2016 population represents roughly 18 percent of the population of France. By the 17th century, Paris had become one of Europe\\'s major centres of finance, commerce, fashion, science, and the arts, a position that it retains still today. The Paris Region had a GDP of €649.6 billion (US $763.4 billion) in 2014, accounting for 30.4 percent of the GDP of France. According to official estimates, in 2013-14 the Paris Region had the third-highest GDP in the world and the largest regional GDP in the EU.', \"Administration of Paris | As the capital of France, Paris is the seat of France's national government. For the executive, the two chief officers each have their own official residences, which also serve as their offices. The President of France resides at the Élysée Palace in the 8th arrondissement, while the Prime Minister's seat is at the Hôtel Matignon in the 7th arrondissement. Government ministries are located in various parts of the city; many are located in the 7th arrondissement, near the Matignon.\"],\n", + " answer='Paris'\n", + ")" + ] + }, + "execution_count": 9, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "baleen = SimplifiedBaleen()\n", + "baleen(question=\"What is the capital of France?\")" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "Average Metric: 31 / 50 (62.0): 100%|██████████| 50/50 [00:00<00:00, 162.38it/s]" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Average Metric: 31 / 50 (62.0%)\n" + ] + }, + { + "name": "stderr", + "output_type": "stream", + "text": [ + "\n", + "/Users/ahle/repos/dspy/dspy/evaluate/evaluate.py:145: FutureWarning: DataFrame.applymap has been deprecated. Use DataFrame.map instead.\n", + " df = df.applymap(truncate_cell)\n" + ] + }, + { + "data": { + "text/plain": [ + "62.0" + ] + }, + "execution_count": 10, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "evaluator(baleen)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [ + "\n", + "for name, module in baleen.named_sub_modules():\n", + " if getattr(module, \"_compiled\", False):\n", + " print(\"Found compiled module\", name)\n", + "\n", + "result = optimize_signature(\n", + " student=baleen,\n", + " evaluator=evaluator,\n", + " initial_prompts=6,\n", + " n_iterations=60,\n", + " max_examples=30,\n", + " verbose=True,\n", + " prompt_model=gpt4,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "[]" + ] + }, + "execution_count": 15, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "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E4sXL0762KJFi3D48GEA0O4n/00p3D/90z/h61//Oj7xiU/gggsuwD/8wz/grrvuwrp16wDwXpdSNve2q6sLg4ODSZ+PRCIYGhoq+P6f8cGH0+nEkiVLsHnzZu1jsVgMmzdvRl9fXwWvbPoTQuC2227D448/ji1btmD+/PlJn1+yZAkcDkfSve/v78fhw4d573N09dVX4/XXX8err76q/Vi6dClWr16t/X/e6+K4/PLLp4yMv/XWW5g7dy4AYP78+ejq6kq616Ojo9ixYwfvdY7Gx8dhsyU/hux2O2KxGADe61LK5t729fVheHgYu3fv1l6zZcsWxGIxLFu2rLALKKhddZrYtGmTcLlc4pFHHhF79+4Vn//850VLS4sYGBio9KVNa1/60pdEc3OzeO6558Tx48e1H+Pj49prvvjFL4qenh6xZcsWsWvXLtHX1yf6+voqeNVnDuO0ixC818Xy8ssvC1VVxT333CP2798vHn30UVFfXy/++7//W3vNfffdJ1paWsTvfvc78de//lXccMMNHP/Mwy233CJmz56tjdr+5je/ER0dHeKrX/2q9hre6/z5/X7xyiuviFdeeUUAED/60Y/EK6+8It555x0hRHb39oMf/KC4+OKLxY4dO8SLL74ozj77bI7a5uI//uM/RE9Pj3A6neLSSy8V27dvr/QlTXsATH9s2LBBe83ExIT48pe/LFpbW0V9fb346Ec/Ko4fP165iz6DpAYfvNfF8+STT4rzzz9fuFwu0dvbK37+858nfT4Wi4lvfvObwuv1CpfLJa6++mrR399foaudvkZHR8Udd9whenp6hNvtFgsWLBDf+MY3RDAY1F7De52/Z5991vTf6FtuuUUIkd29PXXqlLj55ptFY2Oj8Hg84jOf+Yzw+/0FX5sihGGVHBEREVGJnfE9H0RERFRdGHwQERFRWTH4ICIiorJi8EFERERlxeCDiIiIyorBBxEREZUVgw8iIiIqKwYfREREVFYMPoiIiKisGHwQERFRWTH4ICIiorJi8EFERERl9f8DsVC7vKwTdVoAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import matplotlib.pyplot as plt\n", + "plt.plot(result.scores)" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "metadata": {}, + "outputs": [], + "source": [ + "for name, module in baleen.named_sub_modules(TypedPredictor):\n", + " print(name, module)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "metadata": {}, + "outputs": [], + "source": [] } ], "metadata": { diff --git a/intro.ipynb b/intro.ipynb index 1dc2cf6d9..c6db5871a 100644 --- a/intro.ipynb +++ b/intro.ipynb @@ -35,9 +35,20 @@ }, { "cell_type": "code", - "execution_count": 1, + "execution_count": 2, "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/var/folders/qz/yy2p38hj2m9c7bfp30yq99340000gn/T/ipykernel_40349/1846046422.py:20: DeprecationWarning: pkg_resources is deprecated as an API. See https://setuptools.pypa.io/en/latest/pkg_resources.html\n", + " import pkg_resources # Install the package if it's not installed\n", + "/opt/homebrew/lib/python3.11/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html\n", + " from .autonotebook import tqdm as notebook_tqdm\n" + ] + } + ], "source": [ "%load_ext autoreload\n", "%autoreload 2\n", @@ -83,7 +94,7 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 3, "metadata": {}, "outputs": [], "source": [ @@ -137,7 +148,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 4, "metadata": {}, "outputs": [ { @@ -146,7 +157,7 @@ "(20, 50)" ] }, - "execution_count": 3, + "execution_count": 4, "metadata": {}, "output_type": "execute_result" } @@ -177,7 +188,7 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 5, "metadata": {}, "outputs": [ { @@ -204,7 +215,7 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 6, "metadata": {}, "outputs": [ { @@ -233,7 +244,7 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 7, "metadata": {}, "outputs": [ { @@ -295,7 +306,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 8, "metadata": {}, "outputs": [], "source": [ @@ -319,15 +330,39 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 9, "metadata": {}, "outputs": [ { - "name": "stdout", - "output_type": "stream", - "text": [ - "Question: What is the nationality of the chef and restaurateur featured in Restaurant: Impossible?\n", - "Predicted Answer: American\n" + "ename": "OpenAIError", + "evalue": "The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mOpenAIError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[9], line 5\u001b[0m\n\u001b[1;32m 2\u001b[0m generate_answer \u001b[38;5;241m=\u001b[39m dspy\u001b[38;5;241m.\u001b[39mPredict(BasicQA)\n\u001b[1;32m 4\u001b[0m \u001b[38;5;66;03m# Call the predictor on a particular input.\u001b[39;00m\n\u001b[0;32m----> 5\u001b[0m pred \u001b[38;5;241m=\u001b[39m \u001b[43mgenerate_answer\u001b[49m\u001b[43m(\u001b[49m\u001b[43mquestion\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdev_example\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mquestion\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 7\u001b[0m \u001b[38;5;66;03m# Print the input and the prediction.\u001b[39;00m\n\u001b[1;32m 8\u001b[0m \u001b[38;5;28mprint\u001b[39m(\u001b[38;5;124mf\u001b[39m\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mQuestion: \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdev_example\u001b[38;5;241m.\u001b[39mquestion\u001b[38;5;132;01m}\u001b[39;00m\u001b[38;5;124m\"\u001b[39m)\n", + "File \u001b[0;32m~/repos/dspy/dspy/predict/predict.py:49\u001b[0m, in \u001b[0;36mPredict.__call__\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 48\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[0;32m---> 49\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mforward\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/repos/dspy/dspy/predict/predict.py:91\u001b[0m, in \u001b[0;36mPredict.forward\u001b[0;34m(self, **kwargs)\u001b[0m\n\u001b[1;32m 88\u001b[0m template \u001b[38;5;241m=\u001b[39m signature_to_template(signature)\n\u001b[1;32m 90\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mlm \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m---> 91\u001b[0m x, C \u001b[38;5;241m=\u001b[39m \u001b[43mdsp\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mgenerate\u001b[49m\u001b[43m(\u001b[49m\u001b[43mtemplate\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mconfig\u001b[49m\u001b[43m)\u001b[49m\u001b[43m(\u001b[49m\u001b[43mx\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mstage\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mstage\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 92\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 93\u001b[0m \u001b[38;5;66;03m# Note: query_only=True means the instructions and examples are not included.\u001b[39;00m\n\u001b[1;32m 94\u001b[0m \u001b[38;5;66;03m# I'm not really sure why we'd want to do that, but it's there.\u001b[39;00m\n\u001b[1;32m 95\u001b[0m \u001b[38;5;28;01mwith\u001b[39;00m dsp\u001b[38;5;241m.\u001b[39msettings\u001b[38;5;241m.\u001b[39mcontext(lm\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mlm, query_only\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mTrue\u001b[39;00m):\n", + "File \u001b[0;32m~/repos/dspy/dsp/primitives/predict.py:77\u001b[0m, in \u001b[0;36m_generate..do_generate\u001b[0;34m(example, stage, max_depth, original_example)\u001b[0m\n\u001b[1;32m 75\u001b[0m \u001b[38;5;66;03m# Generate and extract the fields.\u001b[39;00m\n\u001b[1;32m 76\u001b[0m prompt \u001b[38;5;241m=\u001b[39m template(example)\n\u001b[0;32m---> 77\u001b[0m completions: \u001b[38;5;28mlist\u001b[39m[\u001b[38;5;28mdict\u001b[39m[\u001b[38;5;28mstr\u001b[39m, Any]] \u001b[38;5;241m=\u001b[39m \u001b[43mgenerator\u001b[49m\u001b[43m(\u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 78\u001b[0m completions: \u001b[38;5;28mlist\u001b[39m[Example] \u001b[38;5;241m=\u001b[39m [template\u001b[38;5;241m.\u001b[39mextract(example, p) \u001b[38;5;28;01mfor\u001b[39;00m p \u001b[38;5;129;01min\u001b[39;00m completions]\n\u001b[1;32m 80\u001b[0m \u001b[38;5;66;03m# Find the completions that are most complete.\u001b[39;00m\n", + "File \u001b[0;32m~/repos/dspy/dsp/modules/gpt3.py:186\u001b[0m, in \u001b[0;36mGPT3.__call__\u001b[0;34m(self, prompt, only_completed, return_sorted, **kwargs)\u001b[0m\n\u001b[1;32m 178\u001b[0m \u001b[38;5;28;01massert\u001b[39;00m return_sorted \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mFalse\u001b[39;00m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mfor now\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 180\u001b[0m \u001b[38;5;66;03m# if kwargs.get(\"n\", 1) > 1:\u001b[39;00m\n\u001b[1;32m 181\u001b[0m \u001b[38;5;66;03m# if self.model_type == \"chat\":\u001b[39;00m\n\u001b[1;32m 182\u001b[0m \u001b[38;5;66;03m# kwargs = {**kwargs}\u001b[39;00m\n\u001b[1;32m 183\u001b[0m \u001b[38;5;66;03m# else:\u001b[39;00m\n\u001b[1;32m 184\u001b[0m \u001b[38;5;66;03m# kwargs = {**kwargs, \"logprobs\": 5}\u001b[39;00m\n\u001b[0;32m--> 186\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mrequest\u001b[49m\u001b[43m(\u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 188\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m dsp\u001b[38;5;241m.\u001b[39msettings\u001b[38;5;241m.\u001b[39mlog_openai_usage:\n\u001b[1;32m 189\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mlog_usage(response)\n", + "File \u001b[0;32m/opt/homebrew/lib/python3.11/site-packages/backoff/_sync.py:105\u001b[0m, in \u001b[0;36mretry_exception..retry\u001b[0;34m(*args, **kwargs)\u001b[0m\n\u001b[1;32m 96\u001b[0m details \u001b[38;5;241m=\u001b[39m {\n\u001b[1;32m 97\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mtarget\u001b[39m\u001b[38;5;124m\"\u001b[39m: target,\n\u001b[1;32m 98\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124margs\u001b[39m\u001b[38;5;124m\"\u001b[39m: args,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 101\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124melapsed\u001b[39m\u001b[38;5;124m\"\u001b[39m: elapsed,\n\u001b[1;32m 102\u001b[0m }\n\u001b[1;32m 104\u001b[0m \u001b[38;5;28;01mtry\u001b[39;00m:\n\u001b[0;32m--> 105\u001b[0m ret \u001b[38;5;241m=\u001b[39m \u001b[43mtarget\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 106\u001b[0m \u001b[38;5;28;01mexcept\u001b[39;00m exception \u001b[38;5;28;01mas\u001b[39;00m e:\n\u001b[1;32m 107\u001b[0m max_tries_exceeded \u001b[38;5;241m=\u001b[39m (tries \u001b[38;5;241m==\u001b[39m max_tries_value)\n", + "File \u001b[0;32m~/repos/dspy/dsp/modules/gpt3.py:152\u001b[0m, in \u001b[0;36mGPT3.request\u001b[0;34m(self, prompt, **kwargs)\u001b[0m\n\u001b[1;32m 149\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmodel_type\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01min\u001b[39;00m kwargs:\n\u001b[1;32m 150\u001b[0m \u001b[38;5;28;01mdel\u001b[39;00m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmodel_type\u001b[39m\u001b[38;5;124m\"\u001b[39m]\n\u001b[0;32m--> 152\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mbasic_request\u001b[49m\u001b[43m(\u001b[49m\u001b[43mprompt\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m~/repos/dspy/dsp/modules/gpt3.py:125\u001b[0m, in \u001b[0;36mGPT3.basic_request\u001b[0;34m(self, prompt, **kwargs)\u001b[0m\n\u001b[1;32m 123\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mmessages\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m [{\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mrole\u001b[39m\u001b[38;5;124m\"\u001b[39m: \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124muser\u001b[39m\u001b[38;5;124m\"\u001b[39m, \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mcontent\u001b[39m\u001b[38;5;124m\"\u001b[39m: prompt}]\n\u001b[1;32m 124\u001b[0m kwargs \u001b[38;5;241m=\u001b[39m {\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mstringify_request\u001b[39m\u001b[38;5;124m\"\u001b[39m: json\u001b[38;5;241m.\u001b[39mdumps(kwargs)}\n\u001b[0;32m--> 125\u001b[0m response \u001b[38;5;241m=\u001b[39m \u001b[43mchat_request\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 127\u001b[0m \u001b[38;5;28;01melse\u001b[39;00m:\n\u001b[1;32m 128\u001b[0m kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mprompt\u001b[39m\u001b[38;5;124m\"\u001b[39m] \u001b[38;5;241m=\u001b[39m prompt\n", + "File \u001b[0;32m~/repos/dspy/dsp/modules/gpt3.py:273\u001b[0m, in \u001b[0;36mchat_request\u001b[0;34m(**kwargs)\u001b[0m\n\u001b[1;32m 270\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m OPENAI_LEGACY:\n\u001b[1;32m 271\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m _cached_gpt3_turbo_request_v2_wrapped(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n\u001b[0;32m--> 273\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mv1_cached_gpt3_turbo_request_v2_wrapped\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mmodel_dump()\n", + "File \u001b[0;32m/opt/homebrew/lib/python3.11/site-packages/joblib/memory.py:655\u001b[0m, in \u001b[0;36mMemorizedFunc.__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 654\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[0;32m--> 655\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_cached_call\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m[\u001b[38;5;241m0\u001b[39m]\n", + "File \u001b[0;32m/opt/homebrew/lib/python3.11/site-packages/joblib/memory.py:598\u001b[0m, in \u001b[0;36mMemorizedFunc._cached_call\u001b[0;34m(self, args, kwargs, shelving)\u001b[0m\n\u001b[1;32m 595\u001b[0m must_call \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 597\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m must_call:\n\u001b[0;32m--> 598\u001b[0m out, metadata \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcall\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 599\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmmap_mode \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 600\u001b[0m \u001b[38;5;66;03m# Memmap the output at the first call to be consistent with\u001b[39;00m\n\u001b[1;32m 601\u001b[0m \u001b[38;5;66;03m# later calls\u001b[39;00m\n\u001b[1;32m 602\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_verbose:\n", + "File \u001b[0;32m/opt/homebrew/lib/python3.11/site-packages/joblib/memory.py:856\u001b[0m, in \u001b[0;36mMemorizedFunc.call\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 854\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_verbose \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m 855\u001b[0m \u001b[38;5;28mprint\u001b[39m(format_call(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfunc, args, kwargs))\n\u001b[0;32m--> 856\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 857\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstore_backend\u001b[38;5;241m.\u001b[39mdump_item(\n\u001b[1;32m 858\u001b[0m [func_id, args_id], output, verbose\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_verbose)\n\u001b[1;32m 860\u001b[0m duration \u001b[38;5;241m=\u001b[39m time\u001b[38;5;241m.\u001b[39mtime() \u001b[38;5;241m-\u001b[39m start_time\n", + "File \u001b[0;32m~/repos/dspy/dsp/modules/gpt3.py:266\u001b[0m, in \u001b[0;36mv1_cached_gpt3_turbo_request_v2_wrapped\u001b[0;34m(**kwargs)\u001b[0m\n\u001b[1;32m 263\u001b[0m \u001b[38;5;129m@functools\u001b[39m\u001b[38;5;241m.\u001b[39mlru_cache(maxsize\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m \u001b[38;5;28;01mif\u001b[39;00m cache_turn_on \u001b[38;5;28;01melse\u001b[39;00m \u001b[38;5;241m0\u001b[39m)\n\u001b[1;32m 264\u001b[0m \u001b[38;5;129m@NotebookCacheMemory\u001b[39m\u001b[38;5;241m.\u001b[39mcache\n\u001b[1;32m 265\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21mv1_cached_gpt3_turbo_request_v2_wrapped\u001b[39m(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[0;32m--> 266\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mv1_cached_gpt3_turbo_request_v2\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/opt/homebrew/lib/python3.11/site-packages/joblib/memory.py:655\u001b[0m, in \u001b[0;36mMemorizedFunc.__call__\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 654\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__call__\u001b[39m(\u001b[38;5;28mself\u001b[39m, \u001b[38;5;241m*\u001b[39margs, \u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs):\n\u001b[0;32m--> 655\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m_cached_call\u001b[49m\u001b[43m(\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m[\u001b[38;5;241m0\u001b[39m]\n", + "File \u001b[0;32m/opt/homebrew/lib/python3.11/site-packages/joblib/memory.py:598\u001b[0m, in \u001b[0;36mMemorizedFunc._cached_call\u001b[0;34m(self, args, kwargs, shelving)\u001b[0m\n\u001b[1;32m 595\u001b[0m must_call \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;01mTrue\u001b[39;00m\n\u001b[1;32m 597\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m must_call:\n\u001b[0;32m--> 598\u001b[0m out, metadata \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcall\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 599\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mmmap_mode \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;129;01mnot\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[1;32m 600\u001b[0m \u001b[38;5;66;03m# Memmap the output at the first call to be consistent with\u001b[39;00m\n\u001b[1;32m 601\u001b[0m \u001b[38;5;66;03m# later calls\u001b[39;00m\n\u001b[1;32m 602\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_verbose:\n", + "File \u001b[0;32m/opt/homebrew/lib/python3.11/site-packages/joblib/memory.py:856\u001b[0m, in \u001b[0;36mMemorizedFunc.call\u001b[0;34m(self, *args, **kwargs)\u001b[0m\n\u001b[1;32m 854\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_verbose \u001b[38;5;241m>\u001b[39m \u001b[38;5;241m0\u001b[39m:\n\u001b[1;32m 855\u001b[0m \u001b[38;5;28mprint\u001b[39m(format_call(\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mfunc, args, kwargs))\n\u001b[0;32m--> 856\u001b[0m output \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mfunc\u001b[49m\u001b[43m(\u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[38;5;241;43m*\u001b[39;49m\u001b[43mkwargs\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 857\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mstore_backend\u001b[38;5;241m.\u001b[39mdump_item(\n\u001b[1;32m 858\u001b[0m [func_id, args_id], output, verbose\u001b[38;5;241m=\u001b[39m\u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39m_verbose)\n\u001b[1;32m 860\u001b[0m duration \u001b[38;5;241m=\u001b[39m time\u001b[38;5;241m.\u001b[39mtime() \u001b[38;5;241m-\u001b[39m start_time\n", + "File \u001b[0;32m~/repos/dspy/dsp/modules/gpt3.py:260\u001b[0m, in \u001b[0;36mv1_cached_gpt3_turbo_request_v2\u001b[0;34m(**kwargs)\u001b[0m\n\u001b[1;32m 258\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mstringify_request\u001b[39m\u001b[38;5;124m\"\u001b[39m \u001b[38;5;129;01min\u001b[39;00m kwargs:\n\u001b[1;32m 259\u001b[0m kwargs \u001b[38;5;241m=\u001b[39m json\u001b[38;5;241m.\u001b[39mloads(kwargs[\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mstringify_request\u001b[39m\u001b[38;5;124m\"\u001b[39m])\n\u001b[0;32m--> 260\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43mopenai\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mchat\u001b[49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43mcompletions\u001b[49m\u001b[38;5;241m.\u001b[39mcreate(\u001b[38;5;241m*\u001b[39m\u001b[38;5;241m*\u001b[39mkwargs)\n", + "File \u001b[0;32m/opt/homebrew/lib/python3.11/site-packages/openai/_utils/_proxy.py:20\u001b[0m, in \u001b[0;36mLazyProxy.__getattr__\u001b[0;34m(self, attr)\u001b[0m\n\u001b[1;32m 19\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__getattr__\u001b[39m(\u001b[38;5;28mself\u001b[39m, attr: \u001b[38;5;28mstr\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m \u001b[38;5;28mobject\u001b[39m:\n\u001b[0;32m---> 20\u001b[0m proxied \u001b[38;5;241m=\u001b[39m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__get_proxied__\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 21\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m \u001b[38;5;28misinstance\u001b[39m(proxied, LazyProxy):\n\u001b[1;32m 22\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m proxied \u001b[38;5;66;03m# pyright: ignore\u001b[39;00m\n", + "File \u001b[0;32m/opt/homebrew/lib/python3.11/site-packages/openai/_utils/_proxy.py:55\u001b[0m, in \u001b[0;36mLazyProxy.__get_proxied__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 54\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__get_proxied__\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m T:\n\u001b[0;32m---> 55\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[38;5;28;43mself\u001b[39;49m\u001b[38;5;241;43m.\u001b[39;49m\u001b[43m__load__\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\n", + "File \u001b[0;32m/opt/homebrew/lib/python3.11/site-packages/openai/_module_client.py:12\u001b[0m, in \u001b[0;36mChatProxy.__load__\u001b[0;34m(self)\u001b[0m\n\u001b[1;32m 10\u001b[0m \u001b[38;5;129m@override\u001b[39m\n\u001b[1;32m 11\u001b[0m \u001b[38;5;28;01mdef\u001b[39;00m \u001b[38;5;21m__load__\u001b[39m(\u001b[38;5;28mself\u001b[39m) \u001b[38;5;241m-\u001b[39m\u001b[38;5;241m>\u001b[39m resources\u001b[38;5;241m.\u001b[39mChat:\n\u001b[0;32m---> 12\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m \u001b[43m_load_client\u001b[49m\u001b[43m(\u001b[49m\u001b[43m)\u001b[49m\u001b[38;5;241m.\u001b[39mchat\n", + "File \u001b[0;32m/opt/homebrew/lib/python3.11/site-packages/openai/__init__.py:297\u001b[0m, in \u001b[0;36m_load_client\u001b[0;34m()\u001b[0m\n\u001b[1;32m 281\u001b[0m _client \u001b[38;5;241m=\u001b[39m _AzureModuleClient( \u001b[38;5;66;03m# type: ignore\u001b[39;00m\n\u001b[1;32m 282\u001b[0m api_version\u001b[38;5;241m=\u001b[39mapi_version,\n\u001b[1;32m 283\u001b[0m azure_endpoint\u001b[38;5;241m=\u001b[39mazure_endpoint,\n\u001b[0;32m (...)\u001b[0m\n\u001b[1;32m 293\u001b[0m http_client\u001b[38;5;241m=\u001b[39mhttp_client,\n\u001b[1;32m 294\u001b[0m )\n\u001b[1;32m 295\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m _client\n\u001b[0;32m--> 297\u001b[0m _client \u001b[38;5;241m=\u001b[39m \u001b[43m_ModuleClient\u001b[49m\u001b[43m(\u001b[49m\n\u001b[1;32m 298\u001b[0m \u001b[43m \u001b[49m\u001b[43mapi_key\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mapi_key\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 299\u001b[0m \u001b[43m \u001b[49m\u001b[43morganization\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43morganization\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 300\u001b[0m \u001b[43m \u001b[49m\u001b[43mbase_url\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mbase_url\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 301\u001b[0m \u001b[43m \u001b[49m\u001b[43mtimeout\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mtimeout\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 302\u001b[0m \u001b[43m \u001b[49m\u001b[43mmax_retries\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mmax_retries\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 303\u001b[0m \u001b[43m \u001b[49m\u001b[43mdefault_headers\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdefault_headers\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 304\u001b[0m \u001b[43m \u001b[49m\u001b[43mdefault_query\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mdefault_query\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 305\u001b[0m \u001b[43m \u001b[49m\u001b[43mhttp_client\u001b[49m\u001b[38;5;241;43m=\u001b[39;49m\u001b[43mhttp_client\u001b[49m\u001b[43m,\u001b[49m\n\u001b[1;32m 306\u001b[0m \u001b[43m \u001b[49m\u001b[43m)\u001b[49m\n\u001b[1;32m 307\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m _client\n\u001b[1;32m 309\u001b[0m \u001b[38;5;28;01mreturn\u001b[39;00m _client\n", + "File \u001b[0;32m/opt/homebrew/lib/python3.11/site-packages/openai/_client.py:98\u001b[0m, in \u001b[0;36mOpenAI.__init__\u001b[0;34m(self, api_key, organization, base_url, timeout, max_retries, default_headers, default_query, http_client, _strict_response_validation)\u001b[0m\n\u001b[1;32m 96\u001b[0m api_key \u001b[38;5;241m=\u001b[39m os\u001b[38;5;241m.\u001b[39menviron\u001b[38;5;241m.\u001b[39mget(\u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mOPENAI_API_KEY\u001b[39m\u001b[38;5;124m\"\u001b[39m)\n\u001b[1;32m 97\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m api_key \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n\u001b[0;32m---> 98\u001b[0m \u001b[38;5;28;01mraise\u001b[39;00m OpenAIError(\n\u001b[1;32m 99\u001b[0m \u001b[38;5;124m\"\u001b[39m\u001b[38;5;124mThe api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable\u001b[39m\u001b[38;5;124m\"\u001b[39m\n\u001b[1;32m 100\u001b[0m )\n\u001b[1;32m 101\u001b[0m \u001b[38;5;28mself\u001b[39m\u001b[38;5;241m.\u001b[39mapi_key \u001b[38;5;241m=\u001b[39m api_key\n\u001b[1;32m 103\u001b[0m \u001b[38;5;28;01mif\u001b[39;00m organization \u001b[38;5;129;01mis\u001b[39;00m \u001b[38;5;28;01mNone\u001b[39;00m:\n", + "\u001b[0;31mOpenAIError\u001b[0m: The api_key client option must be set either by passing api_key to the client or by setting the OPENAI_API_KEY environment variable" ] } ], @@ -354,7 +389,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -399,7 +434,7 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -447,7 +482,7 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -485,7 +520,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -518,7 +553,7 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -544,7 +579,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -590,7 +625,7 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -641,7 +676,7 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -676,7 +711,7 @@ }, { "cell_type": "code", - "execution_count": 17, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -826,7 +861,7 @@ }, { "cell_type": "code", - "execution_count": 18, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -859,7 +894,7 @@ }, { "cell_type": "code", - "execution_count": 19, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1017,7 +1052,7 @@ }, { "cell_type": "code", - "execution_count": 20, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1183,7 +1218,7 @@ }, { "cell_type": "code", - "execution_count": 21, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1206,7 +1241,7 @@ }, { "cell_type": "code", - "execution_count": 22, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1270,7 +1305,7 @@ }, { "cell_type": "code", - "execution_count": 23, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1306,7 +1341,7 @@ }, { "cell_type": "code", - "execution_count": 24, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1437,7 +1472,7 @@ }, { "cell_type": "code", - "execution_count": 25, + "execution_count": null, "metadata": {}, "outputs": [], "source": [ @@ -1462,7 +1497,7 @@ }, { "cell_type": "code", - "execution_count": 26, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1493,16 +1528,28 @@ }, { "cell_type": "code", - "execution_count": 27, + "execution_count": null, "metadata": {}, - "outputs": [], + "outputs": [ + { + "ename": "NameError", + "evalue": "name 'evaluate_on_hotpotqa' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[0;31m---------------------------------------------------------------------------\u001b[0m", + "\u001b[0;31mNameError\u001b[0m Traceback (most recent call last)", + "Cell \u001b[0;32mIn[1], line 1\u001b[0m\n\u001b[0;32m----> 1\u001b[0m uncompiled_baleen_retrieval_score \u001b[38;5;241m=\u001b[39m \u001b[43mevaluate_on_hotpotqa\u001b[49m(uncompiled_baleen, metric\u001b[38;5;241m=\u001b[39mgold_passages_retrieved, display\u001b[38;5;241m=\u001b[39m\u001b[38;5;28;01mFalse\u001b[39;00m)\n", + "\u001b[0;31mNameError\u001b[0m: name 'evaluate_on_hotpotqa' is not defined" + ] + } + ], "source": [ "uncompiled_baleen_retrieval_score = evaluate_on_hotpotqa(uncompiled_baleen, metric=gold_passages_retrieved, display=False)" ] }, { "cell_type": "code", - "execution_count": 28, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1632,7 +1679,7 @@ }, { "cell_type": "code", - "execution_count": 29, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1671,7 +1718,7 @@ }, { "cell_type": "code", - "execution_count": 30, + "execution_count": null, "metadata": {}, "outputs": [ { @@ -1951,7 +1998,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.9.17" + "version": "3.11.8" }, "orig_nbformat": 4 }, diff --git a/tests/functional/test_functional.py b/tests/functional/test_functional.py index 2d680d3b9..7f8f9237e 100644 --- a/tests/functional/test_functional.py +++ b/tests/functional/test_functional.py @@ -9,6 +9,7 @@ import dspy from dspy.functional import predictor, cot, FunctionalModule, TypedPredictor, TypedChainOfThought +from dspy.predict.predict import Predict from dspy.primitives.example import Example from dspy.teleprompt.bootstrap import BootstrapFewShot from dspy.teleprompt.vanilla import LabeledFewShot @@ -232,7 +233,8 @@ def simple_metric(example, prediction, trace=None): lm.inspect_history(n=2) # Check that the compiled student has the correct demos - demos = compiled_student.predictors()[0].demos + _, predict = next(compiled_student.named_sub_modules(Predict, skip_compiled=False)) + demos = predict.demos assert len(demos) == 1 assert demos[0].input == trainset[0].input assert demos[0].output == trainset[0].output diff --git a/tests/primitives/test_program.py b/tests/primitives/test_program.py index 87ce09395..3f8600515 100644 --- a/tests/primitives/test_program.py +++ b/tests/primitives/test_program.py @@ -1,5 +1,4 @@ import dspy -from dspy.primitives.module import BaseModule from dspy.primitives.program import ( Module, set_attribute_by_name, @@ -59,45 +58,81 @@ def __init__(self): assert "hop.predict2" in names -class SubModule(BaseModule): - pass - - -class AnotherSubModule(BaseModule): - pass - - def test_empty_module(): - module = BaseModule() - assert list(module.named_sub_modules()) == [("base", module)] + module = Module() + assert list(module.named_sub_modules()) == [("self", module)] def test_single_level(): - module = BaseModule() - module.sub = SubModule() - expected = [("base", module), ("base.sub", module.sub)] + module = Module() + module.sub = Module() + expected = [("self", module), ("self.sub", module.sub)] assert list(module.named_sub_modules()) == expected def test_multiple_levels(): - module = BaseModule() - module.sub = SubModule() - module.sub.subsub = SubModule() - expected = [("base", module), ("base.sub", module.sub), ("base.sub.subsub", module.sub.subsub)] + module = Module() + module.sub = Module() + module.sub.subsub = Module() + expected = [("self", module), ("self.sub", module.sub), ("self.sub.subsub", module.sub.subsub)] assert list(module.named_sub_modules()) == expected def test_multiple_sub_modules(): - module = BaseModule() - module.sub1 = SubModule() - module.sub2 = SubModule() - expected = [("base", module), ("base.sub1", module.sub1), ("base.sub2", module.sub2)] + module = Module() + module.sub1 = Module() + module.sub2 = Module() + expected = [("self", module), ("self.sub1", module.sub1), ("self.sub2", module.sub2)] assert sorted(list(module.named_sub_modules())) == sorted(expected) def test_non_base_module_attributes(): - module = BaseModule() - module.sub = SubModule() - module.not_a_sub = "Not a BaseModule" - expected = [("base", module), ("base.sub", module.sub)] + module = Module() + module.sub = Module() + module.not_a_sub = "Not a self" + expected = [("self", module), ("self.sub", module.sub)] assert list(module.named_sub_modules()) == expected + + +def test_complex_module_traversal(): + root = Module() + root.sub_module = Module() + root.sub_module.nested_list = [Module(), {"key": Module()}] + same_sub = Module() + root.sub_module.nested_tuple = (Module(), [Module(), Module()]) + expected_names = { + "self", + "self.sub_module", + "self.sub_module.nested_list[0]", + "self.sub_module.nested_list[1][key]", + "self.sub_module.nested_tuple[0]", + "self.sub_module.nested_tuple[1][0]", + "self.sub_module.nested_tuple[1][1]", + } + found_names = {name for name, _ in root.named_sub_modules()} + + assert ( + found_names == expected_names + ), f"Missing or extra modules found. Missing: {expected_names-found_names}, Extra: {found_names-expected_names}" + + +def test_complex_module_traversal(): + root = Module() + root.sub_module = Module() + root.sub_module.nested_list = [Module(), {"key": Module()}] + same_module = Module() + root.sub_module.nested_tuple = (Module(), [same_module, same_module]) + expected_names = { + "self", + "self.sub_module", + "self.sub_module.nested_list[0]", + "self.sub_module.nested_list[1][key]", + "self.sub_module.nested_tuple[0]", + "self.sub_module.nested_tuple[1][0]", + # "self.sub_module.nested_tuple[1][1]", This should not be included, as it's the same module as the previous one + } + found_names = {name for name, _ in root.named_sub_modules()} + + assert ( + found_names == expected_names + ), f"Missing or extra modules found. Missing: {expected_names-found_names}, Extra: {found_names-expected_names}"