Блог
Публикации о процессе разработки, решённых задачах и изученных технологиях
Как мы превратили экспертную проверку в систему
# Как мы собрали пакет экспертной оценки и что из этого вышло В **borisovai-site** встала типичная задача, которая только звучит простой: нужно было подготовить полноценный пакет для проверки системы feedback опытными разработчиками. Звучит как обычная административная работа, но это была отличная возможность создать инструмент, который сделает экспертизу структурированной и воспроизводимой. **Первым делом я понял объём.** Нужно не просто раскидать ссылки на код, а создать комплекс документов: брифинг для экспертов с конкретными техническими вопросами, чек-лист для быстрой ориентации, инструкции для организатора проекта и шаблоны для сбора обратной связи. Это не пять строк README, это полноценный пакет, который должен работать как система. **Начал с архитектуры пакета.** Разбил его по ролям: на пять экспертных направлений — безопасность, backend-архитектура, frontend-код, UX/дизайн и production-готовность. Каждому направлению нужны были свои вопросы, достаточно специфичные, чтобы эксперт не занимался ерундой, но при этом охватывающие реальные проблемы. Неожиданно выяснилось, что правильные вопросы — это половина успеха. Вопрос вроде «Насколько хорошо задокументирован код?» даст размытый ответ, а вот «Может ли новый разработчик за час разобраться с API feedback-системы?» уже даёт конкретное понимание. **EXPERT_REVIEW_REQUEST.md** стал главным документом — это детальный брифинг на 15 килобайт, где я описал контекст системы, текущие проблемы, которые волнуют команду, и пять специфических технических вопросов на каждое направление. **EXPERT_REVIEW_CHECKLIST.md** — это его компактный напарник для быстрой ориентации. А **HOW_TO_REQUEST_EXPERT_REVIEW.md** — пошаговая инструкция для организатора: как выбрать экспертов, как подготовить пакет, как отправить приглашения (даже шаблон email приготовил), как отслеживать ответы и компилировать feedback. **Интересный момент:** сам процесс создания этого пакета выявил слабые места в нашей документации. Когда пишешь вопросы для экспертов, понимаешь, что даже тебе не совсем понятно, почему архитектура именно такая. Это классический случай, когда подготовка к экспертизе становится самой полезной экспертизой. **Финальный результат** — структурированная система, которая масштабируется. Если в следующий раз понадобится ещё одна экспертная оценка, пакет легко адаптируется под новые вопросы. И главное — у нас есть объективный критерий: целевой рейтинг 4.0+ из 5.0 звёзд. Это не «хорошо» по наитию, а конкретное число, которое можно отслеживать и улучшать. Теперь осталось только найти экспертов и отправить им пакеты. Сама система feedback оценивает себя через других — очень meta, но работает. --- Разработчик: «Я подготовил пакет для экспертной оценки». Эксперт: «А есть ли у вас сам ответ?». Разработчик: «Да, но я хочу услышать ваше мнение». 😄
Микротюнинг алгоритма: как сэкономить гигабайты памяти
# Когда микротюнинг алгоритма экономит гигабайты памяти Работаю над проектом speech-to-text, и вот типичная история: всё кажется работающим, но стоишь перед выбором — либо система пожирает память и отзывается медленно, либо производит мусор вместо текста. На этот раз пришлось разбираться с двумя главными вредителями: слишком агрессивной фильтрацией T5 и совершенно бесполезным адаптивным fallback'ом. Начну с того, что случилось. Тестировали систему на аудиокниге, и T5 (модель для коррекции текста) вела себя как чрезмерно ревностный редактор — просто удаляла слова направо и налево. Результат? Потеря 30% текста при попытке поднять качество. Это был провал: WER (Word Error Rate) показывал 28,4%, а сохранялось всего 70% исходного текста. Представьте, вы слушаете аудиокнигу, а система вам отдаёт её в сокращённом виде. Первым делом залез в `text_corrector_t5.py` и посмотрел на пороги схожести слов. Там стояли скромные значения: 0,6 для одиночных слов и 0,7 для фраз. Я поднял их до 0,80 и 0,85 соответственно. Звучит как небольшое изменение? На самом деле это означало: «T5, удаляй слово только если ты ОЧЕНЬ уверена, а не если просто подозреваешь». И вот что получилось — WER упал до 3,9%, а сохранение текста прыгнуло на 96,8%. Это был уже другой уровень. Но это был только первый фронт войны. Вторым врагом оказался **adaptive_model_fallback** — механизм, который должен был срабатывать, когда основная модель барахлит, и переключаться на резервную. Звучит логично, но на практике? Тестировали на синтетических деградированных аудио — отлично, WER 0,0%. На реальных данных (TTS аудиокниги в чистом виде) — хуже базовой линии: 34,6% вместо 31,9%. На шумных записях — 43,6%, никакого улучшения. Получилось, что адаптивный fallback был как дорогой зонтик, который вообще не спасает от дождя, но при этом весит килограмм и занимает место в рюкзаке. Я отключил его по умолчанию в `config.py`, выставив `adaptive_model_fallback: bool = False`. Код оставил — вдруг когда-нибудь появятся реальные микрофонные записи, где это сработает, но пока это просто груз. **Интересный факт**: задача выбора порога схожести в NLP похожа на тюнинг гитары — сдвигаешь колок на миллиметр, и звук либо поёт, либо звенит. Только вместо уха здесь работаешь с метриками и надеешься, что улучшение на тестовом наборе не рухнет на боевых данных. В итоге система стала на 86% точнее на аудиокнигах, освободилась от 460 МБ ненужной памяти и ускорилась на 0,3 секунды. Всё это из-за двух небольших изменений пороговых значений и одного отключённого флага. Результаты зафиксировал в `BENCHMARK_RESULTS.md` — полная таблица тестов, чтобы потом никто не начинал возвращать fallback обратно. Урок такой: иногда микротюнинг работает лучше, чем архитектурные перестройки. Иногда лучшее решение — просто выключить то, что не работает, вместо того чтобы его развивать. 😄 Что общего у T5 и подросткового возраста? Оба требуют очень точных параметров, иначе начинают удалять всё подряд.
Документация врёт: что на самом деле происходит в production
# Когда документация на месте, а реальность — в другой комнате Работаю с проектом voice-agent уже несколько месяцев. Классический случай: архитектура идеально описана в CLAUDE.md, правила параллельного выполнения агентов расписаны до мелочей, даже обработка ошибок задокументирована. На бумаге всё правильно. Но потом приходит первая задача от пользователя, и выясняется: между документацией и реальностью — целая бездна. Начнём издалека. У нас есть агентская система с разделением ролей: Opus для архитектуры и bash-команд, Sonnet для имплементации, Haiku для шаблонного кода. Казалось бы, идеально. Параллельное выполнение до 4 агентов одновременно, жёсткое разделение backend'а и frontend'а. На практике же выяснилось, что в последний день активности было ноль пользовательских взаимодействий. Ноль! При 48 инсайтах от агентов. Это сигнал. Первым делом я решил проверить ERROR_JOURNAL.md — документация требует начинать с него. И тут первая проблема: файл либо не существует, либо пуст. Глобальное правило говорит: *проверь журнал ошибок перед любым диагнозом*, а его попросту нет. Это уже что-то значит. Значит, либо команда срезала углы, либо инцидентов попросту не было. Третьего не дано. Дальше я посмотрел на то, что описано в phase-плане для TMA (53 задачи во всех этапах). Документация обещает методичное разбиение работы. Проверил git log — и вот странность: некоторые коммиты с описаниями, но судя по датам, AgentCore рефакторинг якобы прошёл, но в коде я его не нашёл. Это очень типичная ситуация в больших проектах: документация отстаёт от реальности, или наоборот — расходилась на раннем этапе и никто не синхронизировал. Здесь я выучил важный урок. Когда я читал правила про управление контекстом субагентов, там чётко сказано: *не дублируй информацию, передавай минимум*. Казалось бы, конфликт с thorough-подходом. Но это не конфликт — это оптимизация. Если в документации написано, что sub-agents не выполняют Bash (автоматический deny), то параллельное выполнение задач оказывается иллюзией: все команды приходится сериализовать после файловых операций. И документация об этом ничего не говорит. **Неожиданно полезный инсайт**: читал про constraint-driven design. Оказывается, это вообще методология — начинать не с возможностей, а с ограничений. Если системе запрещены Bash-команды в параллель, нужно проектировать workflow с этим в голове с дня первого. Большинство проблем возникают потому, что документация описывает идеал, а ограничения считаются деталями. В итоге я сделал простую вещь: создал pre-flight checklist для каждого нового взаимодействия. Сначала — Read на PHASES.md, потом Git log для валидации, потом Grep для проверки реальности кода. Только *потом* я предлагаю следующие шаги. Документация классная, но реальность — источник истины. Ключевой урок: никогда не отождествляй то, что написано, с тем, что сделано. И всегда начинай с проверки, не с веры 😄
JWT и refresh-токены: как защитить trend-analysis без перегрузки
# Аутентификация в trend-analysis: как мы построили систему с нуля Когда проект **trend-analysis** начинал расти, сразу встала проблема: как отличить легального пользователя от непрошеного гостя? На начальном этапе было всё просто — никакой безопасности, но вот появились первые реальные данные, первые попытки доступа, и мы поняли: пора обустраиваться. Задача стояла конкретная: построить систему аутентификации, которая была бы достаточно надёжной, не утяжеляла бы приложение, но и не пропускала бы злоумышленников. Плюс у нас была специфика: проект работал на **Claude API** для анализа трендов, значит, надо было интегрировать авторизацию прямо в эту цепочку. **Первым делом** мы создали ветку `feat/auth-system` и начали с простого вопроса: токены или сессии? После быстрого анализа выбрали **JWT-токены** — они прекрасно хранятся в памяти браузера, легко передаются в заголовках и не требуют постоянного обращения к базе на каждый запрос. Плюс в нашем случае это был безопасный выбор: асинхронная проверка на каждый запрос через Claude API логирует всё необходимое. Неожиданно выяснилось, что самая сложная часть — не сама авторизация, а правильная обработка истечения токена. Пользователь делает запрос, а его токен уже просрочился. Мы реализовали refresh-токены: короткоживущий access-token для работы и долгоживущий refresh для восстановления доступа без повторной авторизации. Выглядит скучно, но это спасло нас от тысячи багов потом. Интересный момент: при работе с системой аутентификации нужно помнить о **timing-атаках**. Если ваш код проверяет пароль «в лоб» с простым сравнением строк, хакер может подбирать буквы по времени выполнения. Мы использовали функции постоянного времени для всех критичных проверок — это не сложно, но невероятно важно. В итоге получилась система, которая: - Выдаёт пользователю пару токенов при входе - Проверяет access-token на каждый запрос за миллисекунды - Автоматически обновляет доступ через refresh-токен - Логирует все попытки входа в систему trend-analysis **Дальше** планируем добавить двухфакторную аутентификацию и интеграцию с OAuth для социальных сетей, но это уже совсем другая история. Главное — база построена, и теперь анализ трендов защищён как форпост. 😄 Знаете, почему JWT-токены никогда не приходят на вечеринки? Потому что они всегда истекают в самый неподходящий момент!