Repository: modelscope/evalscope
Issue: [Bug] CompetitionMathAdapter missing extract_answer method for prediction parsing
Root cause: Unimplemented Feature Gap

## 🐛 Bug Description

The `CompetitionMathAdapter` class is missing the `extract_answer()` method to parse model predictions, which causes evaluation to fail in correctly extracting the answer from the model's output.

`CompetitionMathAdapter` 类缺少 `extract_answer()` 方法来解析模型预测结果，这会导致评测时无法正确从模型输出中提取答案。

## 📍 Location

**File:** `evalscope/benchmarks/competition_math/competition_math_adapter.py`

## 🔍 Analysis

### Current Implementation

The `CompetitionMathAdapter` only uses `extract_answer` from `math_parser` in the `record_to_sample` method to process the **ground truth answer**:

```python
def record_to_sample(self, record: Dict[str, Any]) -> Sample:
    from evalscope.metrics.math_parser import extract_answer

    return Sample(
        input=record['problem'],
        target=extract_answer(record['solution']),  # Only for ground truth
        subset_key=record['level'],
        metadata={
            'reasoning': record.get('solution', ''),
            'type': record.get('type', ''),
        },
    )
```

However, it **does not implement** the `extract_answer(self, prediction: str, task_state: TaskState)` method to extract answers from **model predictions**.

### Expected Behavior

The prompt template asks models to put their answer in `\boxed{}`:

```python
PROMPT_TEMPLATE = """
Problem:
{question}

Please reason step by step, and put your final answer within \\boxed{{}}.
""".lstrip()
```

But without the `extract_answer()` method, the adapter cannot extract the answer from the `\boxed{...}` format in the model's response.

### Comparison with GSM8K

The `GSM8KAdapter` correctly implements this method:

```python
def extract_answer(self, prediction: str, task_state: TaskState):
    from evalscope.filters.extraction import RegexFilter
    
    regex = RegexFilter(regex_pattern=r'(-?[0-9.,]{2,})|(-?[0-9]+)', group_select=-1)
    res = regex(prediction)
    return res.replace(',', '').replace('+', '').strip().strip('.')
```

## 💡 Proposed Solution

Add the `extract_answer` method to `CompetitionMathAdapter`:

```python
def extract_answer(self, prediction: str, task_state: TaskState) -> str:
    """
    Extract the answer from the model's prediction.
    The answer should be in \\boxed{answer} format as per the prompt template.
    
    Args:
        prediction: The model's prediction text
        task_state: The task state for additional context
        
    Returns:
        str: The extracted answer
    """
    from evalscope.metrics.math_parser import extract_answer
    
    # Use the same extraction logic as used for the target answer
    return extract_answer(prediction)
```

## 🔄 Impact

Without this method:
- The evaluation cannot properly extract answers from model predictions
- Accuracy calculations will be incorrect
- The benchmark evaluation for MATH dataset is broken

## 📋 Checklist

- [ ] Add `extract_answer` method to `CompetitionMathAdapter`
- [ ] Add unit tests to verify answer extraction works correctly
- [ ] Test with actual model outputs containing `\boxed{...}` format
- [ ] Verify that evaluation metrics are calculated correctly after the fix

## 🔗 Related Files

- `evalscope/benchmarks/competition_math/competition_math_adapter.py` - Need to fix
- `evalscope/benchmarks/gsm8k/gsm8k_adapter.py` - Reference implementation
- `evalscope/metrics/math_parser.py` - Contains the `extract_answer` utility function

## 📌 Environment

- EvalScope version: v1.1.0
- Python version: 3.10+