评估 LLM

LM-Eval 提供了一个统一框架,用于在广泛的评估任务上测试 LLM。该服务基于 EleutherAI's lm-evaluation-harnessUnitxt。TrustyAI Operator 通过 LMEvalJob CRD 实现它,因此可以在集群上创建和管理评估作业。

本文档介绍如何针对作为 Kubernetes InferenceService 提供服务的 LLM 运行评估作业(与 OpenAI API 兼容)。

前提条件

  • 已安装 TrustyAI Operator(参见 安装 TrustyAI)。
  • 在目标命名空间中部署了一个作为 InferenceService 的 LLM(例如 vLLM 或 Hugging Face runtime)。
  • 对于需要从互联网下载的任务或 tokenizer(例如 Hugging Face):必须在 LMEvalJob 上启用 allowOnline,并且集群必须允许该操作(例如在 DataScienceCluster TrustyAI eval 配置中设置 permitOnline: allow)。启用在线访问会带来安全影响;请参阅 Red Hat 文档。

运行评估作业

创建一个指向 InferenceService 并指定评估任务的 LMEvalJob 自定义资源。operator 会在 pod 中运行该作业;作业完成后,结果会写入 status.results

示例:使用 arc_easy 任务(lm-evaluation-harness 任务名称)评估集群内 LLM。模型通过 predictor service URL 访问;tokenizer 从 Hugging Face 加载(需要 allowOnline: true 以及集群授权)。

apiVersion: trustyai.opendatahub.io/v1alpha1
kind: LMEvalJob
metadata:
  name: evaljob-sample
  namespace: <your-namespace>
spec:
  model: local-completions
  modelArgs:
    - name: model
      value: <inference-service-name>
    - name: base_url
      value: http://<inference-service-name>-predictor.<your-namespace>.svc/v1/completions
    - name: num_concurrent
      value: "1"
    - name: max_retries
      value: "3"
    - name: tokenized_requests
      value: "True"
    - name: tokenizer
      value: <huggingface-model-repo>             # e.g. Qwen/Qwen3.5-4B
  taskList:
    taskNames:
      - arc_easy
  allowOnline: true
  allowCodeExecution: false
  batchSize: "1"
  limit: "2"
  logSamples: true
  chatTemplate:
    enabled: false
  outputs:
    pvcManaged:
      size: 10Mi
  pod:
    container:
      env:
        # Optional: only set HF_ENDPOINT if your organization provides a trusted mirror.
        # - name: HF_ENDPOINT
        #  value: https://<your-approved-hf-mirror>
  • 模型类型 (model)

    • 对于与 OpenAI API 兼容的 server(例如 InferenceService predictor),使用 local-completionslocal-chat-completions
    • 它们映射到 OpenAI endpoints:
      • local-completions 对应 /v1/completions
      • local-chat-completions 对应 /v1/chat/completions
    • modelArgs.base_url 必须使用相同的 path(例如 xxx/v1/completionsxxx/v1/chat/completions)。
  • 模型参数 (modelArgs)

    • base_url:包含 path 的 predictor URL
      • local-completions 对应 /v1/completions
      • local-chat-completions 对应 /v1/chat/completions
    • model:通常与 InferenceService 名称一致。
    • tokenizer:当 tokenized_requests 为 true 时,用于分词的 Hugging Face model ID。
    • 其他参数(例如 num_concurrentmax_retriesbatch_size)遵循 lm-evaluation-harness 文档
  • 任务 (taskList.taskNames)

    • lm-evaluation-harness 任务名称列表(例如 arc_easymmlu)。
    • 支持的完整任务集合和通配符由 lm-evaluation-harness(Task Guide / available tasks)定义。
    • 另外,也可以使用带有 Unitxt card/template 的 taskRecipes 来定义自定义任务。
  • 在线模式和代码执行

    • allowOnline:当为 true 时,作业可以从互联网下载数据集和 tokenizer(例如 Hugging Face);需要集群级别的授权。
    • allowCodeExecution:当为 true 时,作业可能会运行来自已下载资源的代码;默认值为 false,仅在需要且被允许时启用。
  • 输出和限制

    • outputs.pvcManaged:创建一个由 operator 管理的 PVC 来存储作业结果(大小,例如 100Mi)。如果只设置了 size,PVC 将使用集群默认的 StorageClass;如果不存在默认 StorageClass,PVC 将保持 Pending,且不会配置存储。也可以使用 outputs.pvcName 绑定到现有 PVC。
    • limit:样本数量的可选上限(例如 "2",用于快速运行)。
    • logSamples:当为 true 时,会保存每个 prompt 的模型输入和输出以供检查。

资源状态

LMEvalJob 的 status 子资源会报告作业状态,并在完成后报告评估结果。

  • status.state:作业的当前状态:NewScheduledRunningCompleteCancelledSuspended。在读取结果之前请等待 Complete
  • status.reason:在作业结束时设置(例如 SucceededFailed)。
  • status.results:当 stateComplete 时,此字段包含 JSON 字符串形式的评估结果(按任务/recipe 划分的指标)。
  • status.message:人类可读的消息;status.podName 是作业 pod 的名称。

在读取流量或结果时,应基于 status.state == Complete(并且,如适用,基于 status.reason == Succeeded)。

获取结果

status.stateComplete 时,结果可在 status.results 中获取(JSON 字符串)。示例:

kubectl get lmevaljob evaljob-sample -n <your-namespace> -o jsonpath='{.status.results}' | jq '.'

arc_easy 任务的示例结果结构(关键字段;完整输出还包括 configsconfign-shotn-samples 和环境信息):

示例结果(arc_easy)
{
  "results": {
    "arc_easy": {
      "alias": "arc_easy",
      "acc,none": 0.5,
      "acc_stderr,none": 0.5,
      "acc_norm,none": 0.5,
      "acc_norm_stderr,none": 0.5
    }
  },
  "group_subtasks": {
    "arc_easy": []
  },
  "configs": {
    "arc_easy": {
      "task": "arc_easy",
      "tag": ["ai2_arc"],
      "dataset_path": "allenai/ai2_arc",
      "dataset_name": "ARC-Easy",
      "training_split": "train",
      "validation_split": "validation",
      "test_split": "test",
      "doc_to_text": "Question: {{question}}\nAnswer:",
      "doc_to_target": "{{choices.label.index(answerKey)}}",
      "unsafe_code": false,
      "doc_to_choice": "{{choices.text}}",
      "description": "",
      "target_delimiter": " ",
      "fewshot_delimiter": "\n\n",
      "num_fewshot": 0,
      "metric_list": [
        { "metric": "acc", "aggregation": "mean", "higher_is_better": true },
        { "metric": "acc_norm", "aggregation": "mean", "higher_is_better": true }
      ],
      "output_type": "multiple_choice",
      "repeats": 1,
      "should_decontaminate": true,
      "doc_to_decontamination_query": "Question: {{question}}\nAnswer:",
      "metadata": { "version": 1.0 }
    }
  },
  "versions": { "arc_easy": 1.0 },
  "n-shot": { "arc_easy": 0 },
  "higher_is_better": { "arc_easy": { "acc": true, "acc_norm": true } },
  "n-samples": {
    "arc_easy": { "original": 2376, "effective": 2 }
  },
  "config": {
    "model": "local-completions",
    "model_args": "model=<inference-service-name>,base_url=http://<inference-service-name>.trustyai-e2e-test.svc/v1/completions,num_concurrent=1,max_retries=3,tokenized_requests=True,tokenizer=......",
    "batch_size": "1",
    "device": "cpu",
    "limit": 2.0,
    "bootstrap_iters": 100000,
    "random_seed": 0,
    "numpy_seed": 1234,
    "torch_seed": 1234,
    "fewshot_seed": 1234
  },
  "model_source": "local-completions",
  "model_name": "<inference-service-name>",
  "start_time": 185129.71525112,
  "end_time": 185190.022770961,
  "total_evaluation_time_seconds": "60.307519840978784"
}

可选:离线存储和 PVC

offline 模式下,评估作业不会访问互联网;模型和数据集必须从 PVC(或镜像)中读取。当集群不允许在线访问或用于 air-gapped 环境时,请使用此模式。

离线模式的 spec 设置

  • 作业字段

    • allowOnline: false:作业不会从互联网下载内容。
    • offline.storage.pvcName:现有 PVC 的名称。operator 会将此 PVC 挂载到作业 pod 中;作业会从该挂载点下的路径加载模型和数据集。
  • spec 中的路径

    • 模型 / 数据集加载器必须指向已挂载的 PVC。
    • 对于 Hugging Face 模型,请配置 modelArgs,使模型路径位于 PVC 挂载目录下(例如 /opt/app-root/src/hf_home/<model-dir>)。
    • 对于从磁盘加载的 taskRecipes 或自定义 Unitxt card,请将加载器路径设置在同一挂载目录下。

用于离线缓存的环境变量

spec.pod.container.env 中设置环境变量,以便加载器使用 PVC 作为缓存/存储。为提高可靠性,请将以下所有变量设置为 PVC 挂载目录下的同一路径(例如 /opt/app-root/src/hf_home):

  • HF_DATASETS_CACHE:Hugging Face datasets 的缓存目录。
  • HF_HOME:Hugging Face 主页目录,供 tokenizer 和其他资源使用。
  • TRANSFORMERS_CACHEtransformers models 和 tokenizer 的缓存目录。

离线模式示例片段:

spec:
  allowOnline: false
  offline:
    storage:
      pvcName: my-offline-pvc
  pod:
    container:
      env:
        - name: HF_DATASETS_CACHE
          value: /opt/app-root/src/hf_home
        - name: HF_HOME
          value: /opt/app-root/src/hf_home
        - name: TRANSFORMERS_CACHE
          value: /opt/app-root/src/hf_home

仅在存储 评估结果 时使用 outputs.pvcNameoutputs.pvcManagedoffline.storage.pvcName 用于 输入(models 和 datasets)。

为离线运行准备 PVC 数据集

在离线模式下,dataset(以及如果使用 HF,则包括 tokenizer/model 文件)必须已经存在于 PVC 中。作业不会从网络获取它们。

准备 PVC 的一种实用方法是:

  1. 在线预热作业

    • 创建一个 allowOnline: true 的 LMEvalJob。
    • 挂载目标 PVC(即稍后在离线模式中使用的 PVC),例如通过 offline.storage.pvcName 或额外卷。
    • 让该作业下载所需的数据集/tokenizer/models,使其存储在 HF_DATASETS_CACHEHF_HOMETRANSFORMERS_CACHE 所使用的 PVC 路径下,以及配置的 modelArgs / 任务加载器路径下。
  2. 离线评估作业

    • 创建真正的评估作业,将 allowOnline: false 并将 offline.storage.pvcName 指向同一个 PVC。
    • 现在作业会在没有任何外部网络访问的情况下,从 PVC 中读取所有 models 和 datasets。