跳转到内容

如何为您的用例评估一个新的 LLM

当一个新的 LLM 发布时,您可能想确定它在您的特定用例中是否优于当前模型。本指南将向您展示如何使用 Ragas 框架在两个模型之间进行准确性比较。

您将完成什么

阅读完本指南后,您将能够:

  • 建立一个结构化的评估,比较两个 LLM
  • 在真实的业务任务上评估模型性能
  • 生成详细结果,为您的模型选择决策提供信息
  • 拥有一个可重用的评估循环,每当新模型发布时都可以重新运行

评估场景

我们将使用折扣计算作为我们的测试用例:给定一个客户资料,计算适当的折扣百分比并解释原因。这项任务需要规则应用和推理能力——这些技能可以区分不同模型的能力。

注意:您可以将此方法应用于任何对您的应用程序重要的用例。

📁 完整代码:此示例的完整源代码可在 Github 上找到

设置环境和 API 访问

首先,安装 ragas-examples 包,其中包含基准 LLM 示例代码

pip install ragas[examples]

接下来,确保您已配置好 API 凭据

export OPENAI_API_KEY=your_actual_api_key

LLM 应用程序

我们在示例包中为您设置了一个简单的 LLM 应用程序,以便您可以专注于评估而不是构建应用程序本身。该应用程序根据业务规则计算客户折扣。

这是定义折扣计算逻辑的系统提示

SYSTEM_PROMPT = """
You are a discount calculation assistant. I will provide a customer profile and you must calculate their discount percentage and explain your reasoning.

Discount rules:
- Age 65+ OR student status: 15% discount
- Annual income < $30,000: 20% discount  
- Premium member for 2+ years: 10% discount
- New customer (< 6 months): 5% discount

Rules can stack up to a maximum of 35% discount.

Respond in JSON format only:
{
  "discount_percentage": number,
  "reason": "clear explanation of which rules apply and calculations",
  "applied_rules": ["list", "of", "applied", "rule", "names"]
}
"""

您可以使用一个示例客户资料来测试该应用程序

from ragas_examples.benchmark_llm.prompt import run_prompt

# Test with a sample customer profile
customer_profile = """
Customer Profile:
- Name: Sarah Johnson
- Age: 67
- Student: No
- Annual Income: $45,000
- Premium Member: Yes, for 3 years
- Account Age: 3 years
"""

result = await run_prompt(customer_profile)
print(result)
📋 输出
{
  "discount_percentage": 25,
  "reason": "Sarah qualifies for a 15% discount due to age (67). She also gets a 10% discount for being a premium member for over 2 years. The total stacking of 15% and 10% discounts results in 25%. No other discounts apply based on income or account age.",
  "applied_rules": ["Age 65+", "Premium member for 2+ years"]
}

检查评估数据集

为了进行此评估,我们构建了一个包含以下测试用例的合成数据集:

  • 结果明确的简单案例
  • 规则边界上的边缘案例
  • 信息模糊的复杂场景

每个案例都指定了:

  • customer_profile:输入数据
  • expected_discount:预期折扣百分比
  • description:案例复杂性指标

数据集结构示例(添加一个 id 列以便于比较)

ID 客户资料 预期折扣 描述
1 玛莎是一位 70 岁的退休人员,喜欢园艺。她最近没有报读任何学术课程,年退休金为 5 万美元,九年前注册了我们的服务,并且从未升级到高级会员。 15 仅老年人
2 阿尔琼,19 岁,是一名全日制计算机科学本科生。他的兼职工作年收入约 4.5 万美元。他一年前开设了账户,没有高级会员资格。 15 仅学生
3 辛西娅是一位 40 岁的自由艺术家,年收入约 2.5 万美元。她没有在任何地方学习,五年前订阅了我们的基础计划,并且从未升级到高级会员。 20 仅低收入

要为您的用例自定义数据集,请创建一个 datasets/ 目录并添加您自己的 CSV 文件。有关更多信息,请参阅核心概念 - 评估数据集

最好从您的应用程序中抽样真实数据来创建数据集。如果没有真实数据,您可以使用 LLM 生成合成数据。由于我们的用例稍微复杂,我们建议使用像 gpt-5-high 这样的模型,它可以生成更准确的数据。请务必手动审查和验证您使用的数据。

注意

虽然本指南中的示例数据集大约有 10 个案例以保持简洁,但对于实际评估,您可以从 20-30 个样本开始,但请确保逐步迭代改进,使其达到 50-100 个样本的范围,以从评估中获得更可信的结果。确保广泛覆盖您的代理可能面临的不同场景(包括边缘案例和复杂问题)。您的准确性最初不需要达到 100%——使用结果进行错误分析,迭代提示、数据和工具,并不断改进。

加载数据集

def load_dataset():
    """Load the dataset from CSV file. Downloads from GitHub if not found locally."""
    import urllib.request
    current_dir = os.path.dirname(os.path.abspath(__file__))
    dataset_path = os.path.join(current_dir, "datasets", "discount_benchmark.csv")
    # Download dataset from GitHub if it doesn't exist locally
    if not os.path.exists(dataset_path):
        os.makedirs(os.path.dirname(dataset_path), exist_ok=True)
        urllib.request.urlretrieve("https://raw.githubusercontent.com/vibrantlabsai/ragas/main/examples/ragas_examples/benchmark_llm/datasets/discount_benchmark.csv", dataset_path)
    return Dataset.load(name="discount_benchmark", backend="local/csv", root_dir=current_dir)

数据集加载器会检查本地是否存在 CSV 文件。如果未找到,它会自动从 GitHub 下载。

指标函数

通常最好使用一个简单的指标。您应该使用与您的用例相关的指标。有关指标的更多信息,请参见核心概念 - 指标。评估使用此准确性指标为每个响应评分。

@discrete_metric(name="discount_accuracy", allowed_values=["correct", "incorrect"])
def discount_accuracy(prediction: str, expected_discount):
    """Check if the discount prediction is correct."""
    import json

    parsed_json = json.loads(prediction)
    predicted_discount = parsed_json.get("discount_percentage")
    expected_discount_int = int(expected_discount)

    if predicted_discount == expected_discount_int:
        return MetricResult(
            value="correct", 
            reason=f"Correctly calculated discount={expected_discount_int}%"
        )
    else:
        return MetricResult(
            value="incorrect",
            reason=f"Expected discount={expected_discount_int}%; Got discount={predicted_discount}%"
        )

实验结构

每个模型评估都遵循此实验模式

@experiment()
async def benchmark_experiment(row, model_name: str):
    # Get model response
    response = await run_prompt(row["customer_profile"], model=model_name)

    # Parse response (strict JSON mode expected)
    try:
        parsed_json = json.loads(response)
        predicted_discount = parsed_json.get('discount_percentage')
    except Exception:
        predicted_discount = None

    # Score the response
    score = discount_accuracy.score(
        prediction=response,
        expected_discount=row["expected_discount"]
    )

    return {
        **row,
        "model": model_name,
        "response": response,
        "predicted_discount": predicted_discount,
        "score": score.value,
        "score_reason": score.reason
    }

运行实验

使用基准模型和候选模型运行评估实验。我们将比较这些示例模型:

  • 基准模型:"gpt-4.1-nano-2025-04-14"
  • 候选模型:"gpt-5-nano-2025-08-07"
from ragas_examples.benchmark_llm.evals import benchmark_experiment, load_dataset

# Load dataset
dataset = load_dataset()
print(f"Dataset loaded with {len(dataset)} samples")

# Run baseline experiment
baseline_results = await benchmark_experiment.arun(
    dataset,
    name="gpt-4.1-nano-2025-04-14",
    model_name="gpt-4.1-nano-2025-04-14"
)

# Calculate and display accuracy
baseline_accuracy = sum(1 for r in baseline_results if r["score"] == "correct") / len(baseline_results)
print(f"Baseline Accuracy: {baseline_accuracy:.2%}")

# Run candidate experiment
candidate_results = await benchmark_experiment.arun(
    dataset,
    name="gpt-5-nano-2025-08-07",
    model_name="gpt-5-nano-2025-08-07"
)

# Calculate and display accuracy
candidate_accuracy = sum(1 for r in candidate_results if r["score"] == "correct") / len(candidate_results)
print(f"Candidate Accuracy: {candidate_accuracy:.2%}")

每个实验都会在 experiments/ 目录下保存一个 CSV 文件,其中包含每行的结果,包括:

  • id, model, response, predicted_discount, score, score_reason
实验输出示例(为便于阅读,仅显示部分列)
ID 描述 预期 预测 得分 得分原因
1 仅老年人 15 15 正确 正确计算折扣=15%
2 仅学生 15 5 不正确 预期折扣=15%;得到折扣=5%
3 仅低收入 20 20 正确 正确计算折扣=20%
4 老年人、低收入、新客户(有上限) 35 35 正确 正确计算折扣=35%
6 仅限 2 年以上高级会员 10 15 不正确 预期折扣=10%;得到折扣=15%

注意

在可能的情况下,固定并记录确切的模型快照/版本(例如,使用“gpt-4o-2024-08-06”而不是仅仅“gpt-4o”)。提供商会定期更新别名,不同快照之间的性能可能会发生变化。您可以在提供商的模型文档中找到可用的快照(例如,参见 OpenAI 的模型目录)。在您的结果中包含快照,可以使未来的比较公平且可复现。

比较结果

在使用不同模型运行实验后,并排比较它们的性能

from ragas_examples.benchmark_llm.evals import compare_inputs_to_output

# Compare the two experiment results
# Update these paths to match your actual experiment output files
output_path = compare_inputs_to_output(
    inputs=[
        "experiments/gpt-4.1-nano-2025-04-14.csv",
        "experiments/gpt-5-nano-2025-08-07.csv"
    ]
)

print(f"Comparison saved to: {output_path}")

这种比较会:

  • 读取两个实验文件
  • 打印每个模型的准确性
  • 创建一个新的 CSV 文件,将结果并排显示

比较文件显示:

  • 测试用例详情(客户资料、预期折扣)
  • 每个模型:其响应、是否正确以及原因
📋 输出
gpt-4.1-nano-2025-04-14 Accuracy: 50.00%
gpt-5-nano-2025-08-07 Accuracy: 90.00%
Comparison saved to: experiments/20250820-150548-comparison.csv

使用合并的 CSV 分析结果

在此次运行示例中:

  • 筛选一个模型优于另一个模型的案例,会显示以下情况:“老年人且新客户”、“学生且新客户”、“仅学生”、“仅限 2 年以上高级会员”。
  • 每个模型响应中的原因字段显示了它给出该输出的原因。
比较 CSV 文件中的示例行(为便于阅读,仅显示部分列)
id customer_profile description expected_discount gpt-4.1-nano-2025-04-14_score gpt-5-nano-2025-08-07_score gpt-4.1-nano-2025-04-14_score_reason gpt-5-nano-2025-08-07_score_reason gpt-4.1-nano-2025-04-14_response gpt-5-nano-2025-08-07_response
2 阿尔琼,19 岁,是一名全日制计算机科学本科生。他的兼职工作年收入约 4.5 万美元。他一年前开设了账户,没有高级会员资格。 仅学生 15 不正确 正确 预期折扣=15%;得到折扣=0% 正确计算折扣=15% ...原因="阿尔琼 19 岁,因此不符合基于年龄或老年人的折扣条件。他 45,000 美元的年收入超过了 30,000 美元的门槛,因此不适用基于收入的折扣。他一年前开设账户,已超过 6 个月,因此不是新客户。他没有高级会员资格,也没有其他适用的折扣。"... ...原因="因学生身份(阿尔琼 19 岁,本科生)有资格享受 15% 的折扣。"...
6 莱昂纳多 64 岁,下个月满 65 岁。他的薪水正好是 30,000 美元。他已维持高级会员订阅两年零七个月,并已使用我们服务五年。 仅限 2 年以上高级会员 10 不正确 正确 预期折扣=10%;得到折扣=25% 正确计算折扣=10% ...原因="莱昂纳多即将满 65 岁,因此他有资格享受 15% 的年龄折扣。注意到有 2 年以上高级会员资格"... ...原因="莱昂纳多 64 岁,下个月满 65 岁。2 年以上高级会员:10%"...

新模型发布时重新运行

一旦这个评估流程与您的项目并存,它就成了一个可重复的检查。当有新的 LLM 发布时(现在通常是每周一次),将其作为候选模型接入,并重新运行相同的评估,以与您当前的基准模型进行比较。

解读结果并做出决策

需要关注什么

  • 基准模型准确性 vs 候选模型准确性 以及 差异
  • 本次运行示例:基准模型 50% (5/10),候选模型 90% (9/10),差异 +40%。

如何解读数据行

  • 快速浏览两个模型结果不一致的行。
  • 使用每行的 score_reason 来查看其被标记为正确/不正确的原因。
  • 寻找规律(例如,错过的规则叠加、边界情况如“将近 65 岁”、精确的收入门槛)。

超越准确性

  • 检查成本延迟。如果速度太慢或成本太高,即使准确性更高也可能不值得。

做出决定

  • 如果新模型在您重要的案例上明显更准确,并且符合您的成本/延迟需求,就切换。
  • 如果提升很小,失败发生在关键案例上,或者成本/延迟不可接受,则保持原样。

在这个例子中: - 我们会切换到 "gpt-5-nano-2025-08-07"。它将准确性从 50% 提高到 90% (+40%),并修复了关键的失败模式(错过的规则叠加、边界条件)。如果其延迟/成本符合您的限制,那么它就是更好的默认选择。

适应您的用例

要为您的特定应用程序评估模型,您可以使用 GitHub 代码 作为模板,并根据您的用例进行调整。

Ragas 框架会自动为您处理编排、并行执行和结果聚合,帮助您专注于评估和您的用例!