> 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-zh/agent/evaluation.md).

# 评估

本指南介绍了评估智能体的方法。有效的评估对于衡量智能体性能、跟踪改进以及确保你的智能体系统符合质量标准至关重要。

在构建 AI 应用时，评估其输出的一致性至关重要，不仅有助于维护智能体，还能在初始设计阶段评估不同的架构或提示方法。

在评估中，重要的是考虑各种定性和定量因素，包括响应语法、任务完成情况、成功率以及不准确或幻觉内容。评估时，还应考虑比较不同配置，以针对特定期望结果进行优化。鉴于 LLM 具有动态且非确定性的特性，进行严格且频繁的评估也很重要，以确保有一个一致的基线来跟踪改进或回退。

### 配置你的应用

就像单元测试一样，最好将你的 AI 系统评估器收集到一个专用目录中。因此，你可以将下面的配置添加到你的应用中 `composer.json` 文件，以便告诉 Composer 如何将你的评估器包含到应用命名空间中：

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

接下来创建 `评估器` 目录。将评估代码与生产代码分开，可以清晰地区分哪些内容会部署到生产环境，哪些内容仅用于开发和质量保障。

### 创建评估器

使用下面的命令来创建 `AgentEvaluator` 类到 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 %}

将创建的类将具有以下结构：

```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. 获取用于评估的数据集
     */
    public function getDataset(): DatasetInterface
    {
        return new JsonDataset(__DIR__ . '/datasets/dataset.json');
    }

    /**
     * 2. 运行被测试的智能体逻辑
     */
    public function run(array $datasetItem): mixed
    {
        $response = MyAgent::make()->chat(
            new UserMessage($datasetItem['input'])
         )->getMessage();
        
        return $response->getContent();
    }

    /**
     * 3. 使用断言将输出与预期结果进行评估
     */
    public function evaluate(mixed $output, array $datasetItem): void
    {
        $this->assert(
            new StringContains($datasetItem['reference']),
            $output,
        );
    }
} 
```

这个逻辑相当直接。评估器首先加载数据集，然后对数据集中的每个项目运行评估。

在 `run` 方法，你可以使用示例输入运行你的智能体实体并返回输出。然后，该输出会传递给 `evaluate` 方法，在那里你可以执行断言，将输出与参考值进行比较，或者实现你想要的任何其他逻辑。

### 数据集加载器

你可以使用任何你想要的内容作为数据集。没有预定义格式。评估器类只是允许你加载一组测试用例并对它们运行评估器。你有两种数据集加载器。

#### ArrayDataset

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

#### JsonDataset

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

你最终也可以创建一个自定义数据集加载器，实现 `NeuronAI\Evaluation\Contracts\DatasetInterface`.

### 运行评估

如果你已正确配置 composer 文件，就可以使用 Neuron CLI 启动评估器：

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

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

{% endtab %}

{% tab title="Windows" %}

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

{% endtab %}
{% endtabs %}

### 断言

我们为最常见的用例提供了一组内置断言。你也可以实现自己的断言来设计自定义评分系统。请查看下一节。

**StringContains**

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

**StringContainsAll**

检查输出是否包含所有关键词：

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

**StringContainsAny**

检查输出是否包含任意关键词：

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

**StringStartsWith**

检查输出是否以某个前缀开头：

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

**StringEndsWith**

检查输出是否以某个后缀结尾：

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

**StringLengthBetween**

检查字符串长度是否在范围内：

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

**StringDistance**

使用 Levenshtein 距离检查字符串相似度：

```php
$this->assert(new StringDistance(
    reference: '预期文本',
    threshold: 0.5, // 最低相似度分数
    maxDistance: 50 // 允许的最大编辑次数
), $output);
```

**StringSimilarity**

使用嵌入向量检查字符串相似度：

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

$this->assert(new StringSimilarity(
    reference: '敏捷的棕色狐狸',
    embeddingsProvider: new OpenAIEmbeddings(key: 'YOUR_KEY'),
    threshold: 0.6
), $output);
```

**MatchesRegex**

与正则表达式匹配：

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

**IsValidJson**

检查输出是否为有效的 JSON：

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

### 作为裁判的 AI

使用一个 AI 智能体按照自定义标准评估输出。Neuron 为你提供了基础类 AgentJudge 来定义自定义标准；否则你可以使用内置的裁判断言之一。

```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('你是一名客户支持回复的专家评估者。');
    }

    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: '回复应当有帮助、礼貌，并直接回答客户的问题',
            threshold: $datasetItem['threshold']
        ), $output);
    }
}
```

#### 忠实性裁判

检查输出是否基于上下文（无幻觉）：

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

#### 正确性裁判

与预期答案进行比较：

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

#### 相关性裁判

检查输出是否回答了问题：

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

#### 有用性裁判

评估实用性和可执行性：

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

### 创建自定义断言

```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,
                '期望数值，得到 ' . gettype($actual),
            );
        }

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

        return AssertionResult::fail(
            0.0,
            "期望 {$actual} 大于 {$this->threshold}",
        );
    }
}
```

### 输出

评估模块使用一个 PHP 配置文件来控制评估结果的显示方式。配置系统支持多个输出驱动，能够将结果同时发送到控制台、文件、数据库或外部 API。

#### **配置文件**

创建 `evaluation.php` 文件到你的项目根目录中：

```php
<?php

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

return [
    'output' => [
        // 在控制台中输出结果
        ConsoleDriver::class => ['verbose' => true],

        // 将结果保存到 json 文件中
        JsonDriver::class => ['path' => 'evaluation-results.json'],
    ],
];
```

你可以为每个输出类声明一个选项数组。这些配置会作为参数传递给输出类实现的构造函数。

**如果不存在配置文件**，系统将默认使用 `ConsoleOutputDriver` 并使用标准输出。

#### 创建自定义输出

实现 `EvaluationOutputInterface` 来创建自定义输出驱动：

```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(),
        ]);
    }
}
```

一旦你创建了输出类，就可以将其注册到配置文件中，以便在下次运行评估时使用。

```php
<?php

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

return [
    'output' => [
        // 在控制台中输出结果
        ConsoleDriver::class => ['verbose' => true],

        // 将结果保存到 json 文件中
        //JsonDriver::class => ['path' => 'evaluation-results.json'],
        
        // 将结果保存到数据库中
        DatabaseOutput::class => [
            'pdo' => new \PDO(...),
            'table' => 'evaluations',
        ]
    ],
];
```
