评估:衡量模型能力的标尺

大模型评估是AI发展中最基础也最具挑战性的工作。没有好的评估方法,就无法判断技术进步,也无法做合理的模型选型。本文构建一个全面的大模型评估框架。

评估维度体系

能力维度

EVALUATION_DIMENSIONS = {
    "知识能力": {
        "MMLU-Pro": "多任务语言理解(学术知识)",
        "C-Eval": "中文综合能力",
        "BBH": "BIG-Bench Hard(推理)",
        "TruthfulQA": "真实性评估"
    },
    "推理能力": {
        "GSM8K": "小学数学推理",
        "MATH": "高等数学推理",
        "GPQA": "研究生水平问答",
        "ARC": "科学推理"
    },
    "代码能力": {
        "HumanEval": "Python代码生成",
        "MBPP": "基础编程",
        "SWE-bench": "软件工程任务",
        "LiveCodeBench": "实时编程竞赛"
    },
    "语言能力": {
        "MT-Bench": "多轮对话",
        "AlpacaEval": "指令跟随",
        "IFEval": "指令执行评估"
    },
    "安全对齐": {
        "AdvBench": "对抗性提示",
        "HarmBench": "有害行为测试",
        "BBQ": "偏见评估"
    }
}

基准测试

标准化测试流程

class BenchmarkRunner:
    def __init__(self, model, config):
        self.model = model
        self.config = config
    
    def run_all(self):
        results = {}
        for bench_name, bench_class in BENCHMARKS.items():
            results[bench_name] = self._run_benchmark(bench_name, bench_class)
        return results
    
    def _run_benchmark(self, name, bench_class):
        benchmark = bench_class()
        
        # 多次运行取平均(降低随机性)
        scores = []
        for run in range(self.config.get("n_runs", 1)):
            score = self._single_run(benchmark)
            scores.append(score)
        
        return {
            "benchmark": name,
            "scores": scores,
            "mean": np.mean(scores),
            "std": np.std(scores),
            "details": self._collect_details(benchmark)
        }
    
    def _single_run(self, benchmark):
        correct = 0
        for question in benchmark.questions:
            response = self.model.generate(
                question.prompt,
                temperature=0.0,  # 贪婪解码,确保可复现
                max_tokens=question.max_tokens
            )
            
            if benchmark.check_answer(response, question.answer):
                correct += 1
        
        return correct / len(benchmark.questions)

评估中的常见陷阱

class EvaluationPitfalls:
    pitfalls = {
        "数据污染": {
            "description": "测试集出现在训练数据中",
            "detection": "检查测试问题是否在训练数据中出现",
            "mitigation": "使用动态更新的测试集,如LiveCodeBench"
        },
        "格式敏感性": {
            "description": "模型答案正确但格式不匹配",
            "detection": "人工检查错误样本",
            "mitigation": "使用灵活的答案匹配(正则/语义匹配)"
        },
        "位置偏差": {
            "description": "多选题中模型偏好某些位置",
            "detection": "打乱选项顺序重新测试",
            "mitigation": "多次测试取平均"
        },
        "提示敏感性": {
            "description": "不同prompt模板导致分数差异大",
            "detection": "用多种prompt模板测试",
            "mitigation": "报告多个模板的平均分"
        }
    }

人类偏好评估

LLM-as-Judge

class LLMJudge:
    def __init__(self, judge_model="gpt-4o"):
        self.judge = judge_model
    
    def evaluate(self, question, response_a, response_b):
        """用强模型评估两个回答的优劣"""
        prompt = f"""
        请评估以下两个回答的质量。
        
        问题:{question}
        
        回答A:{response_a}
        回答B:{response_b}
        
        评估维度(1-10分):
        1. 准确性:信息是否正确
        2. 完整性:是否充分回答了问题
        3. 清晰度:表达是否清晰易懂
        4. 有用性:对提问者是否有帮助
        
        输出JSON:
        {{
            "A": {{"accuracy": X, "completeness": X, "clarity": X, "helpfulness": X}},
            "B": {{"accuracy": X, "completeness": X, "clarity": X, "helpfulness": X}},
            "winner": "A" | "B" | "tie",
            "reasoning": "..."
        }}
        """
        
        return self.judge.generate(prompt)
    
    def evaluate_with_rubric(self, question, response, rubric):
        """基于评分标准的评估"""
        prompt = f"""
        按以下评分标准评估回答:
        
        问题:{question}
        回答:{response}
        
        评分标准:
        {rubric}
        
        对每个标准给出1-5分和具体理由。
        """
        
        return self.judge.generate(prompt)

人类评估

class HumanEvaluation:
    def __init__(self):
        self.evaluators = []
        self.tasks = []
    
    def setup_eval(self, questions, responses, criteria):
        """设置人类评估任务"""
        for q, responses_pair in zip(questions, responses):
            self.tasks.append({
                "question": q,
                "response_a": responses_pair[0],
                "response_b": responses_pair[1],
                "criteria": criteria
            })
    
    def collect_ratings(self):
        """收集人类评估结果"""
        results = []
        for task in self.tasks:
            # 呈现给评估者
            rating = self._present_to_evaluator(task)
            results.append(rating)
        
        # 计算一致性
        agreement = self._compute_inter_annotator_agreement(results)
        
        return {
            "results": results,
            "inter_annotator_agreement": agreement,
            "elo_ratings": self._compute_elo(results)
        }
    
    def _compute_inter_annotator_agreement(self, results):
        """计算评估者间一致性"""
        from sklearn.metrics import cohen_kappa_score
        # 如果一致性<0.6,说明评估标准需要改进
        return cohen_kappa_score(results[0], results[1])

Elo评分系统

class EloRatingSystem:
    def __init__(self, k=32):
        self.k = k
        self.ratings = {}  # model_name -> elo rating
    
    def update(self, model_a, model_b, result):
        """根据对战结果更新Elo分"""
        ra = self.ratings.get(model_a, 1200)
        rb = self.ratings.get(model_b, 1200)
        
        # 预期胜率
        ea = 1 / (1 + 10 ** ((rb - ra) / 400))
        eb = 1 - ea
        
        # 实际结果
        if result == "A":
            sa, sb = 1, 0
        elif result == "B":
            sa, sb = 0, 1
        else:  # tie
            sa, sb = 0.5, 0.5
        
        # 更新分数
        self.ratings[model_a] = ra + self.k * (sa - ea)
        self.ratings[model_b] = rb + self.k * (sb - eb)
    
    def get_rankings(self):
        return sorted(self.ratings.items(), key=lambda x: x[1], reverse=True)

专项评估

代码评估

class CodeEvaluation:
    def evaluate(self, model, problems):
        """代码生成评估"""
        results = {
            "pass@1": 0,
            "pass@10": 0,
            "pass@100": 0,
            "syntax_error_rate": 0,
            "runtime_error_rate": 0
        }
        
        for problem in problems:
            # 生成多个解决方案
            solutions = [model.generate(problem.prompt) for _ in range(100)]
            
            # 逐个测试
            passed = 0
            for solution in solutions:
                result = self._run_tests(solution, problem.test_cases)
                if result["passed"]:
                    passed += 1
                elif result["error_type"] == "syntax":
                    results["syntax_error_rate"] += 1
                elif result["error_type"] == "runtime":
                    results["runtime_error_rate"] += 1
            
            # pass@k
            results["pass@1"] += passed > 0
            results["pass@10"] += passed > 10
            results["pass@100"] += passed > 0
        
        # 归一化
        n = len(problems)
        for k in ["pass@1", "pass@10", "pass@100"]:
            results[k] /= n
        for k in ["syntax_error_rate", "runtime_error_rate"]:
            results[k] /= (n * 100)
        
        return results

安全评估

class SafetyEvaluation:
    def __init__(self):
        self.attack_prompts = self._load_attack_prompts()
    
    def evaluate(self, model):
        """安全评估"""
        results = {
            "jailbreak_success": 0,
            "harmful_content_generated": 0,
            "bias_detected": 0,
            "pii_leaked": 0
        }
        
        # 越狱测试
        for attack in self.attack_prompts["jailbreak"]:
            response = model.generate(attack["prompt"])
            if self._is_jailbreak_successful(response, attack["target"]):
                results["jailbreak_success"] += 1
        
        # 有害内容测试
        for prompt in self.attack_prompts["harmful"]:
            response = model.generate(prompt)
            if self._is_harmful(response):
                results["harmful_content_generated"] += 1
        
        # 偏见测试
        for prompt in self.attack_prompts["bias"]:
            response = model.generate(prompt)
            bias_score = self._measure_bias(response)
            if bias_score > 0.5:
                results["bias_detected"] += 1
        
        total = len(self.attack_prompts["jailbreak"])
        for k in results:
            results[k] = {"count": results[k], "rate": results[k] / total}
        
        return results

评估报告生成

class EvaluationReportGenerator:
    def generate(self, model_name, results):
        """生成综合评估报告"""
        return f"""
# {model_name} 评估报告

## 综合评分
- 知识能力: {results['knowledge']['mean']:.1f}/100
- 推理能力: {results['reasoning']['mean']:.1f}/100
- 代码能力: {results['coding']['pass@1']*100:.1f}%
- 对话能力: {results['dialogue']['elo']:.0f} Elo
- 安全性: {results['safety']['safe_rate']*100:.1f}%

## 详细分析

### 优势
{self._format_strengths(results)}

### 弱项
{self._format_weaknesses(results)}

### 与其他模型对比
{self._format_comparison(model_name, results)}

### 数据污染检查
{self._contamination_report(results)}

## 结论
{self._conclusion(results)}
"""

结语

大模型评估是一个持续演进的领域。随着模型能力提升,旧的基准被攻克,新的更难的基准被提出。没有单一的评估方法能全面衡量模型能力——知识、推理、代码、安全、对齐需要不同的评估方法。最重要的是:评估的目的不是排名,而是理解模型的能力边界,指导合理使用。