-
Notifications
You must be signed in to change notification settings - Fork 15
[WIP] refactor(strategy-executor): implement Strategy and Executor patterns #69
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
- Refactored Grader to separate "what to test" (atomic evaluation) from "how to test" (strategy) - Enhanced controller abstraction for resource scheduling and execution management - Updated all grader implementations to align with new architecture - Modified runner to delegate execution control to dedicated controllers - Updated tests to reflect new pattern implementation
Summary of ChangesHello @ployts, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed! This pull request introduces a significant architectural refactoring to the evaluation framework by integrating the Strategy and Executor design patterns. This change enhances modularity and flexibility by clearly delineating the evaluation logic from its execution and resource management. The update streamlines how graders are configured and run, making the system more adaptable to different testing methodologies and resource constraints. Highlights
🧠 New Feature in Public Preview: You can now enable Memory to help Gemini Code Assist learn from your team's feedback. This makes future code reviews more consistent and personalized to your project's style. Click here to enable Memory in your admin console. Using Gemini Code AssistThe full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips. Invoking Gemini You can request assistance from Gemini at any point by creating a comment using either
Customization To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a Limitations & Feedback Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here. You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension. Footnotes
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Code Review
This pull request introduces a significant and well-executed architectural refactoring, implementing the Strategy and Executor (Controller) patterns. The changes effectively separate concerns, making the framework more modular and extensible. The new strategy and controller modules are cleanly implemented, and the updates across the various grader classes and tests are consistent with the new design. My review includes a couple of suggestions to further enhance the new architecture by making the default strategy more explicit in the BaseGrader and addressing a minor logic issue in the RelevanceGrader. Overall, this is a very positive step forward for the codebase.
| self.name = name | ||
| self.mode = mode | ||
| self.description = description | ||
| self.strategy = strategy |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To make the default strategy more explicit and simplify the aevaluate method, consider initializing self.strategy with DirectStrategy if it's None. This avoids a conditional check later on and makes the code's intent clearer.
You'll need to add the following import at the top of the file:
from openjudge.strategy import DirectStrategy| self.strategy = strategy | |
| self.strategy = strategy or DirectStrategy() |
| if self.strategy: | ||
| return await self.strategy.execute(managed_fn, **data) | ||
| else: | ||
| return await managed_fn(**data) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| # Check if the result is an error | ||
| if isinstance(result, GraderError): | ||
| return result |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The super()._aevaluate() call, which resolves to LLMGrader._aevaluate, is designed to return a GraderScore or GraderRank object, or raise an exception on failure. It does not return GraderError instances directly. Therefore, this check for GraderError will never be true and can be considered dead code. Exceptions are caught by the except block below. This block can be safely removed.
| @@ -0,0 +1,53 @@ | |||
| # -*- coding: utf-8 -*- | |||
| """Base class for evaluation strategies. | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoild using file name "base.py". Name it as base_strategy.py. Make the file name self-explainable.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> base_evaluation_strategy.py
| from typing import Any, Awaitable, Callable | ||
|
|
||
|
|
||
| class BaseStrategy(ABC): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
BaseEvaluationExecutionStrategy, or something similar. BaseStrategy is too general to understand its purpose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> BaseEvaluationStrategy
| @@ -0,0 +1,8 @@ | |||
| # -*- coding: utf-8 -*- | |||
| """Strategy module for evaluation workflows.""" | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The folder name should be renamed to something like eval_execution_strategy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> evaluation_strategy
| from openjudge.strategy.base import BaseStrategy | ||
|
|
||
|
|
||
| class DirectStrategy(BaseStrategy): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
class LocallExecutionStrategy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> LocalEvaluationStrategy
| from openjudge.strategy.base import BaseStrategy | ||
|
|
||
|
|
||
| class MajorityVoteStrategy(BaseStrategy): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nitpick. vote -> voting. class MajorityVotingStrategy
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
代码改动太多,先删除具体实现
|
|
||
| # For now, return the first result as a placeholder | ||
| # In a real implementation, this would aggregate the results appropriately | ||
| return results[0] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better remove this voting strategy from this PR, if you don't plan to correctly implement.
Also this PR is too large. Consider adding concrete strategy classes in a separate PR. Let this CR only focus on the core structure change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
同上,删除具体实现
| @@ -0,0 +1,49 @@ | |||
| # -*- coding: utf-8 -*- | |||
| """Base class for execution controllers. | |||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
avoid using "base.py", too generic. base_controller.py
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> base_resource_executor.py
| R = TypeVar("R") | ||
|
|
||
|
|
||
| class BaseController(ABC): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On a second thought. The name Controller is vague. This class refers to computational resource allocation, and using the resource to run callable. It's more like a concept of "ComputationResourceWrapper".
What to "Control"? The word control is kind of misleading..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-> BaseResourceExecutor
| Called by the Runner to inject the controller. | ||
| """ | ||
| # 1. Apply mapper if available to transform input data | ||
| data = parse_data_with_mapper(kwargs, self.mapper) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
为什么要在grader内部生成data?而不是以前在外部生成
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
主要是考虑GraderConfig还有必要吗,所有mapper跟Grader一对一绑定,跟当前的strategy一样
| # 2. Wrap the atomic evaluation task to submit to the controller | ||
| async def managed_fn(**runtime_kwargs): | ||
| # Submit to Controller for execution | ||
| if controller is None: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
为什么不强制用local controller兜底?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
这个是给到测试使用的,测试可能不需要资源,直接跑就行
|
|
||
| # 3. Execute the strategy | ||
| # The strategy receives a function with resource management capabilities | ||
| if self.strategy: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
同理,为什么不强制direct strategy兜底?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
同上,给到测试使用的边界情况,不过这里默认是有strategy初始化,可以修改
| def __init__( | ||
| self, | ||
| grader_configs: Dict[str, GraderConfig | BaseGrader | Tuple[BaseGrader, Dict[str, str] | Callable | None]], | ||
| graders: Dict[str, "BaseGrader"], |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
应该考虑在runner的_arun()里,对每一个data record,创建一个grader 实例,避免一个grader 实例在asyncio里同时处理多条数据记录。这会带来结果错误。
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
在当前的使用下,去通过config初始化实例确实没问题,但是如果涉及icl引入动态fewshot,多个示例化内存就不高了,这个就必须高代码解决,无法配置化了
OpenJudge Version
0.2.0
Description
This PR implements the Strategy and Executor patterns as part of a major architectural refactoring of the OpenJudge framework. The changes separate concerns between "what to test" (atomic evaluation) and "how to test" (evaluation strategy), and abstract resource scheduling and execution management to dedicated controllers.
Checklist
Please check the following items before code is ready to be reviewed.
pre-commit run --all-filescommand