

# Evaluación del RFT
<a name="nova-hp-evaluate-rft"></a>

**nota**  
La evaluación mediante funciones de recompensas remotas en su propio entorno de AWS solo está disponible si es cliente de Amazon Nova Forge.

**importante**  
El campo de configuración `rl_env` se utiliza exclusivamente para la evaluación, no para el entrenamiento. Durante el entrenamiento, las funciones de recompensas se configuran mediante una infraestructura `reward_lambda_arn` (de turno único) o BYOO `rollout.delegate: true` (de varios turnos).

**¿Qué es la evaluación del RFT?**  
La evaluación del RFT le permite evaluar el rendimiento del modelo mediante funciones de recompensas personalizadas antes, durante o después del entrenamiento de aprendizaje por refuerzo. A diferencia de las evaluaciones estándar que utilizan métricas predefinidas, la evaluación del RFT le permite definir sus propios criterios de éxito mediante una función de Lambda que puntúa los resultados del modelo en función de sus requisitos específicos.

**¿Por qué se debe evaluar con el RFT?**  
La evaluación es crucial para determinar si el proceso de refinamiento de RL:
+ Ha mejorado la alineación del modelo con su caso de uso específico y sus valores humanos.
+ Ha mantenido o mejorado las capacidades del modelo en tareas clave.
+ Ha evitado efectos secundarios no deseados, como la reducción de la objetividad, el aumento de los detalles o la degradación del rendimiento en otras tareas.
+ Ha cumplido con los criterios de éxito personalizados, tal como los define su función de recompensas.

**¿Cuándo se debe utilizar la evaluación del RFT?**  
Utilice la evaluación del RFT en los siguientes escenarios:
+ Antes del entrenamiento RFT: establezca métricas de línea de base en su conjunto de datos de evaluación.
+ Durante el entrenamiento RFT: supervise el progreso del entrenamiento con puntos de control intermedios.
+ Después del entrenamiento RFT: valide que el modelo final cumpla con sus requisitos.
+ Comparación de modelos: evalúe varias versiones del modelo con criterios de recompensa coherentes.

**nota**  
Utilice la evaluación del RFT cuando necesite métricas personalizadas y específicas de un dominio. Para una evaluación de uso general (precisión, perplejidad, BLEU), utilice métodos de evaluación estándar.

**Topics**
+ [Requisitos del formato de los datos](#nova-hp-evaluate-rft-data-format)
+ [Preparación de la fórmula de evaluación](#nova-hp-evaluate-rft-recipe)
+ [Funciones de recompensas predefinidas](#nova-hp-evaluate-rft-preset)
+ [Creación de la función de recompensas](#nova-hp-evaluate-rft-create-function)
+ [Permisos de IAM](#nova-hp-evaluate-rft-iam)
+ [Ejecución del trabajo de evaluación](#nova-hp-evaluate-rft-execution)
+ [Descripción de los resultados de la evaluación](#nova-hp-evaluate-rft-results)

## Requisitos del formato de los datos
<a name="nova-hp-evaluate-rft-data-format"></a>

**Estructura de los datos de entrada**  
Los datos de entrada de la evaluación del RFT deben seguir el formato de refinamiento por refuerzo de OpenAI. Cada ejemplo es un objeto JSON que contiene lo siguiente:
+ `messages`: matriz de turnos conversacionales con los roles `system` y `user`
+ Otros metadatos opcionales, por ejemplo, reference\_answer

**Ejemplo de formato de datos**  
En el siguiente ejemplo se muestra el formato obligatorio:

```
{
  "messages": [
    {
      "role": "user",
      "content": [
        {
          "type": "text",
          "text": "Solve for x. Return only JSON like {\"x\": <number>}. Equation: 2x + 5 = 13"
        }
      ]
    }
  ],
  "reference_answer": {
    "x": 4
  }
}
```

**Limitaciones actuales**  
Las siguientes limitaciones se aplican a la evaluación del RFT:
+ Solo texto: no se admiten entradas multimodales (imágenes, audio, video).
+ Conversaciones de turno único: solo admite mensajes de un solo usuario (no se admiten diálogos de varios turnos).
+ Formato JSON: los datos de entrada deben estar en formato JSONL (un objeto JSON por línea).
+ Resultados del modelo: la evaluación se lleva a cabo en las terminaciones generadas a partir del modelo especificado.

## Preparación de la fórmula de evaluación
<a name="nova-hp-evaluate-rft-recipe"></a>

**Configuración de fórmula de muestra**  
En el siguiente ejemplo se muestra una fórmula de evaluación del RFT completa:

```
run:
  name: nova-lite-rft-eval-job
  model_type: amazon.nova-lite-v1:0:300k
  model_name_or_path: s3://escrow_bucket/model_location    # [MODIFIABLE] S3 path to your model or model identifier
  replicas: 1                                             # [MODIFIABLE] For SageMaker Training jobs only; fixed for  SageMaker HyperPod  jobs
  data_s3_path: ""                                        # [REQUIRED FOR HYPERPOD] Leave empty for SageMaker Training jobs
  output_s3_path: ""                                      # [REQUIRED] Output artifact S3 path for evaluation results

evaluation:
  task: rft_eval                                          # [FIXED] Do not modify
  strategy: rft_eval                                      # [FIXED] Do not modify
  metric: all                                             # [FIXED] Do not modify

# Inference Configuration
inference:
  max_new_tokens: 8196                                    # [MODIFIABLE] Maximum tokens to generate
  top_k: -1                                               # [MODIFIABLE] Top-k sampling parameter
  top_p: 1.0                                              # [MODIFIABLE] Nucleus sampling parameter
  temperature: 0                                          # [MODIFIABLE] Sampling temperature (0 = deterministic)
  top_logprobs: 0

# Evaluation Environment Configuration (NOT used in training)
rl_env:
  reward_lambda_arn: arn:aws:lambda:<region>:<account_id>:function:<reward-function-name>
```

## Funciones de recompensas predefinidas
<a name="nova-hp-evaluate-rft-preset"></a>

Hay dos funciones de recompensas predefinidas (`prime_code` y `prime_math`) disponibles como capa de Lambda para una integración fácil con las funciones de Lambda del RFT.

**Descripción general**  
Estas funciones predefinidas ofrecen capacidades de evaluación listas para usar para:
+ **prime\_code**: generación de código y evaluación de la corrección
+ **prime\_math**: evaluación del razonamiento matemático y la resolución de problemas

**Configuración rápida**  
Para usar funciones de recompensas predefinidas:

1. Descargue la capa de Lambda de las [versiones de nova-custom-eval-sdk](https://github.com/aws/nova-custom-eval-sdk/releases).

1. Publique la capa de Lambda mediante la AWS CLI:

   ```
   aws lambda publish-layer-version \
       --layer-name preset-function-layer \
       --description "Preset reward function layer with dependencies" \
       --zip-file fileb://universal_reward_layer.zip \
       --compatible-runtimes python3.9 python3.10 python3.11 python3.12 \
       --compatible-architectures x86_64 arm64
   ```

1. Agregue la capa a la función de Lambda en la consola de AWS (seleccione preset-function-layer en la capa personalizada y agregue también AWSSDKPandas-Python312 para dependencias de NumPy).

1. Impórtela y úsela en el código de Lambda:

   ```
   from prime_code import compute_score  # For code evaluation
   from prime_math import compute_score  # For math evaluation
   ```

**Función prime\_code**  
**Propósito**: evalúa las tareas de generación de código de Python mediante la ejecución del código en casos de prueba y la medición de la corrección.

**Ejemplo de formato de conjunto de datos de entrada de la evaluación**:

```
{"messages":[{"role":"user","content":"Write a function that returns the sum of two numbers."}],"reference_answer":{"inputs":["3\n5","10\n-2","0\n0"],"outputs":["8","8","0"]}}
{"messages":[{"role":"user","content":"Write a function to check if a number is even."}],"reference_answer":{"inputs":["4","7","0","-2"],"outputs":["True","False","True","True"]}}
```

**Características clave**:
+ Extracción automática de código de bloques de código Markdown
+ Detección de funciones y pruebas basadas en llamadas
+ Ejecución de casos de prueba con protección de tiempo de espera
+ Comprobaciones de compilación y validación de la sintaxis
+ Informes de errores detallados con rastreos

**Función prime\_math**  
**Propósito**: evalúa el razonamiento matemático y las capacidades de resolución de problemas con soporte matemático simbólico.

**Formato de entrada**:

```
{"messages":[{"role":"user","content":"What is the derivative of x^2 + 3x?."}],"reference_answer":"2*x + 3"}
```

**Características clave**:
+ Evaluación matemática simbólica con SymPy
+ Múltiples formatos de respuesta (LaTeX, texto sin formato, simbólico)
+ Comprobación de equivalencia matemática
+ Normalización y simplificación de expresiones

**Prácticas recomendadas**  
Siga estas prácticas recomendadas cuando use funciones de recompensa predefinidas:
+ Utilice los tipos de datos adecuados en los casos de prueba (números enteros frente a cadenas, valores booleanos frente a “verdaderos”).
+ Proporcione firmas de funciones claras en los problemas de código.
+ Incluya casos extremos en las entradas de prueba (cero, números negativos, entradas vacías).
+ Formatee las expresiones matemáticas de forma coherente en las respuestas de referencia.
+ Pruebe la función de recompensas con datos de ejemplo antes de la implementación.

## Creación de la función de recompensas
<a name="nova-hp-evaluate-rft-create-function"></a>

**ARN de Lambda**  
Debe consultar el siguiente formato para el ARN de Lambda:

```
"arn:aws:lambda:*:*:function:*SageMaker*"
```

Si Lambda no tiene este esquema de nombres, el trabajo fallará y mostrará este error:

```
[ERROR] Unexpected error: lambda_arn must contain one of: ['SageMaker', 'sagemaker', 'Sagemaker'] when running on SMHP platform (Key: lambda_arn)
```

**Estructura de la función de Lambda**  
La función de Lambda recibe lotes de salidas del modelo y devuelve las puntuaciones de recompensas. A continuación se muestra un ejemplo de implementación:

```
from typing import List, Any
import json
import re
from dataclasses import asdict, dataclass


@dataclass
class MetricResult:
    """Individual metric result."""
    name: str
    value: float
    type: str


@dataclass
class RewardOutput:
    """Reward service output."""
    id: str
    aggregate_reward_score: float
    metrics_list: List[MetricResult]


def lambda_handler(event, context):
    """ Main lambda handler """
    return lambda_grader(event)


def lambda_grader(samples: list[dict]) -> list[dict]:
    """ Core grader function """
    scores: List[RewardOutput] = []

    for sample in samples:
        print("Sample: ", json.dumps(sample, indent=2))

        # Extract components
        idx = sample.get("id", "no id")
        if not idx or idx == "no id":
            print(f"ID is None/empty for sample: {sample}")

        ground_truth = sample.get("reference_answer")

        if "messages" not in sample:
            print(f"Messages is None/empty for id: {idx}")
            continue

        if ground_truth is None:
            print(f"No answer found in ground truth for id: {idx}")
            continue

        # Get model's response (last turn is assistant turn)
        last_message = sample["messages"][-1]

        if last_message["role"] != "nova_assistant":
            print(f"Last message is not from assistant for id: {idx}")
            continue

        if "content" not in last_message:
            print(f"Completion text is empty for id: {idx}")
            continue

        model_text = last_message["content"]

        # --- Actual scoring logic (lexical overlap) ---
        ground_truth_text = _extract_ground_truth_text(ground_truth)

        # Calculate main score and individual metrics
        overlap_score = _lexical_overlap_score(model_text, ground_truth_text)

        # Create two separate metrics as in the first implementation
        accuracy_score = overlap_score  # Use overlap as accuracy
        fluency_score = _calculate_fluency(model_text)  # New function for fluency

        # Create individual metrics
        metrics_list = [
            MetricResult(name="accuracy", value=accuracy_score, type="Metric"),
            MetricResult(name="fluency", value=fluency_score, type="Reward")
        ]

        ro = RewardOutput(
            id=idx,
            aggregate_reward_score=overlap_score,
            metrics_list=metrics_list
        )

        print(f"Response for id: {idx} is {ro}")
        scores.append(ro)

    # Convert to dict format
    result = []
    for score in scores:
        result.append({
            "id": score.id,
            "aggregate_reward_score": score.aggregate_reward_score,
            "metrics_list": [asdict(metric) for metric in score.metrics_list]
        })

    return result


def _extract_ground_truth_text(ground_truth: Any) -> str:
    """
    Turn the `ground_truth` field into a plain string.
    """
    if isinstance(ground_truth, str):
        return ground_truth

    if isinstance(ground_truth, dict):
        # Common patterns: { "explanation": "...", "answer": "..." }
        if "explanation" in ground_truth and isinstance(ground_truth["explanation"], str):
            return ground_truth["explanation"]
        if "answer" in ground_truth and isinstance(ground_truth["answer"], str):
            return ground_truth["answer"]
        # Fallback: stringify the whole dict
        return json.dumps(ground_truth, ensure_ascii=False)

    # Fallback: stringify anything else
    return str(ground_truth)


def _tokenize(text: str) -> List[str]:
    # Very simple tokenizer: lowercase + alphanumeric word chunks
    return re.findall(r"\w+", text.lower())


def _lexical_overlap_score(model_text: str, ground_truth_text: str) -> float:
    """
    Simple lexical overlap score in [0, 1]:
      score = |tokens(model) ∩ tokens(gt)| / |tokens(gt)|
    """
    gt_tokens = _tokenize(ground_truth_text)
    model_tokens = _tokenize(model_text)

    if not gt_tokens:
        return 0.0

    gt_set = set(gt_tokens)
    model_set = set(model_tokens)
    common = gt_set & model_set

    return len(common) / len(gt_set)


def _calculate_fluency(text: str) -> float:
    """
    Calculate a simple fluency score based on:
    - Average word length
    - Text length
    - Sentence structure

    Returns a score between 0 and 1.
    """
    # Simple implementation - could be enhanced with more sophisticated NLP
    words = _tokenize(text)

    if not words:
        return 0.0

    # Average word length normalized to [0,1] range
    # Assumption: average English word is ~5 chars, so normalize around that
    avg_word_len = sum(len(word) for word in words) / len(words)
    word_len_score = min(avg_word_len / 10, 1.0)

    # Text length score - favor reasonable length responses
    ideal_length = 100  # words
    length_score = min(len(words) / ideal_length, 1.0)

    # Simple sentence structure check (periods, question marks, etc.)
    sentence_count = len(re.findall(r'[.!?]+', text)) + 1
    sentence_ratio = min(sentence_count / (len(words) / 15), 1.0)

    # Combine scores
    fluency_score = (word_len_score + length_score + sentence_ratio) / 3

    return fluency_score
```

**Formato de la solicitud de Lambda**  
La función de Lambda recibe datos en este formato:

```
[
  {
    "id": "sample-001",
    "messages": [
      {
        "role": "user",
        "content": [
          {
            "type": "text",
            "text": "Do you have a dedicated security team?"
          }
        ]
      },
      {
        "role": "nova_assistant",
        "content": [
          {
            "type": "text",
            "text": "As an AI developed by Company, I don't have a dedicated security team in the traditional sense. However, the development and deployment of AI systems like me involve extensive security measures, including data encryption, user privacy protection, and other safeguards to ensure safe and responsible use."
          }
        ]
      }
    ],
    "reference_answer": {
      "compliant": "No",
      "explanation": "As an AI developed by Company, I do not have a traditional security team. However, the deployment involves stringent safety measures, such as encryption and privacy safeguards."
    }
  }
]
```

**nota**  
La estructura del mensaje incluye la matriz `content` anidada, que coincide con el formato de datos de entrada. El último mensaje con el rol `nova_assistant` contiene la respuesta generada por el modelo.

**Formato de la respuesta de Lambda**  
La función de Lambda debe devolver datos en este formato:

```
[
  {
    "id": "sample-001",
    "aggregate_reward_score": 0.75,
    "metrics_list": [
      {
        "name": "accuracy",
        "value": 0.85,
        "type": "Metric"
      },
      {
        "name": "fluency",
        "value": 0.90,
        "type": "Reward"
      }
    ]
  }
]
```

**Campos de la respuesta**
+ `id`: debe coincidir con el ID de muestra de entrada
+ `aggregate_reward_score`: puntuación general (normalmente de 0,0 a 1,0)
+ `metrics_list`, matriz de métricas individuales con:
  + `name`: identificador de la métrica (por ejemplo, “precisión”, “fluidez”)
  + `value`: puntuación de la métrica (normalmente de 0,0 a 1,0)
  + `type`: “Métrica” (para informes) o “Recompensa” (utilizada en el entrenamiento)

## Permisos de IAM
<a name="nova-hp-evaluate-rft-iam"></a>

**Permisos necesarios**  
El rol de ejecución de SageMaker AI debe tener permisos para invocar la función de Lambda. Agregue esta política al rol de ejecución de SageMaker AI:

```
{
  "Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "lambda:InvokeFunction"
      ],
      "Resource": "arn:aws:lambda:region:account-id:function:function-name"
    }
  ]
}
```

**Rol de ejecución de Lambda**  
El rol de ejecución de una función de Lambda necesita permisos de ejecución de Lambda básicos:

```
{
  "Version": "2012-10-17",		 	 	 
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "logs:CreateLogGroup",
        "logs:CreateLogStream",
        "logs:PutLogEvents"
      ],
      "Resource": "arn:aws:logs:*:*:*"
    }
  ]
}
```

**Permisos adicionales**: si la función de Lambda accede a otros servicios de AWS (por ejemplo, Amazon S3 para los datos de referencia o DynamoDB para el registro), agregue esos permisos al rol de ejecución de Lambda.

## Ejecución del trabajo de evaluación
<a name="nova-hp-evaluate-rft-execution"></a>

1. **Preparar los datos**
   + Formatee los datos de evaluación de acuerdo con los requisitos de formato de los datos.
   + Cargue el archivo JSONL en Amazon S3: `s3://your-bucket/eval-data/eval_data.jsonl`.

1. **Configuración de la fórmula**

   Actualice la fórmula de muestra con su configuración:
   + Establezca `model_name_or_path` en la ubicación del modelo.
   + Establezca `lambda_arn` en el ARN de la función de recompensas.
   + Establezca `output_s3_path` en la ubicación de salida deseada.
   + Ajuste los parámetros de `inference` según sea necesario.

   Guarde la fórmula como `rft_eval_recipe.yaml`.

1. **Ejecución de la evaluación**

   Ejecute el trabajo de evaluación con el cuaderno proporcionado: [cuaderno de evaluación del modelo de Nova](https://docs.aws.amazon.com/sagemaker/latest/dg/nova-model-evaluation.html#nova-model-evaluation-notebook).

1. **Supervise el progreso**

   Supervise el trabajo de evaluación con las siguientes herramientas:
   + Consola de SageMaker AI: compruebe el estado y los registros de los trabajos.
   + Registros de CloudWatch: consulte los registros de ejecución detallados.
   + Registros de Lambda: depure problemas de la función de recompensas.

## Descripción de los resultados de la evaluación
<a name="nova-hp-evaluate-rft-results"></a>

**Formato de salida**  
El trabajo de evaluación envía los resultados a la ubicación de Amazon S3 especificada en formato JSONL. Cada línea contiene los resultados de la evaluación de una muestra:

```
{
  "id": "sample-001",
  "aggregate_reward_score": 0.75,
  "metrics_list": [
    {
      "name": "accuracy",
      "value": 0.85,
      "type": "Metric"
    },
    {
      "name": "fluency",
      "value": 0.90,
      "type": "Reward"
    }
  ]
}
```

**nota**  
El resultado del trabajo de evaluación del RFT es idéntico al formato de la respuesta de Lambda. El servicio de evaluación analiza la respuesta de la función de Lambda sin modificaciones, lo que garantiza la coherencia entre los cálculos de recompensas y los resultados finales.

**Interpretación de los resultados**  
**Puntuación total de recompensas**:
+ Rango: normalmente de 0,0 (peor) a 1,0 (mejor), pero depende de la implementación
+ Propósito: un solo número que resume el rendimiento general
+ Uso: comparación de modelos, seguimiento de las mejoras con respecto al entrenamiento

**Métricas individuales**:
+ Tipo de métrica: métricas informativas para el análisis
+ Tipo de recompensa: métricas utilizadas durante el entrenamiento RFT
+ Interpretación: unos valores más altos suelen indicar un mejor rendimiento (a menos que diseñe métricas inversas)

**Puntos de referencia de rendimiento**  
Lo que constituye un rendimiento “bueno” depende de su caso de uso:


| Intervalo de puntuación | Interpretación | Action | 
| --- |--- |--- |
| Entre 0,8 y 1,0 | Excelente | Modelo listo para su implementación | 
| Entre 0,6 y 0,8 | Buena | Podría beneficiarse de mejoras menores | 
| Entre 0,4 y 0,6 | Regular | Necesita una mejora importante | 
| Entre 0,0 y 0,4 | Deficiente | Revisión de los datos de entrenamiento y de la función de recompensas | 

**importante**  
Estas son unas directrices generales. Defina sus propios umbrales en función de los requisitos empresariales, el rendimiento básico del modelo, las restricciones específicas del dominio y el análisis de la relación entre costo y beneficio del entrenamiento continuo.