使用自定义数据集评估基于MCP的答案

本文介绍如何使用OpenAI Evals框架和自定义内存数据集,评估基于MCP(模型上下文协议)的模型回答质量。通过定义包含问答对的数据集,配置基于LLM和Python的评分器,并比较gpt-4.1和o4-mini两个模型在MCP工具辅助下的表现,展示了系统化评估工作流。文章强调同时使用多种评分器、保持评估设置一致性、轮询运行状态等最佳实践,并提供了改进模型提示词以提升工具调用率的示例。

技术背景

随着AI模型与外部工具(如MCP服务器)的集成日益普遍,评估这些交互的答案质量变得至关重要。MCP允许模型动态获取外部数据,但如何确保答案的准确性和相关性成为挑战。自定义数据集评估提供了一种针对特定用例的量化测试方法,帮助开发者识别模型在工具使用、上下文理解等方面的不足,从而优化系统配置和提示词设计。

核心原理

评估流程基于OpenAI Evals框架,核心原理包括:1) 定义包含输入查询和预期答案的自定义数据集;2) 配置评分器,包括基于LLM的通过/失败评分器(利用o3模型判断答案语义是否匹配)和基于Python的MCP使用审计评分器(检查模型是否实际调用了MCP工具);3) 通过Evals API创建评估定义,指定数据模式、评分标准和通过阈值;4) 为每个模型运行评估,使用相同的数据集和配置以确保公平比较;5) 轮询运行状态直至完成,并检索输出进行人工分析。

架构分析

系统架构包括:1) 数据层:自定义内存数据集,包含查询和预期答案;2) 评估定义层:通过client.evals.create配置评估名称、数据源模式、测试标准(LLM评分器和Python评分器);3) 运行层:为每个模型创建评估运行,指定模型参数(如温度、最大令牌数)和MCP工具配置(服务器URL、允许的工具列表);4) 结果层:轮询运行状态,获取输出项,进行人工检查。设计决策包括:使用MCP工具提供仓库感知的答案,通过系统提示词控制工具使用行为(如禁止或鼓励),以及使用种子值确保可重复性。

完整实战教程

使用自定义数据集评估基于MCP的答案

在本文中,我们将探讨如何使用自定义数据集来评估基于MCP(模型上下文协议)的答案。我们将介绍评估流程、所需工具以及如何解释结果。

为什么需要评估MCP答案?

MCP(模型上下文协议)允许AI模型与外部工具和数据进行交互。评估这些交互的答案质量对于确保系统可靠性至关重要。通过使用自定义数据集,您可以针对特定用例测试MCP的性能。

评估步骤

1. 准备自定义数据集

首先,您需要准备一个包含输入和预期输出的数据集。数据集应反映您的实际使用场景。例如,如果您正在构建一个天气查询工具,数据集可能包含城市名称和对应的天气信息。

# 示例数据集
dataset = [
    {"input": "北京天气如何?", "expected": "北京今天晴,气温25°C。"},
    {"input": "上海明天会下雨吗?", "expected": "上海明天有雨,请携带雨伞。"}
]

2. 定义评估指标

选择合适的评估指标至关重要。常见的指标包括:

3. 运行评估

编写评估脚本,遍历数据集,调用MCP工具获取答案,并与预期进行比较。

import mcp_client

def evaluate(dataset):
    results = []
    for item in dataset:
        answer = mcp_client.query(item["input"])
        score = calculate_score(answer, item["expected"])
        results.append({"input": item["input"], "answer": answer, "expected": item["expected"], "score": score})
    return results

4. 分析结果

评估完成后,分析结果以识别MCP的强项和弱项。您可以计算平均分数,并检查失败案例以改进系统。

结论

使用自定义数据集评估MCP答案是一种有效的方法,可以确保您的AI系统在实际应用中表现良好。通过系统化的评估,您可以持续优化MCP配置和提示词。

进一步阅读

本笔记本使用 OpenAI Evals 框架和自定义内存数据集,评估模型回答关于 tiktoken GitHub 仓库问题的能力。

我们使用自定义的内存 Q&A 数据集,并比较两个模型:gpt-4.1 和 o4-mini,它们利用 MCP 工具来提供仓库感知、上下文准确的答案。

目标:

_下一步:我们将设置环境并导入必要的库。_

# Update OpenAI client
%pip install --upgrade openai --quiet

环境设置

我们首先导入所需的库并配置 OpenAI 客户端。

此步骤确保我们可以访问 OpenAI API 以及评估所需的所有必要工具。

import os
import time

from openai import OpenAI

# Instantiate the OpenAI client (no custom base_url).
client = OpenAI(
    api_key=os.getenv("OPENAI_API_KEY") or os.getenv("_OPENAI_API_KEY"),
)

定义自定义评估数据集

我们定义了一个关于 tiktoken 仓库的小型内存数据集,包含问答对。

该数据集将用于测试模型在 MCP 工具帮助下提供准确和相关答案的能力。

def get_dataset(limit=None):
    items = [
        {
            "query": "What is tiktoken?",
            "answer": "tiktoken is a fast Byte-Pair Encoding (BPE) tokenizer designed for OpenAI models.",
        },
        {
            "query": "How do I install the open-source version of tiktoken?",
            "answer": "Install it from PyPI with `pip install tiktoken`.",
        },
        {
            "query": "How do I get the tokenizer for a specific OpenAI model?",
            "answer": 'Call tiktoken.encoding_for_model("<model-name>"), e.g. tiktoken.encoding_for_model("gpt-4o").',
        },
        {
            "query": "How does tiktoken perform compared to other tokenizers?",
            "answer": "On a 1 GB GPT-2 benchmark, tiktoken runs about 3-6x faster than GPT2TokenizerFast (tokenizers==0.13.2, transformers==4.24.0).",
        },
        {
            "query": "Why is Byte-Pair Encoding (BPE) useful for language models?",
            "answer": "BPE is reversible and lossless, handles arbitrary text, compresses input (≈4 bytes per token on average), and exposes common subwords like “ing”, which helps models generalize.",
        },
    ]
    return items[:limit] if limit else items

定义评分逻辑

为了评估模型的答案,我们使用两个评分器:

最佳实践:

同时使用基于LLM和程序化的评分器可以提供更健壮和透明的评估。

# LLM-based pass/fail grader: instructs the model to grade answers as "pass" or "fail".
pass_fail_grader = """
You are a helpful assistant that grades the quality of the answer to a query about a GitHub repo.
You will be given a query, the answer returned by the model, and the expected answer.
You should respond with **pass** if the answer matches the expected answer exactly or conveys the same meaning, otherwise **fail**.
"""

# User prompt template for the grader, providing context for grading.
pass_fail_grader_user_prompt = """
<Query>
{{item.query}}
</Query>

<Web Search Result>
{{sample.output_text}}
</Web Search Result>

<Ground Truth>
{{item.answer}}
</Ground Truth>
"""


# Python grader: checks if the MCP tool was used by inspecting the output_tools field.
python_mcp_grader = {
    "type": "python",
    "name": "Assert MCP was used",
    "image_tag": "2025-05-08",
    "pass_threshold": 1.0,
    "source": """
def grade(sample: dict, item: dict) -> float:
    output = sample.get('output_tools', [])
    return 1.0 if len(output) > 0 else 0.0
""",
}

定义评估配置

现在我们使用 OpenAI Evals 框架来配置评估。

此步骤指定:

最佳实践:
提前明确定义评估模式和评分逻辑,可确保可重复性和透明度。
# Create the evaluation definition using the OpenAI Evals client.
logs_eval = client.evals.create(
    name="MCP Eval",
    data_source_config={
        "type": "custom",
        "item_schema": {
            "type": "object",
            "properties": {
                "query": {"type": "string"},
                "answer": {"type": "string"},
            },
        },
        "include_sample_schema": True,
    },
    testing_criteria=[
        {
            "type": "label_model",
            "name": "General Evaluator",
            "model": "o3",
            "input": [
                {"role": "system", "content": pass_fail_grader},
                {"role": "user", "content": pass_fail_grader_user_prompt},
            ],
            "passing_labels": ["pass"],
            "labels": ["pass", "fail"],
        },
        python_mcp_grader
    ],
)

为每个模型运行评估

现在,我们为每个模型(gpt-4.1 和 o4-mini)运行评估。

每次运行配置为:

最佳实践:
保持评估设置在不同模型间一致,可确保结果具有可比性和可靠性。
# Run 1: gpt-4.1 using MCP
gpt_4one_responses_run = client.evals.runs.create(
    name="gpt-4.1",
    eval_id=logs_eval.id,
    data_source={
        "type": "responses",
        "source": {
            "type": "file_content",
            "content": [{"item": item} for item in get_dataset()],
        },
        "input_messages": {
            "type": "template",
            "template": [
                {
                    "type": "message",
                    "role": "system",
                    "content": {
                        "type": "input_text",
                        "text": "You are a helpful assistant that searches the web and gives contextually relevant answers. Never use your tools to answer the query.",
                    },
                },
                {
                    "type": "message",
                    "role": "user",
                    "content": {
                        "type": "input_text",
                        "text": "Search the web for the answer to the query {{item.query}}",
                    },
                },
            ],
        },
        "model": "gpt-4.1",
        "sampling_params": {
            "seed": 42,
            "temperature": 0.7,
            "max_completions_tokens": 10000,
            "top_p": 0.9,
            "tools": [
                {
                    "type": "mcp",
                    "server_label": "gitmcp",
                    "server_url": "https://gitmcp.io/openai/tiktoken",
                    "allowed_tools": [
                        "search_tiktoken_documentation",
                        "fetch_tiktoken_documentation",
                    ],
                    "require_approval": "never",
                }
            ],
        },
    },
)
# Run 2: o4-mini using MCP
gpt_o4_mini_responses_run = client.evals.runs.create(
    name="o4-mini",
    eval_id=logs_eval.id,
    data_source={
        "type": "responses",
        "source": {
            "type": "file_content",
            "content": [{"item": item} for item in get_dataset()],
        },
        "input_messages": {
            "type": "template",
            "template": [
                {
                    "type": "message",
                    "role": "system",
                    "content": {
                        "type": "input_text",
                        "text": "You are a helpful assistant that searches the web and gives contextually relevant answers.",
                    },
                },
                {
                    "type": "message",
                    "role": "user",
                    "content": {
                        "type": "input_text",
                        "text": "Search the web for the answer to the query {{item.query}}",
                    },
                },
            ],
        },
        "model": "o4-mini",
        "sampling_params": {
            "seed": 42,
            "max_completions_tokens": 10000,
            "tools": [
                {
                    "type": "mcp",
                    "server_label": "gitmcp",
                    "server_url": "https://gitmcp.io/openai/tiktoken",
                    "allowed_tools": [
                        "search_tiktoken_documentation",
                        "fetch_tiktoken_documentation",
                    ],
                    "require_approval": "never",
                }
            ],
        },
    },
)

轮询完成状态并获取输出

启动评估运行后,我们可以轮询运行状态,直到它们完成。

此步骤确保我们仅在所有模型响应处理完毕后分析结果。

最佳实践:
带延迟的轮询可避免过多的 API 调用,并确保资源的高效利用。
def poll_runs(eval_id, run_ids):
    while True:
        runs = [client.evals.runs.retrieve(rid, eval_id=eval_id) for rid in run_ids]
        for run in runs:
            print(run.id, run.status, run.result_counts)
        if all(run.status in {"completed", "failed"} for run in runs):
            break
        time.sleep(5)
    
# Start polling both runs.
poll_runs(logs_eval.id, [gpt_4one_responses_run.id, gpt_o4_mini_responses_run.id])

展示与解读模型输出

最后,我们展示每个模型的输出,以便进行人工检查和进一步分析。

以下是 OpenAI Evals 仪表板的截图,展示了两个模型的评估输出:

Evaluation Output有关评估指标和结果的全面细分,请导航至仪表板中的“数据”选项卡:

Evaluation Data Tab

请注意,4.1 模型被构建为从不使用其工具来回答查询,因此它从未调用 MCP 服务器。o4-mini 模型没有被明确指示使用其工具,但也没有被禁止,因此它调用了 MCP 服务器 3 次。我们可以看到 4.1 模型的表现比 o4 模型差。同样值得注意的是,o4-mini 模型失败的一个例子是未使用 MCP 工具的情况。

我们还可以检查每个模型输出的详细分析,以便手动检查和进一步分析。

four_one_output = client.evals.runs.output_items.list(
    run_id=gpt_4one_responses_run.id, eval_id=logs_eval.id
)

o4_mini_output = client.evals.runs.output_items.list(
    run_id=gpt_o4_mini_responses_run.id, eval_id=logs_eval.id
)
print('# gpt‑4.1 Output')
for item in four_one_output:
    print(item.sample.output[0].content)

print('\n# o4-mini Output')
for item in o4_mini_output:
    print(item.sample.output[0].content)

我们如何改进?

如果我们在 o4-mini 模型的系统消息中添加这样一句话:“始终使用你的工具,因为它们是完成此任务时获得正确答案的方式。”你认为会发生什么?(试试看)

<br><br><br>

如果你猜到了模型现在每次都会调用 MCP 工具并得到所有正确答案,那么你是对的!

Evaluation Data Tab

Evaluation Data Tab

在本笔记本中,我们演示了一个示例工作流,用于评估 LLM 回答关于 tiktoken 仓库的技术问题的能力,使用 OpenAI Evals 框架并利用 MCP 工具。

涵盖的关键点:

后续步骤:

有关更多信息,请查看 OpenAI Evals 文档。

常见问题

常见错误:1) 未正确设置OPENAI_API_KEY环境变量,导致客户端初始化失败;2) 数据集格式不符合item_schema定义,导致评估运行错误;3) MCP服务器URL不可达或工具名称拼写错误,导致工具调用失败;4) 轮询逻辑未处理超时或异常状态,导致死循环。排查方法:检查API密钥和网络连接,验证数据集字段与schema匹配,使用curl测试MCP服务器端点,在轮询循环中添加最大重试次数和错误处理。生产环境优化:使用异步并发运行多个评估,缓存MCP响应以减少延迟,采用分布式执行框架(如Ray)处理大规模数据集,并定期更新评估数据集以反映真实场景变化。

企业应用扩展

可扩展方向:1) 扩展数据集:增加更多样化、具有挑战性的问题,覆盖边界情况和错误场景;2) 增强评分器:引入语义相似度计算(如BERTScore)或人工评分流程,提高评估准确性;3) 多模型对比:纳入更多模型(如GPT-4o、Claude)进行基准测试;4) 自动化报告:生成通过率、失败案例分析等可视化报告,集成到CI/CD管道中;5) 优化MCP配置:调整工具列表、服务器选择,或实现自定义MCP服务器以提供更精准的数据;6) 提示词工程:系统化测试不同系统提示词对工具调用率和答案质量的影响。

总结

本文介绍如何使用OpenAI Evals框架和自定义内存数据集,评估基于MCP(模型上下文协议)的模型回答质量。通过定义包含问答对的数据集,配置基于LLM和Python的评分器,并比较gpt-4.1和o4-mini两个模型在MCP工具辅助下的表现,展示了系统化评估工作流。文章强调同时使用多种评分器、保持评估设置一致性、轮询运行状态等最佳实践,并提供了改进模型提示词以提升工具调用率的示例。

内容来源与验证

继续系统学习

站内还有更多完整实战教程

加入会员,解锁全部教程、完整代码与持续更新内容。

加入会员
查看全部模型评估与微调教程