English
主导航

旧版 API

评分器

了解用于评估和微调的评分器。

评分器是一种根据参考答案评估模型性能的方法。我们的 评分器 API 提供了一种测试评分器、分析实验结果并改进您的微调或评估框架的途径,以获得您期望的结果。

概览

评分器用于将参考答案与模型生成的对应答案进行比较,并返回 0 到 1 范围内的评分。给模型的答案提供部分分数,而不是非 0 即 1 的二元评分,有时会很有帮助。

评分器以 JSON 格式指定,包含以下几种类型:

在强化微调中,你可以使用以下方式嵌套和组合评分器: 多重评分器.

使用本指南了解每种评分器类型并查看入门示例。要构建评分器并开始使用强化微调,请参阅 RFT 指南。或者要开始使用评估,请参阅 评估指南.

模板化

某些评分器的输入使用模板化语法,以便使用相同的配置对多个示例进行评分。任何带有 {{ }} 双大括号的字符串都将被替换为变量值。

其中每个输入 {{}} 必须包含一个 命名空间 and a 变量 with the following format {{ namespace.variable }}。唯一支持的命名空间是 item and sample.

可以使用类似 JSON 路径的语法访问所有嵌套变量。

Item 命名空间

Item 命名空间将填充来自评估输入数据源的变量,以及来自微调时各个数据集项的变量。例如,如果某一行包含以下内容

1
2
3
{
  "reference_answer": "..."
}

这可以在评分器中用作 {{ item.reference_answer }}.

Sample 命名空间

Sample 命名空间将填充来自评估期间模型采样步骤或微调步骤的变量。包含以下变量

  • output_text,模型输出的内容作为字符串。
  • output_json,模型输出的内容作为 JSON 对象,仅当 response_format 包含在 sample 中。
  • output_tools,模型输出 tool_calls,它们与输出中的工具调用具有相同的结构,在 Chat Completions API.
  • choices,即输出选项,其结构与 Chat Completions API.
  • output_audio中的输出选项结构相同,即包含 Base64 编码的模型音频输出对象 data and a transcript.

例如,要以字符串形式访问模型输出内容, {{ sample.output_text }} 可在评分器中使用。

字符串检查评分器

使用这些简单的字符串操作来返回 0 或 1。字符串检查评分器适用于对简单的通过与未通过答案进行评分——例如,正确的城市名称、是或否的回答,或者包含或以正确信息开头的答案。

1
2
3
4
5
6
7
{
    "type": "string_check",
    "name": string,
    "operation": "eq" | "ne" | "like" | "ilike",
    "input": string,
    "reference": string,
}

string-check-grader 支持的操作有:

  • eq: 如果输入与参考匹配(区分大小写),则返回 1,否则返回 0
  • neq: 如果输入与参考不匹配(区分大小写),则返回 1,否则返回 0
  • like: 如果输入包含参考(区分大小写),则返回 1,否则返回 0
  • ilike: 如果输入包含参考(不区分大小写),则返回 1,否则返回 0

文本相似度评分器

当需要评估模型生成的输出与参考文本的接近程度,并使用各种评估框架进行打分时,请使用文本相似度评分器。

这对于开放式的文本回复非常有用。例如,如果您的数据集包含专家以段落形式提供的参考答案,它可以帮您以数值形式查看模型生成的答案与该内容的接近程度。

1
2
3
4
5
6
7
8
{
    "type": "text_similarity",
    "name": string,
    "input": string,
    "reference": string,
    "pass_threshold": number,
    "evaluation_metric": "fuzzy_match" | "bleu" | "gleu" | "meteor" | "cosine" | "rouge_1" | "rouge_2" | "rouge_3" | "rouge_4" | "rouge_5" | "rouge_l"
}

] 支持的操作 string-similarity-grader are:

  • fuzzy_match: 使用以下方式计算输入与参考之间的模糊字符串匹配 rapidfuzz
  • bleu: 计算输入与参考之间的 BLEU 分数
  • gleu: 计算输入与参考之间的 Google BLEU 分数
  • meteor: 计算输入与参考之间的 METEOR 分数
  • cosine: 使用以下方式计算嵌入后的输入与参考之间的余弦相似度 text-embedding-3-large. 仅在评估中可用。
  • rouge-*: 计算输入与参考之间的 ROUGE 分数

模型评分器

通常,使用模型评分器意味着提示一个单独的模型来为您正在微调的模型输出进行评分。您的两个模型协同工作以进行强化微调。 评分器模型 负责评估 训练模型.

分数模型评分器

分数模型评分器将接收输入,并根据给定范围内的提示返回一个数值分数。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
{
    "type": "score_model",
    "name": string,
    "input": Message[],
    "model": string,
    "pass_threshold": number,
    "range": number[],
    "sampling_params": {
        "seed": number,
        "top_p": number,
        "temperature": number,
        "max_completions_tokens": number,
        "reasoning_effort": "minimal" | "low" | "medium" | "high"
    }
}

其中每条消息的格式如下:

1
2
3
4
{
    "role": "system" | "developer" | "user" | "assistant",
    "content": str
}

要使用评分模型评分器,输入是一个聊天消息列表,每条消息包含一个 role and content。评分器的输出将被截断至给定的 range, 并且对于所有非数字输出默认为 0。在每条消息中,可以使用与其他常见评分器相同的模板来引用真实标签或模型样本。

以下是完整的可运行代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
import os
import requests

# get the API key from environment
api_key = os.environ["OPENAI_API_KEY"]
headers = {"Authorization": f"Bearer {api_key}"}

# define a dummy grader for illustration purposes
grader = {
   "type": "score_model",
   "name": "my_score_model",
   "input": [
        {
            "role": "system",
            "content": "You are an expert grader. If the reference and model answer are exact matches, output a score of 1. If they are somewhat similar in meaning, output a score in 0.5. Otherwise, give a score of 0."
        },
        {
            "role": "user",
            "content": "Reference: {{ item.reference_answer }}. Model answer: {{ sample.output_text }}"
        }
   ],
   "pass_threshold": 0.5,
   "model": "o4-mini-2025-04-16",
   "range": [0, 1],
   "sampling_params": {
       "max_completions_tokens": 32768,
       "top_p": 1,
       "reasoning_effort": "medium"
   },
}

# validate the grader
payload = {"grader": grader}
response = requests.post(
    "https://api.openai.com/v1/fine_tuning/alpha/graders/validate",
    json=payload,
    headers=headers
)
print("validate response:", response.text)

# run the grader with a test reference and sample
payload = {
  "grader": grader,
  "item": {
     "reference_answer": 1.0
  },
  "model_sample": "0.9"
}
response = requests.post(
    "https://api.openai.com/v1/fine_tuning/alpha/graders/run",
    json=payload,
    headers=headers
)
print("run response:", response.text)

评分模型评分器输出

在内部, score_model 评分器将使用提供的提示和采样参数来查询请求的模型,并以特定的响应格式请求回复。所使用的响应格式如下

1
2
3
4
{
  "result": float,
  "steps": ReasoningStep[],
}

其中每个推理步骤的格式为

1
2
3
4
{
    description: string,
    conclusion: string
}

此格式不仅要求模型提供数字 result (查询的奖励值),而且还为模型提供了一些空间来思考分数背后的推理过程。在编写评分器提示时,按名称显式引用这两个字段可能会很有用(例如,“在推理步骤的结论中包含有关分子中化学键类型的推理”,或者“在 result 字段,如果输入不满足条件 X”)。

模型评分器约束

  • 仅以下模型支持用于 model 参数`
    • gpt-4o-2024-08-06
    • gpt-4o-mini-2024-07-18
    • gpt-4.1-2025-04-14
    • gpt-4.1-mini-2025-04-14
    • gpt-4.1-nano-2025-04-14
    • o1-2024-12-17
    • o3-mini-2025-01-31
    • o3-2025-04-16
    • o4-mini-2025-04-16
  • temperature 的更改不支持推理模型。
  • reasoning_effort 不支持非推理模型。

如何编写评分器提示词

编写评分器提示词是一个迭代过程。迭代模型评分器提示词的最佳方式是创建一个模型评分器评估。为此,您需要:

  1. 任务提示词: 为所需任务编写极其详尽的提示词,包含分步说明和上下文中的大量具体示例。
  2. 由模型或人类专家生成的回答: 提供许多高质量的回答示例,包括来自模型和可信人类专家的回答。
  3. 这些回答对应的真实评分: 确立什么是好的评分。例如,您的人类专家评分应为 1。

然后,您可以自动评估模型评分器区分不同质量水平回答的有效性。随着时间的推移,当您发现边缘情况并通过修改提示词对其进行修补时,请将这些边缘情况添加到您的模型评分器评估中。

例如,假设你通过人类专家已经知道了哪些答案是最好的:

answer_1 > answer_2 > answer_3

验证模型评估器的答案是否与之匹配:

model_grader(answer_1, reference_answer) > model_grader(answer_2, reference_answer) > model_grader(answer_3, reference_answer)

评分器破解

接受训练的模型有时会学会利用模型评分器的漏洞,这也被称为“评分器破解”或“奖励作弊”。你可以通过对比模型在模型评分器评估和人类专家评估中的表现来检测这种情况。破解了评分器的模型在模型评分器评估中会得分很高,但在人类专家评估中得分很差。随着时间的推移,我们打算改进 API 的可观测性,以便在训练过程中更容易检测到这种情况。

Python 评分器

此评分器允许你执行任意 Python 代码来对模型输出进行评分。该评分器要求提供一个 grade 函数,该函数接收两个参数并输出一个浮点数值。任何其他结果(异常、无效的浮点数值等)都将被标记为无效并返回 0 分。

1
2
3
4
5
{
  "type": "python",
  "source": "def grade(sample, item):\n    return 1.0",
  "image_tag": "2025-05-08"
}

Python 源代码必须包含一个 grade 函数,该函数恰好接收两个参数,并返回一个浮点数值作为评分。

1
2
3
4
5
from typing import Any

def grade(sample: dict[str, Any], item: dict[str, Any]) -> float:
    # your logic here
    return 1.0

提供给评分函数的第一个参数是一个字典,其中填充了训练期间供你评分的模型输出。 output_json 只有在输出使用 response_format.

1
2
3
4
5
6
7
{
    "choices": [...],
    "output_text": "...",
    "output_json": {},
    "output_tools": [...],
    "output_audio": {}
}

提供给评分函数的第二个参数是一个字典,其中填充了输入评分上下文。对于评估,这将包含数据源中的键。对于微调,这将包含每个训练数据行中的键。

1
2
3
4
{
    "reference_answer": "...",
    "my_key": {...}
}

以下是一个可运行的示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import os
import requests

# get the API key from environment
api_key = os.environ["OPENAI_API_KEY"]
headers = {"Authorization": f"Bearer {api_key}"}

grading_function = """
from rapidfuzz import fuzz, utils

def grade(sample, item) -> float:
    output_text = sample["output_text"]
    reference_answer = item["reference_answer"]
    return fuzz.WRatio(output_text, reference_answer, processor=utils.default_process) / 100.0
"""

# define a dummy grader for illustration purposes
grader = {
    "type": "python",
    "source": grading_function
}

# validate the grader
payload = {"grader": grader}
response = requests.post(
    "https://api.openai.com/v1/fine_tuning/alpha/graders/validate",
    json=payload,
    headers=headers
)
print("validate request_id:", response.headers["x-request-id"])
print("validate response:", response.text)

# run the grader with a test reference and sample
payload = {
  "grader": grader,
  "item": {
     "reference_answer": "fuzzy wuzzy had no hair"
  },
  "model_sample": "fuzzy wuzzy was a bear"
}
response = requests.post(
    "https://api.openai.com/v1/fine_tuning/alpha/graders/run",
    json=payload,
    headers=headers
)
print("run request_id:", response.headers["x-request-id"])
print("run response:", response.text)

Tip: 如果你不想手动将评分函数放入字符串中,也可以使用以下方式从 Python 文件中加载它 importlib and inspect。例如,如果你的评分函数位于名为 grader.py, 你可以这样做:

1
2
3
4
5
6
7
8
import importlib
import inspect

grader_module = importlib.import_module("grader")
grader = {
    "type": "python",
    "source": inspect.getsource(grader_module)
}

这将自动使用你的 grader.py 文件的完整源代码作为评分器,这对于较长的评分器非常有用。

技术限制

  • 你上传的代码必须小于 256kB 并且无法访问网络。
  • 评分执行本身的时间限制为 2 分钟。
  • 在运行时,你将获得 2GB 内存和 1GB 磁盘空间的使用限额。
  • CPU 限制为 2 个核心——超出此配额的使用将导致限速

在执行时,对于镜像标签,可以使用以下第三方软件包 2025-05-08

numpy==2.2.4
scipy==1.15.2
sympy==1.13.3
pandas==2.2.3
rapidfuzz==3.10.1
scikit-learn==1.6.1
rouge-score==0.1.2
deepdiff==8.4.2
jsonschema==4.23.0
pydantic==2.10.6
pyyaml==6.0.2
nltk==3.9.1
sqlparse==0.5.3
rdkit==2024.9.6
scikit-bio==0.6.3
ast-grep-py==0.36.2

此外,还提供以下 nltk 语料库:

punkt
stopwords
wordnet
omw-1.4
names

多重评分器

目前,此评分器仅用于强化微调

A multigrader 对象结合多个评分器的输出以生成单个分数。多重评分器的工作原理是对其他评分器对象的字段进行计算评分,然后将这些子评分转换为总评分。这在正确答案取决于满足多个条件时非常有用——例如,文本需要相似 and 答案是否包含特定字符串。

举个例子,假设你希望模型输出包含以下两个字段的 JSON:

1
2
3
4
{
  "name": "John Doe",
  "email": "[email protected]"
}

你会希望评分器对这两个字段进行比较,然后取它们的平均值。

你可以通过将多个评分器组合成一个对象评分器,然后定义一个公式来根据每个字段计算输出分数来实现这一点:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
{
  "type": "multi",
  "graders": {
    "name": {
      "name": "name_grader",
      "type": "text_similarity",
      "input": "{{sample.output_json.name}}",
      "reference": "{{item.name}}",
      "evaluation_metric": "fuzzy_match",
      "pass_threshold": 0.9
    },
    "email": {
      "name": "email_grader",
      "type": "string_check",
      "input": "{{sample.output_json.email}}",
      "reference": "{{item.email}}",
      "operation": "eq"
    }
  },
  "calculate_output": "(name + email) / 2"
}

在这个例子中,模型准确输出电子邮件非常重要(string_check 返回 0 或 1),但我们可以容忍名字的一些拼写错误(text_similarity 返回范围为 0 到 1)。电子邮件输出错误的样本得分将在 0-0.5 之间,而电子邮件输出正确的样本得分将在 0.5-1.0 之间。

你不能在多重评分器内部嵌套多重评分器。

计算输出字段将使用输入的键 graders 作为可用变量,并支持以下功能:

运算符

  • + (加法)
  • - (减法)
  • * (乘法)
  • / (除法)
  • ^ (幂)

函数

  • min
  • max
  • abs
  • floor
  • ceil
  • exp
  • sqrt
  • log

局限性与提示

设计和创建评分器是一个迭代的过程。从小处着手,不断实验,并持续修改以获得更好的结果。

设计提示

为了从评分器中获得最大价值,请遵循以下设计原则:

  • 生成平滑的分数,而非简单的及格/不及格判定。随着答案的改善而逐渐变化的分数,有助于优化器看出哪些更改是关键。
  • 防范奖励作弊。当模型找到一条无需真正掌握技能就能获得高分的捷径时,就会发生这种情况。请增加评分系统被钻空子的难度。
  • 避免数据倾斜。当数据集中某个标签在大多数时候出现时,会诱使模型直接猜测该标签。请平衡数据集或提高稀有案例的权重,以促使模型进行思考。
  • 当代码无法满足需求时,使用 LLM 作为评判。对于内容丰富、开放式的答案,可以请另一个语言模型来评分。在构建 LLM 评分器时,请将多个候选回复和真实答案输入你的 LLM 评审,以确保评分稳定且符合偏好。请在提示词中提供优秀、一般和较差答案的少样本示例。