跳到内容
Skynet文档
页面

概念

指标与评分器

编写评分函数,告诉引擎什么才算更好。

指标告诉 Skynet 一个输出有多好。它是 metric.py 中的一个 Python 函数。每个引擎都调用同一个函数。本页给出契约、返回值和示例。

契约

def score(input, output, expected=None):
    ...
    return score_value, {"feedback": "..."}
参数包含的内容
input一个 dict,包含该用例的输入字段
output你的 run(artifact, input) 为该用例返回的内容
expected该用例的期望值;如果用例没有期望值,则为 None

如果你的函数只接受两个参数,Skynet 会调用 score(input, output)。

对于 DSPy 程序,Skynet 会把 DSPy 的指标调用适配到这同一个函数。你只需为每种产物类型编写一个指标。请阅读优化的工作原理。

返回值

score 必须返回一对值(一个包含两个元素的 tuple 或 list):

  1. 分数。 一个数字。优化器会尽量让它变高。
  2. 附加信息。 一个 dict。它必须有一个 "feedback" 键,其值为字符串。

附加信息还可以有一个 "scores" 键。它把名称映射到数字,例如 {"format": 1.0, "accuracy": 0.5}。

如果返回值的结构不同,契约检查会在 指标返回值 处失败。

返回值是否有效
(0.8, {"feedback": "Close. Missing the date."})是
[1.0, {"feedback": "OK", "scores": {"format": 1.0}}]是
0.8否。没有附加信息。
(0.8, "Close.")否。附加信息不是 dict。
(0.8, {})否。没有反馈字符串。
("0.8", {"feedback": "OK"})否。分数是字符串。
(0.8, {"feedback": "OK", "scores": {"a": "high"}})否。某个命名分数不是数字。

编写有用的反馈

GEPA、DSPy GEPA 和 Auto 会读取反馈文本来编写下一个版本。请说明哪里错了,以及正确的输出是什么样子。

薄弱的反馈有用的反馈
“Wrong.”“Expected 'billing', got 'other'. The message mentions a charge.”
“Bad format.”“The output is not valid JSON. It has a trailing comma after the last field.”

示例

精确匹配

def score(input, output, expected=None):
    want = expected["label"]
    if output == want:
        return 1.0, {"feedback": "Correct."}
    return 0.0, {"feedback": f"Expected {want!r}, got {output!r}."}

expected 是一个以输出列名称为键的 dict。请阅读数据集与划分。

多项检查

import json


def score(input, output, expected=None):
    try:
        data = json.loads(output)
    except ValueError as exc:
        return 0.0, {"feedback": f"Output is not valid JSON: {exc}", "scores": {"format": 0.0, "fields": 0.0}}
    want = expected["fields"]
    found = [key for key in want if key in data]
    fields = len(found) / len(want) if want else 1.0
    missing = [key for key in want if key not in data]
    feedback = "All fields present." if not missing else f"Missing fields: {', '.join(missing)}."
    return 0.5 + 0.5 * fields, {"feedback": feedback, "scores": {"format": 1.0, "fields": fields}}

用模型作为评判

指标可以调用模型。从 skynet 辅助模块导入 llm。从指标发出的调用会使用指标模型。

from skynet import llm


def score(input, output, expected=None):
    verdict = llm(
        "Answer PASS or FAIL, then give one sentence of reasons.",
        input=f"Question: {input['question']}\nAnswer: {output}",
    )
    passed = str(verdict).strip().upper().startswith("PASS")
    return (1.0 if passed else 0.0), {"feedback": str(verdict)}

如果你没有选择 指标模型,指标会使用与反思模型相同的模型。

准确率、速度和成本

指标可以把准确率与测得的运行时间和模型成本结合起来。在模块级定义 REWARD_SPEC,并返回 reward 的值。

from skynet import reward

REWARD_SPEC = {
    "weights": {"accuracy": 0.7, "speed": 0.2, "cost": 0.1},
    "accuracy": {},
    "speed": {"reference": 2000},
    "cost": {"reference": 0.01},
}


def score(input, output, expected=None):
    ok = output == expected["label"]
    return reward(REWARD_SPEC, 1.0 if ok else 0.0, "Correct." if ok else "Wrong label.")
  • weights 必须包含 accuracy、speed 和 cost。每个权重都为 0 或更大,且不能全部为 0。Skynet 会把它们缩放到总和为 1。
  • speed.reference 的单位是毫秒。cost.reference 的单位是美元。两者都必须为正数。
  • 没有 accuracy.reference 时,准确率是 0 到 1 之间的分数。有它时,准确率是一个误差,越低越好。

Skynet 自己测量时间和成本。运行代码无法更改它们。如果 Skynet 无法测量时间或成本,那一部分记为 0 分,反馈中也会说明。

指标也可以用 skynet 中的 observation() 和 service_cost() 直接读取这些测量值。

限制

项目值
指标超时默认 60 秒,最多 600 秒
契约检查样例3 个用例

相关页面