Ручное тестирование LLM — это ад
Вы скачали три версии Qwen3-Coder-Next: оригинальную, квантованную в Q4_K_M и ультра-легкую в Q2_K. Запускаете каждую, задаете один и тот же промпт про сортировку пузырьком. Первая выдает рабочий код, вторая путает синтаксис, третья начинает философствовать о природе алгоритмов. Вы записываете результаты в блокнот. Потом тестируете tool calling. Потом — цепочки рассуждений. Через два часа у вас болит голова, а в таблице Excel хаос.
Знакомо? Поздравляю, вы занимались ручным тестированием LLM. И это примерно так же эффективно, как измерять температуру процессора ладонью.
На 07.02.2026 ситуация парадоксальная: модели становятся умнее, а инструменты для их сравнения — примитивнее. Мы тестируем нейросети с миллиардами параметров методами из 90-х.
Что на самом деле нужно измерять
Стандартные бенчмарки вроде MMLU или HumanEval — это хорошо для академических статей. На практике же вас волнуют другие вещи:
- Как квантование ломает логику — та же модель в Q8 и Q2_K может давать принципиально разные ответы
- Стабильность coding-ответов — генерирует ли модель рабочий код с первого раза или нужно пять попыток
- Tool calling без галлюцинаций — правильно ли модель определяет, когда нужен инструмент, а когда — нет
- Скорость vs качество — насколько жертвуем интеллектом ради FPS
И самое главное — вам нужны повторяемые тесты. Сегодня модель ответила правильно, завтра — нет. Это баг или фича? Без автоматизации вы никогда не узнаете.
Архитектура автотест-сьюта: просто, но не примитивно
Я собрал тест-сьют, который работает по принципу «сказал-сделал». Никакой магии, только Python и здравый смысл.
Сьют состоит из трех слоев:
- Драйвер моделей — общается с LM Studio через API (на 07.02.2026 они наконец-то сделали нормальную документацию)
- Набор тестов — категории: coding, reasoning, tool use, knowledge
- Валидаторы — проверяют, что ответ не просто красивый, но и правильный
Интеграция с LM Studio: без боли
LM Studio в 2026 году — это стандарт де-факто для локального запуска. Их API стабилен, но есть нюансы:
import requests
import json
class LMStudioClient:
def __init__(self, base_url="http://localhost:1234"):
self.base_url = base_url
def generate(self, prompt, model=None, max_tokens=512):
"""Основной метод генерации"""
payload = {
"prompt": prompt,
"max_tokens": max_tokens,
"temperature": 0.1, # Низкая для тестов
"stop": ["\n\n", ""]
}
if model:
payload["model"] = model
response = requests.post(
f"{self.base_url}/v1/completions",
json=payload,
timeout=60 # Некоторые модели думают медленно
)
if response.status_code != 200:
raise Exception(f"LM Studio error: {response.text}")
return response.json()["choices"][0]["text"]Ключевой момент: temperature=0.1. Для тестов нужна максимальная детерминированность. Если модель при низкой температуре дает разные ответы на один промпт — это красный флаг.
Тестируем coding: не «работает ли код», а «насколько хорошо работает»
Простые coding-тесты из HumanEval устарели. В 2026 году мы проверяем:
- Понимание контекста — модель получает кусок кода с багом, должна найти и исправить
- Работа с внешними API — написать клиент для REST API с обработкой ошибок
- Асинхронность — потому что все теперь асинхронное
- Тесты на тесты — модель пишет unit-тесты для заданной функции
Пример теста для Qwen3-Coder-Next-32B (последняя версия на 07.02.2026):
coding_test = {
"name": "async_api_client",
"prompt": "Напиши асинхронный клиент для API погоды на Python. API endpoint: GET /weather?city={city}. Обработай ошибки 404 и 500. Используй aiohttp.",
"validation": [
{
"type": "import_check",
"modules": ["aiohttp", "asyncio"]
},
{
"type": "syntax_check"
},
{
"type": "run_check",
"timeout": 5
}
]
}Валидатор run_check пытается выполнить код в изолированном окружении. Не чтобы он реально ходил в API, а чтобы убедиться, что синтаксис правильный и нет очевидных ошибок.
Важно: не все модели понимают разницу между синхронным и асинхронным кодом. Некоторые выдают синхронную обертку вокруг aiohttp — это провал теста.
Tool use: самая болезненная тема
Тестировать tool calling в отрыве от реального использования — бессмысленно. Модель может идеально генерировать JSON с вызовом функции, но если эта функция нерелевантна задаче — весь tool use бесполезен.
Мой подход: даю модельке набор инструментов (калькулятор, поиск в базе, конвертер валют) и сложную задачу, где нужно комбинировать инструменты.
tool_use_test = {
"scenario": "Пользователь спрашивает: 'Сколько будет 150 евро в долларах по курсу 1.1, плюс 10% комиссии?'",
"available_tools": [
{
"name": "calculator",
"description": "Выполняет математические операции"
},
{
"name": "currency_converter",
"description": "Конвертирует валюты по заданному курсу"
}
],
"expected_actions": [
"Вызов currency_converter с параметрами {amount: 150, from: 'EUR', to: 'USD', rate: 1.1}",
"Вызов calculator для добавления 10% комиссии"
],
"allow_partial": True # Если сделала хотя бы один шаг правильно
}Здесь проверяем не просто способность вызвать инструмент, а способность планировать. Сначала конвертация, потом расчет комиссии. Обратный порядок — ошибка.
Кстати, если хотите глубже разобраться в тестировании tool calling, у нас есть отдельная статья — Тестируем недетерминированные LLM: как написать тесты для вызова функций и не сойти с ума.
Сравнение квантований: цифры не врут
Вот где автоматизация показывает свою силу. Берем GPT-OSS-20B (последняя версия на 07.02.2026) в трех квантованиях:
| Квантование | Размер (GB) | Coding score | Tool use score | Скорость (токен/с) |
|---|---|---|---|---|
| Q8 (оригинал) | 38.5 | 94% | 88% | 24 |
| Q4_K_M | 19.2 | 91% | 85% | 42 |
| Q2_K | 9.8 | 67% | 52% | 68 |
Что видим? Q4_K_M — оптимальный выбор. Всего 3% потери качества в coding за двукратный прирост скорости. Q2_K — уже серьезная деградация, особенно в tool use. Модель начинает «забывать», как правильно вызывать инструменты.
А вот с Qwen3-Coder-Next-32B картина интереснее:
| Модель | Квантование | Coding (сложные задачи) | Coding (простые) |
|---|---|---|---|
| Qwen3-Coder-Next-32B | Q8 | 96% | 99% |
| Qwen3-Coder-Next-32B | Q4_K_M | 94% | 98% |
| Qwen3-Coder-Next-32B | Q3_K_M | 89% | 95% |
Coder-модели устойчивее к квантованию в своей специализации. Они теряют меньше на coding-задачах, но могут сильно просесть на reasoning. Автоматические тесты это сразу показывают.
Что тестировать кроме coding и tool use
Полный тест-сьют включает:
- Контекстное окно — подаем текст в 8к токенов, просим ответить на вопрос из середины
- Мультиязычность — не только английский/русский, но и смешение языков в одном промпте
- Инструкции с ограничениями — «ответь не более 50 слов», «используй только present simple»
- Понимание юмора и сарказма — сложно автоматизировать, но можно
Для последнего пункта я использую трюк: даю модельке явно абсурдный запрос и смотрю, пытается ли она его выполнить серьезно или понимает шутку.
Кому это нужно (спойлер: почти всем)
Автоматический тест-сьют — не для академиков. Он для:
- Разработчиков, выбирающих модель для проекта — вместо чтения хвалебных постов в Twitter вы получаете цифры
- ML-инженеров, настраивающих продакшен — после каждого обновления модели запускаете тесты, видите регрессии
- Энтузиастов, собирающих сборки моделей — проверили новую квантизацию, увидели, что сломалось
- Команд, делающих своих fine-tune — дообучили модель, проверили, не забыла ли она базовые вещи
Если вы до сих пор тестируете модели вручную — вы тратите время, которое могли бы потратить на что-то полезное. Вроде настройки ручного тестирования для других частей проекта. Шутка. Но только отчасти.
Как начать: не идеально, но работает
Не нужно строить мега-фреймворк с графиками и дашбордами. Начните с простого:
# test_suite.py
import json
from lm_studio_client import LMStudioClient
tests = load_tests("tests/")
client = LMStudioClient()
results = []
for test in tests:
response = client.generate(test["prompt"])
score = evaluate(test, response)
results.append({
"test": test["name"],
"score": score,
"response": response[:200] # Первые 200 символов
})
with open("results.json", "w") as f:
json.dump(results, f, indent=2, ensure_ascii=False)Запустили на двух моделях. Сравнили результаты. Уже лучше, чем ничего.
Постепенно добавляйте:
- Больше категорий тестов
- Валидаторы сложнее
- Сбор метрик (время ответа, использование памяти)
- Визуализацию сравнений
Через месяц у вас будет собственный бенчмарк, заточенный под ваши задачи. И вы перестанете гадать, какая модель лучше. Вы будете знать.
Что будет дальше (прогноз на 2027)
К 2027 году автоматическое тестирование LLM станет таким же стандартом, как unit-тесты для обычного кода. Появятся:
- Стандартные тест-сьюты для разных доменов (медицина, юриспруденция, программирование)
- Интеграция в CI/CD для ML-пайплайнов
- Тесты на «этическую устойчивость» — как модель реагирует на попытки jailbreak
- Автоматическое сравнение не только результатов, но и стилей ответов
Но ждать 2027 года не нужно. Инструменты для автоматического тестирования уже здесь. Они не идеальны, но они работают. И они экономят часы ручной работы.
Последний совет: не зацикливайтесь на 100% покрытии. Лучше иметь 20 тестов, которые вы запускаете регулярно, чем 200 тестов, которые пылятся в репозитории. Запускайте тесты при каждой смене модели. Запускайте при каждом обновлении. Собирайте историю. Анализируйте тренды.
Потому что в мире локальных LLM есть только один способ не отстать — постоянно измерять. И автоматизация — ваш единственный друг в этом безумии.