# 第十二章 智能体性能评估
在前面的章节中,我们构建了HelloAgents框架的核心功能,实现了多种智能体范式、工具系统、记忆机制和强化学习训练等。在构建智能体系统时,我们还需要解决一个核心问题:如何客观地评估智能体的性能? 具体来说,我们需要回答以下问题:
1. 智能体是否具备预期的能力?
2. 在不同任务上的表现如何?
3. 与其他智能体相比处于什么水平?
本章将为HelloAgents增加性能评估系统(Evaluation System)。我们将深入理解智能体评估的理论基础,并实现评估的工具。
## 12.1 智能体评估基础
### 12.1.1 为何需要智能体评估
我们现在的SimpleAgent,它已经具备了强大的推理和工具调用能力。让我们看一个典型的使用场景:
```python
from hello_agents import SimpleAgent, HelloAgentsLLM
from hello_agents.tools import SearchTool
# 创建LLM和智能体
llm = HelloAgentsLLM()
# 创建一个强调工具使用的系统提示词
system_prompt = """你是一个AI助手,可以使用搜索工具来获取最新信息。
当需要搜索信息时,请使用以下格式:
[TOOL_CALL:search:搜索关键词]
例如:
- [TOOL_CALL:search:最新AI新闻]
- [TOOL_CALL:search:Python编程教程]
请在回答问题前先使用搜索工具获取最新信息。"""
agent = SimpleAgent(name="AI助手", llm=llm, system_prompt=system_prompt)
# 添加搜索工具
agent.add_tool(SearchTool())
# 示例:使用搜索工具回答问题
response = agent.run("最新的AI技术发展趋势是什么?")
print(f"\n回答:{response}")
```
这个智能体能正常工作,但我们面临一个核心问题:如何客观地评估它的性能?当我们优化提示词或更换LLM模型后,如何知道是否真的有改进?在部署到生产环境前,如何保证智能体的可靠性?这些问题都需要通过系统化的评估来解决。
智能体评估的核心价值在于提供标准化的方法来衡量智能体的能力。通过评估,我们可以用具体的数字指标量化智能体的表现,客观比较不同设计方案的优劣,及时发现智能体在特定场景下的弱点,并向用户证明智能体的可靠性。
与传统软件测试不同,智能体评估面临着独特的挑战。首先是输出的不确定性,同一问题可能有多个正确答案,很难用简单的对错来判断。其次是评估标准的多样性,不同任务需要不同的评估方法,工具调用需要检查函数签名,问答任务需要评估语义相似度。最后是评估成本的高昂,每次评估都需要大量的API调用,成本可能达到数百元甚至更多。
为了应对这些挑战,学术界和工业界提出了多个标准化的评估基准(Benchmark)。这些基准提供了统一的数据集、评估指标和评分方法,使我们能够在相同的标准下评估和对比不同的智能体系统。
### 12.1.2 主流评估基准概览
智能体评估领域已经涌现出多个具有影响力的基准测试。下面介绍一些主流的评估基准和指标:
(1)工具调用能力评估
工具调用是智能体的核心能力之一。智能体需要理解用户意图,选择合适的工具,并正确构造函数调用。相关的评估基准包括:
- BFCL (Berkeley Function Calling Leaderboard)[1]:UC Berkeley推出,包含1120+测试样本,涵盖simple、multiple、parallel、irrelevance四个类别,使用AST匹配算法评估,数据集规模适中,社区活跃。
- ToolBench[2]:清华大学推出,包含16000+真实API调用场景,覆盖真实世界的复杂工具使用场景。
- API-Bank[3]:Microsoft Research推出,包含53个常用API工具,专注于评估智能体对API文档的理解和调用能力。
(2)通用能力评估
评估智能体在真实世界任务中的综合表现,包括多步推理、知识运用、多模态理解等能力:
- GAIA (General AI Assistants)[4]:Meta AI和Hugging Face联合推出,包含466个真实世界问题,分为Level 1/2/3三个难度级别,评估多步推理、工具使用、文件处理、网页浏览等能力,使用准精确匹配(Quasi Exact Match)算法,任务真实且综合性强。
- AgentBench[5]:清华大学推出,包含8个不同领域的任务,全面评估智能体的通用能力。
- WebArena[6]:CMU推出,评估智能体在真实网页环境中的任务完成能力和网页交互能力。
(3)多智能体协作评估
评估多个智能体协同工作的能力:
- ChatEval[7]:评估多智能体对话系统的质量。
- SOTOPIA[8]:评估智能体在社交场景中的互动能力。
- 自定义协作场景:根据具体应用场景设计的评估任务。
(4)常用评估指标
不同基准使用不同的评估指标,常见的包括:
- 准确性指标:Accuracy(准确率)、Exact Match(精确匹配)、F1 Score(F1分数),用于衡量答案的正确性。
- 效率指标:Response Time(响应时间)、Token Usage(Token使用量),用于衡量执行效率。
- 鲁棒性指标:Error Rate(错误率)、Failure Recovery(故障恢复),用于衡量容错能力。
- 协作指标:Communication Efficiency(通信效率)、Task Completion(任务完成度),用于衡量协作效果。
### 12.1.3 HelloAgents评估体系设计
考虑到学习曲线和实用性,本章将重点介绍以下评估场景:
1. BFCL:评估工具调用能力
- 选择理由:数据集规模适中,评估指标清晰,社区活跃
- 适用场景:评估智能体的函数调用准确性
2. GAIA:评估通用AI助手能力
- 选择理由:任务真实,难度分级,综合性强
- 适用场景:评估智能体的综合问题解决能力
3. 数据生成质量评估:评估LLM生成数据质量
- 选择理由:通过这个案例可以完整体验如何使用Agent创造数据,评估数据的完整演示。
- 适用场景:评估生成的训练数据、测试数据的质量
- 评估方法:LLM Judge、Win Rate、人工验证
通过这三个评估场景,我们将构建一个完整的评估体系,如图12.1展示了我们的评估系统构建思路。
图 12.1 HelloAgents评估体系架构图
### 12.1.4 本章学习目标与快速体验
让我们先看看第十二章的学习内容:
```
hello_agents/
├── evaluation/ # 评估模块
│ └── benchmarks/ # 评估基准实现
│ ├── bfcl/ # BFCL评估实现
│ │ ├── dataset.py # BFCL数据集加载器
│ │ ├── evaluator.py # BFCL评估器(AST匹配)
│ │ ├── metrics.py # BFCL专用指标
│ │ └── ast_matcher.py # AST匹配算法
│ ├── gaia/ # GAIA评估实现
│ │ ├── dataset.py # GAIA数据集加载器
│ │ ├── evaluator.py # GAIA评估器(准精确匹配)
│ │ ├── metrics.py # GAIA专用指标
│ │ └── quasi_exact_match.py # 准精确匹配算法
│ └── data_generation/ # 数据生成评估实现
│ ├── dataset.py # AIME数据集加载器
│ ├── llm_judge.py # LLM Judge评估器
│ └── win_rate.py # Win Rate评估器
└── tools/builtin/ # 内置工具模块
├── bfcl_evaluation_tool.py # BFCL评估工具
├── gaia_evaluation_tool.py # GAIA评估工具
├── llm_judge_tool.py # LLM Judge工具
└── win_rate_tool.py # Win Rate工具
```
对于这一章的内容,学习目标是掌握应用评估工具的能力。让我们先准备好开发环境:
```bash
# 安装HelloAgents框架(第12章版本)
pip install hello-agents[evaluation]==0.2.3
# 设置环境变量
export HF_TOKEN="your_huggingface_token" # 用于GAIA数据集(后续也会有设置步骤)
```
在接下来的章节中,我们将深入学习每种评估方法的详细用法和介绍。
## 12.2 BFCL:工具调用能力评估
### 12.2.1 BFCL基准介绍
BFCL (Berkeley Function Calling Leaderboard) 是由加州大学伯克利分校推出的函数调用能力评估基准[1]。在智能体系统中,工具调用(Tool Calling)是核心能力之一。智能体需要完成以下任务:
1. 理解任务需求:从用户的自然语言描述中提取关键信息
2. 选择合适工具:从可用工具集中选择最适合的工具
3. 构造函数调用:正确填写函数名和参数
4. 处理复杂场景:支持多函数调用、并行调用等高级场景
BFCL基准包含四个评估类别,难度递增。从最基础的单函数调用(Simple)开始,逐步增加到需要调用多个函数的场景(Multiple),再到需要并行调用多个函数的复杂场景(Parallel),最后是需要判断是否需要调用函数的场景(Irrelevance)。这四个类别覆盖了智能体在实际应用中可能遇到的各种工具调用场景,如表12.1所示:
表 12.1 BFCL基准中的四个评估类别
BFCL的评估流程遵循标准的基准测试流程:首先加载数据集并选择评估类别,然后运行智能体获取预测结果,接着将预测结果解析为抽象语法树(AST),最后通过AST匹配算法判断预测是否正确。整个流程会遍历所有测试样本,最终计算出准确率等评估指标并生成评估报告。完整的评估流程如图12.2所示:
图 12.2 BFCL评估流程图
(1)BFCL数据集结构
BFCL数据集采用JSON格式,每个测试样本包含以下字段:
```json
{
"id": "simple_001",
"question": "What's the weather like in Beijing today?",
"function": [
{
"name": "get_weather",
"description": "Get the current weather for a location",
"parameters": {
"type": "object",
"properties": {
"location": {
"type": "string",
"description": "The city name"
}
},
"required": ["location"]
}
}
],
"ground_truth": [
{
"name": "get_weather",
"arguments": {
"location": "Beijing"
}
}
]
}
```
关键字段说明:
- `question`: 用户的自然语言请求
- `function`: 可用的函数列表(包含函数签名和描述)
- `ground_truth`: 标准答案(期望的函数调用)
(2)AST匹配说明
BFCL使用AST匹配(Abstract Syntax Tree Matching)作为核心评估算法,因此下文可以了解一下评估的策略。
BFCL使用抽象语法树(AST)进行智能匹配,而不是简单的字符串匹配。AST匹配的核心思想是:将函数调用解析为语法树,然后比较树的结构和节点值。
给定预测的函数调用 $P$ 和标准答案 $G$,AST匹配函数定义为:
$$
\text{AST\_Match}(P, G) = \begin{cases}
1 & \text{if } \text{AST}(P) \equiv \text{AST}(G) \\
0 & \text{otherwise}
\end{cases}
$$
其中 $\text{AST}(x)$ 表示将函数调用解析为抽象语法树,$\equiv$ 表示语法树等价。
两个语法树等价需要满足三个核心条件:函数名必须完全一致(精确匹配),参数键值对集合相等(忽略顺序),以及每个参数的值在语义上等价(例如 `2+3` 等价于 `5`)。在具体的匹配过程中,函数名匹配要求字符串精确匹配,例如 `get_weather` 和 `get_temperature` 被视为不同的函数。参数匹配则使用AST进行智能比较,允许参数顺序不同(`f(a=1, b=2)` 等价于 `f(b=2, a=1)`),允许等价表达式(`f(x=2+3)` 等价于 `f(x=5)`),也允许不同的字符串表示(`f(s="hello")` 等价于 `f(s='hello')`)。对于多函数调用的场景,匹配算法要求调用相同数量的函数,每个函数调用都必须匹配,但调用顺序可以不同(使用集合匹配)。
AST匹配示例:
```python
# 示例1:参数顺序不同(匹配成功)
预测: get_weather(city="Beijing", unit="celsius")
标准: get_weather(unit="celsius", city="Beijing")
结果: ✅ 匹配成功
# 示例2:等价表达式(匹配成功)
预测: calculate(x=2+3)
标准: calculate(x=5)
结果: ✅ 匹配成功
# 示例3:函数名错误(匹配失败)
预测: get_temperature(city="Beijing")
标准: get_weather(city="Beijing")
结果: ❌ 匹配失败
# 示例4:参数值错误(匹配失败)
预测: get_weather(city="Shanghai")
标准: get_weather(city="Beijing")
结果: ❌ 匹配失败
```
(3)BFCL评估指标
BFCL使用以下指标评估智能体性能:
1. 准确率 (Accuracy)
准确率是最核心的指标,定义为AST匹配成功的样本比例:
$$
\text{Accuracy} = \frac{1}{N} \sum_{i=1}^{N} \text{AST\_Match}(P_i, G_i)
$$
其中:
- $N$ 是总样本数
- $P_i$ 是第 $i$ 个样本的预测结果
- $G_i$ 是第 $i$ 个样本的标准答案
- $\text{AST\_Match}(P_i, G_i) \in \{0, 1\}$ 是AST匹配函数
2. AST匹配率 (AST Match Rate)
与准确率相同,强调使用AST匹配算法:
$$
\text{AST Match Rate} = \text{Accuracy}
$$
3. 分类准确率 (Category-wise Accuracy)
对于每个类别 $c \in \{\text{simple}, \text{multiple}, \text{parallel}, \ldots\}$,计算该类别的准确率:
$$
\text{Accuracy}_c = \frac{1}{|D_c|} \sum_{i \in D_c} \text{AST\_Match}(P_i, G_i)
$$
其中 $D_c$ 是类别 $c$ 的样本集合,$|D_c|$ 是该类别的样本数。
4. 加权准确率 (Weighted Accuracy)
考虑不同类别的难度权重:
$$
\text{Weighted Accuracy} = \sum_{c} w_c \cdot \text{Accuracy}_c
$$
其中 $w_c$ 是类别 $c$ 的权重,满足 $\sum_c w_c = 1$。
5. 错误率 (Error Rate)
未能正确调用函数的样本比例:
$$
\text{Error Rate} = 1 - \text{Accuracy} = \frac{1}{N} \sum_{i=1}^{N} (1 - \text{AST\_Match}(P_i, G_i))
$$
指标解释:
- Accuracy = 1.0:所有样本都完全正确
- Accuracy = 0.8:80%的样本正确,20%的样本错误
- Accuracy = 0.0:所有样本都错误
分类准确率示例:
```python
# 假设评估结果
simple_accuracy = 0.95 # Simple类别:95%正确
multiple_accuracy = 0.82 # Multiple类别:82%正确
parallel_accuracy = 0.68 # Parallel类别:68%正确
# 加权准确率(假设权重相等)
weighted_accuracy = (0.95 + 0.82 + 0.68) / 3 = 0.817
```
(4)BFCL官方评估工具
BFCL提供官方CLI工具进行评估:
```bash
# 安装BFCL评估工具
pip install bfcl
# 运行官方评估
bfcl evaluate \
--model-result-path ./results.json \
--test-category simple_python
```
使用官方评估工具的优势在于:它使用官方的AST匹配算法,评估结果与排行榜完全一致,支持所有BFCL v4类别,并且能够自动生成详细的评估报告。
### 12.2.2 获取BFCL数据集
BFCL数据集可以通过以下方式获取:
方法1:从官方GitHub仓库克隆(推荐)
这是最可靠的方式,可以获取完整的数据集和ground truth:
```bash
# 克隆BFCL仓库
git clone https://github.com/ShishirPatil/gorilla.git temp_gorilla
cd temp_gorilla/berkeley-function-call-leaderboard
# 查看BFCL v4数据集
ls bfcl_eval/data/
# 输出: BFCL_v4_simple_python.json BFCL_v4_multiple.json BFCL_v4_parallel.json ...
# 查看ground truth
ls bfcl_eval/data/possible_answer/
# 输出: BFCL_v4_simple_python.json BFCL_v4_multiple.json ...
```
推荐这种方式的原因是:它包含完整的ground truth(标准答案),数据格式与官方评估工具完全一致,可以直接使用官方评估脚本,并且支持BFCL v4最新版本。
方法2:使用HelloAgents加载官方数据
克隆仓库后,使用HelloAgents加载数据:
```python
from hello_agents.evaluation import BFCLDataset
# 加载BFCL官方数据
dataset = BFCLDataset(
bfcl_data_dir="./temp_gorilla/berkeley-function-call-leaderboard/bfcl_eval/data",
category="simple_python" # BFCL v4类别
)
# 加载数据(包括测试数据和ground truth)
data = dataset.load()
print(f"✅ 加载了 {len(data)} 个测试样本")
print(f"✅ 加载了 {len(dataset.ground_truth)} 个ground truth")
# 输出:
# ✅ 加载了 400 个测试样本
# ✅ 加载了 400 个ground truth
```
这个加载器的工作原理是:首先从`bfcl_eval/data/`加载测试数据,然后从`bfcl_eval/data/possible_answer/`加载ground truth,接着自动合并测试数据和ground truth,最后保留原始BFCL数据格式。其中BFCL v4数据集类别可以在表12.2查看。
表 12.2 BFCL基准中的四个评估类别
当然也可以通过代码查看可用类别:
```python
# 获取所有支持的类别
categories = dataset.get_available_categories()
print(f"支持的类别: {categories}")
# 输出: ['simple_python', 'simple_java', 'simple_javascript', 'multiple', ...]
```
### 12.2.3 在HelloAgents中实现BFCL评估
现在让我们看看如何在HelloAgents框架中实现BFCL评估。我们提供了三种使用方式:
方式1:使用BFCLEvaluationTool(推荐)
这是最简单的方式,一行代码完成评估、报告生成和官方评估:
```python
from hello_agents import SimpleAgent, HelloAgentsLLM
from hello_agents.tools import BFCLEvaluationTool
# 1. 创建要评估的智能体
llm = HelloAgentsLLM()
agent = SimpleAgent(name="TestAgent", llm=llm)
# 2. 创建BFCL评估工具
bfcl_tool = BFCLEvaluationTool()
# 3. 运行评估(自动完成所有步骤)
results = bfcl_tool.run(
agent=agent,
category="simple_python", # 评估类别
max_samples=5 # 评估样本数(0表示全部)
)
# 4. 查看结果
print(f"准确率: {results['overall_accuracy']:.2%}")
print(f"正确数: {results['correct_samples']}/{results['total_samples']}")
```
运行输出:
```
============================================================
BFCL一键评估
============================================================
配置:
评估类别: simple_python
样本数量: 5
智能体: TestAgent
============================================================
步骤1: 运行HelloAgents评估
============================================================
✅ BFCL数据集加载完成
数据目录: ./temp_gorilla/berkeley-function-call-leaderboard/bfcl_eval/data
类别: simple_python
样本数: 400
Ground truth数: 400
🔧 开始 BFCL 评估...
进度: 1/5
进度: 5/5
✅ BFCL 评估完成
总体准确率: 100.00%
simple_python: 100.00% (5/5)
📊 评估结果:
准确率: 100.00%
正确数: 5/5
============================================================
步骤2: 导出BFCL格式结果
============================================================
✅ BFCL格式结果已导出
输出文件: ./evaluation_results/bfcl_official/BFCL_v4_simple_python_result.json
============================================================
步骤3: 运行BFCL官方评估
============================================================
✅ 结果文件已复制到: ./result/Qwen_Qwen3-8B/BFCL_v4_simple_python_result.json
🔄 运行命令: bfcl evaluate --model Qwen/Qwen3-8B --test-category simple_python --partial-eval
============================================================
BFCL官方评估结果
============================================================
📊 评估结果汇总:
Model,Overall Acc,simple_python
Qwen/Qwen3-8B,100.00,100.00
🎯 最终结果:
准确率: 100.00%
正确数: 5/5
============================================================
步骤4: 生成评估报告
============================================================
📄 报告已生成: ./evaluation_reports/bfcl_report_20251011_005938.md
准确率: 100.00%
正确数: 5/5
```
自动生成的Markdown报告:
评估完成后,会自动生成一份详细的Markdown报告,包含:
```markdown
# BFCL评估报告
**生成时间**: 2025-10-11 00:59:38
## 📊 评估概览
- **智能体**: TestAgent
- **评估类别**: simple_python
- **总体准确率**: 100.00%
- **正确样本数**: 5/5
## 📈 详细指标
### 分类准确率
- **simple_python**: 100.00% (5/5)
## 📝 样本详情
| 样本ID | 问题 | 预测结果 | 正确答案 | 是否正确 |
|--------|------|----------|----------|----------|
| simple_python_0 | Find the area of a triangle... | [{'name': 'calculate_triangle_area'...}] | [{'function_name': {'base': [10]...}}] | ✅ |
| simple_python_1 | Calculate the factorial of 5... | [{'name': 'calculate_factorial'...}] | [{'function_name': {'number': [5]}}] | ✅ |
...
## 📊 准确率可视化
准确率: ██████████████████████████████████████████████████ 100.00%
## 💡 建议
- ✅ 表现优秀!智能体在工具调用方面表现出色。
```
方式2:使用一键评估脚本
适合命令行快速评估,在这一章配套的代码案例里,我们提供了`04_run_bfcl_evaluation.py`,支持直接命令行调用测评:
```bash
# 运行评估脚本
python chapter12/04_run_bfcl_evaluation.py --category simple_python --samples 10
# 指定模型名称(用于BFCL官方评估)
python examples/04_run_bfcl_evaluation.py \
--category simple_python \
--samples 10 \
--model-name "Qwen/Qwen3-8B"
```
脚本支持三个参数:`--category`指定评估类别(默认simple_python),`--samples`指定评估样本数(默认5,0表示全部),`--model-name`指定模型名称用于BFCL官方评估(默认Qwen/Qwen3-8B)。
方式3:直接使用Dataset和Evaluator
适合需要自定义评估流程的场景:
```python
from hello_agents import SimpleAgent, HelloAgentsLLM
from hello_agents.evaluation import BFCLDataset, BFCLEvaluator
# 1. 创建智能体
llm = HelloAgentsLLM()
agent = SimpleAgent(name="TestAgent", llm=llm)
# 2. 加载数据集
dataset = BFCLDataset(
bfcl_data_dir="./temp_gorilla/berkeley-function-call-leaderboard/bfcl_eval/data",
category="simple_python"
)
data = dataset.load()
# 3. 创建评估器
evaluator = BFCLEvaluator(
dataset=dataset,
category="simple_python",
evaluation_mode="ast" # 使用AST匹配模式
)
# 4. 运行评估
results = evaluator.evaluate(agent, max_samples=10)
# 5. 查看结果
print(f"准确率: {results['overall_accuracy']:.2%}")
print(f"正确数: {results['correct_samples']}/{results['total_samples']}")
# 6. 导出BFCL格式结果(可选)
evaluator.export_to_bfcl_format(
results,
output_path="./evaluation_results/my_results.json"
)
```
通过以上三种方式,我们可以根据不同的需求选择合适的评估方法。如果只是想快速了解智能体的表现,使用BFCLEvaluationTool的一键评估最为便捷;如果需要批量评估或集成到CI/CD流程,使用命令行脚本更加合适;如果需要深度定制评估流程或集成到自己的系统中,直接使用Dataset和Evaluator提供了最大的灵活性。
### 12.2.4 BFCL官方评估工具集成
前面我们学习了如何使用HelloAgents内置的评估功能。实际上,`BFCLEvaluationTool`已经自动集成了BFCL官方评估工具,让你能够获得权威的、可对比的评估结果。
整个评估流程包括四个步骤:首先从BFCL v4数据集加载测试数据,然后使用HelloAgents运行评估获取智能体的预测结果,接着将结果导出为BFCL官方格式(JSONL),最后使用官方评估脚本计算最终分数。这个流程确保了评估结果与BFCL排行榜完全一致,如图12.3所示:
图 12.3 Helloagents载入BFCL评估过程
使用`BFCLEvaluationTool`时,官方评估会自动运行(默认启用):
```python
from hello_agents import SimpleAgent, HelloAgentsLLM
from hello_agents.tools import BFCLEvaluationTool
# 创建智能体
llm = HelloAgentsLLM()
agent = SimpleAgent(name="TestAgent", llm=llm)
# 创建评估工具
bfcl_tool = BFCLEvaluationTool()
# 运行评估(自动运行官方评估)
results = bfcl_tool.run(
agent=agent,
category="simple_python",
max_samples=5,
# run_official_eval=True # 默认为True,可以省略
model_name="Qwen/Qwen3-8B" # 可选,指定模型名称
)
```
工具会自动执行完整的评估流程:首先运行HelloAgents评估获取预测结果,然后将结果导出为BFCL格式并保存到`evaluation_results/bfcl_official/`目录,接着复制结果文件到`result/{model_name}/`目录以符合官方评估工具的要求,随后运行BFCL官方评估命令计算分数,最后显示官方评估结果并生成Markdown格式的评估报告。
官方评估输出示例:
```
============================================================
步骤3: 运行BFCL官方评估
============================================================
✅ 结果文件已复制到:
./result/Qwen_Qwen3-8B/BFCL_v4_simple_python_result.json
🔄 运行命令: bfcl evaluate --model Qwen/Qwen3-8B --test-category simple_python --partial-eval
============================================================
BFCL官方评估结果
============================================================
📊 评估结果汇总:
Model,Overall Acc,simple_python
Qwen/Qwen3-8B,100.00,100.00
🎯 最终结果:
准确率: 100.00%
正确数: 5/5
```
如果你想手动控制评估流程,可以禁用自动官方评估:
```python
# 禁用官方评估
results = bfcl_tool.run(
agent=agent,
category="simple_python",
max_samples=5,
run_official_eval=False # 禁用官方评估
)
# 然后手动运行官方评估
import subprocess
subprocess.run([
"bfcl", "evaluate",
"--model", "Qwen/Qwen3-8B",
"--test-category", "simple_python",
"--partial-eval"
])
```
你也可以手动生成报告:
```python
# 运行评估
results = bfcl_tool.run(agent, category="simple_python", max_samples=5)
# 手动生成报告
report = bfcl_tool.generate_report(
results,
output_file="./my_reports/custom_report.md"
)
# 打印报告内容
print(report)
```
### 12.2.5 核心组件实现细节
在前面的小节中,我们学习了如何使用BFCL评估工具。现在让我们深入了解HelloAgents评估系统的核心组件是如何实现的。理解这些实现细节不仅能帮助你更好地使用评估系统,还能让你根据自己的需求进行定制和扩展。
(1)BFCLDataset:数据集加载器
BFCLDataset负责加载和管理BFCL数据集:
````python
class BFCLDataset:
"""BFCL数据集加载器"""
def __init__(self, category: str = "simple", local_data_path: Optional[str] = None):
self.category = category
self.local_data_path = local_data_path
self.data = []
def load(self) -> List[Dict[str, Any]]:
"""加载数据集"""
# 优先从本地加载
if self.local_data_path:
return self._load_from_local()
# 否则从Hugging Face加载
return self._load_from_huggingface()
````
因为BFCL的数据集就在官方的仓库内,所以这里建议的方式是直接在本地clone一份进行测评。当找不到时才到huggingface进行加载。
(2)BFCLEvaluator:评估执行器
BFCLEvaluator负责执行评估流程。它的核心是`evaluate()`方法,该方法协调整个评估过程:
````python
class BFCLEvaluator:
"""BFCL评估器"""
def evaluate(self, agent: Any, max_samples: Optional[int] = None) -> Dict[str, Any]:
"""执行评估"""
results = []
for item in self.dataset[:max_samples]:
# 1. 构造提示词
prompt = self._build_prompt(item)
# 2. 调用智能体
response = agent.run(prompt)
# 3. 提取函数调用
predicted_calls = self._extract_function_calls(response)
# 4. 与标准答案对比
is_correct = self._compare_calls(predicted_calls, item["ground_truth"])
results.append({
"id": item["id"],
"prediction": predicted_calls,
"ground_truth": item["ground_truth"],
"is_correct": is_correct
})
return {"results": results, "total_samples": len(results)}
````
这个评估器的设计包含三个核心要点:首先是提示词构造,需要将数据集中的问题和函数定义转换为智能体可理解的提示词;其次是函数调用提取,需要从智能体的响应中提取函数调用,并支持多种格式(JSON、代码块等);最后是AST匹配,使用抽象语法树进行函数调用对比,这比简单的字符串匹配更准确。
让我们看看函数调用提取的实现:
```python
def _extract_function_calls(self, response: str) -> List[Dict[str, Any]]:
"""从响应中提取函数调用
支持多种格式:
1. JSON格式:{"name": "func", "arguments": {...}}
2. 代码块格式:```python\nfunc(arg1=val1)\n```
3. 纯文本格式:func(arg1=val1)
"""
calls = []
# 尝试JSON解析
try:
json_match = re.search(r'\{.*\}', response, re.DOTALL)
if json_match:
data = json.loads(json_match.group())
if isinstance(data, dict) and "name" in data:
calls.append(data)
elif isinstance(data, list):
calls.extend(data)
except json.JSONDecodeError:
pass
# 尝试代码块提取
code_blocks = re.findall(r'```(?:python)?\n(.*?)\n```', response, re.DOTALL)
for code in code_blocks:
# 解析Python函数调用
parsed_calls = self._parse_python_calls(code)
calls.extend(parsed_calls)
return calls
```
(3)BFCLMetrics:指标计算器
BFCLMetrics负责计算各种评估指标:
````python
class BFCLMetrics:
"""BFCL指标计算器"""
def compute_metrics(self, results: List[Dict[str, Any]]) -> Dict[str, Any]:
"""计算所有指标"""
return {
"accuracy": self._compute_accuracy(results),
"ast_match_rate": self._compute_ast_match_rate(results),
"parameter_accuracy": self._compute_parameter_accuracy(results),
"f1_score": self._compute_f1_score(results),
"category_statistics": self._compute_category_stats(results)
}
````
AST匹配的实现:
AST匹配是BFCL评估的核心技术。它比简单的字符串匹配更智能,能够识别语义等价的函数调用:
```python
def _ast_match(self, pred_call: Dict, true_call: Dict) -> bool:
"""使用AST匹配函数调用
AST匹配的优势:
1. 忽略参数顺序:func(a=1, b=2) 等价于 func(b=2, a=1)
2. 识别等价表达式:2+3 等价于 5
3. 忽略空格和格式差异
"""
# 1. 函数名必须完全匹配
if pred_call.get("name") != true_call.get("name"):
return False
# 2. 将参数转换为AST节点
pred_args = self._args_to_ast(pred_call.get("arguments", {}))
true_args = self._args_to_ast(true_call.get("arguments", {}))
# 3. 比较AST节点
return ast.dump(pred_args) == ast.dump(true_args)
def _args_to_ast(self, args: Dict[str, Any]) -> ast.AST:
"""将参数字典转换为AST节点"""
# 构造一个虚拟的函数调用
code = f"func({', '.join(f'{k}={repr(v)}' for k, v in args.items())})"
tree = ast.parse(code)
return tree.body[0].value # 返回Call节点
```
(4)工具化封装:BFCLEvaluationTool
最后,我们将这些组件封装成一个Tool,让它可以被智能体直接调用:
````python
class BFCLEvaluationTool(Tool):
"""BFCL评估工具"""
def __init__(self, local_data_path: Optional[str] = None):
super().__init__(
name="bfcl_evaluation",
description="评估智能体的工具调用能力"
)
self.dataset = None
self.evaluator = None
self.metrics_calculator = BFCLMetrics()
def run(self, parameters: Dict[str, Any]) -> str:
"""执行评估"""
# 1. 加载数据集
self.dataset = BFCLDataset(...)
# 2. 创建评估器
self.evaluator = BFCLEvaluator(...)
# 3. 运行评估
results = self.evaluator.evaluate(...)
# 4. 计算指标
metrics = self.metrics_calculator.compute_metrics(...)
# 5. 返回JSON结果
return json.dumps(results, ensure_ascii=False)
````
这个工具的设计遵循三个核心原则:首先继承Tool基类以遵循HelloAgents的工具规范,确保与框架的无缝集成;其次进行严格的参数验证,检查必需参数并提供友好的错误提示,提升用户体验;最后对结果进行格式化,返回JSON字符串以便于解析和展示。通过这种模块化的设计,我们实现了一个既易用又灵活的评估系统,用户可以直接使用高层的Tool接口快速完成评估,也可以深入到底层组件进行定制以满足特殊需求。
### 12.2.6 扩展与优化建议
通过前面的学习,我们已经掌握了如何使用HelloAgents进行BFCL评估。需要注意的是,我们目前的实现是基于SimpleAgent的简单复现,主要完成了BFCL评估的基础功能。在实际应用中,BFCL基准包含多个难度级别和场景,要在排行榜上获得更高的分数,还需要进一步的优化和扩展。
(1)当前实现的局限性
我们当前的SimpleAgent实现主要聚焦于评估流程的搭建,在工具调用能力上还有提升空间。SimpleAgent使用自定义的工具调用格式`[TOOL_CALL:tool_name:parameters]`,这种格式需要LLM主动学习和使用,在复杂场景下的表现可能不如使用原生函数调用(Function Calling)的智能体。此外,我们目前只测试了simple_python等基础类别,对于multiple、parallel、irrelevance等更复杂的场景,还需要针对性的优化。
(2)提升BFCL分数的方向
要进一步提升BFCL评估分数,可以从以下几个方向入手。首先是优化智能体的工具调用能力,可以考虑使用支持原生函数调用的LLM(如GPT-4、Claude等),或者改进提示词让LLM更好地理解工具调用格式。其次是扩展工具库,BFCL测试中涉及各种类型的函数,可以根据测试数据集的特点,预先实现常用的工具类型,提高智能体的工具覆盖率。第三是针对不同难度级别设计不同的策略,例如在multiple场景下需要智能体能够规划多步骤的工具调用序列,在parallel场景下需要识别可以并行执行的工具调用,在irrelevance场景下需要判断是否真的需要调用工具。
(3)实践建议
对于想要在BFCL上取得更好成绩的开发者,建议采用以下实践策略。首先,从simple类别开始,确保基础的单函数调用能够稳定工作,这是后续优化的基础。然后,逐步测试multiple、parallel等更复杂的类别,分析失败案例,找出智能体的薄弱环节。在优化过程中,可以参考BFCL排行榜上的高分模型,学习它们的设计思路和优化技巧。同时,建议使用官方评估工具进行验证,确保优化后的结果与排行榜标准一致。
这里总结一些评估时可以进一步处理的建议:
1. 渐进式评估
从小样本开始,逐步增加样本数:
```python
# 第一步:快速测试(5个样本)
results_quick = bfcl_tool.run(agent, category="simple_python", max_samples=5)
# 第二步:中等规模测试(50个样本)
if results_quick['overall_accuracy'] > 0.8:
results_medium = bfcl_tool.run(agent, category="simple_python", max_samples=50)
# 第三步:完整评估(全部样本)
if results_medium['overall_accuracy'] > 0.8:
results_full = bfcl_tool.run(agent, category="simple_python", max_samples=0)
```
2. 多类别评估
评估不同难度的任务:
```python
categories = ["simple_python", "multiple", "parallel", "irrelevance"]
for category in categories:
print(f"\n评估类别: {category}")
results = bfcl_tool.run(agent, category=category, max_samples=10)
print(f"准确率: {results['overall_accuracy']:.2%}")
```
3. 对比评估
对比不同配置的智能体:
```python
# 配置1:默认提示词
agent1 = SimpleAgent(name="Agent-Default", llm=llm)
results1 = bfcl_tool.run(agent1, category="simple_python", max_samples=10)
# 配置2:优化提示词
agent2 = SimpleAgent(name="Agent-Optimized", llm=llm)
# ... 设置优化的系统提示词 ...
results2 = bfcl_tool.run(agent2, category="simple_python", max_samples=10)
# 对比结果
print(f"默认配置准确率: {results1['overall_accuracy']:.2%}")
print(f"优化配置准确率: {results2['overall_accuracy']:.2%}")
```
如果你的评估结果很好,可以考虑提交到BFCL官方排行榜!
步骤1:准备提交材料
1. 模型描述文档
2. 评估结果文件(所有类别)
3. 模型访问方式(API或开源链接)
步骤2:提交到GitHub
访问BFCL官方仓库,按照说明提交Pull Request:
- 仓库地址:https://github.com/ShishirPatil/gorilla
- 提交指南:参考`CONTRIBUTING.md`
步骤3:等待审核
BFCL团队会审核你的提交,验证结果的准确性。审核通过后,你的模型将出现在官方排行榜上!
## 12.3 GAIA:通用AI助手能力评估
### 12.3.1 GAIA基准介绍
GAIA (General AI Assistants) 是由Meta AI和Hugging Face联合推出的评估基准,专注于评估AI助手的通用能力[2]。与BFCL专注于工具调用不同,GAIA评估的是智能体在真实世界任务中的综合表现。
GAIA的设计理念是:真实世界的问题往往需要多种能力的综合运用。一个优秀的AI助手不仅需要调用工具,还需要:
- 多步推理:将复杂问题分解为多个子问题
- 知识运用:利用内置知识和外部知识库
- 多模态理解:处理文本、图片、文件等多种输入
- 网页浏览:从互联网获取最新信息
- 文件操作:读取和处理各种格式的文件
(1)GAIA数据集结构
了解GAIA的评估理念后,让我们深入了解GAIA数据集的具体结构。GAIA包含466个精心设计的真实世界问题,这些问题按照复杂度和所需推理步骤分为三个难度级别,从简单的零步推理任务到需要多步复杂推理的困难任务,全面覆盖了智能体在实际应用中可能遇到的各种场景,如表12.3所示:
表 12.3 GAIA 数据集难度级别分布
关于GAIA数据集的样本示例可以参考下面的代码片段:
```json
{
"task_id": "gaia_001",
"Question": "What is the total population of the top 3 most populous cities in California?",
"Level": 2,
"Final answer": "12847521",
"file_name": "",
"file_path": "",
"Annotator Metadata": {
"Steps": [
"Search for most populous cities in California",
"Get population data for top 3 cities",
"Sum the populations"
],
"Number of steps": 3,
"How long did this take?": "5 minutes",
"Tools": ["web_search", "calculator"]
}
}
```
关键字段说明:
- `Question`: 问题描述
- `Level`: 难度级别(1-3)
- `Final answer`: 标准答案(可能是数字、文本或文件)
- `file_name/file_path`: 附件文件(如果有)
- `Annotator Metadata`: 标注者提供的元数据(推理步骤、所需工具等)
(2)准精确匹配介绍
GAIA使用准精确匹配(Quasi Exact Match)评估算法,这是GAIA官方定义的评估标准。该算法的核心思想是:先对答案进行归一化处理,然后进行精确匹配。
给定预测答案 $A_{\text{pred}}$ 和标准答案 $A_{\text{true}}$,准精确匹配函数定义为:
$$
\text{Quasi\_Exact\_Match}(A_{\text{pred}}, A_{\text{true}}) = \begin{cases}
1 & \text{if } \mathcal{N}(A_{\text{pred}}) = \mathcal{N}(A_{\text{true}}) \\
0 & \text{otherwise}
\end{cases}
$$
其中 $\mathcal{N}(\cdot)$ 是归一化函数,根据答案类型应用不同的规则。
归一化函数根据答案类型应用不同的规则。对于数字类型,需要移除逗号分隔符(`1,000` → `1000`)和单位符号(`$100` → `100`,`50%` → `50`),例如`"$1,234.56"`归一化为`"1234.56"`。对于字符串类型,需要转换为小写(`"Apple"` → `"apple"`)、移除冠词(`"the apple"` → `"apple"`)、移除多余空格(`"hello world"` → `"hello world"`)和移除末尾标点(`"hello."` → `"hello"`),例如`"The United States"`归一化为`"united states"`。对于列表类型,需要按逗号分隔元素,对每个元素应用字符串归一化,按字母顺序排序后重新连接,例如`"Paris, London, Berlin"`归一化为`"berlin,london,paris"`。
归一化示例:
```python
# 数字答案
原始答案: "$1,234.56"
归一化后: "1234.56"
# 字符串答案
原始答案: "The United States of America"
归一化后: "united states of america"
# 列表答案
原始答案: "Paris, London, Berlin"
归一化后: "berlin, london, paris"
```
(3)GAIA评估指标
GAIA使用以下指标评估智能体性能:
1. 精确匹配率 (Exact Match Rate)
精确匹配率是GAIA的核心指标,定义为准精确匹配成功的样本比例:
$$
\text{Exact Match Rate} = \frac{1}{N} \sum_{i=1}^{N} \text{Quasi\_Exact\_Match}(A_{\text{pred},i}, A_{\text{true},i})
$$
其中:
- $N$ 是总样本数
- $A_{\text{pred},i}$ 是第 $i$ 个样本的预测答案
- $A_{\text{true},i}$ 是第 $i$ 个样本的标准答案
- $\text{Quasi\_Exact\_Match}(\cdot, \cdot) \in \{0, 1\}$ 是准精确匹配函数
2. 分级准确率 (Level-wise Accuracy)
对于每个难度级别 $\ell \in \{1, 2, 3\}$,计算该级别的准确率:
$$
\text{Accuracy}_\ell = \frac{1}{|D_\ell|} \sum_{i \in D_\ell} \text{Quasi\_Exact\_Match}(A_{\text{pred},i}, A_{\text{true},i})
$$
其中 $D_\ell$ 是难度级别 $\ell$ 的样本集合,$|D_\ell|$ 是该级别的样本数。
3. 难度递进下降率 (Difficulty Progression Drop Rate)
衡量智能体在难度增加时的性能衰减:
$$
\text{Drop Rate}_{\ell \to \ell+1} = \frac{\text{Accuracy}_\ell - \text{Accuracy}_{\ell+1}}{\text{Accuracy}_\ell}
$$
- $\text{Drop Rate}_{1 \to 2}$:从Level 1到Level 2的下降率
- $\text{Drop Rate}_{2 \to 3}$:从Level 2到Level 3的下降率
4. 平均推理步骤数 (Average Reasoning Steps)
评估智能体完成任务所需的平均步骤数:
$$
\text{Avg Steps} = \frac{1}{N_{\text{correct}}} \sum_{i \in \text{Correct}} \text{steps}_i
$$
其中 $N_{\text{correct}}$ 是正确回答的样本数,$\text{steps}_i$ 是第 $i$ 个样本的推理步骤数。
指标解释:
- Exact Match Rate = 1.0:所有样本都完全正确
- Exact Match Rate = 0.5:50%的样本正确,50%的样本错误
- Drop Rate = 0.3:难度增加导致准确率下降30%
- Drop Rate = 0.0:难度增加不影响准确率(理想情况)
评估示例:
假设我们评估了10个样本,结果可以参考表12.4所示:
表 12.4 GAIA 数据集难度级别分布
如果要计算这个案例的指标的话,可以参考下面的Python脚本。
```python
# 1. 精确匹配率
total_samples = 10
correct_samples = 7 # 样本1,2,3,5,6,8,9
exact_match_rate = correct_samples / total_samples = 0.70 # 70%
# 2. 分级准确率
level_1_correct = 3 # 样本1,2,3
level_1_total = 3
level_1_accuracy = 3 / 3 = 1.00 # 100%
level_2_correct = 2 # 样本5,6
level_2_total = 3
level_2_accuracy = 2 / 3 = 0.67 # 67%
level_3_correct = 2 # 样本8,9
level_3_total = 4
level_3_accuracy = 2 / 4 = 0.50 # 50%
# 3. 难度递进下降率
drop_rate_1_to_2 = (1.00 - 0.67) / 1.00 = 0.33 # 33%
drop_rate_2_to_3 = (0.67 - 0.50) / 0.67 = 0.25 # 25%
print(f"精确匹配率: {exact_match_rate:.2%}") # 70.00%
print(f"Level 1准确率: {level_1_accuracy:.2%}") # 100.00%
print(f"Level 2准确率: {level_2_accuracy:.2%}") # 66.67%
print(f"Level 3准确率: {level_3_accuracy:.2%}") # 50.00%
print(f"Level 1→2 下降率: {drop_rate_1_to_2:.2%}") # 33.00%
print(f"Level 2→3 下降率: {drop_rate_2_to_3:.2%}") # 25.00%
```
结果分析:
- 整体表现:70%的精确匹配率,表现良好
- 难度敏感性:从Level 1到Level 2下降33%,说明智能体在中等难度任务上有明显衰减
- 能力边界:Level 3准确率为50%,说明智能体在复杂任务上仍有提升空间
下降率越大,说明智能体在处理复杂任务时的能力衰减越明显。
(4)GAIA官方系统提示词
GAIA要求使用特定的系统提示词,确保模型输出符合评估格式:
```python
GAIA_SYSTEM_PROMPT = """You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template: FINAL ANSWER: [YOUR FINAL ANSWER].
YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.
If you are asked for a number, don't use comma to write your number neither use units such as $ or percent sign unless specified otherwise.
If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the digits in plain text unless specified otherwise.
If you are asked for a comma separated list, apply the above rules depending of whether the element to be put in the list is a number or a string."""
```
GAIA对答案格式有严格的要求:答案必须以`FINAL ANSWER: [答案]`的格式给出;对于数字类型的答案,不使用逗号分隔符和单位符号;对于字符串类型的答案,不使用冠词和缩写;对于列表类型的答案,使用逗号分隔并按字母顺序排列。
### 12.3.2 获取GAIA数据集
重要提示:GAIA是受限数据集(Gated Dataset),需要先在HuggingFace上申请访问权限。
步骤1:申请访问权限
1. 访问 https://huggingface.co/datasets/gaia-benchmark/GAIA
2. 点击"Request access"按钮
3. 填写申请表单(通常会在几秒内批准)
4. 获取你的HuggingFace Token:https://huggingface.co/settings/tokens
步骤2:配置环境变量
在`.env`文件中添加你的HuggingFace Token:
```bash
# HuggingFace API 配置
HF_TOKEN=hf_your_token_here
```
方法1:使用HelloAgents自动下载(推荐)
HelloAgents会自动处理GAIA数据集的下载和缓存:
```python
from hello_agents.evaluation import GAIADataset
import os
# 确保设置了HF_TOKEN,如果设置了.env无需这一行
os.environ["HF_TOKEN"] = "hf_your_token_here"
# 自动下载到 ./data/gaia/
dataset = GAIADataset(
dataset_name="gaia-benchmark/GAIA",
split="validation", # 或 "test"
level=1 # 可选: 1, 2, 3, None(全部)
)
items = dataset.load()
print(f"加载了 {len(items)} 个测试样本")
# 输出: 加载了 53 个测试样本 (Level 1)
```
工作原理:
- 首次运行时,使用`snapshot_download`下载整个数据集到`./data/gaia/`
- 数据集包含114个文件(问题、图片、PDF等材料)
- 后续使用直接从本地加载,速度很快
数据集目录结构:
```
./data/gaia/
├── 2023/
│ ├── validation/
│ │ ├── metadata.jsonl (165个问题)
│ │ ├── *.png, *.pdf, *.csv, *.xlsx (附件文件)
│ └── test/
│ ├── metadata.jsonl (301个问题)
│ └── ... (附件文件)
├── GAIA.py
└── README.md
```
方法2:手动下载
如果你想手动下载数据集:
```python
from huggingface_hub import snapshot_download
import os
# 设置Token
os.environ["HF_TOKEN"] = "hf_your_token_here"
# 下载数据集
snapshot_download(
repo_id="gaia-benchmark/GAIA",
repo_type="dataset",
local_dir="./data/gaia",
token=os.getenv("HF_TOKEN")
)
```
查看数据集统计:
```python
# 查看数据集统计
stats = dataset.get_statistics()
print(f"总样本数: {stats['total_samples']}")
print(f"级别分布: {stats['level_distribution']}")
# 输出:
# 总样本数: 165
# 级别分布: {1: 53, 2: 62, 3: 50}
```
### 12.3.3 在HelloAgents中实现GAIA评估
与BFCL类似,我们提供两种评估方式,推荐使用方式1。
方式1:使用GAIAEvaluationTool一键评估
这是最简单的方式,自动完成数据集下载、评估执行、结果导出和报告生成:
```python
from hello_agents import SimpleAgent, HelloAgentsLLM
from hello_agents.tools import GAIAEvaluationTool
# GAIA官方系统提示词(来自论文)
GAIA_SYSTEM_PROMPT = """You are a general AI assistant. I will ask you a question. Report your thoughts, and finish your answer with the following template: FINAL ANSWER: [YOUR FINAL ANSWER].
YOUR FINAL ANSWER should be a number OR as few words as possible OR a comma separated list of numbers and/or strings.
If you are asked for a number, don't use comma to write your number neither use units such as $ or percent sign unless specified otherwise.
If you are asked for a string, don't use articles, neither abbreviations (e.g. for cities), and write the digits in plain text unless specified otherwise.
If you are asked for a comma separated list, apply the above rules depending of whether the element to be put in the list is a number or a string."""
# 1. 创建智能体(使用GAIA官方系统提示词)
llm = HelloAgentsLLM()
agent = SimpleAgent(
name="TestAgent",
llm=llm,
system_prompt=GAIA_SYSTEM_PROMPT # 关键:使用GAIA官方提示词
)
# 2. 创建GAIA评估工具
gaia_tool = GAIAEvaluationTool()
# 3. 一键运行评估
results = gaia_tool.run(
agent=agent,
level=1, # Level 1: 简单任务
max_samples=5, # 评估5个样本
export_results=True, # 导出GAIA格式结果
generate_report=True # 生成评估报告
)
# 4. 查看结果
print(f"精确匹配率: {results['exact_match_rate']:.2%}")
print(f"部分匹配率: {results['partial_match_rate']:.2%}")
print(f"正确数: {results['exact_matches']}/{results['total_samples']}")
```
运行结果:
```
============================================================
GAIA一键评估
============================================================
配置:
智能体: TestAgent
难度级别: 1
样本数量: 5
============================================================
步骤1: 运行HelloAgents评估
============================================================
正在从HuggingFace下载: gaia-benchmark/GAIA
📥 下载GAIA数据集...
✓ 数据集下载完成
✓ 加载了 165 个样本
✅ GAIA数据集加载完成
数据源: gaia-benchmark/GAIA
分割: validation
级别: 1
样本数: 53
🌟 开始 GAIA 评估...
样本数量: 5
进度: 5/5
✅ GAIA 评估完成
精确匹配率: 80.00%
部分匹配率: 80.00%
============================================================
步骤2: 导出GAIA格式结果
============================================================
✅ GAIA格式结果已导出
输出文件: evaluation_results\gaia_official\gaia_level1_result_20251011_012648.jsonl
样本数: 5
包含推理轨迹: True
📄 提交说明已生成: evaluation_results\gaia_official\SUBMISSION_GUIDE_20251011_012648.md
============================================================
步骤3: 生成评估报告
============================================================
📄 报告已生成: evaluation_reports\gaia_report_20251011_012648.md
============================================================
🎯 最终结果
============================================================
精确匹配率: 80.00%
部分匹配率: 80.00%
正确数: 4/5
```
评估完成后会自动生成三类文件:首先是GAIA格式结果文件(`evaluation_results/gaia_official/gaia_level1_result_*.jsonl`),采用JSONL格式(每行一个JSON对象),可直接用于提交到GAIA排行榜;其次是提交说明文件(`evaluation_results/gaia_official/SUBMISSION_GUIDE_*.md`),包含详细的提交步骤、结果文件格式说明和注意事项;最后是评估报告(`evaluation_reports/gaia_report_*.md`),包含评估结果摘要、详细指标、样本详情和可视化图表。
注意:如果你发现生成的评估结果不理想(例如准确率较低),这是正常现象。虽然Level 1是一步推理任务,但仍然需要智能体具备工具调用能力(如搜索引擎、计算器等)才能正确回答问题。我们当前使用的SimpleAgent主要用于演示评估流程,在工具调用能力上还有提升空间。
方式2:使用Dataset + Evaluator(灵活定制)
如果需要更细粒度的控制,可以直接使用底层组件:
```python
from hello_agents.evaluation import GAIADataset, GAIAEvaluator
# 1. 加载数据集
dataset = GAIADataset(level=1)
items = dataset.load()
print(f"加载了 {len(items)} 个样本")
# 2. 创建评估器
evaluator = GAIAEvaluator(dataset=dataset, level=1)
# 3. 运行评估
results = evaluator.evaluate(agent, max_samples=5)
# 4. 导出GAIA格式结果
evaluator.export_to_gaia_format(
results,
"gaia_results.jsonl",
include_reasoning=True
)
```
生成的评估报告(`gaia_report_*.md`)可参考下面的文件:
```markdown
# GAIA评估报告
**生成时间**: 2025-10-11 01:26:48
## 📊 评估概览
- **智能体**: TestAgent
- **难度级别**: 1
- **总样本数**: 2
- **精确匹配数**: 1
- **部分匹配数**: 1
- **精确匹配率**: 50.00%
- **部分匹配率**: 50.00%
## 📈 详细指标
### 分级准确率
- **Level 1**: 50.00% 精确 / 50.00% 部分 (1/2)
## 📝 样本详情(前10个)
| 任务ID | 级别 | 预测答案 | 正确答案 | 精确匹配 | 部分匹配 |
|--------|------|----------|----------|----------|----------|
| e1fc63a2-da7a-432f-be78-7c4a95598703 | 1 | 24000 | 17 | ❌ | ❌ |
| 8e867cd7-cff9-4e6c-867a-ff5ddc2550be | 1 | 3 | 3 | ✅ | ✅ |
## 📊 准确率可视化
精确匹配: █████████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░ 50.00%
部分匹配: █████████████████████████░░░░░░░░░░░░░░░░░░░░░░░░░ 50.00%
## 💡 建议
- ⚠️ 表现一般,需要改进。
- 💡 建议检查工具使用和多步推理能力。
```
**生成的GAIA格式结果(`gaia_level1_result_*.jsonl`):
```json
{"task_id": "e1fc63a2-da7a-432f-be78-7c4a95598703", "model_answer": "24000", "reasoning_trace": "24000"}
{"task_id": "8e867cd7-cff9-4e6c-867a-ff5ddc2550be", "model_answer": "3", "reasoning_trace": "3"}
```
### 12.3.4 提交结果到GAIA官方排行榜
使用GAIAEvaluationTool运行评估后,会在`evaluation_results/gaia_official/`目录下生成提交所需的文件和详细的提交说明。
1. GAIA格式结果文件**:`gaia_level1_result_*.jsonl`
```json
{"task_id": "xxx", "model_answer": "答案", "reasoning_trace": "推理过程"}
{"task_id": "yyy", "model_answer": "答案", "reasoning_trace": "推理过程"}
```
2. 提交说明文件:`SUBMISSION_GUIDE_*.md`
打开自动生成的`SUBMISSION_GUIDE_*.md`文件,里面包含完整的提交指南:
具体来说,打开浏览器,访问:
```
https://huggingface.co/spaces/gaia-benchmark/leaderboard
```
如图12.4所示,提交表单中填写信息即可:
图 12.4 BFCL评估流程图
提交前,可以手动检查生成的JSONL文件:
```python
import json
# 读取结果文件
with open("evaluation_results/gaia_official/gaia_level1_result_*.jsonl", "r") as f:
for line in f:
result = json.loads(line)
print(f"Task ID: {result['task_id']}")
print(f"Answer: {result['model_answer']}")
print(f"Reasoning: {result['reasoning_trace']}")
print("-" * 50)
```
### 12.3.5 核心组件实现细节
GAIA评估系统的实现与BFCL类似,但针对通用能力评估有一些特殊的设计。
(1)GAIADataset:支持多模态的数据加载器
GAIA数据集的特殊之处在于它包含多模态数据(文本、文件、图片等):
````python
class GAIADataset:
"""GAIA数据集加载器
支持从HuggingFace加载GAIA数据集(受限数据集)
"""
def __init__(
self,
level: Optional[int] = None,
split: str = "validation",
local_data_dir: Optional[str] = None
):
self.level = level
self.split = split
self.local_data_dir = local_data_dir or "./data/gaia"
self.data = []
def load(self) -> List[Dict[str, Any]]:
"""加载数据集"""
# 从HuggingFace下载
items = self._load_from_huggingface()
# 按级别过滤
if self.level:
items = [item for item in items if item.get("level") == self.level]
self.data = items
return items
def _load_from_huggingface(self) -> List[Dict[str, Any]]:
"""从HuggingFace下载GAIA数据集"""
from huggingface_hub import snapshot_download
import json
# 下载数据集
repo_id = "gaia-benchmark/GAIA"
local_dir = snapshot_download(
repo_id=repo_id,
repo_type="dataset",
local_dir=self.local_data_dir,
local_dir_use_symlinks=False
)
# 加载JSONL文件
data_file = Path(local_dir) / "2023" / self.split / "metadata.jsonl"
items = []
with open(data_file, 'r', encoding='utf-8') as f:
for line in f:
item = json.loads(line)
items.append(self._standardize_item(item))
return items
````
(2)GAIAEvaluator:实现GAIA官方评估算法
GAIA的评估使用准精确匹配(Quasi Exact Match)算法,需要特殊的答案归一化和匹配逻辑:
````python
class GAIAEvaluator:
"""GAIA评估器
实现GAIA官方的准精确匹配(Quasi Exact Match)评估算法
"""
def evaluate(self, agent: Any, max_samples: Optional[int] = None) -> Dict[str, Any]:
"""执行评估"""
dataset_items = self.dataset.load()
if max_samples:
dataset_items = dataset_items[:max_samples]
results = []
for i, item in enumerate(dataset_items, 1):
# 1. 构造提示词
prompt = self._build_prompt(item["question"], item)
# 2. 调用智能体
response = agent.run(prompt)
# 3. 提取答案(GAIA格式:FINAL ANSWER: [答案])
predicted_answer = self._extract_answer(response)
# 4. 归一化答案(GAIA官方规则)
normalized_pred = self._normalize_answer(predicted_answer)
normalized_truth = self._normalize_answer(item["final_answer"])
# 5. 准精确匹配
exact_match = (normalized_pred == normalized_truth)
results.append({
"task_id": item["task_id"],
"predicted": predicted_answer,
"expected": item["final_answer"],
"exact_match": exact_match,
"level": item.get("level", 0)
})
return self._format_results(results)
````
GAIA使用特定的归一化规则来处理不同类型的答案:
```python
def _normalize_answer(self, answer: str) -> str:
"""标准化答案字符串(GAIA官方标准化规则)
规则:
1. 数字:移除逗号分隔符和单位符号
2. 字符串:移除冠词、转小写、移除多余空格
3. 列表:逗号分隔,按字母顺序排序
"""
if not answer:
return ""
answer = answer.strip()
# 检查是否是逗号分隔的列表
if ',' in answer:
parts = [self._normalize_single_answer(p.strip()) for p in answer.split(',')]
parts.sort() # GAIA要求按字母顺序排序
return ','.join(parts)
else:
return self._normalize_single_answer(answer)
def _normalize_single_answer(self, answer: str) -> str:
"""标准化单个答案(不包含逗号的答案)"""
answer = answer.strip().lower()
# 移除常见的冠词
articles = ['the', 'a', 'an']
words = answer.split()
if words and words[0] in articles:
words = words[1:]
answer = ' '.join(words)
# 移除货币符号和百分号
answer = answer.replace('$', '').replace('%', '').replace('€', '').replace('£', '')
# 移除数字中的逗号分隔符
answer = re.sub(r'(\d),(\d)', r'\1\2', answer)
# 移除多余空格
answer = ' '.join(answer.split())
# 移除末尾的标点符号
answer = answer.rstrip('.,;:!?')
return answer
```
GAIA要求模型输出格式为`FINAL ANSWER: [答案]`:
```python
def _extract_answer(self, response: str) -> str:
"""从响应中提取答案(GAIA格式)
GAIA要求答案格式为:FINAL ANSWER: [答案]
"""
# 首先尝试提取GAIA官方格式的答案
final_answer_pattern = r'FINAL ANSWER:\s*(.+?)(?:\n|$)'
match = re.search(final_answer_pattern, response, re.IGNORECASE | re.MULTILINE)
if match:
answer = match.group(1).strip()
# 移除可能的方括号
answer = answer.strip('[]')
return answer
# 备用方案:查找其他答案标记
answer_patterns = [
r'答案[::]\s*(.+)',
r'最终答案[::]\s*(.+)',
r'Final answer[::]\s*(.+)',
r'Answer[::]\s*(.+)',
]
for pattern in answer_patterns:
match = re.search(pattern, response, re.IGNORECASE)
if match:
return match.group(1).strip()
# 如果没有找到标记,返回最后一个非空行
lines = response.strip().split('\n')
for line in reversed(lines):
line = line.strip()
if line and not line.startswith('#'):
return line
return response.strip()
```
评估完成后,可以导出为GAIA官方要求的JSONL格式:
```python
def export_to_gaia_format(
self,
results: Dict[str, Any],
output_path: Union[str, Path],
include_reasoning: bool = True
) -> None:
"""导出为GAIA官方格式(JSONL)
GAIA要求的格式:
{"task_id": "xxx", "model_answer": "答案", "reasoning_trace": "推理过程"}
"""
output_path = Path(output_path)
output_path.parent.mkdir(parents=True, exist_ok=True)
with open(output_path, 'w', encoding='utf-8') as f:
for result in results.get("detailed_results", []):
entry = {
"task_id": result["task_id"],
"model_answer": result["predicted"]
}
if include_reasoning:
entry["reasoning_trace"] = result.get("response", result["predicted"])
f.write(json.dumps(entry, ensure_ascii=False) + '\n')
```
(3)GAIAEvaluationTool:一键评估工具
GAIAEvaluationTool封装了完整的评估流程,提供一键评估功能:
````python
class GAIAEvaluationTool(Tool):
"""GAIA评估工具
提供一键评估功能:
1. 运行HelloAgents评估
2. 导出GAIA格式结果
3. 生成评估报告
4. 生成提交说明
"""
def run(
self,
agent: Any,
level: Optional[int] = None,
max_samples: Optional[int] = None,
local_data_dir: Optional[str] = None,
export_results: bool = True,
generate_report: bool = True
) -> Dict[str, Any]:
"""执行GAIA一键评估"""
# 步骤1: 运行HelloAgents评估
results = self._run_evaluation(agent, level, max_samples, local_data_dir)
# 步骤2: 导出GAIA格式结果
if export_results:
self._export_results(results)
# 步骤3: 生成评估报告
if generate_report:
self.generate_report(results)
return results
````
GAIAEvaluationTool会自动生成评估报告:
```python
def generate_report(
self,
results: Dict[str, Any],
output_file: Optional[Union[str, Path]] = None
) -> str:
"""生成评估报告"""
report = f"""# GAIA评估报告
**生成时间**: {datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
## 📊 评估概览
- **智能体**: {results.get("agent_name", "Unknown")}
- **难度级别**: {results.get("level_filter") or '全部'}
- **总样本数**: {results.get("total_samples", 0)}
- **精确匹配数**: {results.get("exact_matches", 0)}
- **精确匹配率**: {results.get("exact_match_rate", 0):.2%}
## 📈 详细指标
### 分级准确率
{self._format_level_metrics(results.get("level_metrics", {}))}
## 📝 样本详情(前10个)
{self._format_sample_details(results.get("detailed_results", [])[:10])}
## 📊 准确率可视化
{self._format_visualization(results.get("exact_match_rate", 0))}
## 💡 建议
{self._format_suggestions(results.get("exact_match_rate", 0))}
"""
# 保存报告
if output_file is None:
output_dir = Path("./evaluation_reports")
output_dir.mkdir(parents=True, exist_ok=True)
output_file = output_dir / f"gaia_report_{datetime.now().strftime('%Y%m%d_%H%M%S')}.md"
with open(output_file, 'w', encoding='utf-8') as f:
f.write(report)
return report
```
## 12.4 数据生成质量评估
在AI系统开发中,高质量的训练数据是系统性能的基础。本节介绍如何使用HelloAgents框架评估生成数据的质量,以AIME(美国数学邀请赛)[9]风格的数学题目生成为例。
AIME是美国数学协会(MAA)主办的中等难度数学竞赛,介于AMC 10/12和美国数学奥林匹克(USAMO)之间。AIME题目具有鲜明的特点:每道题的答案都是0到999之间的整数,题目涵盖代数、几何、数论、组合、概率等多个数学领域,需要多步推理但不涉及高深理论,难度适中(相当于AIME第6-9题的水平)。这些特点使得AIME题目成为评估数学题目生成质量的理想基准:答案格式统一便于自动化评估,题目难度适中适合大规模生成。我们使用HuggingFace上的`TianHongZXY/aime-1983-2025`数据集作为参考,该数据集包含从1983年到2025年的900多道AIME真题,为我们的生成和评估提供了丰富的参考样本。
### 12.4.1 评估方法概述
在数据生成质量评估中,我们采用三种互补的评估方法:LLM Judge、Win Rate和人工打分。选择这三种方法有两个重要原因。首先,从方法论角度来看,这些是当前智能体领域常用的自动化测评方案,也是许多学术论文中的主流做法,具有广泛的认可度和实践基础。其次,从适用性角度来看,这三种方法天然适合我们的评估场景:LLM Judge和Win Rate用于评估题目生成质量(从正确性、清晰度、难度匹配等维度进行多维度评估),而人工打分用于评估答案生成质量(通过人类专家验证答案的准确性),这种分工非常合理且易于理解。
下面我们详细介绍这三种评估方法的具体实现。整个案例的实现流程如图12.5所示:
图 12.5 数据生成质量评估流程图
(1)LLM Judge评估
设计动机:在数据生成质量评估中,我们需要对大量生成的题目进行快速、一致的质量评估。传统的人工评估虽然准确,但成本高、效率低,难以应对大规模数据生成的需求。LLM Judge通过使用大语言模型作为评委,可以自动化地从多个维度评估生成数据的质量,不仅大幅提升评估效率,还能保持评估标准的一致性。更重要的是,LLM Judge可以提供详细的评分理由和改进建议,帮助我们理解生成数据的优缺点,为后续优化提供方向。
在我们的实现中,LLM Judge从四个关键维度评估AIME题目的质量:
表 12.5 LLM Judge评估AIME题目的维度
有了四个维度的评分后,我们需要将这些评分汇总成整体的评估指标。我们定义了三个关键指标来衡量生成题目的质量水平:
评估指标:
1. 平均分(Average Score):计算所有题目在四个维度上的平均得分,反映生成题目的整体质量水平。
$$
\text{Average Score} = \frac{1}{N} \sum_{i=1}^{N} \frac{\sum_{d=1}^{4} S_{i,d}}{4}
$$
2. 及格率(Pass Rate):统计平均分达到3.5分及以上的题目比例,反映生成题目的基本质量保障。
$$
\text{Pass Rate} = \frac{|\{i : \text{Score}_i \geq 3.5\}|}{N}
$$
3. 优秀率(Excellent Rate):统计平均分达到4.5分及以上的题目比例,反映生成题目的高质量占比。
$$
\text{Excellent Rate} = \frac{|\{i : \text{Score}_i \geq 4.5\}|}{N}
$$
其中:
- $N$ 是评估的题目总数
- $S_{i,d}$ 是第 $i$ 个题目在第 $d$ 个维度的得分(1-5分)
- $\text{Score}_i$ 是第 $i$ 个题目的平均分(四个维度得分的平均值)
这三个指标从不同角度反映生成质量:平均分给出整体水平,及格率保证基本质量,优秀率衡量高质量产出能力。
(2)Win Rate评估
设计动机:虽然LLM Judge可以提供多维度的绝对评分,但我们还需要一个相对评估指标来衡量生成题目与真题的质量差距。Win Rate评估通过成对对比的方式,让LLM直接判断生成题目和真题哪个更好,这种相对比较比绝对评分更符合人类的判断习惯,也更容易发现生成题目的相对优势和劣势。理想情况下,如果生成题目的质量接近真题,Win Rate应该在50%左右(即生成题目和真题各有50%的胜率)。这个指标简单直观,可以快速判断生成系统的整体质量水平。
在我们的实现中,Win Rate评估通过以下图12.6所示流程进行评估:
图 12.6 数据生成质量评估流程图
在成对对比评估中,每次比较会产生三种可能的结果:生成题目获胜(Win)、真题获胜(Loss)或平局(Tie)。我们通过统计这三种结果的比例来评估生成题目的质量:
评估指标:
1. 胜率(Win Rate):生成题目被判定为更好的比例,反映生成题目相对于真题的优势。
$$
\text{Win Rate} = \frac{\text{Wins}}{\text{Total Comparisons}}
$$
2. 败率(Loss Rate):真题被判定为更好的比例,反映生成题目相对于真题的劣势。
$$
\text{Loss Rate} = \frac{\text{Losses}}{\text{Total Comparisons}}
$$
3. 平局率(Tie Rate):两者被判定为质量相当的比例,反映生成题目与真题的相似程度。
$$
\text{Tie Rate} = \frac{\text{Ties}}{\text{Total Comparisons}}
$$
其中,Total Comparisons是总的对比次数,Wins、Losses和Ties分别是生成题目获胜、失败和平局的次数。这三个指标满足:Win Rate + Loss Rate + Tie Rate = 100%。
理想结果:Win Rate ≈ 50%(说明生成质量接近真题)。如果Win Rate显著低于50%,说明生成题目质量不如真题,需要优化生成策略;如果Win Rate显著高于50%,可能说明生成题目在某些方面超越了真题,或者评估标准存在偏差。
(3)人工验证
设计动机:尽管LLM Judge和Win Rate可以自动化评估题目质量,但对于数学题目这种需要严格逻辑推理的内容,人工验证仍然是不可或缺的。特别是在评估答案生成质量时,需要人类专家验证答案的准确性、解答步骤的完整性和数学推理的严密性。此外,人工验证还可以发现自动化评估可能遗漏的问题,如题目的创新性、趣味性等主观因素。为了提高人工验证的效率和体验,我们开发了基于Gradio的Web界面,让验证者可以方便地浏览题目、评分、标注状态和添加评论,大大降低了人工验证的门槛。
在我们的实现中,人工验证通过以下步骤进行:
1. 阅读题目、答案、解答
2. 评分(1-5分):正确性、清晰度、难度匹配、完整性
3. 标注状态:
- ✅ approved(通过)
- ❌ rejected(拒绝)
- 🔄 needs_revision(需修改)
4. 添加评论
### 12.4.2 系统架构
数据生成与评估系统采用模块化设计:
```
data_generation/
├── aime_generator.py # AIME题目生成器
├── human_verification_ui.py # 人工验证界面
├── run_complete_evaluation.py # 完整评估流程
│
├── generated_data/ # 生成的数据
│ ├── aime_generated_XXXXXX.json
│ └── generation_report_XXXXXX.md
│
└── evaluation_results/ # 评估结果
└── XXXXXX/
├── llm_judge/
├── win_rate/
└── comprehensive_report.md
```
系统包含四个核心组件:首先是AIMEGenerator(题目生成器),使用HelloAgents框架生成AIME风格题目,支持批量生成和进度保存,并能自动处理API速率限制;其次是LLMJudgeTool(LLM Judge评估工具),提供4维度质量评估,自动生成JSON结果和Markdown报告;第三是WinRateTool(Win Rate评估工具),通过成对对比评估计算胜率、败率和平局率;最后是HumanVerificationUI(人工验证界面),基于Gradio Web界面,支持评分和状态标注。
### 12.4.3 AIME题目生成器实现
```python
class AIMEGenerator:
"""AIME Problem Generator"""
def __init__(
self,
llm: HelloAgentsLLM = None,
delay_seconds: float = 1.0,
use_reference_examples: bool = True,
reference_dataset: str = "TianHongZXY/aime-1983-2025"
):
self.llm = llm or HelloAgentsLLM()
self.agent = SimpleAgent(
name="AIME Generator",
llm=self.llm,
system_prompt="You are a professional mathematics competition problem designer."
)
self.delay_seconds = delay_seconds
self.use_reference_examples = use_reference_examples
# Load reference examples from 900+ AIME problems (1983-2025)
if use_reference_examples:
dataset = load_dataset(reference_dataset, split="test")
self.reference_examples = list(dataset)
```
我们的目标是生成类似风格的数据集,所以从900+道AIME真题(1983-2025)中随机选择参考样例
生成提示词设计(英文):
```python
GENERATION_PROMPT = """You are a professional mathematics competition problem designer, skilled in creating AIME (American Invitational Mathematics Examination) style problems.
【Reference Example】(For style reference only, please generate a completely different problem)
Problem: {example_problem}
Answer: {example_answer}
AIME Problem Characteristics:
1. Answer: An integer between 0 and 999
2. Topics: Algebra, Geometry, Number Theory, Combinatorics, Probability, etc.
3. Style: Requires multi-step reasoning, but no advanced theory
4. Difficulty: Medium to hard (similar to AIME problems 6-9)
Please generate a **completely different** AIME-style mathematics problem, including:
1. Problem statement (clear and complete, different from the reference)
2. Answer (an integer between 0 and 999, different from the reference)
3. Detailed solution (including all reasoning steps)
4. Topic classification (Algebra/Geometry/Number Theory/Combinatorics/Probability)
Please output in the following JSON format:
{
"problem": "Problem statement in English",
"answer": 123,
"solution": "Detailed solution steps in English",
"topic": "Algebra"
}
"""
```
我们选择使用英文生成题目有四个重要原因:首先是与AIME真题保持一致(AIME是英文竞赛,生成英文题目更合理),其次是确保评估的公平性(LLM Judge评估时英文vs英文更公平),第三是便于国际化(英文题目可以被更广泛使用),最后是避免翻译问题(不需要担心中英文翻译的准确性)。
批量生成实现:
```python
def generate_and_save(self, num_problems: int = 30, output_dir: str = "data_generation/generated_data"):
"""Generate and save problems with intelligent delay"""
# Clean old checkpoints
for file in os.listdir(output_dir):
if file.startswith("checkpoint_") and file.endswith(".json"):
os.remove(os.path.join(output_dir, file))
# Generate with tqdm progress bar
with tqdm(total=num_problems, desc="Generating AIME problems", unit="problem") as pbar:
last_call_time = 0
for i in range(num_problems):
# Ensure minimum delay between API calls
if last_call_time > 0:
elapsed = time.time() - last_call_time
if elapsed < self.delay_seconds:
wait_time = self.delay_seconds - elapsed
time.sleep(wait_time)
# Generate problem (randomly select reference example)
start_time = time.time()
problem = self.generate_single()
last_call_time = time.time()
generation_time = last_call_time - start_time
# Update progress bar
pbar.set_postfix({
"topic": problem.get('topic', 'N/A'),
"answer": problem.get('answer', 'N/A'),
"time": f"{generation_time:.1f}s"
})
pbar.update(1)
return generated_data_path
```
LaTeX数学公式支持:
生成的AIME题目包含LaTeX数学公式(如 `$\frac{a}{b}$`、`$\sqrt{x}$`),需要特殊处理JSON解析:
```python
def _parse_response(self, response: str) -> Dict[str, Any]:
"""解析LLM响应(支持LaTeX数学公式)"""
import re
# 提取JSON部分
if "```json" in response:
json_str = response.split("```json")[1].split("```")[0].strip()
else:
json_str = response.strip()
try:
problem_data = json.loads(json_str)
except json.JSONDecodeError:
# 修复LaTeX转义问题:将 \frac 转为 \\frac
# 正则表达式:找到未转义的反斜杠
fixed_json_str = re.sub(r'(? str:
"""运行LLM Judge评估"""
# 1. 加载生成数据
gen_dataset = AIDataset(dataset_type="generated", data_path=params["generated_data_path"])
gen_problems = gen_dataset.load()
# 2. 加载参考数据(AIME 2025)
ref_dataset = AIDataset(dataset_type="real", year=2025)
ref_problems = ref_dataset.load()
# 3. 创建评估器
evaluator = LLMJudgeEvaluator(llm=self.llm, judge_model=params.get("judge_model", "gpt-4o"))
# 4. 运行评估
results = evaluator.evaluate_batch(gen_problems, max_samples=params.get("max_samples"))
# 5. 保存结果
evaluator.export_results(results, result_file)
# 6. 生成报告
self._generate_report(results, report_file)
return json.dumps({"status": "success", "metrics": results["metrics"]})
```
**评估提示词**:
```python
EVALUATION_PROMPT = """请评估以下AIME数学题目的质量。
题目:
{problem}
答案:{answer}
解答:
{solution}
请从以下4个维度评分(1-5分):
1. 正确性 (Correctness):数学逻辑是否正确,答案是否准确
2. 清晰度 (Clarity):问题表述是否清晰,解答是否易懂
3. 难度匹配 (Difficulty Match):难度是否符合AIME标准(中等偏难)
4. 完整性 (Completeness):解答步骤是否完整,是否包含必要的推理
请按以下JSON格式输出:
{
"correctness": 5,
"clarity": 4,
"difficulty_match": 4,
"completeness": 5,
"comments": "评价理由"
}
"""
```
**评估报告示例**:
```markdown
# LLM Judge评估报告
## 总体评分
- 平均总分: 4.2/5.0
- 通过率: 85.0% (≥3.5分)
- 优秀率: 40.0% (≥4.5分)
## 各维度评分
| 维度 | 平均分 | 评级 |
|------|--------|------|
| 正确性 | 4.3/5.0 | 良好 ⭐⭐⭐⭐ |
| 清晰度 | 4.1/5.0 | 良好 ⭐⭐⭐⭐ |
| 难度匹配 | 4.0/5.0 | 良好 ⭐⭐⭐⭐ |
| 完整性 | 4.4/5.0 | 良好 ⭐⭐⭐⭐ |
```
### 12.4.5 Win Rate评估工具
Win Rate工具通过成对对比评估生成数据相对于真题的质量。
```python
class WinRateTool(Tool):
"""Win Rate评估工具"""
def run(self, params: Dict[str, Any]) -> str:
"""运行Win Rate评估"""
# 1. 加载生成数据
gen_dataset = AIDataset(dataset_type="generated", data_path=params["generated_data_path"])
gen_problems = gen_dataset.load()
# 2. 加载参考数据(AIME 2025)
ref_dataset = AIDataset(dataset_type="real", year=2025)
ref_problems = ref_dataset.load()
# 3. 创建评估器
evaluator = WinRateEvaluator(llm=self.llm, judge_model=params.get("judge_model", "gpt-4o"))
# 4. 运行评估
results = evaluator.evaluate_win_rate(gen_problems, ref_problems, num_comparisons=params.get("num_comparisons"))
# 5. 保存结果和报告
evaluator.export_results(results, result_file)
self._generate_report(results, report_file)
return json.dumps({"status": "success", "metrics": results["metrics"]})
```
AIDataset负责加载生成数据和AIME真题数据,支持两种数据类型:
```python
class AIDataset:
"""AI数据集加载器
支持两种数据类型:
1. generated: 生成的数据(JSON格式)
2. real: AIME真题(从HuggingFace加载)
"""
def __init__(
self,
dataset_type: str = "generated",
data_path: Optional[str] = None,
year: Optional[int] = None
):
self.dataset_type = dataset_type
self.data_path = data_path
self.year = year # 仅用于real类型,默认2025
def load(self) -> List[Dict[str, Any]]:
"""加载数据集"""
if self.dataset_type == "generated":
return self._load_generated_data()
elif self.dataset_type == "real":
return self._load_real_data()
def _load_real_data(self) -> List[Dict[str, Any]]:
"""从HuggingFace加载AIME 2025真题"""
from huggingface_hub import snapshot_download
# 使用AIME 2025数据集
repo_id = "math-ai/aime25"
# 下载数据集
local_dir = snapshot_download(
repo_id=repo_id,
repo_type="dataset"
)
# 读取JSONL文件
data_file = list(Path(local_dir).glob("*.jsonl"))[0]
data = []
with open(data_file, 'r', encoding='utf-8') as f:
for line in f:
if line.strip():
data.append(json.loads(line))
# 统一数据格式(AIME 2025使用小写字段名)
problems = []
for idx, item in enumerate(data):
problem = {
"problem_id": item.get("id", f"aime_2025_{idx}"),
"problem": item.get("problem", ""),
"answer": item.get("answer", ""),
"solution": item.get("solution", ""), # AIME 2025没有solution字段
}
problems.append(problem)
return problems
```
我们选择只使用AIME 2025数据集有四个原因:首先是数据的时效性(2025年是最新的AIME竞赛数据),其次是简化维护(只维护一个数据集,代码更简洁),第三是格式统一(JSONL格式,字段名统一为小写),最后是代表性充分(30道题目足以评估生成质量)。
**对比提示词**:
```python
COMPARISON_PROMPT = """请比较以下两个AIME数学题目的质量,判断哪个更好。
【题目A - 生成题目】
问题:{problem_a}
答案:{answer_a}
解答:{solution_a}
【题目B - AIME真题】
问题:{problem_b}
答案:{answer_b}
解答:{solution_b}
请从以下方面比较:
1. 数学逻辑的严谨性
2. 问题表述的清晰度
3. 难度的合理性
4. 解答的完整性
请按以下JSON格式输出:
{
"winner": "A" 或 "B" 或 "Tie",
"reason": "判断理由"
}
"""
```
**评估报告示例**:
```markdown
# Win Rate评估报告
## 胜率统计
| 指标 | 数值 | 百分比 |
|------|------|--------|
| 生成数据胜出 | 9次 | 45.0% |
| AIME真题胜出 | 8次 | 40.0% |
| 平局 | 3次 | 15.0% |
Win Rate: 45.0%
✅ 良好: 生成数据质量接近参考数据(差距<10%)。
```
### 12.4.6 人工验证界面
使用Gradio创建Web界面,支持人工验证生成的题目。
```python
class HumanVerificationUI:
"""人工验证界面"""
def launch(self, share: bool = False):
"""启动Gradio界面"""
with gr.Blocks(title="AIME题目人工验证") as demo:
gr.Markdown("# 🎯 AIME题目人工验证系统")
with gr.Row():
with gr.Column(scale=2):
# 题目显示区域
problem_text = gr.Textbox(label="问题描述", lines=5, interactive=False)
answer_text = gr.Textbox(label="答案", interactive=False)
solution_text = gr.Textbox(label="解答过程", lines=10, interactive=False)
with gr.Column(scale=1):
# 评分区域
correctness_slider = gr.Slider(1, 5, value=3, step=1, label="正确性")
clarity_slider = gr.Slider(1, 5, value=3, step=1, label="清晰度")
difficulty_slider = gr.Slider(1, 5, value=3, step=1, label="难度匹配")
completeness_slider = gr.Slider(1, 5, value=3, step=1, label="完整性")
# 状态选择
status_radio = gr.Radio(
choices=["approved", "rejected", "needs_revision"],
value="approved",
label="状态"
)
# 验证按钮
verify_btn = gr.Button("✅ 提交验证", variant="primary")
demo.launch(share=share, server_name="127.0.0.1", server_port=7860)
```
**使用方法**:
```bash
# 启动人工验证界面
python data_generation/human_verification_ui.py data_generation/generated_data/aime_generated_XXXXXX.json
# 打开浏览器访问
http://127.0.0.1:7860
```
最终效果可以参考图12.7所示,对于题目的正确性,最好人工打标Review:
图 12.7 AIME试题人工验证页面
**验证流程**:
1. 浏览器打开验证界面
2. 阅读题目、答案、解答
3. 从4个维度评分(1-5分)
4. 选择验证状态(approved/rejected/needs_revision)
5. 添加评论(可选)
6. 点击"提交验证"
7. 查看下一题
**验证结果保存**:
验证结果自动保存为 `_verifications.json`:
```json
{
"gen_aime_1": {
"problem_id": "gen_aime_1",
"scores": {
"correctness": 5,
"clarity": 4,
"difficulty_match": 4,
"completeness": 5
},
"total_score": 4.5,
"status": "approved",
"comments": "题目质量很好,逻辑严谨",
"verified_at": "2025-01-10T12:00:00"
}
}
```
### 12.4.7 完整评估流程
将所有评估方法整合到一个完整的流程中。
```python
def run_complete_evaluation(
num_problems: int = 30,
delay_seconds: float = 3.0
):
"""
运行完整评估流程
Args:
num_problems: 生成题目数量
delay_seconds: 每次生成之间的延迟(秒),避免API速率限制
"""
# 步骤1: 生成AIME题目
generator = AIMEGenerator(delay_seconds=delay_seconds)
generated_data_path = generator.generate_and_save(
num_problems=num_problems,
output_dir="data_generation/generated_data"
)
# 步骤2: 评估
# 创建评估结果目录
timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
evaluation_dir = f"data_generation/evaluation_results/{timestamp}"
os.makedirs(evaluation_dir, exist_ok=True)
os.makedirs(os.path.join(evaluation_dir, "llm_judge"), exist_ok=True)
os.makedirs(os.path.join(evaluation_dir, "win_rate"), exist_ok=True)
# 创建LLM
llm = HelloAgentsLLM()
# 步骤2.1: LLM Judge评估
llm_judge_result = None
try:
llm_judge_tool = LLMJudgeTool(llm=llm)
llm_judge_result_json = llm_judge_tool.run({
"generated_data_path": generated_data_path,
"reference_year": 2025,
"max_samples": num_problems,
"output_dir": os.path.join(evaluation_dir, "llm_judge"),
"judge_model": "gpt-4o"
})
llm_judge_result = json.loads(llm_judge_result_json)
except Exception as e:
print(f"❌ LLM Judge评估失败: {e}")
# 步骤2.2: Win Rate评估
win_rate_result = None
try:
win_rate_tool = WinRateTool(llm=llm)
win_rate_result_json = win_rate_tool.run({
"generated_data_path": generated_data_path,
"reference_year": 2025,
"num_comparisons": min(num_problems, 20),
"output_dir": os.path.join(evaluation_dir, "win_rate"),
"judge_model": "gpt-4o"
})
win_rate_result = json.loads(win_rate_result_json)
except Exception as e:
print(f"❌ Win Rate评估失败: {e}")
# 步骤3: 生成综合报告
comprehensive_report_path = None
if llm_judge_result or win_rate_result:
comprehensive_report_path = os.path.join(evaluation_dir, "comprehensive_report.md")
report = generate_comprehensive_report(
generated_data_path,
llm_judge_result,
win_rate_result
)
with open(comprehensive_report_path, 'w', encoding='utf-8') as f:
f.write(report)
return {
"generated_data_path": generated_data_path,
"llm_judge_result": llm_judge_result,
"win_rate_result": win_rate_result,
"comprehensive_report_path": comprehensive_report_path
}
```
**运行方法**:
```bash
# 基本用法(默认3秒延迟)
python data_generation/run_complete_evaluation.py 30
# 自定义延迟(推荐3-5秒,避免API速率限制)
python data_generation/run_complete_evaluation.py 30 3.0
# 参数说明:
# - 30: 生成题目数量
# - 3.0: 每次生成之间的延迟(秒)
# 说明:
# - 生成阶段:从900+道AIME真题(1983-2025)中随机选择参考样例
# - 评估阶段:与AIME 2025年真题进行质量对比
# - 数据集来源:math-ai/aime25(JSONL格式)
```
**输出示例**:
```
================================================================================
🚀 AIME数据生成与评估完整流程
================================================================================
配置信息:
- 生成题目数量: 30
- API延迟: 3.0秒/题
- 生成参考数据: TianHongZXY/aime-1983-2025(900+道题)
- 评估参考: AIME 2025真题
================================================================================
📝 步骤1: 生成AIME题目
================================================================================
📚 加载AIME真题数据集: TianHongZXY/aime-1983-2025
✓ 已加载 963 道参考题目
🎯 开始生成AIME题目
目标数量: 30
生成模型: gpt-4o
延迟设置: 3.0秒/题
生成AIME题目: 100%|██████████| 30/30 [01:30<00:00, 3.00s/题, 主题=Algebra, 答案=123, 耗时=3.0s]
✅ 步骤1完成!生成数据保存在: data_generation/generated_data/aime_generated_20250110_120000.json
🎯 步骤2.1: LLM Judge评估 (vs AIME 2025)
✅ LLM Judge评估完成!
平均总分: 4.2/5.0
通过率: 85.0%
🏆 步骤2.2: Win Rate评估 (vs AIME 2025)
✅ Win Rate评估完成!
Win Rate: 45.0%
================================================================================
📊 步骤3: 生成综合报告
================================================================================
✅ 综合报告已保存: data_generation/evaluation_results/20250110_120000/comprehensive_report.md
================================================================================
🎉 完整评估流程完成!
================================================================================
📁 输出文件:
- 生成数据: data_generation/generated_data/aime_generated_20250110_120000.json
- 评估结果目录: data_generation/evaluation_results/20250110_120000
- LLM Judge报告: data_generation/evaluation_results/20250110_120000/llm_judge/llm_judge_report_20250110_120000.md
- Win Rate报告: data_generation/evaluation_results/20250110_120000/win_rate/win_rate_report_20250110_120000.md
- 综合报告: data_generation/evaluation_results/20250110_120000/comprehensive_report.md
💡 下一步:
1. 查看综合报告: data_generation/evaluation_results/20250110_120000/comprehensive_report.md
2. 运行人工验证: python data_generation/human_verification_ui.py data_generation/generated_data/aime_generated_20250110_120000.json
```
### 12.4.8 综合评估报告
系统自动生成综合评估报告,汇总所有评估结果。以下是示例报告:
```markdown
# AIME数据生成与评估综合报告
## 1. 基本信息
- 生成时间: 2025-01-10 12:00:00
- 生成题目数量: 30
- 参考AIME年份: 2025
## 2. 数据生成统计
### 主题分布
| 主题 | 数量 | 占比 |
|------|------|------|
| 代数 | 10 | 33.3% |
| 几何 | 8 | 26.7% |
| 数论 | 7 | 23.3% |
| 组合 | 3 | 10.0% |
| 概率 | 2 | 6.7% |
## 3. LLM Judge评估结果
### 总体评分
- 平均总分: 4.2/5.0
- 通过率: 85.0% (≥3.5分)
- 优秀率: 40.0% (≥4.5分)
### 各维度评分
| 维度 | 平均分 | 评级 |
|------|--------|------|
| 正确性 | 4.3/5.0 | 良好 ⭐⭐⭐⭐ |
| 清晰度 | 4.1/5.0 | 良好 ⭐⭐⭐⭐ |
| 难度匹配 | 4.0/5.0 | 良好 ⭐⭐⭐⭐ |
| 完整性 | 4.4/5.0 | 良好 ⭐⭐⭐⭐ |
## 4. Win Rate评估结果
### 胜率统计
| 指标 | 数值 | 百分比 |
|------|------|--------|
| 生成数据胜出 | 9次 | 45.0% |
| AIME真题胜出 | 8次 | 40.0% |
| 平局 | 3次 | 15.0% |
Win Rate: 45.0%
✅ 良好: 生成数据质量接近参考数据(差距<10%)。
## 5. 综合结论
基于LLM Judge和Win Rate两种评估方法的结果:
1. LLM Judge评估: 生成数据的平均质量为 4.2/5.0
2. Win Rate评估: 生成数据相对于AIME 2025真题的胜率为 45.0%
✅ 结论: 生成数据质量优秀,达到或超过AIME真题水平。可以用于实际应用。
## 6. 改进建议
- ✅ 继续保持当前的生成策略
- ✅ 可以考虑增加生成数量
- ✅ 建议进行人工验证以确保质量
## 7. 下一步行动
1. 人工验证: 运行 `python data_generation/human_verification_ui.py ` 进行人工验证
2. 查看详细结果:
- LLM Judge详细报告
- Win Rate详细报告
3. 数据使用: 如果质量满意,可以将生成的数据用于训练或测试
```
基于实际使用经验,总结以下内容:
在数据生成方面,应该使用合适的延迟时间(2-3秒)避免API速率限制,启用检查点保存以避免中断损失,先小批量测试(10个)确认无问题后再大批量生成,并定期检查生成质量及时调整提示词。在评估策略上,建议结合LLM Judge和Win Rate两种方法,其中LLM Judge用于绝对质量评估,Win Rate用于相对质量对比,人工验证用于最终质量把关。质量标准方面,建议LLM Judge平均分达到4.0/5.0以上,Win Rate达到45%以上(接近50%),通过率达到80%以上,人工验证通过率达到90%以上。在迭代优化过程中,应根据评估结果调整生成提示词,分析低分题目的共同问题,参考高分题目的优点,持续改进生成策略。
通过本节的学习,我们掌握了如何使用HelloAgents框架进行数据生成质量评估,包括LLM Judge评估、Win Rate评估和人工验证三种方法。这套完整的评估体系可以确保生成数据的高质量,为AI系统的训练和测试提供可靠的数据支持。
对于LLM Judge和Win Rate评估,HelloAgents也进行了工具集成,并提供了完整的示例代码。如果你对这两种评估方法的具体实现细节感兴趣,同样可以参考示例代码。
## 12.5 本章小结
在本章中,我们为HelloAgents框架构建了一个完整的性能评估系统。让我们回顾一下学到的核心内容:
(1)评估体系概览
我们建立了一个三层评估体系,全面覆盖智能体的不同能力维度。首先是工具调用能力评估(BFCL),专注于评估智能体的函数调用准确性,包含simple、multiple、parallel、irrelevance四个类别,使用AST匹配技术进行精确评估。其次是通用能力评估(GAIA),评估智能体的综合问题解决能力,包含三个难度级别共466个真实世界问题,关注多步推理、工具使用、文件处理等能力。第三是数据生成质量评估(AIME),评估LLM生成数据的质量,使用LLM Judge和Win Rate两种方法,支持人工验证和综合报告生成,确保生成数据达到参考数据的质量标准。
(2)核心技术要点
在技术实现上,我们采用了六个核心技术要点。首先是模块化设计,评估系统采用三层架构:数据层(Dataset负责数据加载和管理)、评估层(Evaluator负责执行评估流程)和指标层(Metrics负责计算各种评估指标)。其次是工具化封装,所有评估功能都封装成Tool,可以被智能体直接调用、集成到工作流中或通过统一接口使用。第三是AST匹配技术,使用抽象语法树匹配函数调用,比简单字符串匹配更智能,能够忽略参数顺序、识别等价表达式和忽略格式差异。第四是多模态支持,GAIA评估支持文本问题、附件文件和图片输入等多模态数据。第五是LLM Judge评估,使用LLM作为评委评估生成数据质量,提供多维度评分(正确性、清晰度、难度匹配、完整性)、自动化评估流程、详细评估报告,并支持自定义评估维度和标准。第六是Win Rate对比评估,通过成对对比评估生成质量(生成数据vs参考数据),由LLM判断哪个更好并计算胜率统计,接近50%表示质量相当。
(3)扩展方向
基于本章的评估系统,你可以在四个方向上进行扩展。首先是添加新的评估基准,可以参考BFCL和GAIA的实现模式,实现Dataset、Evaluator、Metrics三个组件,并封装成Tool供使用。其次是自定义评估指标,在Metrics类中添加新的指标计算方法,根据具体应用场景设计指标。第三是集成到CI/CD流程,在代码提交时自动运行评估,设置性能阈值防止性能退化,生成评估报告并归档。第四是扩展数据生成评估,支持更多数据类型(代码、对话、文档等),添加更多评估维度(创新性、多样性等),集成更多参考数据集,支持多模型对比评估。
恭喜你完成了第十二章的学习! 🎉
评估是智能体开发的重要环节,它让我们能够:
- 客观衡量智能体的能力
- 发现和修复问题
- 持续改进系统
在下一章中,我们将探讨如何将HelloAgents框架应用于实际项目中。
继续加油! 💪
## 参考文献
[1] Patil, S. G., Zhang, T., Wang, X., & Gonzalez, J. E. (2023). Gorilla: Large Language Model Connected with Massive APIs. arXiv preprint arXiv:2305.15334.
[2] Qin, Y., Liang, S., Ye, Y., Zhu, K., Yan, L., Lu, Y., ... & Sun, M. (2023). ToolLLM: Facilitating Large Language Models to Master 16000+ Real-world APIs. arXiv preprint arXiv:2307.16789.
[3] Li, M., Zhao, Y., Yu, B., Song, F., Li, H., Yu, H., ... & Li, Y. (2023). Api-bank: A comprehensive benchmark for tool-augmented llms. arXiv preprint arXiv:2304.08244.
[4] Mialon, G., Dessì, R., Lomeli, M., Nalmpantis, C., Pasunuru, R., Raileanu, R., ... & Scialom, T. (2023). GAIA: a benchmark for General AI Assistants. arXiv preprint arXiv:2311.12983.
[5] Liu, X., Yu, H., Zhang, H., Xu, Y., Lei, X., Lai, H., ... & Zhang, D. (2023). AgentBench: Evaluating LLMs as Agents. arXiv preprint arXiv:2308.03688.
[6] Zhou, S., Xu, F. F., Zhu, H., Zhou, X., Lo, R., Sridhar, A., ... & Neubig, G. (2023). WebArena: A Realistic Web Environment for Building Autonomous Agents. arXiv preprint arXiv:2307.13854.
[7] Chan, C. M., Chen, W., Su, Y., Yu, J., Xue, W., Zhang, S., ... & Liu, Z. (2023). ChatEval: Towards Better LLM-based Evaluators through Multi-Agent Debate. arXiv preprint arXiv:2308.07201.
[8] Zhou, X., Zhu, H., Mathur, L., Zhang, R., Yu, H., Qi, Z., ... & Neubig, G. (2023). SOTOPIA: Interactive Evaluation for Social Intelligence in Language Agents. arXiv preprint arXiv:2310.11667.
[9] Mathematical Association of America. (2024). American Invitational Mathematics Examination (AIME). Retrieved from https://www.maa.org/math-competitions/invitational-competitions/aime