Top.Mail.Ru
Обзор Qwen3-Coder:30b — лучший локальный ИИ для кодинга | Блог Serverflow Скачать
прайс-лист
Бесплатная
доставка по РФ
Скидка
за отзыв!
Distribution of
Server Components
8 (800) 222-70-01 Консультация IT-специалиста Сравнение

Обзор Qwen3-Coder:30b — лучший локальный ИИ для кодинга

~ 15 мин
4143
Средний
Статьи
Обзор Qwen3-Coder:30b — лучший локальный ИИ для кодинга

Введение

В июне 2025 года компания Alibaba представила свою новую, высокопроизводительную ИИ-модель для кодинга с открытым исходным кодом — Qwen3 Coder. Пользователи, которые уже успели опробовать эту китайскую нейросеть, отмечают ее высочайшую эффективность в генерации, проверке и коррекции кода на разных языках программирования, не уступая таким передовым LLM, как DeepSeek R1/V3GPT-4.1Gemini 2.5-Pro и Kini-K2. Команде ServerFlow стало интересно, так ли это на самом деле, поэтому в этом обзоре наша команда будет использовать Qwen3 Coder для выполнения сложных задач в области программирования, оценив точность, скорость и удобство работы с этой нейросетью. 

Подробнее о Qwen3 Coder

Qwen3-Coder — это большая языковая модель на базе архитектуры MoE (включает 160 экспертов), специализирующаяся на выполнении задач, связанных с программированием. Контекстное окно модели достигает 256 тысяч токенов в базовой версии и может быть расширено до 1 миллиона токенов при развертывании через пакетный менеджер YaRN, благодаря чему в Qwen3-Coder можно работать с полной программной базой на тысячи строк одновременно. Qwen3-Coder доступна на множестве платформ для локального развертывания, таких как Hugging Face, GitHub, API Alibaba Cloud, Ollama, а также поддерживает интеграцию агентского интерфейса Qwen Code CLI и различных графических инструментов. Благодаря наличию открытого исходного кода, Qwen3-Coder могут пользоваться частные и государственные компании, генерируя код критически важных приложений, при этом обеспечивая его сохранность за счет хранения данных на локальном, а не облачном сервере. В рамках нашего теста мы будем использовать версию Qwen3-Coder:30b-a3b, квантизированную по способу Q4-K-M и имеющую 30 миллиардов параметров, запущенную через Open WebUI. Open WebUI — это вебинтерфейс с открытым исходным кодом, предназначенный для работы с различными платформами локального запуска ИИ, в том числе и Ollama, которым мы и будем пользоваться. Мы выбрали именно этот интерфейс из-за наличия встроенного интерпретатора программного кода, что облегчает тестирование работоспособности ПО, которое будет генерировать Qwen3-Coder. Кроме того, в Open WebUI есть множество параметров для настройки чатов и вызова дополнительных функций. Итак, переходим к тестам!

Интерфейс Open WebUI
Веб-интерфейс Open WebUI с запущенной моделью Qwen3-Coder:30b-a3b.

Тесты Qwen3-Coder

В нашем тестировании мы проверим все возможности нейросети Qwen3-Coder:30b-a3b, в частности, ее точность в текстовых задачах, скорость генерации ответов, знание различных языков программирования и, конечно же, ее производительность в написании кода.

Приветствие Qwen3-Coder
Начинаем чат с приветствия. 

Введем простой запрос, чтобы проверить работоспособность модели.

Qwen3-Coder отвечает на вопрос
Простой вопрос на тему технологических новинок и последних тенденций.

Модель поняла вопрос и оперативно сгенерировала релевантный ответ.

Точность текстовых ответов

Несмотря на то, что Qwen3-Coder ориентирована именно на генерацию программного кода, мы не могли не проверить возможности нейросети в области создания текстовых материалов. 

Задача на генерацию креативных идей
Задача на генерацию креативных идей для декора офиса.

Несмотря на то, что модель иногда выдает языковые ошибки (вставка китайских иероглифов), она справилась довольно неплохо для своего малого количества параметров, оперативно сгенерировав ответ, допустив минимум ошибок. Если сравнивать этот результат с текстовыми ответами языковой модели от LG, которая регулярно допускала вставку корейских иероглифов, то Qwen3-Coder демонстрирует достойные результаты. Да, это не самая сложная задача, но уже становится очевидно, что модель не сталкивается с трудностями в восприятии запросов и генерации ответов на русском языке. 

Теперь попробуем повторить ту же задачу, но на английском языке.

Задача на английском языке
Ответ Qwen3-Coder на креативную задачу на английском языке.

Конечно же, с английским языком Qwen3-Coder справился лучше, не допустив ни одной галлюцинации, поскольку при обучении этой нейросети в основном использовались дата-сеты на английском и китайском языке. 

Попробуем дать нейросети более сложную задачу по написанию реферата на тему “Разработка новых алгоритмов шифрования в области постквантовой криптографии”.

Нейросеть пишет реферат
Ответ нейросети по написанию реферата.

Нейросеть интегрирует таблицы
Нейросеть активно внедряет различные таблицы, маркерные списки и другие текстовые элементы для удобства восприятия контента.

Продолжение реферата
Продолжение реферата.

Qwen3-Coder не смогла сгенерировать реферат полностью, остановившись на одной из последних глав. Скорее всего, это связано с ограничениями контекста ответа нейросети. Тем не менее, реферат получился вполне неплохим и очень объемным.

Конец ответа нейросети
Нейросети не удалось закончить реферат до конца.

Знание языков программирования

Alibaba заявляет, что нейросеть Qwen3-Coder знает 358 языков программирования, чего вполне достаточно для работы даже с самыми малораспространенными программами и приложениями. Мы не будем экспериментировать, требуя от Qwen генерации кода на экзотических языках, поскольку ими мало кто пользуется. Вместо этого дадим модели несколько задач для генерации ПО на Assembler, 1С и, конечно же, Python. 

Assembler

Попробуем запросить у модели сгенерировать программный код на языке assembler для генерации чисел Фибоначчи без рекурсии для процессоров с архитектурой x86-64.

.section .data
    # Массив для хранения чисел Фибоначчи
    fib_array: .quad 0, 1, 0, 0, 0, 0, 0, 0, 0, 0
    # Сообщение для вывода
    msg: .ascii "Fibonacci numbers: "
    msg_len = . - msg

.section .text
    .global _start

_start:
    # Инициализация переменных
    mov $0, %rax        # i = 0 (счетчик)
    mov $0, %rbx        # fib_prev = 0
    mov $1, %rcx        # fib_curr = 1
    mov $2, %rdx        # next_fib = 0

    # Вывод заголовка
    mov $1, %rax        # sys_write
    mov $1, %rdi        # stdout
    mov $msg, %rsi      # сообщение
    mov $msg_len, %rdx  # длина
    syscall

    # Генерация первых 10 чисел Фибоначчи
    mov $0, %r8         # счетчик цикла

fib_loop:
    cmp $10, %r8        # если i >= 10, то выйти
    jge fib_end

    # Вывод текущего числа (fib_prev)
    push %rbx           # сохраняем fib_prev
    call print_number   # выводим число
    pop %rbx            # восстанавливаем fib_prev

    # Вывод пробела
    mov $1, %rax        # sys_write
    mov $1, %rdi        # stdout
    mov $space, %rsi    # пробел
    mov $1, %rdx        # длина
    syscall

    # Вычисление следующего числа Фибоначчи
    add %rbx, %rcx      # fib_curr = fib_prev + fib_curr
    mov %rcx, %rbx      # fib_prev = fib_curr
    mov %rax, %rcx      # fib_curr = next_fib

    inc %r8             # i++
    jmp fib_loop

fib_end:
    # Вывод новой строки
    mov $1, %rax        # sys_write
    mov $1, %rdi        # stdout
    mov $newline, %rsi  # новая строка
    mov $1, %rdx        # длина
    syscall

    # Завершение программы
    mov $60, %rax       # sys_exit
    mov $0, %rdi        # код возврата
    syscall

# Функция для вывода числа
print_number:
    push %rbx
    push %rcx
    push %rdx
    push %rsi
    
    mov %rbx, %rax      # число для вывода
    mov $10, %rcx       # делитель
    mov $0, %rdx        # счетчик цифр
    mov $buffer + 15, %rsi  # указатель на конец буфера
    
    cmp $0, %rax
    jz print_zero
    
    # Деление на 10 для получения цифр
    mov $0, %rbx        # счетчик цифр
    mov $buffer + 15, %rdi  # указатель на конец буфера
    
print_digits:
    cmp $0, %rax
    jz digits_done
    
    xor %rdx, %rdx      # очистка RDX
    div %rcx            # делим на 10
    add $48, %rdx       # преобразуем в ASCII
    mov %dl, %byte [%rdi]
    dec %rdi
    inc %rbx
    jmp print_digits
    
digits_done:
    # Выводим цифры
    mov $1, %rax        # sys_write
    mov $1, %rdi        # stdout
    inc %rdi            # указатель на начало строки
    mov %rbx, %rdx      # длина
    syscall
    
    pop %rsi
    pop %rdx
    pop %rcx
    pop %rbx
    ret

print_zero:
    mov $48, %al        # ASCII '0'
    push %rax
    mov $1, %rax        # sys_write
    mov $1, %rdi        # stdout
    mov %rsp, %rsi      # указатель на символ
    mov $1, %rdx        # длина
    syscall
    pop %rax
    ret

# Вспомогательные символы
space: .ascii " "
newline: .ascii "\n"
buffer: .space 16

Код на Assembler под CPU на x86-64 для генерации чисел Фибоначчи.

Qwen3-Coder отлично справился с задачей, сгенерировав Assembler-код с различными пояснениями и гайдом по его запуску.

Python

Assembler — далеко не такой востребованный язык программирования, как Python. Посмотрим, справится ли Qwen3-Coder с генерацией кода Python для системы прогнозирования отказа компонентов. 

pip install scikit-learn pandas matplotlib seaborn numpy

1. `smart_collector.py` — Сбор данных SMART

import subprocess
import json
from datetime import datetime

def get_smart_data(device_path):
    try:
        result = subprocess.run(['smartctl', '--json', '--all', device_path], capture_output=True, text=True)
        data = json.loads(result.stdout)
        return data
    except Exception as e:
        print(f"Ошибка при чтении SMART: {e}")
        return None

def extract_smart_metrics(data):
    if not data:
        return {}

    metrics = {
        'device': data.get('device', {}).get('name'),
        'model': data.get('model', {}).get('name'),
        'temperature': data.get('temperature', {}).get('current'),
        'reallocated_sectors_count': data.get('smartctl', {}).get('ata_smart_attributes', {}).get('table', [{}])[0].get('raw', {}).get('value'),
        'uncorrectable_errors': data.get('smartctl', {}).get('ata_smart_attributes', {}).get('table', [{}])[1].get('raw', {}).get('value'),
        'power_on_hours': data.get('power_on_time', {}).get('hours'),
        'time_to_full': data.get('rotation_rate'),
        'timestamp': datetime.now().isoformat()
    }
    return metrics

2. `ipmi_collector.py` — Сбор данных IPMI

import subprocess
import json

def get_ipmi_sensors():
    try:
        result = subprocess.run(['ipmitool', 'sdr', 'list'], capture_output=True, text=True)
        return result.stdout
    except Exception as e:
        print(f"Ошибка при чтении IPMI: {e}")
        return None

def parse_ipmi_data(log):
    # Пример обработки (можно расширить)
    lines = log.splitlines()
    sensors = []
    for line in lines:
        if 'Temperature' in line or 'Fan' in line or 'Voltage' in line:
            sensors.append(line.strip())
    return sensors

3. `ml_model.py` — Простая модель ML (пример)

import pandas as pd
from sklearn.ensemble import RandomForestClassifier
from sklearn.model_selection import train_test_split

# Предположим, у нас есть датасет с признаками и меткой отказа
def load_and_train_model():
    # Заглушка — замените на реальные данные из открытых датасетов
    data = pd.read_csv('smart_dataset.csv')  # Формат: ['temp', 'reallocated', 'uncorr_errors', 'health']
    X = data[['temp', 'reallocated', 'uncorr_errors']]
    y = data['health']  # 0 — не отказ, 1 — отказ
    model = RandomForestClassifier()
    model.fit(X, y)
    return model

def predict_failure(model, features):
    return model.predict_proba([features])[0][1]  # Вероятность отказа

4. `visualizer.py` — Визуализация трендов

import matplotlib.pyplot as plt
import seaborn as sns

def plot_smart_trends(data):
    df = pd.DataFrame(data)
    df['timestamp'] = pd.to_datetime(df['timestamp'])
    df.set_index('timestamp', inplace=True)

    fig, ax = plt.subplots(figsize=(10, 6))
    df[['temperature', 'reallocated_sectors_count']].plot(ax=ax)
    plt.title("Тренды SMART параметров")
    plt.xlabel("Время")
    plt.ylabel("Значение")
    plt.legend()
    plt.grid(True)
    plt.tight_layout()
    plt.savefig("smart_trends.png")

5. `notifier.py` — Уведомления

import smtplib
from email.mime.text import MIMEText

def send_alert(message):
    # Пример уведомления (можно заменить на Telegram, Slack и т.п.)
    print(f"[ALERT] {message}")

6. `main.py` — Основной скрипт

from smart_collector import get_smart_data, extract_smart_metrics
from ipmi_collector import get_ipmi_sensors, parse_ipmi_data
from ml_model import load_and_train_model, predict_failure
from visualizer import plot_smart_trends
from notifier import send_alert
import time

def main():
    devices = ['/dev/sda', '/dev/sdb']  # Укажите нужные диски
    model = load_and_train_model()
    smart_data_history = []

    for device in devices:
        data = get_smart_data(device)
        metrics = extract_smart_metrics(data)

        if metrics:
            features = [
                metrics.get('temperature', 0),
                metrics.get('reallocated_sectors_count', 0),
                metrics.get('uncorrectable_errors', 0)
            ]

            risk = predict_failure(model, features)
            print(f"Риск отказа для {device}: {risk:.2f}")

            if risk > 0.7:
                send_alert(f"Высокий риск отказа на диске {device} ({risk:.2f})")

            smart_data_history.append(metrics)

    plot_smart_trends(smart_data_history)

if __name__ == "__main__":
    main()

Итоговый результат.

Qwen3-Coder справился с задачей, написав 6 скриптов на Python, которые отвечают за работу системы прогнозирования отказа компонентов.

Assembler и Python являются широко известными языками программирования и Qwen3-Coder отлично справляется с написанием кода на этих языках. Однако нам стало интересно, знакома ли эта нейросеть с такой популярной в СНГ платформой, как 1С, и сможет ли Qwen3-Coder сгенерировать код на одноименном языке программирования. Попробуем дать Qwen3-Coder задачу на создание доп обработки в 1С УТ, которая будет формировать отчет по продажам выбранного менеджера.

&НаКлиенте
Процедура ФормированиеОтчетаПоПродажам(КонецПериода)
	
	// Создаем форму отчета
	Форма = Новый Форма("ФормаОтчетаПоПродажам");
	
	// Заполняем таблицу с данными
	Запрос = Новый Запрос;
	Запрос.Текст = "
		ВЫБРАТЬ
			|	Покупатель.Имя,
			|	Менеджер.Имя,
			|	СуммаПродажи = Сумма(Продажа.СуммаОплаты),
			|	КоличествоТоваров = Сумма(Продажа.Количество)
		|ИЗ
			|	Документ.РеализацияТоваров.Продажа КАК Продажа,
			|	Справочник.Менеджеры.Менеджер КАК Менеджер,
			|	Справочник.Покупатели.Покупатель КАК Покупатель
		|ГДЕ
			|	Продажа.Дата <= &КонецПериода
			|	И Продажа.Статус = ""Закрыто""
			|	И Продажа.Менеджер = Менеджер.Ссылка
			|	И Продажа.Покупатель = Покупатель.Ссылка
		|ГРУППИРОВАТЬ ПО
			|	Покупатель.Имя,
			|	Менеджер.Имя
		|ПОРЯДОК ПО
			|	СуммаПродажи УБЫВАЮЩИЙ";
	
	Запрос.УстановитьПараметр("КонецПериода", КонецПериода);
	
	Результат = Запрос.Выполнить();
	
	// Формируем таблицу данных для отчета
	ТаблицаДанных = Новый ТаблицаЗначений;
	ТаблицаДанных.Колонки.Добавить("Менеджер", Тип("Строка"));
	ТаблицаДанных.Колонки.Добавить("СуммаПродажи", Тип("Число"));
	ТаблицаДанных.Колонки.Добавить("КоличествоТоваров", Тип("Число"));
	
	// Заполняем таблицу данными
	Пока Результат.Следующий() Цикл
		
		Запись = ТаблицаДанных.Добавить();
		Запись.Установить("Менеджер", Результат.Поле("Менеджер"));
		Запись.Установить("СуммаПродажи", Результат.Поле("СуммаПродажи"));
		Запись.Установить("КоличествоТоваров", Результат.Поле("КоличествоТоваров"));
		
	КонецЦикла;
	
	// Отображаем отчет
	Форма.Элементы.ТаблицаДанных.Значение = ТаблицаДанных;
	Форма.Открыть();
	
КонецПроцедуры

&НаСервере
Процедура ОбработкаВыбораМенеджера(ВыбранныйМенеджер)
	
	// Получаем данные по выбранному менеджеру
	Если ВыбранныйМенеджер = Неопределено Тогда
		// Если не выбран конкретный менеджер - показываем все
		Возврат;
	КонецЕсли;
	
	// Формируем отчет для конкретного менеджера
	Запрос = Новый Запрос;
	Запрос.Текст = "
		ВЫБРАТЬ
			|	Менеджер.Имя,
			|	СуммаПродажи = Сумма(Продажа.СуммаОплаты),
			|	КоличествоТоваров = Сумма(Продажа.Количество)
		|ИЗ
			|	Документ.РеализацияТоваров.Продажа КАК Продажа,
			|	Справочник.Менеджеры.Менеджер КАК Менеджер
		|ГДЕ
			|	Продажа.Дата <= &КонецПериода
			|	И Продажа.Статус = ""Закрыто""
			|	И Продажа.Менеджер = &ВыбранныйМенеджер
		|ГРУППИРОВАТЬ ПО
			|	Менеджер.Имя";
	
	Запрос.УстановитьПараметр("КонецПериода", ТекущаяДата());
	Запрос.УстановитьПараметр("ВыбранныйМенеджер", ВыбранныйМенеджер);
	
	Результат = Запрос.Выполнить();
	
	// Обновляем отчет
	Если Результат.Следующий() Тогда
		// Обновление отчета в форме
		Форма = НайтиФорму("ФормаОтчетаПоПродажам");
		Если Форма <> Неопределено Тогда
			Форма.Элементы.ТаблицаДанных.Значение = ПолучитьТаблицуДанныхИзРезультата(Результат);
		КонецЕсли;
	КонецЕсли;
	
КонецПроцедуры

// Функция для получения таблицы данных из результата запроса
Функция ПолучитьТаблицуДанныхИзРезультата(Результат)
	
	ТаблицаДанных = Новый ТаблицаЗначений;
	ТаблицаДанных.Колонки.Добавить("Менеджер", Тип("Строка"));
	ТаблицаДанных.Колонки.Добавить("СуммаПродажи", Тип("Число"));
	ТаблицаДанных.Колонки.Добавить("КоличествоТоваров", Тип("Число"));
	
	Пока Результат.Следующий() Цикл
		Запись = ТаблицаДанных.Добавить();
		Запись.Установить("Менеджер", Результат.Поле("Менеджер"));
		Запись.Установить("СуммаПродажи", Результат.Поле("СуммаПродажи"));
		Запись.Установить("КоличествоТоваров", Результат.Поле("КоличествоТоваров"));
	КонецЦикла;
	
	Возврат ТаблицаДанных;
	
КонецФункции

Результат генерации кода на языке 1С.

Qwen3-Coder справился с задачей и предоставил код на языке программирования 1С.

Скорость генерации текста

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

Запись:

Qwen3-Coder

Нейросеть всего за 30 секунд сгенерировала готовый программный код. Рассмотрим результат:

Все функции сайта работают, имеется каталог и конфигуратор. Однако некоторые кнопки все-таки не функциональны, но при корректировке промпта это можно легко исправить. 

Интерфейс сайта
Результат генерации кода сайта на скорость.

Сайт с конфигуратором сервера

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

<header> <h1>Серверное оборудование</h1> <p>Продажа и поставка серверов, комплектующих и IT-оборудования</p> </header> <nav> <a href="#home">Главная</a> <a href="#products">Товары</a> <a href="#about">О нас</a> <a href="#contact">Контакты</a> </nav> <div class="container"> <section id="products"> <h2>Наши товары</h2> <div class="product-card"> <img src="https://via.placeholder.com/300x200?text=Сервер+Dell+PowerEdge" alt="Сервер Dell PowerEdge"> <h3>Dell PowerEdge R740</h3> <p>Высокопроизводительный сервер для корпоративных решений. 2x Intel Xeon, 128 ГБ RAM.</p> <p><strong>Цена:</strong> 150 000 ₽</p> <button>Купить</button> </div> <div class="product-card"> <img src="https://via.placeholder.com/300x200?text=Сервер+HP+ProLiant" alt="Сервер HP ProLiant"> <h3>HP ProLiant DL385 Gen10</h3> <p>Многофункциональный сервер с поддержкой виртуализации и высокой надежностью.</p> <p><strong>Цена:</strong> 200 000 ₽</p> <button>Купить</button> </div> <div class="product-card"> <img src="https://via.placeholder.com/300x200?text=Сервер+IBM+System_x" alt="Сервер IBM System x"> <h3>IBM System x3650 M5</h3> <p>Стабильный сервер для средних и крупных предприятий с высокой производительностью.</p> <p><strong>Цена:</strong> 180 000 ₽</p> <button>Купить</button> </div> </section> <section id="about"> <h2>О компании</h2> <p>Мы предлагаем широкий выбор серверного оборудования от ведущих мировых производителей. Наша компания специализируется на поставке и обслуживании серверов, сетевого оборудования и IT-решений для бизнеса любого масштаба.</p> </section> <section id="contact"> <h2>Контакты</h2> <p><strong>Адрес:</strong> г. Москва, ул. Примерная, д. 10</p> <p><strong>Телефон:</strong> +7 (495) 123-45-67</p> <p><strong>Email:</strong> info@server-shop.ru</p> </section> </div> <footer> <p>&copy; 2025 Серверное оборудование. Все права защищены.</p> </footer>

Qwen3-Coder сгенерировала код сайта с конфигуратором серверов.

Qwen3-Coder отлично справился с задачей, оперативно написав рабочий программный код с требуемыми функциями.

Интерфейс сайта
Готовый сайт со встроенным конфигуратором серверных компонентов.

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

Модель снова успешно справилась задачей, внедрив на сайт дополнительные модели серверов.

Интерфейс сайта с конфигуратором
Интерфейс конфигуратора серверного оборудования с дополнительными моделями серверов.

Теперь добавим простое визуальное оформление в стиле ServerFlow.

Промпт для интеграции визуального оформления
Промпт для интеграции визуального оформления на сайт конфигуратора.

Модель успешно внедрила визуальное оформление в стиле нашего сайта.

Интеграция визуала ServerFlow
Результат интеграции визуального оформления в стиле ServerFlow.

Калькулятор RAID

Теперь дадим нейросети задачу сгенерировать простой сайт с калькулятором RAID-уровней.

<h1>Калькулятор RAID</h1> <div class="calculator"> <label for="raidType">Выберите тип RAID:</label> <select id="raidType"> <option value="0">RAID 0 (Stripe)</option> <option value="1">RAID 1 (Mirror)</option> <option value="5">RAID 5 (Striped with parity)</option> <option value="6">RAID 6 (Striped with double parity)</option> <option value="10">RAID 10 (Mirror + Stripe)</option> </select> <label for="diskCount">Количество дисков:</label> <input type="number" id="diskCount" min="1" value="2"> <label for="diskSize">Емкость одного диска (ГБ):</label> <input type="number" id="diskSize" min="1" value="1000"> <button onclick="calculateRAID()">Рассчитать</button> <div class="result" id="result"></div> </div> <script> function calculateRAID() { const raidType = document.getElementById('raidType').value; const diskCount = parseInt(document.getElementById('diskCount').value); const diskSize = parseFloat(document.getElementById('diskSize').value); if (isNaN(diskCount) || isNaN(diskSize) || diskCount < 1 || diskSize < 1) { alert("Пожалуйста, введите корректные значения."); return; } let totalCapacity = diskCount * diskSize; let usableCapacity = 0; let efficiency = 0; switch (raidType) { case "0": // RAID 0: вся емкость используется usableCapacity = totalCapacity; efficiency = 100; break; case "1": // RAID 1: половина емкости используется usableCapacity = totalCapacity / 2; efficiency = 50; break; case "5": // RAID 5: (n-1)/n емкости используется if (diskCount < 3) { alert("RAID 5 требует минимум 3 диска."); return; } usableCapacity = totalCapacity * (diskCount - 1) / diskCount; efficiency = Math.round((diskCount - 1) / diskCount * 100); break; case "6": // RAID 6: (n-2)/n емкости используется if (diskCount < 4) { alert("RAID 6 требует минимум 4 диска."); return; } usableCapacity = totalCapacity * (diskCount - 2) / diskCount; efficiency = Math.round((diskCount - 2) / diskCount * 100); break; case "10": // RAID 10: половина емкости используется if (diskCount % 2 !== 0) { alert("RAID 10 требует четного количества дисков."); return; } usableCapacity = totalCapacity / 2; efficiency = 50; break; default: alert("Неизвестный тип RAID"); return; } const resultDiv = document.getElementById('result'); resultDiv.innerHTML = ` <p><strong>Общая емкость:</strong> ${totalCapacity} ГБ</p> <p><strong>Используемая емкость:</strong> ${usableCapacity.toFixed(2)} ГБ</p> <p><strong>Эффективность использования:</strong> ${efficiency}%</p> `; } </script>

Qwen3-Coder сгенерировала код RAID-калькулятора.

Qwen3-Coder успешно создал код по заданному запросу.

Калькулятор RAID
Код RAID-калькулятора оказался работоспособным.

Также мы дали Qwen3-Coder задачи на генерацию кода визуализатора уровней RAID, который может анализировать состояние RAID-массива, визуализировать расположение данных и их четности и показывает деградировавшие диски.

import argparse
import time
import numpy as np
import matplotlib.pyplot as plt
import seaborn as sns
from collections import defaultdict
import psutil
import os
import sys

class DiskHeatmap:
    def __init__(self, device_path, block_size=512):
        self.device_path = device_path
        self.block_size = block_size
        self.access_counts = defaultdict(int)
        self.total_blocks = 0
        self.is_running = False
        
    def get_disk_info(self):
        """Получение информации о диске"""
        try:
            # Получаем размер диска
            statvfs = os.statvfs(self.device_path)
            block_size = statvfs.f_frsize
            total_blocks = statvfs.f_blocks
            
            self.total_blocks = total_blocks
            return {
                'total_blocks': total_blocks,
                'block_size': block_size,
                'total_size': total_blocks * block_size
            }
        except Exception as e:
            print(f"Ошибка получения информации о диске: {e}")
            return None
    
    def monitor_disk_activity(self, duration=10):
        """Мониторинг активности диска в течение заданного времени"""
        print(f"Начинаем мониторинг диска {self.device_path} на {duration} секунд...")
        
        # Получаем начальное состояние
        initial_io = psutil.disk_io_counters()
        if not initial_io:
            print("Не удалось получить информацию о диске")
            return
            
        start_time = time.time()
        
        # Собираем данные о доступах
        while time.time() - start_time < duration:
            try:
                # Получаем текущую активность
                io_counters = psutil.disk_io_counters(perdisk=True)
                
                if self.device_path in io_counters:
                    current_io = io_counters[self.device_path]
                    
                    # Просто считаем количество операций (для примера)
                    # В реальности здесь нужно анализировать конкретные LBA
                    print(f"Данные: read_bytes={current_io.read_bytes}, write_bytes={current_io.write_bytes}")
                
                time.sleep(1)
                
            except KeyboardInterrupt:
                print("Остановка мониторинга...")
                break
            except Exception as e:
                print(f"Ошибка при мониторинге: {e}")
                time.sleep(1)
    
    def generate_sample_data(self):
        """Генерация симулированных данных для демонстрации"""
        print("Генерируем симулированные данные для тепловой карты...")
        
        # Генерируем случайные данные
        num_blocks = min(10000, self.total_blocks)  # Ограничиваем количество блоков
        
        # Создаем "горячие" зоны
        hot_zones = [
            (int(num_blocks * 0.2), int(num_blocks * 0.3)),  # Первая горячая зона
            (int(num_blocks * 0.7), int(num_blocks * 0.8)),  # Вторая горячая зона
        ]
        
        for i in range(num_blocks):
            count = 0
            
            # Увеличиваем счетчики для горячих зон
            for start, end in hot_zones:
                if start <= i < end:
                    count += np.random.poisson(10) + 5  # Горячие зоны
            
            # Добавляем случайные операции
            count += np.random.poisson(2)
            
            self.access_counts[i] = count
    
    def create_heatmap(self):
        """Создание тепловой карты"""
        if not self.access_counts:
            print("Нет данных для визуализации")
            return
            
        # Подготавливаем данные для визуализации
        num_blocks = len(self.access_counts)
        
        # Преобразуем данные в матрицу
        max_count = max(self.access_counts.values())
        heatmap_data = np.zeros(num_blocks)
        
        for block, count in self.access_counts.items():
            heatmap_data[block] = count
        
        # Создаем тепловую карту
        plt.figure(figsize=(15, 8))
        
        # Используем seaborn для лучшего вида
        sns.set_style("whitegrid")
        
        # Визуализация как линия с цветовой кодировкой
        x = np.arange(len(heatmap_data))
        y = heatmap_data
        
        # Создаем цветовую шкалу
        norm = plt.Normalize(vmin=0, vmax=max_count)
        colors = plt.cm.plasma(norm(y))
        
        # Рисуем график
        plt.figure(figsize=(15, 6))
        scatter = plt.scatter(x, y, c=y, cmap='plasma', alpha=0.7, s=1)
        
        # Добавляем цветовую шкалу
        cbar = plt.colorbar(scatter)
        cbar.set_label('Частота доступа')
        
        # Оси и заголовок
        plt.xlabel('LBA (Logical Block Addressing)')
        plt.ylabel('Количество операций')
        plt.title(f'Тепловая карта диска {self.device_path}\n(Горячие зоны отмечены высокой частотой доступа)')
        
        # Добавляем сетку для лучшей читаемости
        plt.grid(True, alpha=0.3)
        
        # Уменьшаем количество меток на оси X для лучшей читаемости
        plt.xticks(np.arange(0, len(heatmap_data), max(1, len(heatmap_data)//10)))
        
        plt.tight_layout()
        plt.show()
    
    def create_matrix_heatmap(self):
        """Создание тепловой карты в виде матрицы (для больших объемов)"""
        if not self.access_counts:
            print("Нет данных для визуализации")
            return
            
        # Преобразуем данные в двумерную матрицу
        num_blocks = len(self.access_counts)
        
        # Выбираем размеры матрицы (для демонстрации)
        rows, cols = 100, min(1000, num_blocks)
        
        # Создаем матрицу данных
        matrix_data = np.zeros((rows, cols))
        
        for i in range(rows):
            for j in range(cols):
                block_index = int(i * (num_blocks / rows) + j * (num_blocks / cols))
                if block_index < num_blocks:
                    matrix_data[i, j] = self.access_counts.get(block_index, 0)
        
        # Визуализация матрицы
        plt.figure(figsize=(12, 8))
        
        # Используем тепловую карту seaborn
        sns.heatmap(matrix_data, cmap='plasma', cbar_kws={'label': 'Частота доступа'})
        
        plt.title(f'Тепловая карта диска {self.device_path}')
        plt.xlabel('LBA (Logical Block Addressing)')
        plt.ylabel('Блоки')
        
        plt.tight_layout()
        plt.show()
    
    def save_data(self, filename):
        """Сохранение данных в файл"""
        try:
            with open(filename, 'w') as f:
                for block, count in sorted(self.access_counts.items()):
                    f.write(f"{block},{count}\n")
            print(f"Данные сохранены в {filename}")
        except Exception as e:
            print(f"Ошибка при сохранении данных: {e}")

def main():
    parser = argparse.ArgumentParser(description='Утилита для мониторинга и визуализации тепловой карты диска')
    parser.add_argument('device', help='Путь к устройству (например, /dev/sda)')
    parser.add_argument('--duration', type=int, default=10, help='Длительность мониторинга в секундах')
    parser.add_argument('--output', help='Файл для сохранения данных')
    parser.add_argument('--matrix', action='store_true', help='Использовать матричную визуализацию')
    
    args = parser.parse_args()
    
    # Проверка существования устройства
    if not os.path.exists(args.device):
        print(f"Устройство {args.device} не существует")
        sys.exit(1)
    
    # Создание объекта тепловой карты
    heatmap = DiskHeatmap(args.device)
    
    # Получаем информацию о диске
    disk_info = heatmap.get_disk_info()
    if not disk_info:
        print("Не удалось получить информацию о диске")
        sys.exit(1)
    
    print(f"Информация о диске:")
    print(f"  Путь: {args.device}")
    print(f"  Всего блоков: {disk_info['total_blocks']}")
    print(f"  Размер блока: {disk_info['block_size']} байт")
    print(f"  Общий размер: {disk_info['total_size'] / (1024**3):.2f} ГБ")
    
    # Симулируем мониторинг и генерируем данные
    heatmap.generate_sample_data()
    
    # Визуализация
    if args.matrix:
        heatmap.create_matrix_heatmap()
    else:
        heatmap.create_heatmap()
    
    # Сохранение данных при необходимости
    if args.output:
        heatmap.save_data(args.output)

if __name__ == "__main__":
    main()

Qwen3-Coder сгенерировала код визуализатора RAID.

Результат получился неоднозначным. Скорее всего, Qwen3-Coder не до конца понял задачу и предоставил код, который запускает интерфейс с произвольными данными о дисках.

Визуализатор RAID
Результат запуска кода визуализатора RAID-уровней.

Калькулятор TCO

Поскольку на нашем сайте нет калькулятора TCO (совокупной стоимости владения оборудования), мы решили исправить этот недочет, воссоздав код калькулятора TCO с помощью Qwen3-Coder.

<div class="container"> <header> <h1>Серверное оборудование</h1> <p class="subtitle">Продажа, конфигурация и расчет TCO</p> </header> <div class="main-content"> <div class="calculator-section"> <h2>Калькулятор TCO</h2> <form id="tcoCalculator"> <div class="form-group"> <label for="serverType">Тип сервера:</label> <select id="serverType" required> <option value="">Выберите тип</option> <option value="rack">Рейковый сервер</option> <option value="blade">Blade-сервер</option> <option value="tower">Башенный сервер</option> </select> </div> <div class="form-group"> <label for="serverCount">Количество серверов:</label> <input type="number" id="serverCount" min="1" value="1" required> </div> <div class="form-group"> <label for="hoursPerDay">Часов в сутки:</label> <input type="number" id="hoursPerDay" min="1" max="24" value="24" required> </div> <div class="form-group"> <label for="daysPerYear">Дней в году:</label> <input type="number" id="daysPerYear" min="1" max="365" value="365" required> </div> <div class="form-group"> <label for="electricityCost">Стоимость электроэнергии (руб/кВт·ч):</label> <input type="number" id="electricityCost" step="0.01" min="0" value="5.5" required> </div> <div class="form-group"> <label for="maintenanceCost">Стоимость обслуживания (руб/год):</label> <input type="number" id="maintenanceCost" step="0.01" min="0" value="15000" required> </div> <div class="form-group"> <label for="supportCost">Стоимость поддержки (руб/год):</label> <input type="number" id="supportCost" step="0.01" min="0" value="25000" required> </div> <button type="submit" class="btn">Рассчитать TCO</button> </form> <div class="result-section"> <h3>Результат расчета:</h3> <div id="result">Введите данные и нажмите "Рассчитать"</div> <div class="result-value" id="totalCost">0 руб</div> <p>Средняя стоимость на один сервер в год</p> </div> <div class="tco-info"> <h3>Что такое TCO?</h3> <p>TCO (Total Cost of Ownership) - это общая стоимость владения IT-оборудованием, включая:</p> <ul> <li>Первоначальная покупка оборудования</li> <li>Электроэнергия и охлаждение</li> <li>Обслуживание и поддержка</li> <li>Ремонт и замена компонентов</li> <li>Администрирование и обучение персонала</li> </ul> </div> </div> <div class="products-section"> <h2>Наши серверы</h2> <div class="product-card"> <h3 class="product-title">HP ProLiant DL385 Gen10+</h3> <div class="product-price">245 000 руб</div> <p>Высокопроизводительный сервер для корпоративных решений</p> <ul class="product-features"> <li>Intel Xeon Platinum 8351</li> <li>256 ГБ RAM DDR4</li> <li>4x 1.92 ТБ SSD NVMe</li> <li>Поддержка RAID 1,5,6,10</li> <li>Гарантия 3 года</li> </ul> </div> <div class="product-card"> <h3 class="product-title">Dell PowerEdge R740</h3> <div class="product-price">215 000 руб</div> <p>Надежный сервер для виртуализации и баз данных</p> <ul class="product-features"> <li>Intel Xeon Silver 4314</li> <li>128 ГБ RAM DDR4</li> <li>2x 960 ГБ SSD NVMe</li> <li>Поддержка Hyper-V, VMware</li> <li>Система охлаждения с двойным потоком</li> </ul> </div> <div class="product-card"> <h3 class="product-title">Lenovo ThinkSystem SR650</h3> <div class="product-price">185 000 руб</div> <p>Экономичный сервер для малого бизнеса</p> <ul class="product-features"> <li>Intel Xeon E-2378</li> <li>64 ГБ RAM DDR4</li> <li>1x 1.92 ТБ SSD SATA</li> <li>Поддержка Windows Server</li> <li>Комплектация с RAID-контроллером</li> </ul> </div> </div> </div> <footer> <p>© 2024 Серверное оборудование. Все права защищены.</p> </footer> </div> <script> document.getElementById('tcoCalculator').addEventListener('submit', function(e) { e.preventDefault(); // Получаем значения из формы const serverType = document.getElementById('serverType').value; const serverCount = parseInt(document.getElementById('serverCount').value); const hoursPerDay = parseInt(document.getElementById('hoursPerDay').value); const daysPerYear = parseInt(document.getElementById('daysPerYear').value); const electricityCost = parseFloat(document.getElementById('electricityCost').value); const maintenanceCost = parseFloat(document.getElementById('maintenanceCost').value); const supportCost = parseFloat(document.getElementById('supportCost').value); // Пример мощности сервера (в ваттах) let powerConsumption; switch(serverType) { case 'rack': powerConsumption = 250; // Ватты break; case 'blade': powerConsumption = 180; break; case 'tower': powerConsumption = 300; break; default: powerConsumption = 200; } // Расчет TCO const totalHours = hoursPerDay * daysPerYear; const energyConsumption = (powerConsumption * serverCount * totalHours) / 1000; // кВт·ч const energyCost = energyConsumption * electricityCost; const annualCost = energyCost + maintenanceCost + supportCost; const costPerServer = annualCost / serverCount; // Отображение результата document.getElementById('totalCost').textContent = Math.round(costPerServer).toLocaleString() + ' руб'; document.getElementById('result').innerHTML = ` <p>Годовая стоимость владения ${serverCount} серверами:</p> <p>Энергия: ${Math.round(energyCost).toLocaleString()} руб</p> <p>Обслуживание: ${Math.round(maintenanceCost).toLocaleString()} руб</p> <p>Поддержка: ${Math.round(supportCost).toLocaleString()} руб</p> `; }); // Инициализация калькулятора при загрузке document.addEventListener('DOMContentLoaded', function() { document.getElementById('tcoCalculator').dispatchEvent(new Event('submit')); }); </script>

Qwen3-Coder написала код калькулятора TCO.

В результате получилась страница сайта с отличным интерфейсом калькулятора TCO с различными параметрами и верным подсчетом стоимости владения.

Калькулятор TCO
Калькулятор TCO от Qwen3-Coder.

Функционал калькулятора TCO
Все функции калькулятора TCO работают.

Аркада про системного администратора

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

<div id="game-container"> <canvas id="game-canvas" width="800" height="600" class="pixel-art"></canvas> <div id="score">Очки: 0</div> <div id="instructions"> Управление: WASD - движение | Пробел - чинить серверы </div> </div> <script> // Игровые переменные const canvas = document.getElementById('game-canvas'); const ctx = canvas.getContext('2d'); const scoreElement = document.getElementById('score'); // Размеры пикселей const pixelSize = 16; const playerSize = pixelSize * 2; const serverSize = pixelSize * 3; // Игровые объекты let player = { x: 100, y: 100, width: playerSize, height: playerSize, speed: 4, isFixing: false }; let servers = []; let score = 0; let gameRunning = true; // Клавиши управления const keys = {}; // Создание серверов function createServers() { servers = []; for (let i = 0; i < 15; i++) { servers.push({ x: Math.random() * (canvas.width - serverSize), y: Math.random() * (canvas.height - serverSize), width: serverSize, height: serverSize, broken: true, repairTime: 0 }); } } // Рисование игрока (пиксельный персонаж) function drawPlayer() { ctx.fillStyle = '#00ff00'; // Тело администратора ctx.fillRect(player.x, player.y, player.width, player.height); // Голова ctx.fillRect(player.x + 4, player.y - 4, 8, 8); // Пиксельные детали ctx.fillStyle = '#008800'; ctx.fillRect(player.x + 6, player.y + 2, 4, 4); // глаз } // Рисование сервера function drawServer(server) { if (server.broken) { // Сломанный сервер ctx.fillStyle = '#ff0000'; } else { // Работающий сервер ctx.fillStyle = '#0088ff'; } // Основание сервера ctx.fillRect(server.x, server.y, server.width, server.height); // Пиксельные детали сервера ctx.fillStyle = '#ffffff'; for (let i = 0; i < 3; i++) { for (let j = 0; j < 3; j++) { if (Math.random() > 0.7) { ctx.fillRect(server.x + 2 + i * 4, server.y + 2 + j * 4, 2, 2); } } } // Индикатор состояния if (server.broken) { ctx.fillStyle = '#ff0000'; ctx.fillRect(server.x + 10, server.y + 10, 6, 6); } else { ctx.fillStyle = '#00ff00'; ctx.fillRect(server.x + 10, server.y + 10, 6, 6); } } // Рисование фона function drawBackground() { // Сетка ctx.fillStyle = '#002200'; for (let x = 0; x < canvas.width; x += pixelSize * 4) { for (let y = 0; y < canvas.height; y += pixelSize * 4) { if ((x + y) % 2 === 0) { ctx.fillRect(x, y, pixelSize, pixelSize); } } } } // Обновление игры function update() { if (!gameRunning) return; // Движение игрока if (keys['w'] || keys['W']) player.y -= player.speed; if (keys['s'] || keys['S']) player.y += player.speed; if (keys['a'] || keys['A']) player.x -= player.speed; if (keys['d'] || keys['D']) player.x += player.speed; // Ограничение движения player.x = Math.max(0, Math.min(canvas.width - player.width, player.x)); player.y = Math.max(0, Math.min(canvas.height - player.height, player.y)); // Чинка серверов if (keys[' '] && !player.isFixing) { player.isFixing = true; setTimeout(() => { player.isFixing = false; }, 500); // Проверка попадания в сервер servers.forEach(server => { if (server.broken && player.x < server.x + server.width && player.x + player.width > server.x && player.y < server.y + server.height && player.y + player.height > server.y) { // Чинка сервера server.broken = false; server.repairTime = 5000; // 5 секунд score += 100; scoreElement.textContent = `Очки: ${score}`; } }); } // Обновление времени ремонта серверов servers.forEach(server => { if (!server.broken && server.repairTime > 0) { server.repairTime -= 16; // Примерно 60 FPS if (server.repairTime <= 0) { server.broken = true; score += 50; scoreElement.textContent = `Очки: ${score}`; } } }); } // Рисование игры function draw() { // Очистка экрана ctx.clearRect(0, 0, canvas.width, canvas.height); // Фон drawBackground(); // Серверы servers.forEach(drawServer); // Игрок drawPlayer(); } // Главный игровой цикл function gameLoop() { update(); draw(); requestAnimationFrame(gameLoop); } // Обработка событий клавиатуры document.addEventListener('keydown', (e) => { keys[e.key] = true; }); document.addEventListener('keyup', (e) => { keys[e.key] = false; }); // Инициализация игры createServers(); gameLoop(); </script>

Нейросеть Qwen3-Coder генерирует код аркадной игры

Игра запустилась, но ее визуальная составляющая и геймплей нас не впечатлили, а подсчет очков работал некорректно.

Первая версия мини-игры
Первая версия аркадной игры, сгенерированной Qwen3-Coder.

Мы улучшили промпт, после чего повторили наш запрос. Получилось лучше, появился подсчет очков и “сисадмином” теперь можно было управлять.

Вторая версия мини-игры
Вторая версия аркадной игры, сгенерированной Qwen3-Coder.

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

Выводы

Китайская языковая модель Qwen3-Coder показала себя исключительно с хорошей стороны, выполнив все задачи практически без ошибок. Это свидетельствует о том, что индустрия искусственного интеллекта в Китае продолжает свое активное развитие, порождая все новые и новые LLM, эффективность которых не только не уступает, но и превосходит языковые модели конкурентов, такие как Claude и ChatGPT. С учетом такого успеха, Alibaba вряд ли заморозит разработку новых версий модели Qwen-Coder, поэтому в будущем, когда выйдет Qwen4-Coder, мы обязательно протестируем возможности этой передовой нейросети для программирования.
Автор: Serverflow Serverflow
Поделиться

Комментарии 0

Написать комментарий
Сейчас тут ничего нет. Ваш комментарий может стать первым.
Написать отзыв
До 6 фото, размером до 12Мб каждое
Мы получили ваш отзыв!

Он появится на сайте после модерации.

Написать комментарий

Комментарий появится на сайте после предварительной модерации

До 6 фото, размером до 12Мб каждое
Мы получили ваш отзыв!

Он появится на сайте после модерации.

Мы свяжемся с вами утром

График работы: Пн-Пт 10:00-19:00 (по МСК)

Обработаем вашу заявку
в ближайший рабочий день

График работы: Пн-Пт 10:00-19:00 (по МСК)