From 91c34578b1b7d633c04072282fcae856b0ab3f55 Mon Sep 17 00:00:00 2001 From: femto Date: Sun, 12 Jan 2025 22:18:35 +0800 Subject: [PATCH] code contests --- examples/smart_minion/brain.py | 9 ++++ .../code_contests/code_contests_config.json | 2 +- .../code_contests/evalute_code_contests.py | 4 +- minion/main/minion.py | 25 ++++++++--- minion/main/prompt.py | 15 +++++++ minion/main/worker.py | 44 ++++++++++++++++++- 6 files changed, 87 insertions(+), 12 deletions(-) diff --git a/examples/smart_minion/brain.py b/examples/smart_minion/brain.py index 04d0eeb6..d530eab5 100644 --- a/examples/smart_minion/brain.py +++ b/examples/smart_minion/brain.py @@ -32,6 +32,15 @@ async def smart_brain(): ) # obs, score, *_ = await brain.step(query="what's the solution for game of 24 for 4 3 9 8") # print(obs) + current_file_dir = os.path.dirname(os.path.abspath(__file__)) + cache_plan = os.path.join(current_file_dir, "aime", "plan_gpt4o.1.json") + obs, score, *_ = await brain.step( + query="Every morning Aya goes for a $9$-kilometer-long walk and stops at a coffee shop afterwards. When she walks at a constant speed of $s$ kilometers per hour, the walk takes her 4 hours, including $t$ minutes spent in the coffee shop. When she walks $s+2$ kilometers per hour, the walk takes her 2 hours and 24 minutes, including $t$ minutes spent in the coffee shop. Suppose Aya walks at $s+\frac{1}{2}$ kilometers per hour. Find the number of minutes the walk takes her, including the $t$ minutes spent in the coffee shop.", + route="plan", + dataset="aime 2024", + cache_plan=cache_plan, + ) + print(obs) # 从 HumanEval/88 提取的测试用例 test_data = { diff --git a/examples/smart_minion/code_contests/code_contests_config.json b/examples/smart_minion/code_contests/code_contests_config.json index db5e9248..972dc7e0 100644 --- a/examples/smart_minion/code_contests/code_contests_config.json +++ b/examples/smart_minion/code_contests/code_contests_config.json @@ -1,6 +1,6 @@ { "type": "ensemble", - + "pre_processing": ["problem_reflect"], "workers": [ { "name": "python", diff --git a/examples/smart_minion/code_contests/evalute_code_contests.py b/examples/smart_minion/code_contests/evalute_code_contests.py index 9438754a..0d8e3210 100644 --- a/examples/smart_minion/code_contests/evalute_code_contests.py +++ b/examples/smart_minion/code_contests/evalute_code_contests.py @@ -218,10 +218,8 @@ async def solve_single_question(item, route="cot"): return { "result": 0, "item_id": item_id, - "task_id": item["task_id"], + "item": item, "question": question, - "canonical_solution": canonical_solution, - "test": test, "answer": answer, "reason": ret[1], "idx": item_id, diff --git a/minion/main/minion.py b/minion/main/minion.py index 35a69da2..1dbdb0e4 100644 --- a/minion/main/minion.py +++ b/minion/main/minion.py @@ -16,6 +16,7 @@ MINION_REGISTRY = {} WORKER_MINIONS = {} IMPROVER_MINIONS = {} +PRE_PROCESSING_REGISTRY = {} # New registry for pre-processing minions # a dummy score that does nothing, always return 1 to shortcut the score process @@ -29,21 +30,21 @@ def __init__(cls, name, bases, clsdict): super().__init__(name, bases, clsdict) cls._subclassed_hook() +def register_minion(name): + def decorator(cls): + MINION_REGISTRY[name] = cls + return cls + return decorator + def register_worker_minion(cls=None, *, name=None): """Decorator to register worker minions. Can be used as @register_worker_minion or @register_worker_minion(name="custom_name") - - Args: - cls: The class to register (when used as @register_worker_minion) - name: Optional custom name (when used as @register_worker_minion(name="custom_name")) """ def decorator(cls): - # Use custom name if provided, otherwise convert class name to snake_case register_name = name if name is not None else camel_case_to_snake_case(cls.__name__) WORKER_MINIONS[register_name] = cls return cls - # Handle both @register_worker_minion and @register_worker_minion(name="custom_name") if cls is None: return decorator return decorator(cls) @@ -61,6 +62,18 @@ def decorator(cls): return decorator return decorator(cls) +def register_pre_processing_minion(cls=None, *, name=None): + """Decorator to register pre-processing minions. + Can be used as @register_pre_processing_minion or @register_pre_processing_minion(name="custom_name") + """ + def decorator(cls): + register_name = name if name is not None else camel_case_to_snake_case(cls.__name__).replace('_minion', '') + PRE_PROCESSING_REGISTRY[register_name] = cls + return cls + + if cls is None: + return decorator + return decorator(cls) class Minion(metaclass=SubclassHookMeta): def __init__(self, input=None, brain=None, id=None, score_func=None, worker_config=None, task=None, **kwargs): diff --git a/minion/main/prompt.py b/minion/main/prompt.py index 9912d755..c3e5b094 100644 --- a/minion/main/prompt.py +++ b/minion/main/prompt.py @@ -615,3 +615,18 @@ """ + ASK_PROMPT_JINJA ) + +PROBLEM_REFLECT_PROMPT = """Please analyze the following problem and provide a detailed reflection: + +Problem Description: +{{input.query}} + +Please provide: +1. Key concepts and requirements +2. Potential challenges and edge cases +3. Similar problems you've encountered +4. Suggested approach and methodology +5. Any assumptions that need to be validated + +Your reflection should help guide the solution process. +""" diff --git a/minion/main/worker.py b/minion/main/worker.py index 490f2829..9f118090 100644 --- a/minion/main/worker.py +++ b/minion/main/worker.py @@ -22,6 +22,7 @@ from minion.actions.action_node import ActionNode from minion.configs.config import config from minion.logs import logger +from minion.main.pre_processing import PreProcessingMinion from minion.main.check import CheckMinion from minion.main.check_route import CheckRouterMinion from minion.main.improve import ImproverMinion @@ -562,6 +563,40 @@ def __init__(self, **kwargs): super().__init__(**kwargs) self.execution_state: Dict[str, Any] = {} + async def execute_pre_processing(self): + """Execute pre-processing steps if configured""" + if not hasattr(self.input, 'execution_config'): + return + + pre_processing_steps = self.input.execution_config.get('pre_processing', []) + if not pre_processing_steps: + return + + # Ensure pre_processing_steps is a list + if isinstance(pre_processing_steps, str): + pre_processing_steps = [pre_processing_steps] + + # Get pre-processing minion registry + from minion.main.minion import PRE_PROCESSING_REGISTRY + + # Execute each pre-processing step in sequence + for step in pre_processing_steps: + pre_processing_class = PRE_PROCESSING_REGISTRY.get(step) + if not pre_processing_class: + logger.warning(f"Pre-processing minion {step} not found") + continue + self.execution_state["current_pre_processing"] = step + self.save_execution_state() + + # Execute pre-processing + pre_processing_minion = pre_processing_class(input=self.input, brain=self.brain) + await pre_processing_minion.execute() + + # Update execution state + + self.execution_state["current_pre_processing"] = None + self.save_execution_state() + async def invoke_minion(self, minion_name, worker_config=None): self.input.run_id = uuid.uuid4() # a new run id for each run self.input.route = minion_name @@ -588,6 +623,9 @@ async def execute_ensemble(self): if 'workers' not in self.input.execution_config: return await self.execute_single() + # Execute pre-processing first + await self.execute_pre_processing() + results = {} total_count = sum(worker["count"] for worker in self.input.execution_config["workers"]) majority_count = total_count // 2 + 1 @@ -627,6 +665,8 @@ async def execute_ensemble(self): return most_voted_result async def execute_single(self): + # Execute pre-processing first + await self.execute_pre_processing() return await self.invoke_minion(self.input.route) async def execute(self): @@ -649,12 +689,12 @@ async def execute(self): def save_execution_state(self): """保存执行状态""" if self.input.save_state: - self.input.exec_save_state(f"state_{self.input.query_id}.pkl") + self.input.save_state(f"state_{self.input.query_id}.pkl") def load_execution_state(self): """加载执行状态""" if self.input.save_state: - loaded_input = Input.exec_load_state(f"state_{self.input.query_id}.pkl") + loaded_input = Input.load_state(f"state_{self.input.query_id}.pkl") if loaded_input: self.input = loaded_input