Dev48
ЯЗЫК
  • О нас
  • Услуги
  • Индустрии
  • Технологии
  • Статьи
  • Контакты
Забронировать звонок
    Главная/Статьи/God fast apply put k 10 tysyacham tokenov v sekundu blog
Dev48

© 2026 · All rights reserved.

Год Fast Apply — путь к 10 тысячам токенов в секунду — Блог

Источник: Relace

Год Fast Apply — путь к 10 тысячам токенов в секунду — Блог

Источник: Relace

Relace Apply 3 и история создания серии моделей, которые позволили нам преодолеть отметку в 1 млн долларов годовой выручки (ARR).

25 сентября 2026 г.

Ровно год назад мы представили публике нашу первую модель Fast Apply. С тех пор мы многое узнали о том, как дообучать небольшие специализированные модели для задач, связанных с программированием.

Сегодня мы открываем исходные данные о том, чему научились при обучении этой серии моделей: кураторство наборов данных, методы обучения и техники вывода, которые привели к созданию Relace Apply 3 — нашей лучшей на данный момент модели, способной работать со скоростью более 10 тысяч токенов в секунду при сохранении передовой точности.

Проблема

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

Редактирование файла на тысячу строк (~10 тысяч токенов) путем его полной перезаписи с помощью Claude 4.5 Sonnet занимает более 100 секунд и стоит не менее 0,18 доллара. Для агентов-программистов это неприемлемо с точки зрения продукта.

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

Долгое время LLM были неспособны надежно создавать форматы diff, которые могли бы быть объединены фиксированным алгоритмом, таким как string replace или UDiff.

Cursor первыми предложили гибкое решение этой проблемы: позволить передовой модели создавать «ленивые» (lazy) diff, а в качестве алгоритма слияния использовать небольшую быструю модель apply. Однако Cursor никогда не предоставляла свою модель для использования другими компаниями вне своей IDE.

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

Зачем использовать LLM в качестве алгоритма слияния?

На практике передовые модели могут создавать огромное разнообразие патологических diff. Любой алгоритм с закрытой формой, который вы напишете для выполнения слияния, будет уязвим для граничных случаев. В агентских средах, где часто отсутствует контроль со стороны человека, эти ошибки накапливаются и приводят к появлению некорректного кода.

В приведенном выше коде пользователь начинает с функции под названием handler. Цель diff справа — переименовать функцию handler в messageHandler и добавить параметр для столбца name в SQL-запросе.

Было бы сложно написать алгоритм, который предугадал бы эти два шага. Стандартный алгоритм слияния, скорее всего, просто добавил бы новую функцию с именем messageHandler, дублируя исходную.

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

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

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

Создание набора данных

Обучающая выборка для fast apply содержит три компонента: initial_code (исходный код), diff и merged_code (объединенный код). Исходный код и diff передаются в качестве входных данных модели, а объединенный код — это результат, который мы учим модель выдавать.

Для дообучения требуется небольшой набор высококачественных примеров. Мы обнаружили, что размер набора данных гораздо менее важен, чем разнообразие и качество данных для слияния. Наша первая модель была обучена всего на 30 тысячах точек данных, и мы наблюдали лишь незначительный прирост при увеличении объема свыше 100 тысяч точек.

Входные данные

Ранее Kortix AI выпустили набор данных с открытым исходным кодом, полученный путем постобработки данных, собранных из публичных репозиториев GitHub. Имея некоторый исходный код, они просили передовую модель, такую как Claude, (1) придумать изменение и (2) создать для него «ленивый» diff.

Оказалось, что это неверный подход, так как он не отражает реальное распределение данных в производственных средах. Богатое разнообразие граничных случаев в diff возникает из-за перегрузки контекстом. LLM должна придерживаться инструкций в длинных системных промптах, одновременно пытаясь уловить намерение из шумных диалогов с нетехническими пользователями.

Чтобы получить высококачественные, сложные слияния с множеством граничных случаев в обучающем наборе, мы начали сотрудничать с компаниями, занимающимися разработкой приложений через промпты. Мы делали снимки реального контекста для задач программирования с помощью LLM и повторно запускали их с дополнительными инструкциями для создания «ленивых» правок. Это позволило нам делать выборку непосредственно из истинного распределения исходного кода и diff, которые встречаются в продакшене.

Выходные данные

Для генерации правильного merged_code мы используем дистилляцию с выборочным отклонением (rejection sampling). Идея заключается в том, чтобы подать исходный код и diff в хорошо промптированную передовую модель-«учитель», руководствуясь набором правил о том, как следует обрабатывать слияния.

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

Однако правильно настроить фильтрацию сложно. Мы разработали многоэтапный процесс для создания высококачественной системы «LLM как судья», которая могла бы масштабироваться до тысяч точек данных.

Оценка слияний

Мы начали с ручного просмотра 500 случайно выбранных примеров, чтобы создать набор неоспоримых эталонных истин. Для нашей первой модели Apply эти данные были полностью синтетическими, но позже мы повторили процесс, используя реальные производственные данные из предыдущих итераций размещенной модели.

Чтобы оптимизировать процесс при сохранении качества, мы создали собственный внутренний инструмент оценки: просмотрщик diff в стиле Git с инструментами аннотирования для классификации результатов слияния.

Даже с этим инструментом нам потребовалось более 40 часов, чтобы кропотливо обеспечить 100% точность. В процессе начали проявляться закономерности, и мы разбили слияния на 6 категорий:

  • Correct Merge: Модель правильно реализовала намерение diff.

Correct Merge: Модель правильно реализовала намерение diff.

  • Non-functional Error: Модель реализовала намерение diff, за исключением несущественных деталей, таких как различия в комментариях и форматировании (например, разный порядок определений функций).

Non-functional Error: Модель реализовала намерение diff, за исключением несущественных деталей, таких как различия в комментариях и форматировании (например, разный порядок определений функций).

  • Smoothing: Модель исправила ошибку, внесенную diff, которая привела бы к некомпилируемому или сломанному коду.

Smoothing: Модель исправила ошибку, внесенную diff, которая привела бы к некомпилируемому или сломанному коду.

  • Functional/Merge Error: Модель не выполнила намерение diff (например, пропустила части кода или вставила код в неправильные места).

Functional/Merge Error: Модель не выполнила намерение diff (например, пропустила части кода или вставила код в неправильные места).

  • Hallucination Error: Модель добавила или изменила код, не указанный в diff (могут быть неудачными попытками сглаживания).

Ошибка галлюцинации: модель добавила или изменила код, не указанный в diff (возможно, неудачные попытки сглаживания).

  • Ошибки усечения: модель выполнила неполное слияние (с вырезанными частями итогового кода), что привело к некомпилируемому коду.

Ошибки усечения: модель выполнила неполное слияние (с вырезанными частями итогового кода), что привело к некомпилируемому коду.

Примечание: категории 1-3 считаются правильными слияниями, а 4-6 — неправильными. Мы сохраняем шестиклассовую систему для более тонкой оценки, но при создании LLM-судьи сводим её к бинарной классификации.

Отступление о сглаживании

Мы часто обнаруживали, что передовые LLM создавали diff-файлы, приводящие к незначительно некорректному коду. Самый распространенный пример — когда в diff используется новая библиотека без её фактического импорта.

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

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

LLM-как-судья

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

Метод LLM-как-судья использует разрыв между генерацией и верификацией. То есть LLM проще оценить, является ли ответ правильным, чем фактически сгенерировать его. Тем не менее, LLM часто совершает ошибки, и важно сначала правильно настроить её с помощью человеческой оценки.

Как и в любой задаче бинарной классификации, существуют два режима ошибок:

  • Ложноположительный результат — плохое слияние ошибочно классифицируется как хорошее.

Ложноположительный результат — плохое слияние ошибочно классифицируется как хорошее.

  • Ложноотрицательный результат — хорошее слияние ошибочно классифицируется как плохое.

Ложноотрицательный результат — хорошее слияние ошибочно классифицируется как плохое.

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

Мы использовали Claude 4 Sonnet в качестве судьи и итеративно настраивали промпт, пока не достигли уровня ложноположительных результатов около 1%. Для сравнения, у первоначального наивного судьи без настройки уровень ложноположительных результатов составлял около 16%!

Масштабирование

С настроенным LLM-судьей можно фильтровать остальную часть данных в масштабе.

Для Relace Apply 3 мы начали с 200 тысяч наборов initial_code, diff и синтетически сгенерированного merged_code. Мы выбрали репрезентативное распределение примеров по десяткам языков, но сосредоточились преимущественно на TypeScript/Javascript, Markdown, Python, Ruby и HTML.

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

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

Обучение с помощью LoRA

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

Мы обучали наши модели применения с использованием контролируемой донастройки (SFT) поверх моделей с открытым исходным кодом для программирования в диапазоне 3–8 миллиардов параметров. Это дало нам правильный баланс выразительности, скорости вывода и экономической эффективности.

Мы построили собственный конвейер обучения поверх библиотеки HuggingFace transformers, но вы также можете использовать готовые библиотеки, такие как axolotl или unsloth.

Поскольку пост-обучение обычно использует гораздо меньшие наборы данных, чем предварительное обучение, обновление каждого параметра в модели является расточительным. Вместо переобучения всех миллиардов весов мы используем низкоранговую адаптацию (LoRA) — легкий метод донастройки, который добавляет небольшое количество обучаемых «адаптерных» матриц поверх замороженной базовой модели.

Это позволяет нам специализировать модель для задач слияния, не стирая её интуицию в программировании. Базовая модель остается нетронутой, в то время как адаптеры изучают алгоритм слияния, который нас интересует.

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

Ранг LoRA

LoRA альфа

Скорость обучения

Оптимизатор

128

5e-5

AdamW

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

Использование LoRA позволило нам обучить Relace Apply 3 на всех ~145 тысячах точек данных, используя один графический процессор Nvidia H200 на Modal с длиной контекста до 64 тысяч токенов.

Использование Modal позволило нам запускать параллельные процессы обучения на графических процессорах H200, не разбираясь со сложными облачными провайдерами. Несмотря на то, что обучение небольших моделей позволяет использовать размер пакета 1 на одном GPU, запуск большого перебора гиперпараметров обычно требует много ручной настройки. С Modal мы запускали наши скрипты на Python и позволяли ему заниматься масштабированием за нас — не нужно каждый раз подключаться по ssh к новым экземплярам GPU.

После обучения в BF16 мы конвертируем веса модели в FP8, используя библиотеку llm-compressor из vLLM. Этот этап конвертации имеет решающее значение — используя ядра FP8 на новых графических процессорах Nvidia, мы достигаем существенного скачка в пропускной способности без ущерба для точности.

Чтобы подтвердить, что процесс квантования был практически без потерь, мы оценили полученную модель на наших 500 отложенных примерах с эталонными данными, чтобы подтвердить, что результаты были идентичными.

10 тысяч токенов/с со спекулятивной декодировкой

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

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

Спекулятивная декодировка использует тот факт, что прямые проходы сильно ограничены памятью. То есть передача весов LLM в sRAM графического процессора занимает гораздо больше времени, чем фактическое выполнение матричного умножения с тензорными ядрами. Угадывая последовательность из k токенов, мы можем обрабатывать многие токены параллельно (как при предварительном заполнении) и двигаться в сторону режима, ограниченного вычислениями.

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

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

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

Обучаясь на тщательно очищенном наборе данных, мы минимизировали эти прерывания и смогли довести скорость Relace Apply 3 до 10 тыс. токенов в секунду:

Результаты

Мы протестировали Relace Apply на двух наборах данных: (1) наш вручную проверенный бенчмарк из 500 примеров и (2) второй набор данных, состоящий из сложных случаев слияния, собранных на основе отзывов клиентов.

В обоих случаях Relace Apply 3 достигает передовой точности слияния. Были достигнуты существенные улучшения по сравнению с предыдущим поколением моделей Apply благодаря целевой настройке набора данных на основе отзывов клиентов.

Предыдущие поколения Fast Apply испытывали трудности, когда фрагменты правок содержали несколько форматов diff одновременно (например, сочетание формата \\ ... существующий код ... с правками UDiff). Мы включили подмножества правок UDiff и String Replace в обучающие данные для Relace Apply 3, что позволило ей выступать в качестве универсального инструмента слияния.

Relace Apply 3 также внедряет нативную поддержку контекста в 256 тыс. токенов, что позволяет обрабатывать очень большие файлы без снижения производительности. В сочетании с пропускной способностью 10 тыс. токенов в секунду это делает Relace Apply 3 самой быстрой, точной и поддерживающей самый длинный контекст моделью на рынке.

Fast Apply, год спустя

Когда мы выпустили нашу первую модель Fast Apply год назад, LLM были печально известны своей неспособностью выводить корректные форматы diff. Детерминированные подходы, такие как Search-and-Replace или UDiff, были хрупкими, зависели от конкретной модели и требовали обширного промпт-инжиниринга.

Точность форматирования diff стала таким узким местом, что полиглот-лидерборд Aider отслеживал её как отдельную метрику — один столбец для точности, другой для производительности.

Fast Apply изменил это. Это была первая модель, которая сделала структурированное редактирование кода надежным, и наши клиенты сразу почувствовали разницу.

Сегодня передовые модели стали намного лучше справляться с форматированием diff благодаря интенсивному обучению с подкреплением на инструментах редактирования строк, но они всё ещё не идеальны. Компаниям, которые используют исключительно детерминированные стратегии, такие как Cline, требуется дополнительный алгоритм слияния, чтобы еще больше повысить точность правок diff.

Лучшие модели сейчас достигают примерно 96% успеха при редактировании, но модели без такой настройки всё ещё ошибаются примерно в 10% случаев.

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

Fast Apply доказал, что небольшие специализированные модели могут обеспечивать результаты уровня SoTA при обучении на высококачественных, специфических для задачи наборах данных. Разработанные нами методы теперь направляют нашу более широкую работу по ускорению генерации кода с помощью небольших агентных моделей для таких утилитарных задач, как поиск, разрешение конфликтов слияния и рефакторинг.

Следите за новыми релизами в ближайшее время!

Мы нанимаем

Если вы дочитали до этого места, скорее всего, вам это показалось интересным!

Мы нанимаем прагматичных исследователей (физика/математика/информатика/ML) и исключительных инженеров для создания подобных моделей, на которые полагаются реальные продуктовые команды. Загляните на нашу страницу вакансий и присоединяйтесь к нам!

← Все статьи