Skip to content

Commit 963d260

Browse files
peteryang1you-n-g
andauthored
feat: enhance timeout management and knowledge base handling in CoSTEER components (#1130)
* feat: enhance timeout management and knowledge base handling in CoSTEER components * fix a little bug * fix small bug * fix a small bug * Update rdagent/scenarios/data_science/loop.py Co-authored-by: you-n-g <[email protected]> * add scale check * fix a small bug * fix CI * use dynamic chat_token_limit & remove repeated lines * fix CI * remove useless comment * fix small bug * update draft appendix * fix prompt * add code correctness as top priority --------- Co-authored-by: you-n-g <[email protected]>
1 parent 512d08f commit 963d260

File tree

26 files changed

+336
-130
lines changed

26 files changed

+336
-130
lines changed

rdagent/app/data_science/conf.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -119,12 +119,14 @@ class DataScienceBasePropSetting(KaggleBasePropSetting):
119119

120120
model_architecture_suggestion_time_percent: float = 0.75
121121
allow_longer_timeout: bool = False
122-
coder_longer_timeout_multiplier: int = 3
123-
runner_longer_timeout_multiplier: int = 2
122+
coder_longer_timeout_multiplier_upper: int = 3
123+
runner_longer_timeout_multiplier_upper: int = 2
124+
timeout_increase_stage: float = 0.3
124125

125126
#### hypothesis critique and rewrite
126127
enable_hypo_critique_rewrite: bool = True
127128
"""Enable hypothesis critique and rewrite stages for improving hypothesis quality"""
129+
enable_scale_check: bool = False
128130

129131

130132
DS_RD_SETTING = DataScienceBasePropSetting()

rdagent/components/coder/CoSTEER/__init__.py

Lines changed: 18 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -6,13 +6,11 @@
66
from rdagent.components.coder.CoSTEER.evaluators import CoSTEERMultiFeedback
77
from rdagent.components.coder.CoSTEER.evolvable_subjects import EvolvingItem
88
from rdagent.components.coder.CoSTEER.knowledge_management import (
9-
CoSTEERKnowledgeBaseV1,
10-
CoSTEERKnowledgeBaseV2,
119
CoSTEERRAGStrategyV1,
1210
CoSTEERRAGStrategyV2,
1311
)
1412
from rdagent.core.developer import Developer
15-
from rdagent.core.evaluation import Evaluator, Feedback
13+
from rdagent.core.evaluation import Evaluator
1614
from rdagent.core.evolving_agent import EvolvingStrategy, RAGEvoAgent
1715
from rdagent.core.exception import CoderError
1816
from rdagent.core.experiment import Experiment
@@ -26,8 +24,8 @@ def __init__(
2624
settings: CoSTEERSettings,
2725
eva: Evaluator,
2826
es: EvolvingStrategy,
29-
evolving_version: int,
3027
*args,
28+
evolving_version: int = 2,
3129
max_seconds: int | None = None,
3230
with_knowledge: bool = True,
3331
with_feedback: bool = True,
@@ -37,6 +35,8 @@ def __init__(
3735
**kwargs,
3836
) -> None:
3937
super().__init__(*args, **kwargs)
38+
self.settings = settings
39+
4040
self.max_loop = settings.max_loop if max_loop is None else max_loop
4141
self.max_seconds = max_seconds
4242
self.knowledge_base_path = (
@@ -54,37 +54,22 @@ def __init__(
5454
self.evaluator = eva
5555
self.evolving_version = evolving_version
5656

57-
# init knowledge base
58-
self.knowledge_base = self.load_or_init_knowledge_base(
59-
former_knowledge_base_path=self.knowledge_base_path,
60-
component_init_list=[],
61-
)
6257
# init rag method
6358
self.rag = (
64-
CoSTEERRAGStrategyV2(self.knowledge_base, settings=settings)
59+
CoSTEERRAGStrategyV2(
60+
settings=settings,
61+
former_knowledge_base_path=self.knowledge_base_path,
62+
dump_knowledge_base_path=self.new_knowledge_base_path,
63+
evolving_version=self.evolving_version,
64+
)
6565
if self.evolving_version == 2
66-
else CoSTEERRAGStrategyV1(self.knowledge_base, settings=settings)
67-
)
68-
69-
def load_or_init_knowledge_base(self, former_knowledge_base_path: Path = None, component_init_list: list = []):
70-
if former_knowledge_base_path is not None and former_knowledge_base_path.exists():
71-
knowledge_base = pickle.load(open(former_knowledge_base_path, "rb"))
72-
if self.evolving_version == 1 and not isinstance(knowledge_base, CoSTEERKnowledgeBaseV1):
73-
raise ValueError("The former knowledge base is not compatible with the current version")
74-
elif self.evolving_version == 2 and not isinstance(
75-
knowledge_base,
76-
CoSTEERKnowledgeBaseV2,
77-
):
78-
raise ValueError("The former knowledge base is not compatible with the current version")
79-
else:
80-
knowledge_base = (
81-
CoSTEERKnowledgeBaseV2(
82-
init_component_list=component_init_list,
83-
)
84-
if self.evolving_version == 2
85-
else CoSTEERKnowledgeBaseV1()
66+
else CoSTEERRAGStrategyV1(
67+
settings=settings,
68+
former_knowledge_base_path=self.knowledge_base_path,
69+
dump_knowledge_base_path=self.new_knowledge_base_path,
70+
evolving_version=self.evolving_version,
8671
)
87-
return knowledge_base
72+
)
8873

8974
def develop(self, exp: Experiment) -> Experiment:
9075

@@ -98,6 +83,8 @@ def develop(self, exp: Experiment) -> Experiment:
9883
with_knowledge=self.with_knowledge,
9984
with_feedback=self.with_feedback,
10085
knowledge_self_gen=self.knowledge_self_gen,
86+
enable_filelock=self.settings.enable_filelock,
87+
filelock_path=self.settings.filelock_path,
10188
)
10289

10390
start_datetime = datetime.now()
@@ -116,11 +103,6 @@ def develop(self, exp: Experiment) -> Experiment:
116103
if self.with_feedback and self.filter_final_evo:
117104
evo_exp = self._exp_postprocess_by_feedback(evo_exp, self.evolve_agent.evolving_trace[-1].feedback)
118105

119-
# save new knowledge base
120-
if self.new_knowledge_base_path is not None:
121-
with self.new_knowledge_base_path.open("wb") as f:
122-
pickle.dump(self.knowledge_base, f)
123-
logger.info(f"New knowledge base saved to {self.new_knowledge_base_path}")
124106
exp.sub_workspace_list = evo_exp.sub_workspace_list
125107
exp.experiment_workspace = evo_exp.experiment_workspace
126108
return exp

rdagent/components/coder/CoSTEER/config.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,9 @@ class Config:
3333
new_knowledge_base_path: Union[str, None] = None
3434
"""Path to the new knowledge base"""
3535

36+
enable_filelock: bool = False
37+
filelock_path: Union[str, None] = None
38+
3639
max_seconds_multiplier: int = 10**6
3740

3841

rdagent/components/coder/CoSTEER/evolving_strategy.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,16 +75,18 @@ def evolve(
7575
evolving_trace: list[EvoStep] = [],
7676
**kwargs,
7777
) -> EvolvingItem:
78+
code_list = [None for _ in range(len(evo.sub_tasks))]
79+
7880
# 1.找出需要evolve的task
7981
to_be_finished_task_index: list[int] = []
8082
for index, target_task in enumerate(evo.sub_tasks):
8183
target_task_desc = target_task.get_task_information()
8284
if target_task_desc in queried_knowledge.success_task_to_knowledge_dict:
8385
# NOTE: very weird logic:
8486
# it depends on the knowledge to set the already finished task
85-
evo.sub_workspace_list[index] = queried_knowledge.success_task_to_knowledge_dict[
87+
code_list[index] = queried_knowledge.success_task_to_knowledge_dict[
8688
target_task_desc
87-
].implementation
89+
].implementation.file_dict
8890
elif (
8991
target_task_desc not in queried_knowledge.success_task_to_knowledge_dict
9092
and target_task_desc not in queried_knowledge.failed_task_info_set
@@ -111,7 +113,6 @@ def evolve(
111113
],
112114
n=RD_AGENT_SETTINGS.multi_proc_n,
113115
)
114-
code_list = [None for _ in range(len(evo.sub_tasks))]
115116
for index, target_index in enumerate(to_be_finished_task_index):
116117
code_list[target_index] = result[index]
117118

rdagent/components/coder/CoSTEER/knowledge_management.py

Lines changed: 66 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import copy
44
import json
5+
import pickle
56
import random
67
import re
78
from itertools import combinations
@@ -51,6 +52,53 @@ def get_implementation_and_feedback_str(self) -> str:
5152
"""
5253

5354

55+
class CoSTEERRAGStrategy(RAGStrategy):
56+
def __init__(self, *args, dump_knowledge_base_path: Path = None, **kwargs):
57+
super().__init__(*args, **kwargs)
58+
self.dump_knowledge_base_path = dump_knowledge_base_path
59+
60+
def load_or_init_knowledge_base(
61+
self, former_knowledge_base_path: Path = None, component_init_list: list = [], evolving_version: int = 2
62+
) -> EvolvingKnowledgeBase:
63+
if former_knowledge_base_path is not None and former_knowledge_base_path.exists():
64+
knowledge_base = pickle.load(open(former_knowledge_base_path, "rb"))
65+
if evolving_version == 1 and not isinstance(knowledge_base, CoSTEERKnowledgeBaseV1):
66+
raise ValueError("The former knowledge base is not compatible with the current version")
67+
elif evolving_version == 2 and not isinstance(
68+
knowledge_base,
69+
CoSTEERKnowledgeBaseV2,
70+
):
71+
raise ValueError("The former knowledge base is not compatible with the current version")
72+
else:
73+
knowledge_base = (
74+
CoSTEERKnowledgeBaseV2(
75+
init_component_list=component_init_list,
76+
)
77+
if evolving_version == 2
78+
else CoSTEERKnowledgeBaseV1()
79+
)
80+
return knowledge_base
81+
82+
def dump_knowledge_base(self):
83+
if self.dump_knowledge_base_path is None:
84+
logger.warning("Dump knowledge base path is not set, skip dumping.")
85+
else:
86+
if not self.dump_knowledge_base_path.parent.exists():
87+
self.dump_knowledge_base_path.parent.mkdir(parents=True, exist_ok=True)
88+
with open(self.dump_knowledge_base_path, "wb") as f:
89+
pickle.dump(self.knowledgebase, f)
90+
91+
def load_dumped_knowledge_base(self, *args, **kwargs):
92+
if self.dump_knowledge_base_path is None:
93+
logger.warning("Dump knowledge base path is not set, skip dumping.")
94+
elif not Path(self.dump_knowledge_base_path).exists():
95+
logger.info(f"Dumped knowledge base {self.dump_knowledge_base_path} does not exist, skip loading.")
96+
else:
97+
with open(self.dump_knowledge_base_path, "rb") as f:
98+
self.knowledgebase = pickle.load(f)
99+
logger.info(f"Loaded dumped knowledge base from {self.dump_knowledge_base_path}")
100+
101+
54102
class CoSTEERQueriedKnowledge(QueriedKnowledge):
55103
def __init__(self, success_task_to_knowledge_dict: dict = {}, failed_task_info_set: set = set()) -> None:
56104
self.success_task_to_knowledge_dict = success_task_to_knowledge_dict
@@ -85,9 +133,9 @@ def __init__(
85133
super().__init__(*args, **kwargs)
86134

87135

88-
class CoSTEERRAGStrategyV1(RAGStrategy):
89-
def __init__(self, knowledgebase: CoSTEERKnowledgeBaseV1, settings: CoSTEERSettings) -> None:
90-
super().__init__(knowledgebase)
136+
class CoSTEERRAGStrategyV1(CoSTEERRAGStrategy):
137+
def __init__(self, settings: CoSTEERSettings, *args, **kwargs) -> None:
138+
super().__init__(*args, **kwargs)
91139
self.current_generated_trace_count = 0
92140
self.settings = settings
93141

@@ -213,9 +261,9 @@ def __init__(
213261
)
214262

215263

216-
class CoSTEERRAGStrategyV2(RAGStrategy):
217-
def __init__(self, knowledgebase: CoSTEERKnowledgeBaseV2, settings: CoSTEERSettings) -> None:
218-
super().__init__(knowledgebase)
264+
class CoSTEERRAGStrategyV2(CoSTEERRAGStrategy):
265+
def __init__(self, settings: CoSTEERSettings, *args, **kwargs) -> None:
266+
super().__init__(*args, **kwargs)
219267
self.current_generated_trace_count = 0
220268
self.settings = settings
221269

@@ -249,6 +297,12 @@ def generate_knowledge(
249297
target_task_information not in self.knowledgebase.success_task_to_knowledge_dict
250298
and implementation is not None
251299
):
300+
if target_task_information not in self.knowledgebase.task_to_component_nodes:
301+
self.knowledgebase.task_to_component_nodes[target_task_information] = (
302+
self.analyze_component(
303+
target_task_information,
304+
)
305+
)
252306
self.knowledgebase.working_trace_knowledge.setdefault(target_task_information, []).append(
253307
single_knowledge,
254308
) # save to working trace
@@ -465,7 +519,6 @@ def component_query(
465519
self.knowledgebase.task_to_component_nodes[target_task_information] = self.analyze_component(
466520
target_task_information,
467521
)
468-
469522
component_analysis_result = self.knowledgebase.task_to_component_nodes[target_task_information]
470523

471524
if len(component_analysis_result) > 1:
@@ -557,12 +610,14 @@ def component_query(
557610
queried_from_gt_knowledge_list = [
558611
knowledge
559612
for knowledge in queried_knowledge_list
560-
if knowledge.feedback is not None and knowledge.feedback.final_decision_based_on_gt == True
613+
if knowledge.feedback is not None
614+
and (
615+
hasattr(knowledge.feedback, "final_decision_based_on_gt")
616+
and knowledge.feedback.final_decision_based_on_gt == True
617+
)
561618
]
562619
queried_without_gt_knowledge_list = [
563-
knowledge
564-
for knowledge in queried_knowledge_list
565-
if knowledge.feedback is not None and knowledge.feedback.final_decision_based_on_gt == False
620+
knowledge for knowledge in queried_knowledge_list if knowledge not in queried_from_gt_knowledge_list
566621
]
567622
queried_from_gt_knowledge_count = max(
568623
min((v2_query_component_limit // 2 + 1), len(queried_from_gt_knowledge_list)),

rdagent/components/coder/data_science/pipeline/__init__.py

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,11 +63,6 @@ def implement_one_task(
6363
data_folder_info = self.scen.processed_data_folder_description
6464
pipeline_task_info = target_task.get_task_information()
6565

66-
queried_similar_successful_knowledge = (
67-
queried_knowledge.task_to_similar_task_successful_knowledge[pipeline_task_info]
68-
if queried_knowledge is not None
69-
else []
70-
)
7166
queried_former_failed_knowledge = (
7267
queried_knowledge.task_to_former_failed_traces[pipeline_task_info] if queried_knowledge is not None else []
7368
)
@@ -82,7 +77,6 @@ def implement_one_task(
8277

8378
system_prompt = T(".prompts:pipeline_coder.system").r(
8479
task_desc=pipeline_task_info,
85-
queried_similar_successful_knowledge=queried_similar_successful_knowledge,
8680
queried_former_failed_knowledge=queried_former_failed_knowledge[0],
8781
out_spec=PythonAgentOut.get_spec(),
8882
runtime_environment=self.scen.get_runtime_environment(),

rdagent/components/coder/data_science/pipeline/eval.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,10 +158,17 @@ def evaluate(
158158
else:
159159
eda_output = implementation.file_dict.get("EDA.md", None)
160160

161+
queried_similar_successful_knowledge = (
162+
queried_knowledge.task_to_similar_task_successful_knowledge[target_task.get_task_information()]
163+
if queried_knowledge is not None
164+
else []
165+
)
166+
161167
system_prompt = T(".prompts:pipeline_eval.system").r(
162168
is_sub_enabled=test_eval.is_sub_enabled(self.scen.competition),
163169
debug_mode=DS_RD_SETTING.sample_data_by_LLM,
164170
mle_check=(DS_RD_SETTING.sample_data_by_LLM and test_eval.is_sub_enabled(self.scen.competition)),
171+
queried_similar_successful_knowledge=queried_similar_successful_knowledge,
165172
)
166173
user_prompt = T(".prompts:pipeline_eval.user").r(
167174
scenario=self.scen.get_scenario_all_desc(eda_output=eda_output),

0 commit comments

Comments
 (0)