Enterprise-контур не пускает облачную модель внутрь. Значит, экспертиза должна приехать туда в весах.
Проверили. Взяли сеньора-интервьюера с жёсткой рубрикой: конкретный инцидент и цифры ценит, красивый жаргон без доказательств режет. Собрали 47 его собеседований и дистиллировали суждения в LoRA поверх Qwen 3B. Железо - RTX 3090 за $0.14 в час.
На held-out кандидатах, которых двойник не видел: F1 0.857 против 0.706 у базовой модели.
Но интереснее другое. Промпт "ты - сеньор Пётр" на той же модели не дал ничего: те же 0.706 и ноль пойманных блефёров из трёх. Двойник поймал все три.
Блеф не ловится инструкцией. Он ловится весами.
Честно: датасет пока синтетический, held-out маленький. Это не паритет с фронтиром вообще - это паритет на одной узкой задаче. Но бизнесу нужна ровно она: внутри периметра, за копейки в час, судить как ваш сеньор.
Проверили. Взяли сеньора-интервьюера с жёсткой рубрикой: конкретный инцидент и цифры ценит, красивый жаргон без доказательств режет. Собрали 47 его собеседований и дистиллировали суждения в LoRA поверх Qwen 3B. Железо - RTX 3090 за $0.14 в час.
На held-out кандидатах, которых двойник не видел: F1 0.857 против 0.706 у базовой модели.
Но интереснее другое. Промпт "ты - сеньор Пётр" на той же модели не дал ничего: те же 0.706 и ноль пойманных блефёров из трёх. Двойник поймал все три.
Блеф не ловится инструкцией. Он ловится весами.
Честно: датасет пока синтетический, held-out маленький. Это не паритет с фронтиром вообще - это паритет на одной узкой задаче. Но бизнесу нужна ровно она: внутри периметра, за копейки в час, судить как ваш сеньор.
Один LoRA-эксперт - это лотерея.
Обучили трёх на одних и тех же данных, отличались только сиды. Первый и второй согласились с живым сеньором идеально. Третий пропустил двух блефёров из трёх.
Тот же рецепт. Тот же датасет. Разброс - как повезёт.
Совет из этих же трёх, простым голосованием, сработал на уровне лучшего и починил слабого: блефёров пропущено ноль.
Вот зачем нужен совет. Не чтобы выжать лишние проценты у сильного эксперта, а чтобы убрать провал у слабого. В найме цена ошибки - двенадцать окладов, и "как повезёт" тут не работает.
Всё крутится на одной RTX 3090 внутри контура. Облачная модель, которая вашего сеньора не знает, набрала заметно меньше.
Данные предварительные: held-out всего 11 примеров, три блефёра. На такой выборке единица - это не "идеально", это шум. Гоним датасет в пять раз больше и доверительные интервалы.
Обучили трёх на одних и тех же данных, отличались только сиды. Первый и второй согласились с живым сеньором идеально. Третий пропустил двух блефёров из трёх.
Тот же рецепт. Тот же датасет. Разброс - как повезёт.
Совет из этих же трёх, простым голосованием, сработал на уровне лучшего и починил слабого: блефёров пропущено ноль.
Вот зачем нужен совет. Не чтобы выжать лишние проценты у сильного эксперта, а чтобы убрать провал у слабого. В найме цена ошибки - двенадцать окладов, и "как повезёт" тут не работает.
Всё крутится на одной RTX 3090 внутри контура. Облачная модель, которая вашего сеньора не знает, набрала заметно меньше.
Данные предварительные: held-out всего 11 примеров, три блефёра. На такой выборке единица - это не "идеально", это шум. Гоним датасет в пять раз больше и доверительные интервалы.
Вчера я написал, что совет из трёх LoRA-экспертов чинит слабого. Сегодня увеличил датасет в пять раз, и мой собственный результат развалился.
На одиннадцати примерах совет давал единицу. Красиво. На пятидесяти девяти - 0.875, а одиночный эксперт 0.915 ± 0.036. Совет ниже нижней границы доверительного интервала. Это не шум, это провал.
Причина скучная и важная. Эксперты учились на одних данных и ошибаются одинаково - все чуть слишком строгие. Голосование такую ошибку не гасит, а складывает. Совет начал резать хороших кандидатов чаще, чем любой эксперт поодиночке.
Что устояло: оцифрованный сеньор на RTX 3090 согласуется с живым на 0.941 против 0.900 у облачной модели, которая вашего сеньора не знает. И не пропустил ни одного плохого - облако пропустило десять из четырнадцати.
Вывод дороже вчерашнего: "навесить ансамбль и проголосовать" не работает. Нужна обучаемая агрегация, а не демократия среди одинаково предвзятых.
Одиннадцать примеров - это не эксперимент. Это гадание с красивым графиком.
На одиннадцати примерах совет давал единицу. Красиво. На пятидесяти девяти - 0.875, а одиночный эксперт 0.915 ± 0.036. Совет ниже нижней границы доверительного интервала. Это не шум, это провал.
Причина скучная и важная. Эксперты учились на одних данных и ошибаются одинаково - все чуть слишком строгие. Голосование такую ошибку не гасит, а складывает. Совет начал резать хороших кандидатов чаще, чем любой эксперт поодиночке.
Что устояло: оцифрованный сеньор на RTX 3090 согласуется с живым на 0.941 против 0.900 у облачной модели, которая вашего сеньора не знает. И не пропустил ни одного плохого - облако пропустило десять из четырнадцати.
Вывод дороже вчерашнего: "навесить ансамбль и проголосовать" не работает. Нужна обучаемая агрегация, а не демократия среди одинаково предвзятых.
Одиннадцать примеров - это не эксперимент. Это гадание с красивым графиком.
Пять экспертов. Трое систематически строгие, двое точные. Голосование просто считает голоса - трое побеждают. Совет выдал 0.875: хуже, чем любой из них поодиночке.
Дело оказалось не в экспертах, а в том, как склеиваются их мнения. Дали им пересмотреть вердикт, увидев остальных, - 1.000.
Через день наткнулся на свежую статью (Kong et al.): SFT даёт модули, а RL должен выучить routing - то, как модули склеиваются. Ровно то место, куда мы уперлись. Приятно дойти самому, а потом найти теорию, которая объясняет почему.
Бизнес в том, ГДЕ спорить. Текстовый дебат - 8 секунд на раунд. Латентный, обменом скрытых состояний, - 122 миллисекунды. В 67 раз быстрее и вчетверо точнее по итоговому баллу.
8 секунд - это "подумаем и вернёмся". 122 миллисекунды - это пока кандидат договаривает фразу. Совет успевает поспорить и подсказать следующий вопрос прямо в разговоре.
Честно: гипотеза, что в латенте эксперт упрямее держится против большинства, не подтвердилась. Он выигрывает скоростью и точностью, а не упрямством.
Дело оказалось не в экспертах, а в том, как склеиваются их мнения. Дали им пересмотреть вердикт, увидев остальных, - 1.000.
Через день наткнулся на свежую статью (Kong et al.): SFT даёт модули, а RL должен выучить routing - то, как модули склеиваются. Ровно то место, куда мы уперлись. Приятно дойти самому, а потом найти теорию, которая объясняет почему.
Бизнес в том, ГДЕ спорить. Текстовый дебат - 8 секунд на раунд. Латентный, обменом скрытых состояний, - 122 миллисекунды. В 67 раз быстрее и вчетверо точнее по итоговому баллу.
8 секунд - это "подумаем и вернёмся". 122 миллисекунды - это пока кандидат договаривает фразу. Совет успевает поспорить и подсказать следующий вопрос прямо в разговоре.
Честно: гипотеза, что в латенте эксперт упрямее держится против большинства, не подтвердилась. Он выигрывает скоростью и точностью, а не упрямством.
LinkedIn у меня перестал быть доской вакансий. Не знаю точно, что они поменяли в рекомендациях, но лента вдруг начала приносить не "10 способов пройти собеседование", а свежие препринты - и людей, которые их читали.
Оттуда пришла статья Kong et al. о том, почему связка SFT → RL даёт сильное рассуждение: SFT выдаёт модули, а RL учится их склеивать - выучивает routing. Мы за день до этого уперлись ровно в routing: наш совет экспертов проваливался на голосовании и начинал работать только тогда, когда экспертам давали пересмотреть вердикт, увидев остальных.
Я оставил под постом комментарий со своими цифрами. Ответил Malkesh Dalia, AI/ML инженер из Сурата. Формально - просто согласился и написал, что ждёт наш OOD-тест.
Фактически - заставил перепроверить дизайн. И там нашлась дыра: наши пять "экспертов" оказались бутстрап-ресемплами одного распределения. Они отличаются сидом, а не компетенцией. Роутинг над такими - это снижение дисперсии, а не композиционная перекомбинация модулей. Мы бы прогнали красивый эксперимент, который меряет совсем не то, что заявляет.
Это и есть рецензирование. Просто бесплатное и за сутки, а не за полгода.
Лучшие наводки на литературу за последние месяцы я получил не из рассылок и не из твиттера, а из ленты, которую все до сих пор считают местом для поиска работы.
Оттуда пришла статья Kong et al. о том, почему связка SFT → RL даёт сильное рассуждение: SFT выдаёт модули, а RL учится их склеивать - выучивает routing. Мы за день до этого уперлись ровно в routing: наш совет экспертов проваливался на голосовании и начинал работать только тогда, когда экспертам давали пересмотреть вердикт, увидев остальных.
Я оставил под постом комментарий со своими цифрами. Ответил Malkesh Dalia, AI/ML инженер из Сурата. Формально - просто согласился и написал, что ждёт наш OOD-тест.
Фактически - заставил перепроверить дизайн. И там нашлась дыра: наши пять "экспертов" оказались бутстрап-ресемплами одного распределения. Они отличаются сидом, а не компетенцией. Роутинг над такими - это снижение дисперсии, а не композиционная перекомбинация модулей. Мы бы прогнали красивый эксперимент, который меряет совсем не то, что заявляет.
Это и есть рецензирование. Просто бесплатное и за сутки, а не за полгода.
Лучшие наводки на литературу за последние месяцы я получил не из рассылок и не из твиттера, а из ленты, которую все до сих пор считают местом для поиска работы.
Заставили несколько LoRA-экспертов спорить не текстом, а скрытыми состояниями - и научились читать эти "мысли" обратно в текст.
Оценку senior-инженера выносит не один судья, а совет ролей: технарь, лидер, аудитор достоверности. Они обмениваются hidden state через обучаемую проекцию и пересматривают вердикты по ходу собеседования.
Что проверили честно, с контролями:
- латент технаря и лидера декодируется на 89-95% против уровня монетки;
- латент аудитора не декодируется вообще - не прячем;
- дебат двигает оценку в нужную сторону (−7,2 ± 3,3, интервал не накрывает ноль), но прирост на решении мал: узкое место - точность экспертов, а не дебат.
И грабли: сырой hidden-state нельзя класть прямо в эмбеддинги, unsloth глобально патчит transformers, а max_new_tokens тихо обрезал отрицательные вердикты и выдал ложный Brier=0.
Код, цифры и диаграммы - в статье: https://iconicompany.com/blog/latent-debate-lora-experts-decoded
Оценку senior-инженера выносит не один судья, а совет ролей: технарь, лидер, аудитор достоверности. Они обмениваются hidden state через обучаемую проекцию и пересматривают вердикты по ходу собеседования.
Что проверили честно, с контролями:
- латент технаря и лидера декодируется на 89-95% против уровня монетки;
- латент аудитора не декодируется вообще - не прячем;
- дебат двигает оценку в нужную сторону (−7,2 ± 3,3, интервал не накрывает ноль), но прирост на решении мал: узкое место - точность экспертов, а не дебат.
И грабли: сырой hidden-state нельзя класть прямо в эмбеддинги, unsloth глобально патчит transformers, а max_new_tokens тихо обрезал отрицательные вердикты и выдал ложный Brier=0.
Код, цифры и диаграммы - в статье: https://iconicompany.com/blog/latent-debate-lora-experts-decoded
Li Auto (да, автопроизводитель) показал, как посттрейном дотянуть малую модель до уровня гигантов. Mach-Mind - MoE на 35B, 3B активных, поверх Qwen3.5.
Идея: не учить одну модель RL сразу на смеси наград (математика, код, агенты) - начинаются качели, подтянул одно, просело другое. Вместо этого обучили десяток RL-экспертов по доменам порознь, у каждого свои данные и награды.
Потом слили обратно мультиучительской дистилляцией (MOPD, от Xiaomi): каждый пример уходит к своему замороженному эксперту, и тот через reverse-KL подтягивает ученика к себе. Агентные навыки качали в песочницах - модель читает файлы, правит код, гоняет тесты.
Работает "и да, и нет": на агентных бенчах обошли даже отдельных экспертов, а на SWE-bench просели (73.8 → 71.1) - узкая специализация смазывается при дистилляции. Зато 92.7 на AIME и топ на IFBench - уровень куда более крупных моделей.
Нам близко: у нас тоже совет доменных экспертов и та же граница - способ их сведения не главный рычаг, важна точность самих экспертов.
Идея: не учить одну модель RL сразу на смеси наград (математика, код, агенты) - начинаются качели, подтянул одно, просело другое. Вместо этого обучили десяток RL-экспертов по доменам порознь, у каждого свои данные и награды.
Потом слили обратно мультиучительской дистилляцией (MOPD, от Xiaomi): каждый пример уходит к своему замороженному эксперту, и тот через reverse-KL подтягивает ученика к себе. Агентные навыки качали в песочницах - модель читает файлы, правит код, гоняет тесты.
Работает "и да, и нет": на агентных бенчах обошли даже отдельных экспертов, а на SWE-bench просели (73.8 → 71.1) - узкая специализация смазывается при дистилляции. Зато 92.7 на AIME и топ на IFBench - уровень куда более крупных моделей.
Нам близко: у нас тоже совет доменных экспертов и та же граница - способ их сведения не главный рычаг, важна точность самих экспертов.
Разработчик получает на руки 250 000 ₽. Заказчик платит за него 400. Разницу в 150 тысяч в месяц принято списывать на "маржу рынка" и не смотреть, из чего она.
А там слоёный пирог: наценки посредников (10-30%, у агентств до 60%), налоги, страховка от неоплат. И слой, который вслух не называют, - стоимость денег.
Бигтех платит с отсрочкой до полугода. Всё это время подрядчик платит разработчику из своего кармана, а кассовый разрыв закрывает оборотным кредитом под 25-30% годовых. На команде в 10 человек - около 375 тысяч ₽ в месяц одних процентов. Не за экспертизу и не за скорость: за то, что деньги заказчика придут потом.
Эти проценты зашиты в вашу ставку. Вы оплачиваете кредит, который кто-то взял за вас.
Разобрал ставку по слоям, с цифрами: https://iconicompany.com/blog/outstaffing-model-is-broken
А там слоёный пирог: наценки посредников (10-30%, у агентств до 60%), налоги, страховка от неоплат. И слой, который вслух не называют, - стоимость денег.
Бигтех платит с отсрочкой до полугода. Всё это время подрядчик платит разработчику из своего кармана, а кассовый разрыв закрывает оборотным кредитом под 25-30% годовых. На команде в 10 человек - около 375 тысяч ₽ в месяц одних процентов. Не за экспертизу и не за скорость: за то, что деньги заказчика придут потом.
Эти проценты зашиты в вашу ставку. Вы оплачиваете кредит, который кто-то взял за вас.
Разобрал ставку по слоям, с цифрами: https://iconicompany.com/blog/outstaffing-model-is-broken
На бумаге AI-native инженер и тот, кто просто выучил слово "ai-native", выглядят одинаково. Оба пишут Cursor, "MVP за 2 недели" и пять лет нужного стека.
Разница не в резюме, а в артефактах. Резюме - это заявленное, код - сделанное. "5 лет SQL" при нуле схем и миграций за эти годы - не эксперт, а правки строк в готовых запросах.
Поэтому мы не верим полям резюме. Вытаскиваем реальные концепты прямо из репозитория - какие библиотеки, версии БД, инфраструктура, а не абстрактный "бэкенд". Считаем вероятность fit-а по смыслу, а не по ключевым словам. Проверяем глубину голосовым скринингом за минуту.
При этом "Senior" и "AI-native" - не одно и то же: из 487 заявок за март Senior-ов было 40-60% почти в каждом стеке, но работать по-старому можно и с восемью годами опыта.
Спрашивать бесполезно - все отвечают правильными словами. Настоящего видно по тому, что он уже собрал.
Как мы это читаем: https://iconicompany.com/blog/how-to-find-ai-native-developer
Разница не в резюме, а в артефактах. Резюме - это заявленное, код - сделанное. "5 лет SQL" при нуле схем и миграций за эти годы - не эксперт, а правки строк в готовых запросах.
Поэтому мы не верим полям резюме. Вытаскиваем реальные концепты прямо из репозитория - какие библиотеки, версии БД, инфраструктура, а не абстрактный "бэкенд". Считаем вероятность fit-а по смыслу, а не по ключевым словам. Проверяем глубину голосовым скринингом за минуту.
При этом "Senior" и "AI-native" - не одно и то же: из 487 заявок за март Senior-ов было 40-60% почти в каждом стеке, но работать по-старому можно и с восемью годами опыта.
Спрашивать бесполезно - все отвечают правильными словами. Настоящего видно по тому, что он уже собрал.
Как мы это читаем: https://iconicompany.com/blog/how-to-find-ai-native-developer
AI-агент берёт задачу и уходит на 52 шага и 36 тысяч токенов. Часто уже в начале видно, что не решится - но узнаёте вы об этом в конце, когда бюджет сожжён.
Свежая работа (Silva, Tu, Monperrus) показывает: сама модель понимает это раньше. Простой классификатор поверх её скрытых состояний угадывает, заработает ли код (AUC до 0,83), ещё до того, как код дописан. И частично предсказывает будущее - направление на ~25 шагов вперёд. Причём сигнал сильнее не в последнем слое, а в середине сети.
Нам это знакомо с другой стороны: мы читаем тот же латент в оценке кандидата - совет LoRA-экспертов спорит скрытыми состояниями, а мы их декодируем (латент читается на 89-95%). Вывод один: модель знает больше, чем говорит в ответе, и полезное "мнение" лежит в середине, а не на выходе.
Главное - не прочитать сигнал, а рулить по нему: гасить провальную попытку до того, как она сожжёт десятки тысяч токенов.
Разбор: https://iconicompany.com/blog/model-knows-if-code-will-work-before-writing
Свежая работа (Silva, Tu, Monperrus) показывает: сама модель понимает это раньше. Простой классификатор поверх её скрытых состояний угадывает, заработает ли код (AUC до 0,83), ещё до того, как код дописан. И частично предсказывает будущее - направление на ~25 шагов вперёд. Причём сигнал сильнее не в последнем слое, а в середине сети.
Нам это знакомо с другой стороны: мы читаем тот же латент в оценке кандидата - совет LoRA-экспертов спорит скрытыми состояниями, а мы их декодируем (латент читается на 89-95%). Вывод один: модель знает больше, чем говорит в ответе, и полезное "мнение" лежит в середине, а не на выходе.
Главное - не прочитать сигнал, а рулить по нему: гасить провальную попытку до того, как она сожжёт десятки тысяч токенов.
Разбор: https://iconicompany.com/blog/model-knows-if-code-will-work-before-writing
Арендовал 3090, чтобы отсеивать плохих кандидатов до дорогого LLM-этапа. Проиграл скрипту, который считает на процессоре за копейки.
Проблема была видна в цифрах: косинусный поиск нагоняет по 391 кандидату на вакансию, и почти половина того, что доходит до LLM, - мусор. Тысячи холостых прогонов самого дорогого этапа в конвейере.
Логично было взять сильный реранкер и резать мусор им. Я прогнал bge-reranker-v2-m3 и mmarco на полном тексте "вакансия x резюме". Оба еле отличали мусор от годных - почти как монетка. Дообучение CrossEncoder вообще не сошлось: у нас есть данные про тех, кто подошёл, но нет размеченных "не подошёл", и модель училась на противоречиях.
А выиграло самое скучное - пересечение навыков. Оно и понятно: LLM-судья смотрит не на "похож ли текст", а на то, закрывает ли кандидат требования вакансии. Текстовый реранкер этого не видит - для него все кандидаты и так по теме.
Гейт уже выложили: дешёвая проверка навыков до записи в базу режет ~9% мусора, сохраняя 99% годных. Без GPU, включается одной переменной.
Иногда лучший апгрейд матчинга - не модель поумнее, а более честный вопрос к данным.
Разбор с цифрами и графиками: https://iconicompany.com/blog/cheap-skill-gate-beats-gpu-rerankers-candidate-filtering
Проблема была видна в цифрах: косинусный поиск нагоняет по 391 кандидату на вакансию, и почти половина того, что доходит до LLM, - мусор. Тысячи холостых прогонов самого дорогого этапа в конвейере.
Логично было взять сильный реранкер и резать мусор им. Я прогнал bge-reranker-v2-m3 и mmarco на полном тексте "вакансия x резюме". Оба еле отличали мусор от годных - почти как монетка. Дообучение CrossEncoder вообще не сошлось: у нас есть данные про тех, кто подошёл, но нет размеченных "не подошёл", и модель училась на противоречиях.
А выиграло самое скучное - пересечение навыков. Оно и понятно: LLM-судья смотрит не на "похож ли текст", а на то, закрывает ли кандидат требования вакансии. Текстовый реранкер этого не видит - для него все кандидаты и так по теме.
Гейт уже выложили: дешёвая проверка навыков до записи в базу режет ~9% мусора, сохраняя 99% годных. Без GPU, включается одной переменной.
Иногда лучший апгрейд матчинга - не модель поумнее, а более честный вопрос к данным.
Разбор с цифрами и графиками: https://iconicompany.com/blog/cheap-skill-gate-beats-gpu-rerankers-candidate-filtering
ИИ забрал у вас рутину - и теперь вы вайбкодите по 16 часов в день. Промпт на каждую задачу, глаз да глаз. Это не автоматизация - вы стали диспетчером у модели.
Если так, вы уже опоздали: пока вы правите за агентом каждую строчку, узкое место давно не код.
Сегодня я собрал цепочку, где человек кода не пишет. На входе - требования, BRD/FR. Дальше сами собой: use cases с проверяемыми критериями, глоссарий, модель данных, схема БД, API. Каждый шаг - читаемый аналитиком markdown, следующий выводится из предыдущего. Схема Drizzle, миграция в живой Postgres, OpenAPI и типизированный клиент выпадают из спеки сами.
Критерии приёмки - галочки, которые ставит не человек, а тестовый прогон. Соврать себе "работает" нельзя.
Ремесло никуда не делось - оно съехало на уровень выше: ты пишешь не код, а спеку, по которой команда агентов соберёт и протестирует его сама. Кто всё ещё сверяет каждый шаг руками - соревнуется не с коллегой, а с конвейером.
Код больше не то, что вы пишете. Это то, что выпадает из спеки.
Если так, вы уже опоздали: пока вы правите за агентом каждую строчку, узкое место давно не код.
Сегодня я собрал цепочку, где человек кода не пишет. На входе - требования, BRD/FR. Дальше сами собой: use cases с проверяемыми критериями, глоссарий, модель данных, схема БД, API. Каждый шаг - читаемый аналитиком markdown, следующий выводится из предыдущего. Схема Drizzle, миграция в живой Postgres, OpenAPI и типизированный клиент выпадают из спеки сами.
Критерии приёмки - галочки, которые ставит не человек, а тестовый прогон. Соврать себе "работает" нельзя.
Ремесло никуда не делось - оно съехало на уровень выше: ты пишешь не код, а спеку, по которой команда агентов соберёт и протестирует его сама. Кто всё ещё сверяет каждый шаг руками - соревнуется не с коллегой, а с конвейером.
Код больше не то, что вы пишете. Это то, что выпадает из спеки.
Спрашиваю у ChatGPT: есть купе Москва - Владивосток на четверых? "Есть, четыре места".
Формально правда. Фактически - четыре места в четырёх разных купе и двух вагонах. Семья едет шесть суток по разным дверям.
Модель не соврала. Ей просто никто не объяснил разницу между "четыре свободных места" и "четыре места за одной дверью". В ответе API РЖД такого поля нет, разницу надо вычислять: календарь → поезда → вагоны → схема вагона → номера мест, сгруппированные по купе. Пять шагов, и только на пятом понятно, что показывать человеку.
Я вынес эти шаги в MCP-инструменты, чтобы проверка жила в коде, а не в голове модели. Не удалось подтвердить по схеме - ассистент пишет "вагон минимум с четырьмя местами", а не "нашёл купе".
Отдельным сюрпризом было то, что из Vercel запросы к РЖД висли по сто секунд. Healthcheck при этом горел зелёным.
Разобрал весь путь - Bun, MCP, Vercel, свой reverse proxy: https://habr.com/ru/articles/1067268/
Агент честен ровно настолько, насколько честны инструменты, которые вы ему дали.
Формально правда. Фактически - четыре места в четырёх разных купе и двух вагонах. Семья едет шесть суток по разным дверям.
Модель не соврала. Ей просто никто не объяснил разницу между "четыре свободных места" и "четыре места за одной дверью". В ответе API РЖД такого поля нет, разницу надо вычислять: календарь → поезда → вагоны → схема вагона → номера мест, сгруппированные по купе. Пять шагов, и только на пятом понятно, что показывать человеку.
Я вынес эти шаги в MCP-инструменты, чтобы проверка жила в коде, а не в голове модели. Не удалось подтвердить по схеме - ассистент пишет "вагон минимум с четырьмя местами", а не "нашёл купе".
Отдельным сюрпризом было то, что из Vercel запросы к РЖД висли по сто секунд. Healthcheck при этом горел зелёным.
Разобрал весь путь - Bun, MCP, Vercel, свой reverse proxy: https://habr.com/ru/articles/1067268/
Агент честен ровно настолько, насколько честны инструменты, которые вы ему дали.
🔥1
Работающий продукт собирается за несколько вечеров. Сложности начинаются в день, когда кто-то спрашивает: а чем докажешь, что вот эта часть работает?
Спросить оказывается не у кого.
Принято считать, что разница между "быстро накидал" и "сделано по-взрослому" - в дисциплине. Сначала спека, потом код, ревью внимательнее. Я тоже так думал.
Разница в другом: где после работы остаётся истина о системе.
Вайб-кодинг не производит побочных продуктов. Кроме приложения не остаётся ничего - ни плана, ни утверждения, что требование выполнено. Знание живёт в голове автора и в контексте сессии. Сессия закончилась - и спрашивать больше некого.
AI-DLC отличается одним. Между намерением и исполнением на каждом шаге появляется объект, который кто-то утверждает. План. Критерий приёмки. Гейт в сборке. Живёт он отдельно от кода и отдельно от автора.
На практике это выглядит как отчёт покрытия, который генерируется прогоном. 314 критериев из 422. И честные нули внутри: трассировка 0 из 11, политика аккаунта 0 из 14. Нули видны именно потому, что отчёт машинный - галочку из добрых побуждений поставить нельзя.
Таким отчётам верят охотнее, чем нарисованным ста процентам.
Пока систему делает и оценивает один человек, всё это лишние расходы. Появляется второй - соавтор, преемник, инвестор - и цена отсутствующих артефактов начисляется задним числом, сразу за всё.
https://iconicompany.com/blog/vibe-coding-to-production-ai-dlc-evidence
Спросить оказывается не у кого.
Принято считать, что разница между "быстро накидал" и "сделано по-взрослому" - в дисциплине. Сначала спека, потом код, ревью внимательнее. Я тоже так думал.
Разница в другом: где после работы остаётся истина о системе.
Вайб-кодинг не производит побочных продуктов. Кроме приложения не остаётся ничего - ни плана, ни утверждения, что требование выполнено. Знание живёт в голове автора и в контексте сессии. Сессия закончилась - и спрашивать больше некого.
AI-DLC отличается одним. Между намерением и исполнением на каждом шаге появляется объект, который кто-то утверждает. План. Критерий приёмки. Гейт в сборке. Живёт он отдельно от кода и отдельно от автора.
На практике это выглядит как отчёт покрытия, который генерируется прогоном. 314 критериев из 422. И честные нули внутри: трассировка 0 из 11, политика аккаунта 0 из 14. Нули видны именно потому, что отчёт машинный - галочку из добрых побуждений поставить нельзя.
Таким отчётам верят охотнее, чем нарисованным ста процентам.
Пока систему делает и оценивает один человек, всё это лишние расходы. Появляется второй - соавтор, преемник, инвестор - и цена отсутствующих артефактов начисляется задним числом, сразу за всё.
https://iconicompany.com/blog/vibe-coding-to-production-ai-dlc-evidence
Чаще всего поиск для RAG делают в один проход: у каждого фрагмента лежит один вектор, запрос превращается в такой же вектор, база отдаёт ближайшие. Это быстро, потому что представления фрагментов посчитаны заранее и лежат в базе статикой - на запрос считается только вопрос. Когда качества такого поиска не хватает, сверху обычно ставят реранкер: кросс-энкодер или внешний API, который заново читает пары "вопрос + фрагмент".
Есть третий вариант, и он ближе к первому: late interaction. У фрагмента хранится не один вектор, а матрица - по вектору на каждый токен. Эти матрицы тоже статика в базе, поэтому второй проход не зовёт никакую модель: он считает арифметику по уже посчитанным числам.
Мы решили выяснить, окупается ли этот второй проход. Короткий ответ: на нашем корпусе он вдвое повышает точность первого места - нужный фрагмент оказывается первым в 73% случаев вместо 36%.
https://iconicompany.com/ru/research/late-interaction-measured-maxsim-doubles-hit-rate
Есть третий вариант, и он ближе к первому: late interaction. У фрагмента хранится не один вектор, а матрица - по вектору на каждый токен. Эти матрицы тоже статика в базе, поэтому второй проход не зовёт никакую модель: он считает арифметику по уже посчитанным числам.
Мы решили выяснить, окупается ли этот второй проход. Короткий ответ: на нашем корпусе он вдвое повышает точность первого места - нужный фрагмент оказывается первым в 73% случаев вместо 36%.
https://iconicompany.com/ru/research/late-interaction-measured-maxsim-doubles-hit-rate
Наш агент отвечал кандидату 28 секунд. Не думал 28 секунд - столько уходило, чтобы вообще начать думать.
Человек в чате за это время успевает уйти. Я решил, что дело в модели, и поменял движок: вместо Antigravity CLI поставил omp (Oh My Pi). Он работает и по токенам, и по подписке, а главное - умеет режим RPC, где агент живёт процессом и получает реплики кадрами, а не поднимается на каждую заново.
Стало 13 секунд на первый ответ и 2.5 на следующий. А в живом чате - по-прежнему 23 и 12.
Дело было в двух заголовках. Агент носит с собой токен человека и его последнюю реплику: по ней продукт сверяет, что цитата не выдумана. Оба меняются с каждым сообщением - а заголовки инструментов читаются один раз, при подключении. Каждое "привет" поднимало процесс с нуля. Я грел ровно то, что сам же и выбрасывал.
Починка - разделить. Движку выдаётся ключ на всю жизнь его процесса, а настоящие заголовки подставляет шлюз в момент вызова. 3.6 секунды на ответ в переписке.
Побочный выигрыш вышел дороже скорости: токен человека теперь не попадает в контейнер с моделью вовсе. А модель умеет запускать команды - и попросить её об этом может любой, кто пишет в чат.
Скоро откроем агента всем.
Человек в чате за это время успевает уйти. Я решил, что дело в модели, и поменял движок: вместо Antigravity CLI поставил omp (Oh My Pi). Он работает и по токенам, и по подписке, а главное - умеет режим RPC, где агент живёт процессом и получает реплики кадрами, а не поднимается на каждую заново.
Стало 13 секунд на первый ответ и 2.5 на следующий. А в живом чате - по-прежнему 23 и 12.
Дело было в двух заголовках. Агент носит с собой токен человека и его последнюю реплику: по ней продукт сверяет, что цитата не выдумана. Оба меняются с каждым сообщением - а заголовки инструментов читаются один раз, при подключении. Каждое "привет" поднимало процесс с нуля. Я грел ровно то, что сам же и выбрасывал.
Починка - разделить. Движку выдаётся ключ на всю жизнь его процесса, а настоящие заголовки подставляет шлюз в момент вызова. 3.6 секунды на ответ в переписке.
Побочный выигрыш вышел дороже скорости: токен человека теперь не попадает в контейнер с моделью вовсе. А модель умеет запускать команды - и попросить её об этом может любой, кто пишет в чат.
Скоро откроем агента всем.
Своя модель вместо облачной заработала с первого раза. Числа правдоподобные, чек-лист заполняется, ошибок нет.
И она отвечала примерно одно и то же на что угодно.
Мы учим модель проверять, закрывает ли резюме требование вакансии, - чтобы считать это у заказчика, а не гонять данные кандидатов во внешний API. Обучение оказалось лёгкой частью: час на арендованной видеокарте, 77 центов, качество на уровне облака.
Трудным оказалось доказать, что продукт считает то же самое, что обучение.
Требование "Знание Kubernetes и Helm" против резюме фронтендера, который инфраструктуру в глаза не видел. Эталон: 0.011. Наш продукт: 0.795. Рядом честное совпадение по Python - 0.807.
То есть на всё подряд - "вроде подходит".
Причина в одну строку: модели подаётся разметка, где кончается требование и начинается резюме. Мы подавали туда нули. Слова при этом бились с эталоном идеально, до последнего токена.
Ничего не падало. Ни один тест не краснел. Заказчик получил бы шум вместо оценки и не заметил бы - числа же выглядят как числа.
Теперь рядом стоит сверка с эталоном до четвёртого знака и отдельная проверка, что модель вообще отвечает по-разному: первая вырождение не ловит.
Сломанная модель не падает. Она соглашается со всем.
Разбор целиком: чем мы заменили облачную модель и как это проверяли
И она отвечала примерно одно и то же на что угодно.
Мы учим модель проверять, закрывает ли резюме требование вакансии, - чтобы считать это у заказчика, а не гонять данные кандидатов во внешний API. Обучение оказалось лёгкой частью: час на арендованной видеокарте, 77 центов, качество на уровне облака.
Трудным оказалось доказать, что продукт считает то же самое, что обучение.
Требование "Знание Kubernetes и Helm" против резюме фронтендера, который инфраструктуру в глаза не видел. Эталон: 0.011. Наш продукт: 0.795. Рядом честное совпадение по Python - 0.807.
То есть на всё подряд - "вроде подходит".
Причина в одну строку: модели подаётся разметка, где кончается требование и начинается резюме. Мы подавали туда нули. Слова при этом бились с эталоном идеально, до последнего токена.
Ничего не падало. Ни один тест не краснел. Заказчик получил бы шум вместо оценки и не заметил бы - числа же выглядят как числа.
Теперь рядом стоит сверка с эталоном до четвёртого знака и отдельная проверка, что модель вообще отвечает по-разному: первая вырождение не ловит.
Сломанная модель не падает. Она соглашается со всем.
Разбор целиком: чем мы заменили облачную модель и как это проверяли
"Никто не подходит" - самая дорогая строка в подборе.
Мы неделю смотрели на вакансию, где ни один кандидат не набирал и половины. Людей на рынке хватало, а список был пуст.
Дело оказалось в одном требовании: "опыт прохождения процедур ИБ". Такое в резюме не пишет никто, даже когда опыт есть. Модель честно не находила упоминания и ставила ноль. Всем сразу. Одна такая строка обнуляет вакансию целиком.
Посмотрели на потоке: 20 371 вердикт из 75 769 были нулями за молчание резюме. Каждый четвёртый ответ означал "я не нашёл", а читался как "у человека этого нет".
Починили различением. Названный инструмент, которого в резюме нет, это честный ноль. Процесс, о котором резюме молчит всегда, это вопрос кандидату, а не приговор. На проверочной вакансии доля нулей упала с 42% до 18%.
Дальше интереснее. Мы научили свою модель говорить "не знаю": она отдаёт оценку вместе с уверенностью, и уверенность проверена на вакансиях, которых модель не видела. Половину строк она закрывает сама, с точностью 95%, на обычном процессоре и без обращения к облаку. Остальное уходит туда, где дороже и умнее.
Скрининг, который умеет сказать "я не знаю", отсеивает меньше людей, чем скрининг, который всегда уверен.
Мы неделю смотрели на вакансию, где ни один кандидат не набирал и половины. Людей на рынке хватало, а список был пуст.
Дело оказалось в одном требовании: "опыт прохождения процедур ИБ". Такое в резюме не пишет никто, даже когда опыт есть. Модель честно не находила упоминания и ставила ноль. Всем сразу. Одна такая строка обнуляет вакансию целиком.
Посмотрели на потоке: 20 371 вердикт из 75 769 были нулями за молчание резюме. Каждый четвёртый ответ означал "я не нашёл", а читался как "у человека этого нет".
Починили различением. Названный инструмент, которого в резюме нет, это честный ноль. Процесс, о котором резюме молчит всегда, это вопрос кандидату, а не приговор. На проверочной вакансии доля нулей упала с 42% до 18%.
Дальше интереснее. Мы научили свою модель говорить "не знаю": она отдаёт оценку вместе с уверенностью, и уверенность проверена на вакансиях, которых модель не видела. Половину строк она закрывает сама, с точностью 95%, на обычном процессоре и без обращения к облаку. Остальное уходит туда, где дороже и умнее.
Скрининг, который умеет сказать "я не знаю", отсеивает меньше людей, чем скрининг, который всегда уверен.
Со-автор RLHF и ChatGPT 15 сентября выпустил модель, которая не пишет текст вообще. Jev от TypeSafe AI отвечает решением и числом уверенности. $0.042 за миллион токенов.
У нас ровно такая задача: закрывает ли резюме требование вакансии. Считает свой кросс-энкодер на 278M, на процессоре.
Поставил Jev на наш отложенный набор. 2000 пар, 82 вакансии, 17 центов, четыре минуты.
0.868 ROC-AUC против наших 0.883. Бутстрэп по вакансиям: разность 0.014, интервал [-0.030; 0.067]. Ноль внутри, модели неразличимы. Zero-shot, на русском, впервые видя наши данные.
Калибровка, главное заявление Jev, при этом вдвое хуже нашей: ECE 0.117 против 0.071.
А потом я разложил набор по видам меток и понял, что мерил не совсем то.
40% отрицательных меток у нас поставлены за молчание резюме: "Kafka не упомянута" значит "навыка нет". Этот дефект мы промпту запретили ещё в сентябре. На таких парах Jev нас обходит, 0.929 против 0.920. На честных проседает сильнее, 0.827 против 0.858.
Часть его согласия с нами - совпадение предрассудков, а не качество.
Ставить Jev к себе всё равно нельзя, открытых весов нет. Забрать стоит другое: бенчмарк, где метки ставила одна модель, а проверяют другую, меряет заодно и их общие ошибки. На итоговом числе этого не видно.
Разбор: https://iconicompany.com/ru/research/jev-system-one-vs-fine-tuned-cross-encoder
У нас ровно такая задача: закрывает ли резюме требование вакансии. Считает свой кросс-энкодер на 278M, на процессоре.
Поставил Jev на наш отложенный набор. 2000 пар, 82 вакансии, 17 центов, четыре минуты.
0.868 ROC-AUC против наших 0.883. Бутстрэп по вакансиям: разность 0.014, интервал [-0.030; 0.067]. Ноль внутри, модели неразличимы. Zero-shot, на русском, впервые видя наши данные.
Калибровка, главное заявление Jev, при этом вдвое хуже нашей: ECE 0.117 против 0.071.
А потом я разложил набор по видам меток и понял, что мерил не совсем то.
40% отрицательных меток у нас поставлены за молчание резюме: "Kafka не упомянута" значит "навыка нет". Этот дефект мы промпту запретили ещё в сентябре. На таких парах Jev нас обходит, 0.929 против 0.920. На честных проседает сильнее, 0.827 против 0.858.
Часть его согласия с нами - совпадение предрассудков, а не качество.
Ставить Jev к себе всё равно нельзя, открытых весов нет. Забрать стоит другое: бенчмарк, где метки ставила одна модель, а проверяют другую, меряет заодно и их общие ошибки. На итоговом числе этого не видно.
Разбор: https://iconicompany.com/ru/research/jev-system-one-vs-fine-tuned-cross-encoder
Мы дописали алертинг по логам и сели за регламент для дежурного: пришло письмо - открой агента idevops, скопируй туда текст алерта. На этой строчке стало неловко.
Письмо порождает машина. Копирует его человек. Разбирает снова машина.
Шлюз к агенту у нас уже был - для клиентских обращений: живая сессия
Переходник занял триста строк на Bun: вебхук Alertmanager разворачивается в промпт и уходит в ту же сессию. Упёрлись в 429 по квоте - повторяем через agy.
Скормили настоящий алерт: HighErrorRate, cloudauto-sandbox/app, 45 ошибок за 5 минут.
Агент за один ход сходил в VictoriaLogs по LogsQL, дёрнул kubectl за подами и сопоставил. Под живой, 2/2 Running, три дня без рестартов. В логах
Сорок минут моей работы. У агента - один ход.
Разбор целиком, вместе с тем, почему агент при этом ничего не чинит и где у
Письмо порождает машина. Копирует его человек. Разбирает снова машина.
Шлюз к агенту у нас уже был - для клиентских обращений: живая сессия
omp --mode rpc, кадры JSON через stdin/stdout, инструменты подключаются конфигом. Алерт из Alertmanager - то же обращение, просто его пишет vmalert, а не человек.Переходник занял триста строк на Bun: вебхук Alertmanager разворачивается в промпт и уходит в ту же сессию. Упёрлись в 429 по квоте - повторяем через agy.
Скормили настоящий алерт: HighErrorRate, cloudauto-sandbox/app, 45 ошибок за 5 минут.
Агент за один ход сходил в VictoriaLogs по LogsQL, дёрнул kubectl за подами и сопоставил. Под живой, 2/2 Running, три дня без рестартов. В логах
client_fetch_error ... read ECONNRESET на собственный https-домен. В кластерном шлюзе для sandbox-хоста поднят слушатель на 80 и не поднят на 443, сертификата тоже нет. NextAuth стучится по https - Envoy рвёт TCP по отсутствующему SNI.Сорок минут моей работы. У агента - один ход.
Разбор целиком, вместе с тем, почему агент при этом ничего не чинит и где у
--auto-approve граница: https://iconicompany.com/ru/blog/alert-is-a-ticket-sre-agent-over-omp-rpc