

# Avaliação de RFT
<a name="nova-hp-evaluate-rft"></a>

**nota**  
A avaliação por meio de funções de recompensa remotas em seu próprio ambiente da AWS só estará disponível se você for cliente do Amazon Nova Forge.

**Importante**  
O campo de configuração `rl_env` é usado exclusivamente para avaliação, não para treinamento. Durante o treinamento, você configura as funções de recompensa usando a infraestrutura `reward_lambda_arn` (turno único) ou BYOO com `rollout.delegate: true` (vários turnos).

**O que é avaliação de RFT?**  
A avaliação de RFT permite que você avalie o desempenho do seu modelo usando funções de recompensa personalizadas antes, durante ou após o treinamento de aprendizado por reforço. Ao contrário das avaliações padrão que usam métricas predefinidas, a avaliação de RFT permite que você defina seus próprios critérios de sucesso por meio de uma função do Lambda que pontua os resultados do modelo com base em seus requisitos específicos.

**Por que avaliar com o RFT?**  
A avaliação é crucial para determinar se o processo de ajuste fino do RL:
+ Aprimorou o alinhamento de modelos com seu caso de uso específico e valores humanos
+ Manteve ou aprimorou os recursos dos modelos nas principais tarefas
+ Evitou efeitos colaterais indesejados, como redução da factualidade, aumento da verbosidade ou degradação do desempenho em outras tarefas
+ Atendeu aos seus critérios de sucesso personalizados, conforme definido por sua função de recompensa

**Quando usar a avaliação de RFT**  
Use a avaliação de RFT nestes cenários:
+ Antes do treinamento de RFT: estabeleça métricas de linha de base em seu conjunto de dados de avaliação
+ Durante o treinamento de RFT: monitore o progresso do treinamento com pontos de verificação intermediários
+ Após o treinamento de RFT: valide se o modelo final atende aos seus requisitos
+ Comparando modelos: avalie várias versões do modelo usando critérios de recompensa consistentes

**nota**  
Use a avaliação de RFT quando precisar de métricas personalizadas e específicas do domínio. Para avaliação de propósito geral (precisão, perplexidade, BLEU), use métodos de avaliação padrão.

**Topics**
+ [Requisitos de formato de dados](#nova-hp-evaluate-rft-data-format)
+ [Preparação da sua fórmula de avaliação](#nova-hp-evaluate-rft-recipe)
+ [Funções de recompensa predefinidas](#nova-hp-evaluate-rft-preset)
+ [Criação da função de recompensa](#nova-hp-evaluate-rft-create-function)
+ [permissões do IAM](#nova-hp-evaluate-rft-iam)
+ [Execução da tarefa de avaliação](#nova-hp-evaluate-rft-execution)
+ [Conceitos básicos dos resultados da avaliação](#nova-hp-evaluate-rft-results)

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

**Estrutura de dados de entrada**  
Os dados de entrada da avaliação de RFT devem seguir o formato de ajuste fino por reforço da OpenAI. Cada exemplo é um objeto JSON que contém:
+ `messages`: matriz de turnos de conversação com os perfis `system` e `user`
+ Outros metadados opcionais, por exemplo, reference\_answer

**Exemplo de formato de dados**  
O seguinte exemplo mostra o formato correto:

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

**Limitações atuais**  
As limitações a seguir se aplicam à avaliação de RFT:
+ Somente texto: não há compatibilidade com entradas multimodais (imagens, áudio, vídeo)
+ Conversas em um único turno: compatível apenas com mensagens de um único usuário (sem diálogos com vários turnos)
+ Formato JSON: os dados de entrada devem estar no formato JSONL (um objeto JSON por linha)
+ Saídas do modelo: a avaliação é realizada nas conclusões geradas do modelo específico

## Preparação da sua fórmula de avaliação
<a name="nova-hp-evaluate-rft-recipe"></a>

**Configuração do exemplo de fórmula**  
O exemplo a seguir mostra uma fórmula completa de avaliação de RFT:

```
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>
```

## Funções de recompensa predefinidas
<a name="nova-hp-evaluate-rft-preset"></a>

Duas funções de recompensa predefinidas (`prime_code` e `prime_math`) estão disponíveis como uma camada do Lambda para facilitar a integração com suas funções de RFT do Lambda.

**Visão geral**  
Essas funções predefinidas fornecem recursos de avaliação prontos para uso para:
+ **prime\_code**: geração de código e avaliação da exatidão
+ **prime\_math**: raciocínio matemático e avaliação da resolução de problemas

**Configuração rápida**  
Para usar funções de recompensa predefinidas:

1. Baixe a camada do Lambda das [versões nova-custom-eval-sdk](https://github.com/aws/nova-custom-eval-sdk/releases)

1. Publique a camada do Lambda usando a 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. Adicione a camada à sua função do Lambda no Console da AWS (selecione preset-function-layer na camada personalizada e também adicione AWSSDKPandas-Python312 para dependências numpy)

1. Importe e use no seu código do Lambda:

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

**função prime\_code**  
**Objetivo**: avalia as tarefas de geração de código Python executando o código em casos de teste e avaliando a exatidão.

**Exemplo de formato de conjunto de dados de entrada da avaliação**:

```
{"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"]}}
```

**Principais atributos**:
+ Extração automática de código de blocos de código markdown
+ Detecção de funções e testes baseados em chamadas
+ Execução de casos de teste com proteção de tempo limite
+ Verificações de compilação e validação de sintaxe
+ Relatórios detalhados de erros com rastreamentos

**prime\_math function**  
**Objetivo**: avalia o raciocínio matemático e as capacidades de resolução de problemas com suporte matemático simbólico.

**Formato de entrada**:

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

**Principais atributos**:
+ Avaliação matemática simbólica usando SymPy
+ Vários formatos de resposta (LaTeX, texto simples, simbólico)
+ Verificação de equivalência matemática
+ Simplificação e normalização da expressão

**Práticas recomendadas**  
Siga estas práticas recomendadas ao usar funções de recompensa predefinidas:
+ Use tipos de dados adequados em casos de teste (inteiros vs. strings, booleanos vs. “True”)
+ Forneça assinaturas de funções claras em problemas de código
+ Inclua casos de borda nas entradas de teste (zero, números negativos, entradas vazias)
+ Formate expressões matemáticas de forma consistente nas respostas de referência
+ Teste sua função de recompensa com dados de exemplo antes da implantação

## Criação da função de recompensa
<a name="nova-hp-evaluate-rft-create-function"></a>

**ARN do Lambda**  
Você deve consultar o seguinte formato para o ARN do Lambda:

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

Se o Lambda não tiver esse esquema de nomenclatura, a tarefa falhará com este erro:

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

**Estrutura da função do Lambda**  
Sua função do Lambda recebe lotes de resultados de modelos e retorna pontuações de recompensa. Confira abaixo um exemplo de implementação:

```
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 solicitação do Lambda**  
Sua função do Lambda recebe dados neste 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**  
A estrutura da mensagem inclui a matriz `content` aninhada, correspondente ao formato dos dados de entrada. A última mensagem com o perfil `nova_assistant` contém a resposta gerada pelo modelo.

**Formato de resposta do Lambda**  
Sua função do Lambda deve retornar dados neste 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 resposta**:
+ `id`: deve corresponder ao ID do exemplo de entrada
+ `aggregate_reward_score`: pontuação geral (normalmente de 0,0 a 1,0)
+ `metrics_list`: matriz de métricas individuais com:
  + `name`: identificador de métricas (por exemplo, “precisão”, “fluência”)
  + `value`: pontuação de métricas (normalmente de 0,0 a 1,0)
  + `type`: “métrica” (para relatórios) ou “recompensa” (usada no treinamento)

## permissões do IAM
<a name="nova-hp-evaluate-rft-iam"></a>

**Permissões obrigatórias**  
O perfil de execução do SageMaker AI precisa de permissões para invocar sua função do Lambda. Anexe esta política ao seu perfil de execução do SageMaker AI:

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

**Função de execução do Lambda**  
O perfil de execução de uma função do Lambda precisa de permissões básicas de execução do Lambda:

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

**Permissões adicionais**: se sua função do Lambda acessar outros serviços da AWS (por exemplo, Amazon S3 para dados de referência, DynamoDB para registro em log), adicione essas permissões ao perfil de execução do Lambda.

## Execução da tarefa de avaliação
<a name="nova-hp-evaluate-rft-execution"></a>

1. **Preparar seus dados**
   + Formate seus dados de avaliação de acordo com os requisitos de formato de dados
   + Faça upload de seu arquivo JSONL no Amazon S3: `s3://your-bucket/eval-data/eval_data.jsonl`

1. **Configurar sua fórmula**

   Atualize a fórmula do exemplo com sua configuração:
   + Defina `model_name_or_path` para a localização do seu modelo
   + Defina `lambda_arn` para o ARN da função de recompensa
   + Defina `output_s3_path` para o local de saída desejado
   + Ajuste os parâmetros `inference` conforme necessário

   Salve a fórmula como `rft_eval_recipe.yaml`

1. **Executar a avaliação**

   Execute a tarefa de avaliação usando o caderno fornecido: [caderno de avaliação do modelo Nova](https://docs.aws.amazon.com/sagemaker/latest/dg/nova-model-evaluation.html#nova-model-evaluation-notebook)

1. **Monitore o progresso**

   Monitore sua tarefa de avaliação por meio do:
   + Console do SageMaker AI: verifique o status e os logs da tarefa
   + CloudWatch Logs: visualize logs de execução detalhados
   + Lambda Logs: depure problemas na função de recompensa

## Conceitos básicos dos resultados da avaliação
<a name="nova-hp-evaluate-rft-results"></a>

**Formato de saída**  
A tarefa de avaliação gera resultados para a localização específica do Amazon S3 no formato JSONL. Cada linha contém os resultados da avaliação de um exemplo:

```
{
  "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**  
A saída da tarefa de avaliação de RFT é idêntica ao formato da resposta do Lambda. O serviço de avaliação passa pela resposta da função do Lambda sem modificação, garantindo a consistência entre seus cálculos de recompensa e os resultados finais.

**Como interpretar os resultados do**  
**Pontuação de recompensa agregada**:
+ Intervalo: normalmente de 0,0 (pior) a 1,0 (melhor), mas depende da sua implementação
+ Objetivo: número único resumindo o desempenho geral
+ Uso: compare modelos, acompanhe a melhoria em relação ao treinamento

**Métricas individuais**:
+ Tipo de métrica: métricas informativas para análise
+ Tipo de recompensa: métricas usadas durante o treinamento de RFT
+ Interpretação: valores mais altos geralmente indicam melhor desempenho (a menos que você crie métricas inversas)

**Benchmarks de desempenho**  
O que constitui um desempenho “bom” depende do seu caso de uso:


| Intervalo de pontuação | Interpretação | Ação | 
| --- |--- |--- |
| 0,8 a 1,0 | Excelente | Modelo pronto para implantação | 
| 0,6 a 0,8 | Boa | Pequenas melhorias podem ser benéficas | 
| 0,4 a 0,6 | Razoável | Melhoria significativa necessária | 
| 0,0 a 0,4 | Ruim | Revise os dados de treinamento e a função de recompensa | 

**Importante**  
Essas são as diretrizes gerais. Defina seus próprios limites com base nos requisitos de negócios, no desempenho do modelo de base, nas restrições específicas do domínio e na análise de custo-benefício do treinamento adicional.