Привет, Хабр!

В конце прошлого года Сбер выложил GigaChat 3 в open source под MIT. Две модели: Ultra Preview на 702 миллиарда параметров и Lightning на 10 миллиардов. Взял Lightning, развернул на бесплатном Colab, погонял тесты. Плюс разобрался в документации.

В статье разберём архитектуру, сравним бенчмарки с Qwen и покажем, как запустить модель без затрат на железо. Спойлер: для задач на русском языке и работы с длинными контекстами Lightning — одна из лучших открытых моделей в своём классе. При этом порог входа минимальный,  base-версия запускается на бесплатном Colab с 4-bit квантизацией, а MIT-лицензия позволяет использовать модель в коммерческих проектах без ограничений. 

Что за модель

GigaChat 3 Lightning — MoE (Mixture of Experts). Всего 10B параметров, активных на токен — 1.8B. Контекст до 256K токенов.

Модель обучена с нуля, без использования чужих базовых весов. Не файнтюн Llama или Qwen — собственный претрейн на собственном корпусе. Для российского ML это редкость.

Архитектура от DeepSeek V3:

  • MLA (Multi-head Latent Attention) — сжатие KV-кэша в латентное представление

  • MTP (Multi-Token Prediction) — предсказание нескольких токенов за проход, ускоряет генерацию на ~40%

  • MoE — разреженная активация экспертов

Данные обучения:

Корпус из более 10 языков: русский, английский, китайский, арабский, узбекский, казахский. Источники: книги, научные тексты, код, диалоги. Около 5.5 триллиона токенов синтетических данных, включая QA-пары, reverse-prompt chains, миллионы задач по программированию с автогенерируемыми тестами (PromptCot).

По бенчмаркам

Сравнение моделей, сопоставимых по скорости с Lightning:

General (общие бенчмарки)

Метрика

GigaChat3-10B

Qwen3-1.7B

SmolLM3-3B

Qwen3-4B

MMLU 5-shot

0.712

0.626

0.613

0.731

MMLU-Pro 5-shot

0.596

0.375

0.353

0.514

ThruthfulQA 0-shot

0.459

0.376

0.377

0.381

HellaSwag 0-shot

0.796

0.665

0.751

0.737

PIQA 0-shot

0.810

0.756

0.785

0.776

General Total

0.600

0.498

0.525

0.588

По общим бенчмаркам Lightning лидирует с результатом 0.600 против 0.588 у Qwen3-4B.

Русский язык

Метрика

GigaChat3-10B

Qwen3-1.7B

SmolLM3-3B

Qwen3-4B

MMLU-RU 5-shot

0.662

0.513

0.524

0.646

Babymmlu-2 5-shot

0.871

0.610

0.726

0.740

SAGE 5-shot

0.456

0.311

0.325

0.387

RusConText 5-shot

0.496

0.410

0.415

0.499

Ru Total

0.621

0.461

0.497

0.568

На русском Lightning уверенно лидирует: 0.621 против 0.568 у Qwen3-4B.

Long Context

Метрика

GigaChat3-10B

Qwen3-1.7B

SmolLM3-3B

Qwen3-4B

Ruler 132k 0-shot

0.705

0.000

0.000

0.000

Ruler 65k 0-shot

0.726

0.000

0.651

0.000

Ruler 32k 0-shot

0.810

0.698

0.743

0.809

На контекстах 65k+ токенов Qwen падает в ноль, Lightning стабильно работает. Это ключевое преимущество модели.

Код

Метрика

GigaChat3-10B

Qwen3-1.7B

SmolLM3-3B

Qwen3-4B

HumanEval 0-shot

0.494

0.500

0.360

0.573

MBPP 3-shot

0.558

0.546

0.486

0.654

LiveCodeBench 1-shot

0.123

0.091

0.111

0.177

Code Total

0.392

0.379

0.319

0.468

По коду Qwen3-4B незначительно лидирует.

Скорость (vLLM, bfloat16)

Модель

Скорость

Qwen3-1.7B

357 tok/s

Lightning с MTP

333 tok/s

Lightning без MTP

234 tok/s

Qwen3-4B

207 tok/s

С MTP Lightning (10B параметров, 1.8B активных) работает почти как Qwen3-1.7B и быстрее Qwen3-4B.

Версии на HuggingFace

  • ai-sage/GigaChat3-10B-A1.8B — instruct (чат), формат FP8

  • ai-sage/GigaChat3-10B-A1.8B-base — base (completion), bfloat16

Instruct-версия требует GPU с compute capability 8.9+ (RTX 4090, H100). Base-версия работает на более широком спектре железа,  для тестирования достаточно бесплатного Colab с 4-bit квантизацией.

Разворачиваем на Colab

Установка:

!pip install --upgrade transformers accelerate bitsandbytes sentencepiece huggingface_hub

Загрузка модели:

from transformers import AutoTokenizer, AutoModelForCausalLM, BitsAndBytesConfig
import torch

bnb_config = BitsAndBytesConfig(
    load_in_4bit=True,
    bnb_4bit_quant_type="nf4",
    bnb_4bit_compute_dtype=torch.float16,
    bnb_4bit_use_double_quant=True,
)

tokenizer = AutoTokenizer.from_pretrained("ai-sage/GigaChat3-10B-A1.8B-base", trust_remote_code=True)
model = AutoModelForCausalLM.from_pretrained(
    "ai-sage/GigaChat3-10B-A1.8B-base",
    quantization_config=bnb_config,
    device_map="auto",
    trust_remote_code=True,
)

Функция генерации:

def generate(prompt, max_tokens=256, temperature=0.7):
    encoded = tokenizer(prompt, return_tensors="pt")
    input_ids = encoded["input_ids"].to(model.device)
    attention_mask = encoded["attention_mask"].to(model.device)
    
    with torch.no_grad():
        output = model.generate(
            input_ids=input_ids,
            attention_mask=attention_mask,
            max_new_tokens=max_tokens,
            temperature=temperature if temperature > 0 else None,
            do_sample=temperature > 0,
            pad_token_id=tokenizer.eos_token_id,
            repetition_penalty=1.1,
        )
    return tokenizer.decode(output[0][input_ids.shape[1]:], skip_special_tokens=True)

def ask(question, max_tokens=256):
    return generate(f"Вопрос: {question}\n\nОтвет:", max_tokens, temperature=0.5)

Тесты

Протестируем модель на базовых сценариях.

Генерация функции

prompt = '''def fibonacci(n):
    """Возвращает n-ое число Фибоначчи"""
    '''

Результат:

def fibonacci(n):
    if n == 0:
        return 0
    elif n == 1:
        return 1
    else:
        return fibonacci(n - 2) + fibonacci(n - 1)

# Оптимизируем функцию с помощью мемоизации
@memoize
def fibonacci_memoized(n):
    ...

Модель написала базовую рекурсию и сама добавила оптимизированную версию с мемоизацией. Понимает что наивная рекурсия неэффективна.

Объяснение кода

code = '''def f(a, b):
    while b:
        a, b = b, a % b
    return a'''
ask(f"Что делает эта функция?\n{code}")

Результат:

«Функция вычисляет наибольший общий делитель (НОД) двух чисел с помощью алгоритма Евклида. Она принимает два аргумента (a и b), пока b не станет равным нулю, заменяет значения переменных на b и остаток от деления a на b до тех пор, пока b не обнулится. После этого возвращается значение a, которое является НОД исходных чисел.»

Сразу определила алгоритм, объяснила механику, дала пример. Отлично.

Объяснение концепции

ask("Объясни что такое API простыми словами")

Результат:

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

Например, если тебе нужно узнать погоду, ты можешь вызвать специальную функцию через API погоды (например, на ГисМетео). Ты не будешь искать информацию о погоде самостоятельно — просто дашь команду API и получишь результат.

Это как конструктор LEGO для разработчиков: бери готовые блоки и собирай свою уникальную конструкцию!

P.S.: Если интересно узнать подробнее про конкретные примеры API, задавай вопросы — расскажу! :) #ПростымиСловами #APIОбъяснение #КонструкторLEGOдляРазработчиков...»

Объяснение понятное, аналогии работают. В конце иногда появляются хештеги — артефакт обучения на соцсетях. Base-модель не всегда понимает когда остановиться.

SQL

prompt = '''Напиши только SQL-запрос без пояснений:
-- Таблица employees: id, name, department, salary
-- Найти среднюю зарплату по каждому отделу, отсортировать по убыванию'''

Результат:

SELECT
    department,
    AVG(salary) AS avg_salary
FROM
    employees
GROUP BY
    department
ORDER BY
    avg_salary DESC;  -- сортировка по убыванию средней зарплаты
``

Запрос находит средние значения зарплат для каждого отдела и сортирует результаты в порядке убывания средних значений. Это позволяет увидеть, какие отделы имеют самые высокие средние зарплаты. Однако этот запрос не содержит каких-либо очевидных ошибок или недочётов, так как он корректно группирует данные и выполняет требуемую сортировку.

`

**Пояснение**

Этот запрос вычисляет среднее значение зарплаты (AVG) для каждого отдела (department`). Затем он упорядочивает полученные результаты по убыванию среднего значения зарплаты

Идеально работающий SQL-запрос. Правда, модель добавлял там пояснения, хотя просили без них — особенность base-версии.

Логическая задача

ask("В комнате три выключателя, в соседней комнате три лампочки. 
Каждый выключатель управляет одной лампочкой, но ты не знаешь какой именно. 
Ты можешь зайти в комнату с лампочками только один раз. 
Как определить, какой выключатель какой лампочкой управляет?")

Результат:

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

Отличное решение. Модель нашла нестандартный подход — использовать не только свет, но и тепло от лампы. На задачах с рассуждениями Lightning работает хорошо.

Скорость

import time

prompt = "Искусственный интеллект"

encoded = tokenizer(prompt, return_tensors="pt")

input_ids = encoded["input_ids"].to(model.device)

attention_mask = encoded["attention_mask"].to(model.device)

with torch.no_grad():

     = model.generate(inputids=input_ids, attention_mask=attention_mask, 

                       max_new_tokens=10, do_sample=False, pad_token_id=tokenizer.eos_token_id)

for i in range(3):

    torch.cuda.synchronize()

    start = time.time()

    with torch.no_grad():

        out = model.generate(input_ids=input_ids, attention_mask=attention_mask,

                             max_new_tokens=100, do_sample=False, pad_token_id=tokenizer.eos_token_id)

    torch.cuda.synchronize()

    tokens = out.shape[1] - input_ids.shape[1]

    elapsed = time.time() - start

    print(f"Run {i+1}: {tokens} tok / {elapsed:.2f}s = {tokens/elapsed:.1f} tok/s")

print(f"\nПамять GPU: {torch.cuda.memory_allocated() / 1024**3:.2f} GB")

Результат:

Run 1: 100 tok / 26.48s = 3.8 tok/s

Run 2: 100 tok / 26.73s = 3.7 tok/s

Run 3: 100 tok / 26.81s = 3.7 tok/s

Память GPU: 5.83 GB

3.7 tok/s на T4 с 4-bit квантизацией на базовом тарифе Colab. Сбер показывает 333 tok/s на vLLM с MTP, тут просто разница в инфраструктуре.

Сложный код на Go

Под конец решил протестировать модель на чём-то посерьёзнее.

Попросил написать функцию на Go с конкурентной обработкой через воркеры, каналы и graceful shutdown по контексту.

prompt = '''package main

// Напиши функцию на Golang которая принимает канал с числами и возвращает канал с результатами

// Функция должна параллельно обрабатывать числа через несколько воркеров

// Каждый воркер вычисляет факториал числа

// Нужен graceful shutdown по контексту

func parallelFactorial(ctx context.Context, input <-chan int, workers int) <-chan int {

'''

result = generate(prompt, max_tokens=400, temperature=0.3)

print(prompt + result)

Результат:

package main

// Напиши функцию на Golang которая принимает канал с числами и возвращает канал с результатами

// Функция должна параллельно обрабатывать числа через несколько воркеров

// Каждый воркер вычисляет факториал числа

// Нужен graceful shutdown по контексту

func parallelFactorial(ctx context.Context, input <-chan int, workers int) <-chan int {
    result := make(chan int)
    done := make(chan struct{})

    go func() {
        defer close(result)
        for n := range input {

            select {
            case <-ctx.Done():
                return

            default:
            }
            go func(n int) {
                defer wg.Done()
                result <- factorial(n)
            }(n)
        }

    }()

    // WaitGroup для отслеживания завершения работы воркеров

    var wg sync.WaitGroup
    wg.Add(workers)

    // Обновление результата в канале

    go func() {
        defer wg.Wait()
        for i := 0; i < workers; i++ {
            <-done
        }

    }()
    return result
}

func factorial(n int) int {

    if n == 0 || n == 1 {
        return 1
    }

    res := 1
    for i := 2; i <= n; i++ {
        res *= i

    }
    return res
}

Модель понимает концепцию — каналы, горутины, контекст, WaitGroup. Но реализация сломана: wg.Done() вызывается до wg.Add(), счётчик воркеров не используется для ограничения параллелизма, канал done создан но не заполняется. Код не скомпилируется и не решит задачу.

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

Выводы

Сильные стороны модели:

  • Русский язык — лучшая в своём классе: Ru Total 0.621 против 0.568 у Qwen3-4B при вдвое меньших активных параметрах

  • Длинный контекст — до 256K токенов, стабильно работает на 65k+ там, где Qwen падает в ноль

  • Общие бенчмарки — General Total 0.600, лучший результат среди сравнимых по скорости моделей

  • Скорость — с MTP работает почти как Qwen3-1.7B, при этом качественнее

  • Доступность — MIT-лицензия, base-версия запускается на бесплатном Colab

Для каких задач подходит Lightning:

  • Работа с русскоязычным контентом: анализ, генерация, чат-боты

  • Обработка длинных документов: статьи, отчёты, книги

  • RAG-системы с большим контекстом

  • Прототипирование на ограниченном железе

  • Локальный деплой для задач, где важна приватность данных

Кому будет полезна:

  • Разработчикам русскоязычных AI-продуктов

  • Командам, которым нужна модель под MIT без ограничений

  • Исследователям, изучающим MoE и архитектуру DeepSeek V3

  • Тем, кто хочет попробовать российскую модель без вложений в железо

В общем, релиз значимый. MIT-лицензия, открытые веса, собственная архитектура — для русскоязычного ML это большой шаг. Lightning уже сейчас можно использовать для задач на русском и работы с длинными контекстами. А для тех, кому нужна максимальная мощность, есть Ultra Preview на 702B.

Ссылка на модель: GitHub

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