Skip to content

10.3 LLM-as-Judge

上一节我们建立了 Benchmark 和测试集——有了"考卷"。但开放式问答题怎么打分?精确匹配太死板,人工评分太昂贵。这一节我们介绍一种"用 AI 当裁判"的评估方法——LLM-as-Judge。

生活类比:LLM-as-Judge 就像是请了一个资深教师来批阅作文——他不是死板地核对标准答案,而是从立意、结构、语言等多个维度给出评分和评语。而这位"教师"不知疲倦、成本可控、还能同时批改一万份试卷。

为什么需要 LLM-as-Judge?

传统评估方法在面对 Agent 的开放式输出时捉襟见肘:

┌──────────────────────────────────────────────────────────────────┐
│              传统评估 vs LLM-as-Judge                             │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│  传统方法:                                                       │
│  ├─ 精确匹配(Exact Match):只有完全一致才算对                     │
│  │   └─ 问题:对于开放式回答,语义相同但表达不同被判错              │
│  ├─ 规则匹配(Regex/Keywords):检查关键词是否出现                  │
│  │   └─ 问题:规则难以覆盖所有变体,维护成本高                      │
│  └─ 人工评估(Human Evaluation):最准确但最昂贵                    │
│      └─ 问题:成本高、速度慢、不可扩展                             │
│                                                                  │
│  LLM-as-Judge:                                                   │
│  ├─ 语义理解:能判断语义等价而非字面匹配                           │
│  ├─ 灵活评分:可给出多维度、多粒度的评分                           │
│  ├─ 可解释性:能给出评分理由和改进建议                             │
│  └─ 可扩展:一次 API 调用即可评估,成本可控                        │
│                                                                  │
│  核心理念:用更强的 LLM 来评估较弱 LLM / Agent 的输出              │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

生活类比:精确匹配就像让机器按"标准答案一字不差"来阅卷——"今天天气晴"和"今天是晴天"会被判为不同答案。LLM-as-Judge 则像人类老师,理解两者表达的是同一个意思。

LLM-as-Judge 的典型应用场景

场景评估内容示例
回答质量正确性、完整性、相关性"这个回答是否准确回答了用户问题?"
安全性有害内容、偏见、违规"这个回答是否包含不安全的建议?"
Agent 轨迹规划合理性、工具选择"Agent 的工具调用顺序是否合理?"
RAG 质量忠实度、上下文利用"生成内容是否忠实于检索到的文档?"
对话质量流畅度、共情、一致性"这个回复是否自然且符合上下文?"

Judge 模型的选型策略

选 Judge 模型就像选裁判——不同级别的比赛需要不同水平的裁判。社区篮球赛找个懂规则的就行,NBA 总决赛得请最顶级的裁判。

┌──────────────────────────────────────────────────────────────────┐
│                  Judge 模型选型决策树                             │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│  需要评估什么?                                                   │
│  ├─ 简单事实正确性 ──► 中等模型即可(GPT-4o-mini / Claude Haiku) │
│  ├─ 复杂推理质量 ──► 强推理模型(GPT-4o / Claude Sonnet)        │
│  ├─ 代码质量 ──► 代码专用模型或强模型(Claude 3.5 / GPT-4o)     │
│  ├─ 创意/主观质量 ──► 多 Judge 投票 + 人工校准                   │
│  └─ 安全/合规 ──► 专用安全模型 + 人工审核                        │
│                                                                  │
│  关键原则:                                                       │
│  1. Judge 模型能力 > 被评估模型能力(通常)                        │
│  2. 成本与效果平衡:高频评估用轻量模型,关键评估用强模型           │
│  3. 多模型交叉验证:减少单一模型的系统性偏差                       │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

常用 Judge 模型对比

模型优势劣势适用场景
GPT-4o综合能力强,指令遵循好成本较高通用评估
GPT-4o-mini成本低,速度快推理能力有限简单评估、大规模
Claude 3.5 Sonnet推理细腻,长文本好有时过于谨慎代码、复杂推理
Gemini 1.5 Pro长上下文,多模态一致性略低多模态评估
DeepSeek-V3性价比高生态不如 OpenAI中文场景

核心原则:用博士生改本科生的作业没问题,但反过来就会出错。Judge 模型的能力必须强于被评估的模型。

Judge Prompt 设计方法论

Judge Prompt 的设计直接决定了评估质量——就像考试评分标准写得越清楚,阅卷越准确。以下是核心设计框架:

┌──────────────────────────────────────────────────────────────────┐
│              Judge Prompt 设计框架                                │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. 角色定义(Role)                                              │
│     "你是一个专业的 AI 输出质量评估专家..."                        │
│                                                                  │
│  2. 评估维度(Dimensions)                                        │
│     明确列出评估的各个维度及权重                                   │
│                                                                  │
│  3. 评分标准(Rubric)                                            │
│     每个维度的具体评分标准,用示例说明                             │
│                                                                  │
│  4. 输出格式(Output Format)                                     │
│     严格的 JSON 格式要求,便于自动化解析                           │
│                                                                  │
│  5. 示例(Few-shot Examples)                                     │
│     提供 2-3 个标注好的评估示例                                   │
│                                                                  │
│  6. 约束条件(Constraints)                                       │
│     避免常见偏差的指令(如位置偏差、长度偏差)                     │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

Judge Prompt 模板示例

python
# Judge Prompt 模板——用于评估 Agent 回答质量
# 使用 {user_query}、{agent_response}、{expected_response} 作为占位符

JUDGE_PROMPT_TEMPLATE = """
你是一个专业的 AI Agent 输出质量评估专家。请根据以下标准评估 Agent 的回答质量。

## 评估维度

请从以下 5 个维度对回答进行评分(每个维度 1-5 分):

1. **正确性(Correctness)**:回答的事实是否正确?信息是否准确无误?
   - 5分:完全正确,所有信息准确
   - 3分:大部分正确,有少量不准确
   - 1分:严重错误,误导用户

2. **完整性(Completeness)**:回答是否完整覆盖了用户问题的所有方面?
   - 5分:全面覆盖,无遗漏
   - 3分:覆盖了主要方面,有少量遗漏
   - 1分:严重不完整,遗漏关键信息

3. **相关性(Relevance)**:回答是否与用户问题紧密相关?有无无关内容?
   - 5分:高度相关,直击要点
   - 3分:基本相关,有少量偏离
   - 1分:答非所问

4. **清晰度(Clarity)**:回答的表达是否清晰易懂?结构是否合理?
   - 5分:表达清晰,结构合理
   - 3分:基本清晰,结构可优化
   - 1分:混乱难懂

5. **有用性(Helpfulness)**:回答是否真正解决了用户的问题?
   - 5分:完美解决用户问题
   - 3分:部分解决,用户仍需补充信息
   - 1分:毫无帮助

## 用户问题
{user_query}

## Agent 回答
{agent_response}

## 期望回答(参考)
{expected_response}

## 输出格式
请严格按照以下 JSON 格式输出评估结果,不要包含任何其他内容:

```json
{{
  "scores": {{
    "correctness": <1-5>,
    "completeness": <1-5>,
    "relevance": <1-5>,
    "clarity": <1-5>,
    "helpfulness": <1-5>
  }},
  "overall_score": <1-5>,
  "strengths": ["<优点1>", "<优点2>"],
  "weaknesses": ["<不足1>", "<不足2>"],
  "suggestion": "<改进建议>"
}}

重要提醒

  • 请客观公正,不要因为回答长度而影响评分
  • 考虑回答是否真正解决了用户的问题,而非形式上的完美
  • 如果期望回答标记为"无",请仅基于用户问题判断 """

#### 实现 LLM-as-Judge 评估器

下面是完整的 LLM-as-Judge 评估器实现,代码逐行注释:

```python
import json                                      # JSON 解析
import asyncio                                   # 异步处理
from typing import Dict, List, Optional          # 类型注解
from dataclasses import dataclass, field          # 数据类
from openai import AsyncOpenAI                   # OpenAI 异步客户端


@dataclass
class EvalDimension:
    """
    评估维度定义——描述一个评估维度及其评分标准
    
    每个维度有名称、描述、权重和评分指南。
    权重决定了该维度在总分中的占比。
    """
    name: str                                 # 维度名称,如"正确性"
    description: str                          # 维度描述
    weight: float                             # 权重(0.0-1.0,所有维度权重之和为 1.0)
    scoring_guide: Dict[int, str]             # 评分指南:{5: "完全正确", 3: "大部分正确", 1: "严重错误"}


@dataclass
class EvalResult:
    """单次评估结果——一个 Judge 对一次评估的完整输出"""
    scores: Dict[str, float]                  # 各维度得分,如 {"正确性": 4.5}
    overall_score: float                      # 总分(加权平均)
    strengths: List[str]                      # 优点列表
    weaknesses: List[str]                     # 不足列表
    suggestion: str                           # 改进建议
    judge_model: str                          # 使用的 Judge 模型名称
    raw_response: str                         # Judge 的原始 JSON 响应


class LLMJudge:
    """
    LLM-as-Judge 评估器——使用 LLM 自动评估 Agent 输出质量
    
    核心流程:
    1. 构建 System Prompt(包含评估维度和评分标准)
    2. 构建 User Prompt(包含用户问题和 Agent 回答)
    3. 调用 LLM 获取评估结果(JSON 格式)
    4. 解析结果并返回 EvalResult
    """

    # 默认评估维度——5 个维度的权重之和为 1.0
    DEFAULT_DIMENSIONS = [
        EvalDimension(
            name="正确性",
            description="回答的事实准确性",
            weight=0.25,                      # 正确性权重最高
            scoring_guide={
                5: "完全正确,所有信息准确无误",
                3: "大部分正确,有少量不准确信息",
                1: "严重错误,包含误导性信息",
            }
        ),
        EvalDimension(
            name="完整性",
            description="回答是否覆盖了问题的所有方面",
            weight=0.20,
            scoring_guide={
                5: "全面覆盖,无遗漏",
                3: "覆盖主要方面,有少量遗漏",
                1: "严重不完整,遗漏关键信息",
            }
        ),
        EvalDimension(
            name="相关性",
            description="回答与用户问题的相关程度",
            weight=0.20,
            scoring_guide={
                5: "高度相关,直击要点",
                3: "基本相关,有少量偏离",
                1: "答非所问",
            }
        ),
        EvalDimension(
            name="清晰度",
            description="回答的表达清晰度和结构合理性",
            weight=0.15,
            scoring_guide={
                5: "表达清晰,结构合理,易于理解",
                3: "基本清晰,结构可优化",
                1: "混乱难懂,逻辑不清",
            }
        ),
        EvalDimension(
            name="有用性",
            description="回答是否真正解决了用户问题",
            weight=0.20,
            scoring_guide={
                5: "完美解决用户问题,可直接使用",
                3: "部分解决,用户仍需补充信息",
                1: "毫无帮助,未解决用户问题",
            }
        ),
    ]

    def __init__(
        self,
        model: str = "gpt-4o",               # Judge 模型,默认 GPT-4o
        api_key: Optional[str] = None,        # API Key
        base_url: Optional[str] = None,       # 自定义 API 地址(可选)
    ):
        self.model = model                    # 保存模型名称
        self.client = AsyncOpenAI(            # 初始化异步 OpenAI 客户端
            api_key=api_key,
            base_url=base_url,
        )
        self.dimensions = self.DEFAULT_DIMENSIONS  # 使用默认评估维度

    def _build_system_prompt(self) -> str:
        """构建系统提示词——包含评估维度、评分规则和输出格式"""
        # 拼接所有维度的描述
        dims_desc = "\n".join([
            f"  - {d.name}(权重 {d.weight}):{d.description}\n"
            f"    {d.scoring_guide}"
            for d in self.dimensions
        ])

        return f"""你是一个专业的 AI 输出质量评估专家。请严格按照以下标准评估回答质量。

## 评估维度
{dims_desc}

## 评分规则
- 每个维度给出 1-5 分的整数评分
- 总分 = sum(各维度分数 × 权重)
- 必须给出具体的优点和不足
- 必须给出可操作的改进建议

## 输出格式
必须是合法的 JSON,格式如下:
{{
  "scores": {{"维度名": 分数, ...}},
  "overall_score": 总分(保留 1 位小数),
  "strengths": ["优点1", "优点2"],
  "weaknesses": ["不足1", "不足2"],
  "suggestion": "改进建议"
}}

## 重要提醒
- 客观公正,不受回答长度影响
- 基于回答内容本身判断,不为缺失的信息编造理由
- 如果回答确实优秀,大方给高分;如果确实差,果断给低分
"""

    async def evaluate(
        self,
        user_query: str,                     # 用户问题
        agent_response: str,                  # Agent 的回答
        expected_response: Optional[str] = None,  # 期望回答(可选)
    ) -> EvalResult:
        """执行评估——核心方法"""
        # 构建 User Prompt
        user_prompt = f"""## 用户问题
{user_query}

## Agent 回答
{agent_response}
"""
        # 如果有期望回答,添加到 Prompt 中
        if expected_response:
            user_prompt += f"""
## 参考回答
{expected_response}
"""

        # 调用 LLM API
        response = await self.client.chat.completions.create(
            model=self.model,
            messages=[
                {"role": "system", "content": self._build_system_prompt()},
                {"role": "user", "content": user_prompt},
            ],
            temperature=0.1,                 # 低温度以获得一致的评估结果
            response_format={"type": "json_object"},  # 强制 JSON 输出
        )

        raw = response.choices[0].message.content  # 获取原始响应文本
        parsed = json.loads(raw)                    # 解析 JSON

        return EvalResult(
            scores=parsed["scores"],
            overall_score=parsed["overall_score"],
            strengths=parsed["strengths"],
            weaknesses=parsed["weaknesses"],
            suggestion=parsed["suggestion"],
            judge_model=self.model,
            raw_response=raw,
        )


# 使用示例
async def main():
    """演示 LLM-as-Judge 的使用"""
    judge = LLMJudge(model="gpt-4o")         # 初始化 Judge

    # 测试用例
    test_cases = [
        {
            "query": "Python 中如何读取 CSV 文件?",
            "response": "用 pandas 的 read_csv 函数即可,例如 pd.read_csv('file.csv')",
            "expected": "可以使用 csv 模块或 pandas 库。csv 模块:csv.reader();pandas:pd.read_csv()。",
        },
        {
            "query": "解释一下什么是递归?",
            "response": "递归就是函数自己调用自己。",
            "expected": "递归是一种编程技巧,函数通过调用自身来解决子问题。需要基准条件和递归条件。",
        },
    ]

    for i, case in enumerate(test_cases):
        result = await judge.evaluate(
            user_query=case["query"],
            agent_response=case["response"],
            expected_response=case["expected"],
        )
        print(f"\n{'='*50}")
        print(f"测试用例 {i+1}: {case['query'][:30]}...")
        print(f"总分: {result.overall_score}")
        print(f"各维度: {json.dumps(result.scores, ensure_ascii=False)}")
        print(f"优点: {result.strengths}")
        print(f"不足: {result.weaknesses}")
        print(f"建议: {result.suggestion}")


if __name__ == "__main__":
    asyncio.run(main())                      # 运行异步主函数

多 Judge 投票机制

单一 Judge 可能存在系统性偏差——就像只有一个裁判的比赛,裁判的主观倾向会影响结果。多 Judge 投票可以显著提升评估的可靠性。

┌──────────────────────────────────────────────────────────────────┐
│                  多 Judge 投票架构                                │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│                    ┌──────────────┐                              │
│                    │  待评估输出   │                              │
│                    └──────┬───────┘                              │
│                           │                                      │
│          ┌────────────────┼────────────────┐                     │
│          │                │                │                     │
│     ┌────▼────┐     ┌────▼────┐     ┌────▼────┐                  │
│     │ Judge A │     │ Judge B │     │ Judge C │                  │
│     │(GPT-4o) │     │(Claude) │     │(Gemini) │                  │
│     └────┬────┘     └────┬────┘     └────┬────┘                  │
│          │               │               │                       │
│          │   评分 A      │   评分 B      │   评分 C              │
│          └───────────────┼───────────────┘                       │
│                          │                                       │
│                   ┌──────▼──────┐                                │
│                   │  投票/聚合   │                                │
│                   │  - 多数投票  │                                │
│                   │  - 加权平均  │                                │
│                   │  - 一致性检查│                                │
│                   └──────┬──────┘                                │
│                          │                                       │
│                    ┌─────▼─────┐                                 │
│                    │  最终评分  │                                 │
│                    └───────────┘                                 │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

生活类比:多 Judge 投票就像选秀节目的评委团——三个评委各自打分,取平均或多数意见。单个评委可能有偏好(比如偏爱某种风格),但三个不同风格的评委一起评,偏好就被中和了。

多 Judge 聚合策略

策略方法适用场景
多数投票取多数 Judge 一致的结果分类任务(通过/不通过)
加权平均按 Judge 可靠性加权取平均连续评分任务
中位数取中位数,抵抗极端值存在 outlier Judge 时
一致性过滤仅保留一致性高的评估需要高置信度时

多 Judge 投票系统实现

python
import asyncio                                  # 异步并发
import json
import numpy as np                               # 数值计算
from typing import Dict, List, Optional
from dataclasses import dataclass


@dataclass
class JudgeConfig:
    """
    Judge 配置——描述一个 Judge 实例的配置
    
    weight 用于加权平均:权重越高,该 Judge 的评分影响力越大。
    """
    name: str                                 # Judge 名称,如 "judge_gpt4o"
    model: str                                # 模型名称,如 "gpt-4o"
    api_key: str                              # API Key
    base_url: str                             # API 地址
    weight: float = 1.0                      # 权重(默认 1.0,等权)


class MultiJudgeSystem:
    """
    多 Judge 投票系统——并行调用多个 Judge 并聚合结果
    
    优势:
    - 减少单一模型的系统性偏差
    - 不同模型家族交叉验证
    - 一致性检查可识别分歧较大的评估项
    """

    def __init__(self, judges: List[JudgeConfig]):
        """初始化多 Judge 系统"""
        self.judges = judges                  # Judge 配置列表
        self.judge_instances = {}             # Judge 实例字典
        for config in judges:
            self.judge_instances[config.name] = LLMJudge(
                model=config.model,
                api_key=config.api_key,
                base_url=config.base_url,
            )

    async def evaluate(
        self,
        user_query: str,
        agent_response: str,
        expected_response: Optional[str] = None,
    ) -> Dict:
        """多 Judge 并行评估——同时调用所有 Judge"""
        tasks = []                            # 异步任务列表
        for name, judge in self.judge_instances.items():
            tasks.append(
                judge.evaluate(user_query, agent_response, expected_response)
            )

        # 并行执行所有 Judge 评估
        results: List[EvalResult] = await asyncio.gather(*tasks)

        aggregated = self._aggregate_results(results)    # 聚合结果
        consensus = self._check_consensus(results)        # 一致性检查

        return {
            "aggregated": aggregated,          # 聚合后的评分
            "consensus": consensus,            # 一致性分析
            "individual_results": [             # 各 Judge 的详细结果
                {
                    "judge": config.name,
                    "model": config.model,
                    "overall_score": result.overall_score,
                    "scores": result.scores,
                }
                for config, result in zip(self.judges, results)
            ],
        }

    def _aggregate_results(self, results: List[EvalResult]) -> Dict:
        """聚合多个 Judge 的结果——加权平均"""
        weights = [j.weight for j in self.judges]  # 提取权重列表

        # 加权平均总分
        overall_scores = [r.overall_score for r in results]
        weighted_avg = np.average(overall_scores, weights=weights)

        # 各维度加权平均
        dim_scores = {}                       # 维度 -> 分数列表
        all_dims = set()                      # 所有出现的维度
        for r in results:
            all_dims.update(r.scores.keys())

        for dim in all_dims:
            dim_values = [r.scores.get(dim, 0) for r in results]
            dim_scores[dim] = np.average(dim_values, weights=weights)

        std_dev = np.std(overall_scores)      # 标准差(衡量一致性)
        median = np.median(overall_scores)    # 中位数

        return {
            "weighted_avg": round(weighted_avg, 1),
            "median": round(median, 1),
            "std_dev": round(std_dev, 2),     # 标准差越小,一致性越高
            "dimension_scores": {
                dim: round(score, 1) for dim, score in dim_scores.items()
            },
            "min_score": min(overall_scores),
            "max_score": max(overall_scores),
        }

    def _check_consensus(
        self, results: List[EvalResult], threshold: float = 0.5
    ) -> Dict:
        """
        检查 Judges 之间的一致性
        
        - 高一致性:std_dev < 0.5(可直接采纳)
        - 中一致性:std_dev < 1.0(建议人工抽检)
        - 低一致性:std_dev >= 1.0(需要人工评估)
        """
        scores = [r.overall_score for r in results]
        std_dev = np.std(scores)              # 计算标准差

        if std_dev < 0.5:
            level = "高"
            action = "可以直接采纳聚合结果"
        elif std_dev < 1.0:
            level = "中"
            action = "建议人工抽检低分项"
        else:
            level = "低"
            action = "需要进行人工评估,或检查 Judge Prompt"

        # 找出分歧较大的维度
        disagreements = []
        if std_dev >= 0.5:
            dim_scores = {}
            for r in results:
                for dim, score in r.scores.items():
                    if dim not in dim_scores:
                        dim_scores[dim] = []
                    dim_scores[dim].append(score)
            for dim, values in dim_scores.items():
                if np.std(values) >= 1.0:     # 维度内标准差 >= 1.0
                    disagreements.append(dim)

        return {
            "level": level,
            "std_dev": round(std_dev, 2),
            "action": action,
            "disagreed_dimensions": disagreements,  # 分歧较大的维度
        }


# 使用示例
async def multi_judge_demo():
    """多 Judge 评估演示"""
    judges = [
        JudgeConfig(
            name="judge_gpt4o",
            model="gpt-4o",
            api_key="your-openai-key",
            base_url="https://api.openai.com/v1",
            weight=1.0,                      # 等权
        ),
        JudgeConfig(
            name="judge_claude",
            model="claude-3-5-sonnet-20241022",
            api_key="your-anthropic-key",
            base_url="https://api.anthropic.com/v1",
            weight=1.0,
        ),
        JudgeConfig(
            name="judge_gpt4o_mini",
            model="gpt-4o-mini",
            api_key="your-openai-key",
            base_url="https://api.openai.com/v1",
            weight=0.5,                      # 轻量模型权重较低
        ),
    ]

    system = MultiJudgeSystem(judges)

    result = await system.evaluate(
        user_query="解释 Kubernetes 中 Pod 和 Service 的关系",
        agent_response="Pod 是 K8s 中运行容器的基本单元,Service 是为 Pod 提供稳定网络访问的抽象。",
        expected_response="Pod 是部署和运行容器的最小单元。Service 是为一组 Pod 提供统一访问入口的抽象层。",
    )

    print("多 Judge 评估结果")
    print("=" * 50)
    print(f"\n聚合结果:")
    print(f"  加权平均: {result['aggregated']['weighted_avg']}")
    print(f"  中位数:   {result['aggregated']['median']}")
    print(f"  标准差:   {result['aggregated']['std_dev']}")

    print(f"\n一致性:")
    print(f"  级别: {result['consensus']['level']}")
    print(f"  建议: {result['consensus']['action']}")

    print(f"\n各 Judge 详细结果:")
    for r in result['individual_results']:
        print(f"  {r['judge']} ({r['model']}): {r['overall_score']}")


if __name__ == "__main__":
    asyncio.run(multi_judge_demo())

LLM-as-Judge 的常见偏差与缓解

LLM 作为 Judge 并非完美,它也有自己的"偏见"。了解这些偏差并采取缓解策略,是保证评估质量的关键:

┌──────────────────────────────────────────────────────────────────┐
│              常见偏差类型及缓解策略                                │
├──────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. 位置偏差(Position Bias)                                     │
│     问题:Judge 倾向于给靠前的选项更高分                          │
│     缓解:随机打乱选项顺序,多次评估取平均                         │
│                                                                  │
│  2. 长度偏差(Length Bias)                                       │
│     问题:Judge 倾向于给更长的回答更高分                          │
│     缓解:在 Prompt 中明确要求忽略长度,控制输出长度               │
│                                                                  │
│  3. 自我增强偏差(Self-enhancement Bias)                         │
│     问题:Judge 倾向于给风格与自己相似的输出更高分                 │
│     缓解:使用不同家族的模型作为 Judge                            │
│                                                                  │
│  4. 顺序效应(Order Effect)                                      │
│     问题:评估顺序影响评分(疲劳效应或对比效应)                   │
│     缓解:随机化评估顺序,控制批次大小                            │
│                                                                  │
│  5. 锚定效应(Anchoring Effect)                                  │
│     问题:先看到的评分标准或示例会影响后续判断                     │
│     缓解:使用明确的 Rubric,减少模糊空间                        │
│                                                                  │
│  6. 幻觉(Hallucination in Judge)                                │
│     问题:Judge 自己编造不存在的错误或优点                        │
│     缓解:要求 Judge 引用原文中的具体内容来支持判断               │
│                                                                  │
└──────────────────────────────────────────────────────────────────┘

生活类比

  • 位置偏差:就像老师阅卷时,先看的几份卷子普遍给分宽松,后面的越改越严。
  • 长度偏差:就像"作文写得长就给高分"——内容空洞但字数多的反而比精炼的好文得分高。
  • 自我增强偏差:就像文科老师给文科风格的文章打分更高,理科风格被低估。
  • 幻觉:Judge 说"第三段引用了错误的数据",但其实原文根本没有第三段——这就是 Judge 自己"编"出来的。

常见误区

误区一:Judge 模型和被评估模型用同一个

用 GPT-4o 评估 GPT-4o 的输出,Judge 会天然偏好与自己风格相似的回答——这就是"自我增强偏差"。正确做法是使用不同家族的模型,或至少用更强版本的模型评估较弱版本的输出。

误区二:Prompt 写得太简单,Judge 自由发挥

如果只告诉 Judge "请评估这个回答的好坏",它可能给出"挺好的"这样模糊的评语。必须明确评估维度、评分标准(Rubric)和输出格式,才能得到可量化、可自动解析的结果。

误区三:不校准 Judge 的一致性

LLM-as-Judge 不是"设好就忘"的。随着模型版本更新和业务变化,Judge 的评估标准可能漂移。建议定期用人工标注的样本校准 Judge,确保评估质量不退化。

误区四:忽视 JSON 解析失败的情况

LLM 有时不会严格按 JSON 格式输出——可能多了说明文字、嵌套了代码块、或者格式错误。生产代码必须包含 JSON 解析失败的重试逻辑和容错处理。

本节小结

概念关键点实践建议
Judge 模型选择能力 > 被评估模型用 GPT-4o 评估 GPT-4o-mini,不要反向
Prompt 设计明确维度 + Rubric + 示例至少提供 2-3 个标注示例
输出格式强制 JSON使用 response_format={"type": "json_object"}
多 Judge不同模型家族交叉验证3 个不同模型家族的 Judge
偏差缓解位置/长度/自我增强随机化、Rubric 约束、多模型
成本控制高频评估用轻量模型GPT-4o-mini 做初筛,GPT-4o 做复核

关键原则

  • LLM-as-Judge 是目前评估开放式 Agent 输出的最实用方案,但需要精心设计 Prompt
  • Judge 模型的选择应遵循"用更强的模型评估较弱模型"的原则
  • 多 Judge 投票可以显著降低单一模型的系统性偏差,代价是成本和延迟增加
  • 定期用人工评估校准 Judge 的一致性,确保评估质量不退化
  • 结构化输出(JSON)是自动化评估流水线的基础

有了自动评分的"阅卷老师",下一步需要把评估流程嵌入开发流水线——这正是 10.4 节评估自动化要解决的问题。