• Русский
  • Оценка LLM

    LM-Eval предоставляет единый фреймворк для тестирования LLM на широком спектре задач оценки. Сервис построен на основе EleutherAI's lm-evaluation-harness и Unitxt. Оператор TrustyAI реализует его через CRD LMEvalJob, что позволяет создавать и управлять заданиями оценки в кластере.

    В этом документе описывается запуск задания оценки для LLM, развернутой как Kubernetes InferenceService (совместимый с OpenAI API).

    Предварительные требования

    • Установлен TrustyAI Operator (см. Install TrustyAI).
    • LLM развернута как InferenceService в целевом namespace (например, vLLM или Hugging Face runtime).
    • Для задач или токенизаторов, требующих загрузки из интернета (например, Hugging Face): allowOnline должен быть включён в LMEvalJob, и кластер должен это разрешать (например, permitOnline: allow в конфиге TrustyAI eval DataScienceCluster). Включение онлайн-доступа имеет последствия для безопасности; см. документацию Red Hat.

    Запуск задания оценки

    Создайте кастомный ресурс LMEvalJob, указывающий на InferenceService и задающий задачи оценки. Оператор запускает задание в pod; после завершения результаты записываются в status.results.

    Пример: оценка LLM в кластере с задачей arc_easy (имя задачи lm-evaluation-harness). Модель доступна через URL сервиса предсказаний; токенизатор загружается из 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>             # например, 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:
            # Опционально: задайте HF_ENDPOINT, если ваша организация предоставляет доверенное зеркало.
            # - name: HF_ENDPOINT
            #  value: https://<your-approved-hf-mirror>
    • Тип модели (model)

      • local-completions или local-chat-completions для сервера, совместимого с OpenAI API (например, InferenceService predictor).
      • Они соответствуют эндпоинтам OpenAI:
        • local-completions/v1/completions
        • local-chat-completions/v1/chat/completions
      • modelArgs.base_url должен использовать тот же путь (например, xxx/v1/completions или xxx/v1/chat/completions).
    • Аргументы модели (modelArgs)

      • base_url: URL предиктора с указанием пути
        • /v1/completions для local-completions
        • /v1/chat/completions для local-chat-completions
      • model: обычно совпадает с именем InferenceService.
      • tokenizer: ID модели Hugging Face, используемый для токенизации при tokenized_requests = true.
      • Другие параметры (например, num_concurrent, max_retries, batch_size) соответствуют документации lm-evaluation-harness.
    • Задачи (taskList.taskNames)

      • Список имён задач lm-evaluation-harness (например, arc_easy, mmlu).
      • Полный набор поддерживаемых задач и шаблонов определён в lm-evaluation-harness (Task Guide / available tasks).
      • Альтернативно, используйте taskRecipes с Unitxt карточками/шаблонами для кастомных задач.
    • Онлайн-режим и выполнение кода

      • allowOnline: при true задание может загружать датасеты и токенизаторы из интернета (например, Hugging Face); требует разрешения на уровне кластера.
      • allowCodeExecution: при true задание может выполнять код из загруженных ресурсов; по умолчанию false, включайте только при необходимости и разрешении.
    • Выводы и ограничения

      • outputs.pvcManaged: создаёт PVC, управляемый оператором, для хранения результатов задания (размер, например 100Mi). Если задан только размер, PVC использует StorageClass по умолчанию кластера; если StorageClass по умолчанию отсутствует, PVC остаётся в состоянии Pending и хранилище не выделяется. Альтернативно, используйте outputs.pvcName для привязки к существующему PVC.
      • limit: необязательное ограничение на количество примеров (например, "2" для быстрого прогона).
      • logSamples: при true сохраняет входные данные и результаты модели для каждого запроса для последующего анализа.

    Статус ресурса

    Подресурс LMEvalJob status отображает состояние задания и, по завершении, результаты оценки.

    • status.state: Текущее состояние задания: New, Scheduled, Running, Complete, Cancelled или Suspended. Ожидайте Complete перед чтением результатов.
    • status.reason: Устанавливается при завершении задания (например, Succeeded, Failed).
    • status.results: При состоянии Complete содержит результаты оценки в виде JSON-строки (метрики по задачам/рецептам).
    • status.message: Читаемое сообщение; status.podName — имя pod с заданием.

    Трафик или чтение результатов должны основываться на status.state == Complete (и, если применимо, status.reason == Succeeded).

    Получение результатов

    Когда status.state равно Complete, результаты доступны в status.results (JSON-строка). Пример:

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

    Пример структуры результата для задачи arc_easy (ключевые поля; полный вывод включает configs, config, n-shot, n-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

    В офлайн режиме задание оценки не обращается к интернету; модели и датасеты должны читаться с PVC (или из образа). Используйте это, если кластер запрещает онлайн-доступ или для изолированных сред.

    Настройки spec для офлайн-режима

    • Поля задания

      • allowOnline: false: задание не загружает данные из интернета.
      • offline.storage.pvcName: имя существующего PVC. Оператор монтирует этот PVC в pod задания; задание загружает модели и датасеты из путей внутри этого монтирования.
    • Пути в spec

      • Загрузчики моделей/датасетов должны указывать на монтируемый PVC.
      • Для моделей Hugging Face настройте modelArgs так, чтобы путь модели находился внутри монтирования PVC (например, /opt/app-root/src/hf_home/<model-dir>).
      • Для taskRecipes или кастомных Unitxt карточек, загружающих с диска, задайте пути загрузчиков внутри того же монтирования.

    Переменные окружения для офлайн-кэшей

    Задайте переменные окружения в spec.pod.container.env, чтобы загрузчики использовали PVC как кэш/хранилище. Для надёжности укажите все следующие переменные на одну и ту же директорию внутри монтирования PVC (например, /opt/app-root/src/hf_home):

    • HF_DATASETS_CACHE: директория кэша для Hugging Face datasets.
    • HF_HOME: домашняя директория Hugging Face, используется токенизаторами и другими ресурсами.
    • TRANSFORMERS_CACHE: директория кэша для моделей и токенизаторов transformers.

    Пример фрагмента для офлайн-режима:

    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.pvcName или outputs.pvcManaged только для хранения результатов оценки; offline.storage.pvcName предназначен для входных данных (моделей и датасетов).

    Подготовка PVC с датасетами для офлайн-запусков

    В офлайн-режиме датасет (и файлы токенизатора/модели при использовании HF) должны уже существовать в PVC. Задание не загружает их из сети.

    Практический способ подготовки PVC:

    1. Онлайн-запуск для прогрева

      • Создайте LMEvalJob с allowOnline: true.
      • Смонтируйте целевой PVC (тот, что будет использоваться в офлайн-режиме), например через offline.storage.pvcName или дополнительный том.
      • Позвольте этому заданию загрузить необходимые датасеты/токенизаторы/модели, чтобы они сохранились в путях PVC, используемых переменными HF_DATASETS_CACHE, HF_HOME и TRANSFORMERS_CACHE, а также в конфигурируемых modelArgs / загрузчиках задач.
    2. Офлайн-запуск оценки

      • Создайте реальное задание оценки с allowOnline: false и offline.storage.pvcName, указывающим на тот же PVC.
      • Теперь задание читает все модели и датасеты с PVC без доступа к внешней сети.