Conceptos
Métricas y evaluadores
Escribe la función de puntuación que le dice al motor qué significa «mejor».
La métrica le dice a Skynet lo buena que es una salida. Es una función de Python en metric.py. Todos los motores llaman a la misma función. Esta página explica el contrato, el valor devuelto y algunos ejemplos.
El contrato
def score(input, output, expected=None):
...
return score_value, {"feedback": "..."}| Argumento | Qué contiene |
|---|---|
input | Un dict con los campos de entrada del caso |
output | Lo que devolvió tu run(artifact, input) para el caso |
expected | El valor esperado del caso, o None cuando el caso no tiene ninguno |
Si tu función solo recibe dos argumentos, Skynet llama a score(input, output).
Para un programa DSPy, Skynet adapta la llamada a la métrica de DSPy a esta misma función. Escribes una sola métrica para todos los tipos de artefacto. Lee Cómo funciona la optimización.
El valor devuelto
score debe devolver un par (una tupla o una lista de dos elementos):
- La puntuación. Un número. El optimizador intenta que sea más alto.
- La información adicional. Un dict. Debe tener una clave
"feedback"con un valor de tipo cadena.
La información adicional también puede tener una clave "scores". Asocia nombres a números, por ejemplo {"format": 1.0, "accuracy": 0.5}.
Si el valor devuelto tiene otra forma, la comprobación del contrato falla en Valor que devuelve la métrica.
| Valor devuelto | Válido |
|---|---|
(0.8, {"feedback": "Close. Missing the date."}) | Sí |
[1.0, {"feedback": "OK", "scores": {"format": 1.0}}] | Sí |
0.8 | No. No hay información adicional. |
(0.8, "Close.") | No. La información adicional no es un dict. |
(0.8, {}) | No. No hay cadena de comentarios. |
("0.8", {"feedback": "OK"}) | No. La puntuación es una cadena. |
(0.8, {"feedback": "OK", "scores": {"a": "high"}}) | No. Una puntuación con nombre no es un número. |
Escribe comentarios útiles
GEPA, DSPy GEPA y Auto leen el texto de los comentarios para escribir la siguiente versión. Di qué está mal y cómo es una salida correcta.
| Comentario pobre | Comentario útil |
|---|---|
| «Incorrecto.» | «Se esperaba 'billing' y se obtuvo 'other'. El mensaje menciona un cargo.» |
| «Formato erróneo.» | «La salida no es un JSON válido. Tiene una coma sobrante después del último campo.» |
Ejemplos
Coincidencia exacta
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 es un dict cuya clave es el nombre de tu columna de salida. Lee Conjuntos de datos y divisiones.
Varias comprobaciones
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}}Modelo como juez
La métrica puede llamar a un modelo. Importa llm desde el módulo auxiliar skynet. Una llamada desde la métrica va al modelo de la métrica.
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)}Si no seleccionas un Modelo de la métrica, la métrica usa el mismo modelo que el modelo de reflexión.
Precisión, velocidad y coste
Una métrica puede combinar la precisión con el tiempo de ejecución medido y el coste del modelo. Define REWARD_SPEC a nivel de módulo y devuelve el valor de 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.")weightsdebe teneraccuracy,speedycost. Cada peso es 0 o más, y no pueden ser todos 0. Skynet los escala para que sumen 1.speed.referenceestá en milisegundos.cost.referenceestá en dólares estadounidenses. Ambos deben ser positivos.- Sin
accuracy.reference, la precisión es una puntuación de 0 a 1. Con él, la precisión es un error, y cuanto más bajo, mejor.
Skynet mide el tiempo y el coste por sí mismo. El código de ejecución no puede cambiarlos. Si Skynet no puede medir el tiempo o el coste, esa parte puntúa 0 y los comentarios lo indican.
La métrica también puede leer las mediciones directamente con observation() y service_cost() de skynet.
Límites
| Elemento | Valor |
|---|---|
| Tiempo límite de la métrica | 60 segundos por defecto, como máximo 600 |
| Muestras de la comprobación del contrato | 3 casos |