> For the complete documentation index, see [llms.txt](https://docs.neuron-ai.dev/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.neuron-ai.dev/neuron-v3-es/agente/evaluation.md).

# Evaluaciones

Esta guía cubre enfoques para evaluar agentes. Una evaluación eficaz es esencial para medir el rendimiento del agente, hacer seguimiento de las mejoras y garantizar que tu sistema agéntico cumpla con los estándares de calidad.

Al construir aplicaciones de IA, evaluar la consistencia de su salida es crucial, no solo para el mantenimiento del agente, sino también para evaluar diferentes arquitecturas o enfoques de prompting en la fase de diseño inicial.

Es importante considerar diversos factores cualitativos y cuantitativos, incluida la sintaxis de la respuesta, la finalización de la tarea, el éxito y las inexactitudes o alucinaciones. En las evaluaciones, también es importante considerar la comparación de diferentes configuraciones para optimizar resultados específicos deseados. Dada la naturaleza dinámica y no determinista de los LLM, también es importante realizar evaluaciones rigurosas y frecuentes para garantizar una línea base coherente para hacer seguimiento de mejoras o regresiones.

### Configurando tu aplicación

Al igual que con las pruebas unitarias, podría ser mejor recopilar los evaluadores de tu sistema de IA en un directorio dedicado. Así, puedes añadir la configuración siguiente a tu aplicación `composer.json` archivo para indicarle a Composer cómo incluir tus evaluadores en los espacios de nombres de la aplicación:

```json
"autoload-dev": {
    "psr-4": {
        ...,
        "App\\Evaluators\\": "evaluators/"
    }
},
```

A continuación, crea el `evaluators` directorio en la carpeta raíz de tu proyecto. Mantener el código de evaluación separado del código de producción crea un límite claro entre lo que se despliega en producción y lo que existe únicamente para el desarrollo y la garantía de calidad.

### Creando evaluadores

Usa el comando siguiente para crear la `AgentEvaluator` clase dentro de la carpeta evaluators:

{% tabs %}
{% tab title="Unix" %}

```bash
vendor/bin/neuron make:evaluator App\\Neuron\\Evaluators\\AgentEvaluator
```

{% endtab %}

{% tab title="Windows" %}

```powershell
.\vendor\bin\neuron make:evaluators App\Neuron\Evaluators\AgentEvaluator
```

{% endtab %}
{% endtabs %}

La clase que se creará tendrá la siguiente estructura:

```php
namespace App\Neuron\Evaluators;

use NeuronAI\Evaluation\Assertions\StringContains;
use NeuronAI\Evaluation\BaseEvaluator;
use NeuronAI\Evaluation\Contracts\DatasetInterface;
use NeuronAI\Evaluation\Dataset\JsonDataset;

class AgentEvaluator extends BaseEvaluator
{
    /**
     * 1. Obtén el conjunto de datos contra el que evaluar
     */
    public function getDataset(): DatasetInterface
    {
        return new JsonDataset(__DIR__ . '/datasets/dataset.json');
    }

    /**
     * 2. Ejecuta la lógica del agente que se está probando
     */
    public function run(array $datasetItem): mixed
    {
        $response = MyAgent::make()->chat(
            new UserMessage($datasetItem['input'])
        )->getMessage();
        
        return $response->getContent();
    }

    /**
     * 3. Evalúa la salida frente a los resultados esperados, con aserciones
     */
    public function evaluate(mixed $output, array $datasetItem): void
    {
        $this->assert(
            new StringContains($datasetItem['reference']),
            $output,
        );
    }
} 
```

La lógica es bastante sencilla. El evaluador primero carga el conjunto de datos y luego ejecuta la evaluación para cada elemento del conjunto de datos.

En el `ejecutar` método puedes ejecutar tus entidades agénticas con el ejemplo de entrada y devolver la salida. Luego, la salida se pasa al `evaluar` método donde puedes realizar aserciones comparando la salida con un valor de referencia o cualquier otra lógica que desees.

### Cargador de conjuntos de datos

Puedes usar lo que quieras como conjunto de datos. No hay un formato predefinido. La clase evaluadora simplemente te permite cargar una lista de casos de prueba y ejecutar los evaluadores contra ellos. Tienes dos cargadores de conjuntos de datos.

#### ArrayDataset

```php
class AgentEvaluator extends BaseEvaluator
{
    public function getDataset(): DatasetInterface
    {
        return new ArrayDataset([
            [
                'input' => 'Hola',
                'reference' => 'ayuda'
            ]
        ]);
    }
    
    ...
}
```

#### JsonDataset

```php
class AgentEvaluator extends BaseEvaluator
{
    public function getDataset(): DatasetInterface
    {
        return new JsonDataset(__DIR__ . '/datasets/dataset.json');
    }
    
    ...
}
```

Eventualmente puedes crear un cargador de conjunto de datos personalizado implementando `NeuronAI\Evaluation\Contracts\DatasetInterface`.

### Ejecutando evaluaciones

Si has configurado correctamente tu archivo composer, puedes usar la CLI de Neuron para lanzar los evaluadores:

{% tabs %}
{% tab title="Unix" %}

```bash
vendor/bin/neuron evaluations --path=evaluators
```

{% endtab %}

{% tab title="Windows" %}

```powershell
.\vendor\bin\neuron evaluations --path=evaluators
```

{% endtab %}
{% endtabs %}

### Aserciones

Proporcionamos un conjunto de aserciones integradas para los casos de uso más comunes. También puedes implementar tu propia aserción para diseñar sistemas de puntuación personalizados. Consulta la siguiente sección.

**StringContains**

```php
$this->assert(new StringContains('positive'), $output);
```

**StringContainsAll**

Comprueba si la salida contiene todas las palabras clave:

```php
$this->assert(new StringContainsAll(['hello', 'world']), $output);
```

**StringContainsAny**

Comprueba si la salida contiene alguna de las palabras clave:

```php
$this->assert(new StringContainsAny(['success', 'completed']), $output);
```

**StringStartsWith**

Comprueba si la salida comienza con un prefijo:

```php
$this->assert(new StringStartsWith('Hello'), $output);
```

**StringEndsWith**

Comprueba si la salida termina con un sufijo:

```php
$this->assert(new StringEndsWith('!'), $output);
```

**StringLengthBetween**

Comprueba si la longitud de la cadena está dentro del rango:

```php
$this->assert(new StringLengthBetween(10, 100), $output);
```

**StringDistance**

Comprueba la similitud de cadenas usando la distancia de Levenshtein:

```php
$this->assert(new StringDistance(
    reference: 'texto esperado',
    threshold: 0.5, // Puntuación mínima de similitud
    maxDistance: 50 // Máximo de ediciones permitido
), $output);
```

**StringSimilarity**

Comprueba la similitud de cadenas usando embeddings:

```php
use NeuronAI\Evaluation\Assertions\StringSimilarity;
use NeuronAI\RAG\Embeddings\OpenAI\OpenAIEmbeddings;

$this->assert(new StringSimilarity(
    reference: 'El rápido zorro marrón',
    embeddingsProvider: new OpenAIEmbeddings(key: 'YOUR_KEY'),
    threshold: 0.6
), $output);
```

**MatchesRegex**

Coincide con una expresión regular:

```php
$this->assert(new MatchesRegex('/^\d{3}-\d{2}-\d{4}$/'), $output);
```

**IsValidJson**

Comprueba si la salida es JSON válido:

```php
$this->assert(new IsValidJson(), $output);
```

### IA como juez

Usa un agente de IA para evaluar salidas con criterios personalizados. Neuron te proporciona la clase primitiva AgentJudge para definir tus criterios personalizados; de lo contrario, puedes usar una de las aserciones de juez integradas.

```php
use NeuronAI\Evaluation\Assertions\AgentJudge;

class AgentJudgeEvaluator extends BaseEvaluator
{
    protected AgentInterface $judge;

    public function setUp(): void
    {
        $this->judge = Agent::make()
            ->setAiProvider(
                new Antrhopic(...)
            )
            ->setInstructions('Eres un evaluador experto de respuestas de atención al cliente.');
    }

    public function getDataset(): DatasetInterface
    {
        return new JsonDataset(...);
    }

    public function run(array $datasetItem): mixed
    {
        $response = MyAgent::make()->chat(
            new UserMessage($datasetItem['input'])
        )->getMessage();
        
        return $response->getContent();
    }
    
    public function evaluate(mixed $output, array $datasetItem): void
    {
        $this->assert(new AgentJudge(
            judge: $this->judge,
            criteria: 'La respuesta debe ser útil, educada y abordar directamente la pregunta del cliente',
            threshold: $datasetItem['threshold']
        ), $output);
    }
}
```

#### Juez de fidelidad

Comprueba si la salida está fundamentada en el contexto (sin alucinaciones):

```php
$this->assert(new FaithfulnessJudge(
    judge: $this->judge,
    context: $retrievedDocuments,
    threshold: 0.7
), $output);
```

#### Juez de corrección

Compara con la respuesta esperada:

```php
$this->assert(new CorrectnessJudge(
    judge: $judge,
    expected: $datasetItem['expected_answer'],
    threshold: 0.7
), $output);
```

#### Juez de relevancia

Comprueba si la salida responde a la pregunta:

```php
$this->assert(new RelevanceJudge(
    judge: $judge,
    question: $datasetItem['question'],
    threshold: 0.7
), $output);
```

#### Juez de utilidad

Evalúa la utilidad y la capacidad de acción:

```php
$this->assert(new HelpfulnessJudge(
    judge: $judge,
    threshold: 0.7
), $output);
```

### Creando aserciones personalizadas

```php
use NeuronAI\Evaluation\Assertions\AbstractAssertion;
use NeuronAI\Evaluation\AssertionResult;

class GreaterThanAssertion extends AbstractAssertion
{
    public function __construct(
        private readonly float $threshold
    ) {}

    public function evaluate(mixed $actual): AssertionResult
    {
        if (!is_numeric($actual)) {
            return AssertionResult::fail(
                0.0,
                'Se esperaba un valor numérico, se obtuvo ' . gettype($actual),
            );
        }

        if ($actual > $this->threshold) {
            return AssertionResult::pass(1.0);
        }

        return AssertionResult::fail(
            0.0,
            "Se esperaba que {$actual} fuera mayor que {$this->threshold}",
        );
    }
}
```

### Salida

El módulo de evaluación utiliza un archivo de configuración PHP para controlar cómo se muestran los resultados de la evaluación. El sistema de configuración admite varios controladores de salida, lo que permite enviar los resultados a la consola, archivos, bases de datos o APIs externas simultáneamente.

#### **Archivo de configuración**

Crea el `evaluation.php` archivo en la raíz de tu proyecto:

```php
<?php

use NeuronAI\Evaluation\OutputDrivers\ConsoleDriver;
use NeuronAI\Evaluation\OutputDrivers\JsonDriver;

return [
    'output' => [
        // Muestra los resultados en la consola
        ConsoleDriver::class => ['verbose' => true],

        // Guarda los resultados en un archivo JSON
        JsonDriver::class => ['path' => 'evaluation-results.json'],
    ],
];
```

Puedes declarar una matriz de opciones para cada clase de salida. Estas configuraciones se pasarán como argumentos al constructor de la implementación de la clase de salida.

**Si no existe un archivo de configuración**, el sistema usa por defecto `ConsoleOutputDriver` con salida estándar.

#### Creando salida personalizada

Implementa `EvaluationOutputInterface` para crear controladores de salida personalizados:

```php
namespace App\Neuron\Evaluations;

use NeuronAI\Evaluation\Contracts\EvaluationOutputInterface;
use NeuronAI\Evaluation\Runner\EvaluatorSummary;

class DatabaseOutput implements EvaluationOutputInterface
{
    public function __construct(
        private readonly \PDO $pdo,
        private readonly string $table = 'evaluations'
    ) {}

    public function output(EvaluatorSummary $summary): void
    {
        $stmt = $this->pdo->prepare(
            "INSERT INTO {$this->table} (passed, failed, success_rate, total_time, created_at, updated_at) VALUES (?, ?, ?, ?, NOW(), NOW())"
        );
        $stmt->execute([
            $summary->getPassedCount(),
            $summary->getFailedCount(),
            $summary->getSuccessRate(),
            $summary->getTotalExecutionTime(),
        ]);
    }
}
```

Una vez que hayas creado tu clase de salida, puedes registrarla en el archivo de configuración para que se use la próxima vez que ejecutes las evaluaciones.

```php
<?php

use NeuronAI\Evaluation\OutputDrivers\ConsoleDriver;
use NeuronAI\Evaluation\OutputDrivers\JsonDriver;

return [
    'output' => [
        // Muestra los resultados en la consola
        ConsoleDriver::class => ['verbose' => true],

        // Guarda los resultados en un archivo JSON
        //JsonDriver::class => ['path' => 'evaluation-results.json'],
        
        // Guarda los resultados en la base de datos
        DatabaseOutput::class => [
            'pdo' => new \PDO(...),
            'table' => 'evaluations',
        ]
    ],
];
```
