Обзор Qwen3 MAX, VL и Coder — новых моделей от Alibaba

Обзор Qwen3-MAX, Qwen3-VL и Qwen3-Coder — новых моделей от Alibaba

Антон Дятлов
Антон Дятлов Инженер по ИБ
15 октября 2025

Три практических сравнения Qwen3 и ChatGPT — reasoning, мультимодальность и код.

Изображение записи

В конце сентября Alibaba выпустила три новые модели Qwen3 — MAX, VL и Coder. На бумаге они выглядят впечатляюще: триллион параметров, миллион токенов контекста и результаты на уровне GPT-5. А главное — они бесплатны и доступны из России без ограничений.

В тексте проведем честный тест: как Qwen3 справляется с задачами на рассуждение, генерацией кода и работой с интерфейсами. Сравним с ChatGPT и посмотрим, где китайская линейка уже догнала конкурента, а где еще буксует.

Qwen3-MAX

Начнем сравнение с Qwen3-MAX — самой крупной модели Alibaba. 

Характеристики:

  • параметров — 1 трлн;
  • датасет — 36 трлн токенов;
  • контекст — до 1 млн токенов (примерно 750 тыс. слов);
  • фокус — сложные рассуждения, математика, программирование.

В особенности привлекли внимание заявленные 100% в бенчмарках AIME25 и HMMT25, поэтому я решил проверить модель по задачам AIME с официального сайта. Прогоняем через Qwen-MAX шесть задач, результат — все ответы правильные. Решения не всегда совпадают с официальными, а вычисления иногда времязатратны, однако ход рассуждений корректный. Самая простая задача заняла около 30 секунд — разберем ее решение.

Проблема (задача): 

Формулировка задачи: Find the sum of all positive integers n such that n + 2 divides the product 3(n + 3)(n^2 + 9).

Решение:

Решение модели.
Решение модели.

Иногда модель сбивается и пытается «подсмотреть» ответ — будто сверяется с интернетом, хотя онлайн-поиск был отключен. При этом промт явно не запрещал использовать внешние источники.

Решение модели.

Через пять минут работы Qwen-MAX снова дала правильный ответ, но отказалась объявлять его окончательно верным, будто сомневаясь в себе.

Финальный ответ Qwen-Max.

Сравнение с ChatGPT

Для сравнения я прогнал несколько задач из AIME через ChatGPT. Взглянем на ход его мыслей и поищем отличия от китайского собрата.

Решение ChatGPT.

Ответы лаконичные и точные. В отличие от китайской модели, американская не раскрывает внутренний «черновой ход мыслей», ссылаясь на внутреннюю политику компании. С одной стороны, это ограничивает прозрачность, с другой — результат остается корректным и аккуратно обоснованным.

Вывод по Qwen3-MAX

На мой взгляд, Qwen-MAX более «рассудительна», но не всегда рациональна в вычислениях. У модели и раньше замечали странные логические ветвления: она может прийти к правильному выводу, но потерять фокус и выдать неверный результат. По этой причине важно проверять ответы — как у Qwen, так и у других LLM. Плашка с дисклеймером о «неответственности LLM» тут не случайна.

Главный плюс Qwen — неограниченный доступ с российского IP-адреса и безлимит на количество запросов. Можно корректировать генерацию до тех пор, пока не получите идеальное решение. Модель точно заслуживает внимания, не стоит списывать ее со счетов.

Qwen3-VL

Следующая на очереди — модель Qwen3-VL. Это мультимодальная версия, способная работать как визуальный агент. Ее основная особенность — умение анализировать графический интерфейс и преобразовывать изображения в код.

Характеристики:

  • параметров — 235 млрд;
  • контекст — до 256 000 токенов (расширяемый до 1 млн);
  • среди особенностей — распознавание элементов GUI, генерация кода из макетов, управление приложениями по скриншотам.

Задаем промт:

Ты — агент, который по скриншоту дизайна генерирует рабочий веб-файл. Выдай ровно один файл index.html, содержащий HTML, встроенные CSS и минимальный JS. Цель — максимально визуально соответствовать буферу обмена. Не используй внешние CDN — все в одном файле.

К промту прикрепляю скриншот лендинга — случайного примера из интернета:

Скриншот первоначального лендинга.

Результат — оперативно сгенерированный HTML-файл, визуально близкий к исходнику:

Новый файл от Qwen (на основе исходного лендинга).

Проверим модель на чуть более детализированном сайте:

Скриншот детализированного первоначального лендинга.

Но модель справилась с задачей посредственно — где-то потеряны буквы, шрифты, не передана плашка «консультация перед заказом». 

Генерация Qwen на основе детализированного лендинга.

Не меняя промт, генерируем такой же лендинг с помощью ChatGPT:

Генерация ChatGPT на основе простого лендинга.

С усложненной задачей модель справилась еще хуже, чем Qwen:

Генерация ChatGPT на основе детализированного лендинга.

Вывод по Qwen3-VL

На мой взгляд, модель Qwen3-VL справилась с задачей лучше: она четче сгенерировала HTML-код, а при необходимости результат можно доработать дополнительными запросами, чтобы точнее воспроизвести исходный лендинг. Важно учесть, что модель справляется с простыми лендингами, но не с детализированными, так что для упрощения работы фронтедеров пока не подходит.

Qwen3-Coder

Qwen3-Coder — специализированная модель для программирования.

Характеристики:

  • датасет — 7,5 трлн токенов;
  • контекст — до 256 000 токенов.

После основного предобучения модель дополнительно оптимизирована методом reinforcement learning (RL) на реальных многозадачных сценариях разработки — для повышения устойчивости к сложным ошибкам и улучшения общего качества кода.

Основные критерии, по которым проверим модель:

  • понимание задачи без запутывания и бесконечных рассуждений;
  • генерация компактного, корректного и читаемого кода;
  • умение обрабатывать ошибки при работе.

Промт:

Напиши на Python программу, которая скачивает JSON-данные по ссылке https://jsonplaceholder.typicode.com/todos и сохраняет их в локальный файл todos.json. Далее — загружает этот файл и выводит статистику:

  • общее количество задач,
  • количество выполненных и невыполненных,
  • пользователя (userId) с наибольшим числом выполненных задач.

Программа должна содержать функции:

  • download_data(url, filename)
  • analyze_data(filename)
  • main()

Добавь обработку ошибок и комментарии.

Результат Qwen3-Coder:


      import json
import requests


def download_data(url, filename):
       try:
        response = requests.get(url)
        response.raise_for_status()  # Вызывает исключение для кодов ошибок HTTP
        with open(filename, 'w', encoding='utf-8') as f:
            json.dump(response.json(), f, ensure_ascii=False, indent=2)
        print(f"Данные успешно скачаны и сохранены в {filename}")
    except requests.exceptions.RequestException as e:
        print(f"Ошибка при загрузке данных: {e}")
        raise
    except IOError as e:
        print(f"Ошибка при сохранении файла: {e}")
        raise


def analyze_data(filename):
      try:
        with open(filename, 'r', encoding='utf-8') as f:
            data = json.load(f)
    except FileNotFoundError:
        print(f"Ошибка: файл {filename} не найден.")
        raise
    except json.JSONDecodeError:
        print(f"Ошибка: файл {filename} содержит некорректный JSON.")
        raise


    if not isinstance(data, list):
        raise ValueError("Ожидался список задач в JSON.")


    total_tasks = len(data)
    completed_tasks = 0
    user_completed_count = {}


    for item in data:
        if not isinstance(item, dict):
            raise ValueError("Элемент списка задач должен быть объектом (dict).")
        if 'completed' not in item or 'userId' not in item:
            raise KeyError("Отсутствует обязательное поле 'completed' или 'userId' в задаче.")


        if item['completed']:
            completed_tasks += 1
            user_id = item['userId']
            user_completed_count[user_id] = user_completed_count.get(user_id, 0) + 1


    uncompleted_tasks = total_tasks - completed_tasks


    # Найти пользователя с максимальным количеством выполненных задач
    max_completed_user_id = None
    max_completed_count = 0
    for user_id, count in user_completed_count.items():
        if count > max_completed_count:
            max_completed_count = count
            max_completed_user_id = user_id


    print("--- Статистика задач ---")
    print(f"Общее количество задач: {total_tasks}")
    print(f"Количество выполненных задач: {completed_tasks}")
    print(f"Количество невыполненных задач: {uncompleted_tasks}")


    if max_completed_user_id is not None:
        print(f"Пользователь с наибольшим числом выполненных задач: {max_completed_user_id} ({max_completed_count} задач)")
    else:
        print("Не найдено ни одной выполненной задачи.")


def main():
    url = "https://jsonplaceholder.typicode.com/todos"
    filename = "todos.json"
   
    try:
        download_data(url, filename)
        analyze_data(filename)
    except Exception as e:
        print(f"Программа завершена с ошибкой: {e}")
        return 1 # Возврат кода ошибки
   
    return 0 # Успешное завершение


# Запуск основной программы
if __name__ == "__main__":
    main()

Вывод:

Данные успешно скачаны и сохранены в todos json

– – – Статистика задач – – –

Общее количество задач: 200.

Количество выполненных задач: 90

Количество невыполненных задач: 110

Пользователь с наибольшим числом выполненных задач: 5 (12 задач)

Код выполняется без ошибок, структура соблюдена: есть main(), функции, отладка через try/except. Вывод аккуратный, читаемый. Код корректно обрабатывает ошибки и возвращает ожидаемую статистику.

Сравнение с ChatGPT

Сгенерируем с тем же промтом код через ChatGPT:


      from typing import Tuple, Dict, Any, List
import json
import logging
import sys
import time


try:
    import requests  # type: ignore
    HAS_REQUESTS = True
except Exception:
    from urllib import request, error
    HAS_REQUESTS = False


logging.basicConfig(level=logging.INFO, format="%(levelname)s: %(message)s")




def download_data(url: str, filename: str, timeout: int = 10) -> bool:
    logging.info("Начинаю загрузку данных с %s", url)
    try:
        if HAS_REQUESTS:
            # requests — удобнее; обработаем ошибки статуса
            resp = requests.get(url, timeout=timeout)
            resp.raise_for_status()  # выбросит исключение для HTTP ошибок
            data_text = resp.text
        else:
            # стандартная библиотека urllib
            with request.urlopen(url, timeout=timeout) as resp:
                # проверка кода состояния в urllib: .status доступен в Py3
                status = getattr(resp, "status", None)
                if status is not None and status >= 400:
                    raise error.HTTPError(url, status, "HTTP error", hdrs=None, fp=None)
                data_bytes = resp.read()
                # предполагаем utf-8 (обычно так)
                data_text = data_bytes.decode("utf-8")
    except Exception as e:
        logging.error("Ошибка при загрузке данных: %s", e)
        return False


    try:
        parsed = json.loads(data_text)
    except json.JSONDecodeError as e:
        logging.error("Полученные данные не являются корректным JSON: %s", e)
        return False


    try:
        with open(filename, "w", encoding="utf-8") as f:
            json.dump(parsed, f, ensure_ascii=False, indent=2)
        logging.info("Данные успешно сохранены в '%s'", filename)
        return True
    except OSError as e:
        logging.error("Ошибка записи в файл '%s': %s", filename, e)
        return False




def analyze_data(filename: str) -> Tuple[int, int, int, List[int]]:
    logging.info("Читаю данные из '%s'...", filename)
    try:
        with open(filename, "r", encoding="utf-8") as f:
            data = json.load(f)
    except FileNotFoundError:
        raise FileNotFoundError(f"Файл '{filename}' не найден.")
    except json.JSONDecodeError as e:
        raise ValueError(f"Файл '{filename}' содержит некорректный JSON: {e}") from e
    except OSError as e:
        raise OSError(f"Ошибка при чтении файла '{filename}': {e}") from e


    if not isinstance(data, list):
        raise ValueError("Ожидался JSON-массив задач (list).")


    total = len(data)
    completed = 0
    not_completed = 0


   
    completed_by_user: Dict[int, int] = {}


    for i, item in enumerate(data):
        if not isinstance(item, dict):
            logging.warning("Запись %d не является объектом (пропускается).", i)
            continue


        user_id = item.get("userId")
        is_completed = item.get("completed")


        if not isinstance(user_id, int):
            logging.warning("Запись %d: некорректный или отсутствующий userId (%r). Пропускаю.", i, user_id)
            continue
        if not isinstance(is_completed, bool):
            logging.warning("Запись %d: поле 'completed' некорректно (%r). Пропускаю.", i, is_completed)
            continue


        if is_completed:
            completed += 1
            completed_by_user[user_id] = completed_by_user.get(user_id, 0) + 1
        else:
            not_completed += 1


    if completed_by_user:
        max_completed = max(completed_by_user.values())
        users_with_max = [uid for uid, cnt in completed_by_user.items() if cnt == max_completed]
    else:
        max_completed = 0
        users_with_max = []


    logging.info("Анализ завершён.")
    return total, completed, not_completed, users_with_max




def main() -> None:
   
    url = "https://jsonplaceholder.typicode.com/todos"
    filename = "todos.json"


    success = download_data(url, filename)
    if not success:
        logging.error("Не удалось загрузить данные. Программа завершает работу.")
        sys.exit(1)
    time.sleep(0.1)


    try:
        total, completed, not_completed, users_with_max = analyze_data(filename)
    except Exception as e:
        logging.error("Ошибка при анализе данных: %s", e)
        sys.exit(1)


    print()
    print("Статистика по задачам:")
    print(f"  Общее количество задач: {total}")
    print(f"  Выполнено: {completed}")
    print(f"  Не выполнено: {not_completed}")


    if users_with_max:
        # Если несколько users имеют одинаковое максимальное значение — покажем их всех
        users_str = ", ".join(str(u) for u in sorted(users_with_max))
        print(f"  Пользователь(и) с наибольшим числом выполненных задач: {users_str}")
    else:
        print("  Нет информации о выполненных задачах (нет корректных записей).")




if __name__ == "__main__":
    main()

Вывод:

Статистика по задачам.

Общее количество задач: 200.

Выполнено: 90.

Не выполнено: 110.

Пользователь(и) с наибольшим числом выполненных задач: 5, 10.

Вывод по Qwen3-Coder

По сравнению с Qwen3-Coder, версия ChatGPT выглядит более продуманной с точки зрения инженерной практики: есть логирование, контроль ошибок на всех этапах, fallback-механизм, а также строгие проверки типов. Тем не менее, Qwen генерирует код быстрее и компактнее — хорошо подходит для прототипирования, где важна скорость.

Заключение

После тестов трех новых моделей Qwen3 можно уверенно сказать: серия получилась зрелой и конкурентоспособной. По качеству генерации она уже не уступает топовым конкурентам, а по соотношению функциональности и доступности выглядит даже привлекательнее — пусть иногда качество генераций хромает.

Qwen3-MAX — флагман линейки с триллионом параметров и контекстом до миллиона токенов. В reasoning-задачах (AIME25, HMMT25) модель показывает 100% точность, выстраивает логичные рассуждения, но порой расходует ресурсы нерационально. Подходит для сложных вычислительных и научных задач, где требуется глубокое рассуждение.

Qwen3-VL — мультимодальная модель, которая справляется с генерацией кода по визуальным макетам. В тесте с лендингом она создала более точный HTML, чем ChatGPT, относительно корректно передала структуру интерфейса и элементы. Перспективное решение для UI-разработчиков, дизайнеров и фронтендеров, но пока не для сложных лендингов.

Qwen3-Coder — надежная модель для генерации и анализа кода. Сгенерированный скрипт оказался корректным, структурированным и чистым. В сравнении с ChatGPT код проще, но читается легче и не перегружен деталями. Подходит для прототипирования, учебных и рабочих задач, однако для продвинутых кейсов GPT по-прежнему лидирует.

Главное преимущество Qwen — в том, что все модели бесплатны и полностью доступны из России. На фоне частичных ограничений ChatGPT это становится весомым аргументом в пользу китайских решений.