mirror of
https://github.com/qodo-ai/pr-agent.git
synced 2025-07-05 21:30:40 +08:00
Support multiple model types for different reasoning tasks
This commit is contained in:
@ -416,18 +416,18 @@ Qodo Merge uses a dynamic strategy to generate code suggestions based on the siz
|
|||||||
#### 1. Chunking large PRs
|
#### 1. Chunking large PRs
|
||||||
|
|
||||||
- Qodo Merge divides large PRs into 'chunks'.
|
- Qodo Merge divides large PRs into 'chunks'.
|
||||||
- Each chunk contains up to `pr_code_suggestions.max_context_tokens` tokens (default: 14,000).
|
- Each chunk contains up to `pr_code_suggestions.max_context_tokens` tokens (default: 24,000).
|
||||||
|
|
||||||
#### 2. Generating suggestions
|
#### 2. Generating suggestions
|
||||||
|
|
||||||
- For each chunk, Qodo Merge generates up to `pr_code_suggestions.num_code_suggestions_per_chunk` suggestions (default: 3).
|
- For each chunk, Qodo Merge generates up to `pr_code_suggestions.num_code_suggestions_per_chunk` suggestions (default: 4).
|
||||||
|
|
||||||
This approach has two main benefits:
|
This approach has two main benefits:
|
||||||
|
|
||||||
- Scalability: The number of suggestions scales with the PR size, rather than being fixed.
|
- Scalability: The number of suggestions scales with the PR size, rather than being fixed.
|
||||||
- Quality: By processing smaller chunks, the AI can maintain higher quality suggestions, as larger contexts tend to decrease AI performance.
|
- Quality: By processing smaller chunks, the AI can maintain higher quality suggestions, as larger contexts tend to decrease AI performance.
|
||||||
|
|
||||||
Note: Chunking is primarily relevant for large PRs. For most PRs (up to 500 lines of code), Qodo Merge will be able to process the entire code in a single call.
|
Note: Chunking is primarily relevant for large PRs. For most PRs (up to 600 lines of code), Qodo Merge will be able to process the entire code in a single call.
|
||||||
|
|
||||||
## Configuration options
|
## Configuration options
|
||||||
|
|
||||||
|
@ -12,7 +12,7 @@ from pr_agent.algo.git_patch_processing import (
|
|||||||
from pr_agent.algo.language_handler import sort_files_by_main_languages
|
from pr_agent.algo.language_handler import sort_files_by_main_languages
|
||||||
from pr_agent.algo.token_handler import TokenHandler
|
from pr_agent.algo.token_handler import TokenHandler
|
||||||
from pr_agent.algo.types import EDIT_TYPE, FilePatchInfo
|
from pr_agent.algo.types import EDIT_TYPE, FilePatchInfo
|
||||||
from pr_agent.algo.utils import ModelType, clip_tokens, get_max_tokens, get_weak_model
|
from pr_agent.algo.utils import ModelType, clip_tokens, get_max_tokens, get_model
|
||||||
from pr_agent.config_loader import get_settings
|
from pr_agent.config_loader import get_settings
|
||||||
from pr_agent.git_providers.git_provider import GitProvider
|
from pr_agent.git_providers.git_provider import GitProvider
|
||||||
from pr_agent.log import get_logger
|
from pr_agent.log import get_logger
|
||||||
@ -339,7 +339,9 @@ async def retry_with_fallback_models(f: Callable, model_type: ModelType = ModelT
|
|||||||
|
|
||||||
def _get_all_models(model_type: ModelType = ModelType.REGULAR) -> List[str]:
|
def _get_all_models(model_type: ModelType = ModelType.REGULAR) -> List[str]:
|
||||||
if model_type == ModelType.WEAK:
|
if model_type == ModelType.WEAK:
|
||||||
model = get_weak_model()
|
model = get_model('model_weak')
|
||||||
|
elif model_type == ModelType.REASONING:
|
||||||
|
model = get_model('model_reasoning')
|
||||||
else:
|
else:
|
||||||
model = get_settings().config.model
|
model = get_settings().config.model
|
||||||
fallback_models = get_settings().config.fallback_models
|
fallback_models = get_settings().config.fallback_models
|
||||||
|
@ -30,12 +30,13 @@ from pr_agent.config_loader import get_settings, global_settings
|
|||||||
from pr_agent.log import get_logger
|
from pr_agent.log import get_logger
|
||||||
|
|
||||||
|
|
||||||
def get_weak_model() -> str:
|
def get_model(model_type: str = "model_weak") -> str:
|
||||||
if get_settings().get("config.model_weak"):
|
if model_type == "model_weak" and get_settings().get("config.model_weak"):
|
||||||
return get_settings().config.model_weak
|
return get_settings().config.model_weak
|
||||||
|
elif model_type == "model_reasoning" and get_settings().get("config.model_reasoning"):
|
||||||
|
return get_settings().config.model_reasoning
|
||||||
return get_settings().config.model
|
return get_settings().config.model
|
||||||
|
|
||||||
|
|
||||||
class Range(BaseModel):
|
class Range(BaseModel):
|
||||||
line_start: int # should be 0-indexed
|
line_start: int # should be 0-indexed
|
||||||
line_end: int
|
line_end: int
|
||||||
@ -45,6 +46,7 @@ class Range(BaseModel):
|
|||||||
class ModelType(str, Enum):
|
class ModelType(str, Enum):
|
||||||
REGULAR = "regular"
|
REGULAR = "regular"
|
||||||
WEAK = "weak"
|
WEAK = "weak"
|
||||||
|
REASONING = "reasoning"
|
||||||
|
|
||||||
class PRReviewHeader(str, Enum):
|
class PRReviewHeader(str, Enum):
|
||||||
REGULAR = "## PR Reviewer Guide"
|
REGULAR = "## PR Reviewer Guide"
|
||||||
|
@ -6,8 +6,9 @@
|
|||||||
|
|
||||||
[config]
|
[config]
|
||||||
# models
|
# models
|
||||||
model="o4-mini"
|
model_reasoning="o4-mini"
|
||||||
fallback_models=["gpt-4.1"]
|
model="gpt-4.1"
|
||||||
|
fallback_models=["o4-mini"]
|
||||||
#model_weak="gpt-4o" # optional, a weaker model to use for some easier tasks
|
#model_weak="gpt-4o" # optional, a weaker model to use for some easier tasks
|
||||||
# CLI
|
# CLI
|
||||||
git_provider="github"
|
git_provider="github"
|
||||||
@ -123,7 +124,7 @@ use_conversation_history=true
|
|||||||
|
|
||||||
|
|
||||||
[pr_code_suggestions] # /improve #
|
[pr_code_suggestions] # /improve #
|
||||||
max_context_tokens=16000
|
max_context_tokens=24000
|
||||||
#
|
#
|
||||||
commitable_code_suggestions = false
|
commitable_code_suggestions = false
|
||||||
dual_publishing_score_threshold=-1 # -1 to disable, [0-10] to set the threshold (>=) for publishing a code suggestion both in a table and as commitable
|
dual_publishing_score_threshold=-1 # -1 to disable, [0-10] to set the threshold (>=) for publishing a code suggestion both in a table and as commitable
|
||||||
@ -144,7 +145,7 @@ new_score_mechanism_th_high=9
|
|||||||
new_score_mechanism_th_medium=7
|
new_score_mechanism_th_medium=7
|
||||||
# params for '/improve --extended' mode
|
# params for '/improve --extended' mode
|
||||||
auto_extended_mode=true
|
auto_extended_mode=true
|
||||||
num_code_suggestions_per_chunk=3
|
num_code_suggestions_per_chunk=4
|
||||||
max_number_of_calls = 3
|
max_number_of_calls = 3
|
||||||
parallel_calls = true
|
parallel_calls = true
|
||||||
|
|
||||||
|
@ -19,7 +19,7 @@ from pr_agent.algo.pr_processing import (add_ai_metadata_to_diff_files,
|
|||||||
retry_with_fallback_models)
|
retry_with_fallback_models)
|
||||||
from pr_agent.algo.token_handler import TokenHandler
|
from pr_agent.algo.token_handler import TokenHandler
|
||||||
from pr_agent.algo.utils import (ModelType, load_yaml, replace_code_tags,
|
from pr_agent.algo.utils import (ModelType, load_yaml, replace_code_tags,
|
||||||
show_relevant_configurations, get_max_tokens, clip_tokens)
|
show_relevant_configurations, get_max_tokens, clip_tokens, get_model)
|
||||||
from pr_agent.config_loader import get_settings
|
from pr_agent.config_loader import get_settings
|
||||||
from pr_agent.git_providers import (AzureDevopsProvider, GithubProvider,
|
from pr_agent.git_providers import (AzureDevopsProvider, GithubProvider,
|
||||||
GitLabProvider, get_git_provider,
|
GitLabProvider, get_git_provider,
|
||||||
@ -121,7 +121,7 @@ class PRCodeSuggestions:
|
|||||||
# if not self.is_extended:
|
# if not self.is_extended:
|
||||||
# data = await retry_with_fallback_models(self._prepare_prediction, model_type=ModelType.REGULAR)
|
# data = await retry_with_fallback_models(self._prepare_prediction, model_type=ModelType.REGULAR)
|
||||||
# else:
|
# else:
|
||||||
data = await retry_with_fallback_models(self._prepare_prediction_extended, model_type=ModelType.REGULAR)
|
data = await retry_with_fallback_models(self.prepare_prediction_main, model_type=ModelType.REGULAR)
|
||||||
if not data:
|
if not data:
|
||||||
data = {"code_suggestions": []}
|
data = {"code_suggestions": []}
|
||||||
self.data = data
|
self.data = data
|
||||||
@ -416,9 +416,14 @@ class PRCodeSuggestions:
|
|||||||
data = self._prepare_pr_code_suggestions(response)
|
data = self._prepare_pr_code_suggestions(response)
|
||||||
|
|
||||||
# self-reflect on suggestions (mandatory, since line numbers are generated now here)
|
# self-reflect on suggestions (mandatory, since line numbers are generated now here)
|
||||||
model_reflection = get_settings().config.model
|
model_reflect_with_reasoning = get_model('model_reasoning')
|
||||||
|
if model_reflect_with_reasoning == get_settings().config.model and model != get_settings().config.model and model == \
|
||||||
|
get_settings().config.fallback_models[0]:
|
||||||
|
# we are using a fallback model (should not happen on regular conditions)
|
||||||
|
get_logger().warning(f"Using the same model for self-reflection as the one used for suggestions")
|
||||||
|
model_reflect_with_reasoning = model
|
||||||
response_reflect = await self.self_reflect_on_suggestions(data["code_suggestions"],
|
response_reflect = await self.self_reflect_on_suggestions(data["code_suggestions"],
|
||||||
patches_diff, model=model_reflection)
|
patches_diff, model=model_reflect_with_reasoning)
|
||||||
if response_reflect:
|
if response_reflect:
|
||||||
await self.analyze_self_reflection_response(data, response_reflect)
|
await self.analyze_self_reflection_response(data, response_reflect)
|
||||||
else:
|
else:
|
||||||
@ -675,7 +680,7 @@ class PRCodeSuggestions:
|
|||||||
get_logger().error(f"Error removing line numbers from patches_diff_list, error: {e}")
|
get_logger().error(f"Error removing line numbers from patches_diff_list, error: {e}")
|
||||||
return patches_diff_list
|
return patches_diff_list
|
||||||
|
|
||||||
async def _prepare_prediction_extended(self, model: str) -> dict:
|
async def prepare_prediction_main(self, model: str) -> dict:
|
||||||
# get PR diff
|
# get PR diff
|
||||||
if get_settings().pr_code_suggestions.decouple_hunks:
|
if get_settings().pr_code_suggestions.decouple_hunks:
|
||||||
self.patches_diff_list = get_pr_multi_diffs(self.git_provider,
|
self.patches_diff_list = get_pr_multi_diffs(self.git_provider,
|
||||||
|
Reference in New Issue
Block a user