Разработка: ai-agents-voice-agent
Хроника разработки проекта ai-agents-voice-agent. Основные направления: новые функции, исправления багов, изменения кода. Всего 13 записей в потоке. Последние темы: Как я обновил архитектуру голосового агента за один вечер; Собрали агента с руками: как мы добавили управление рабочим столом; Как мы защитили голосового агента от интернета.
Voice Agent: Как я добавил интеллектуальную систему сбора IT-новостей
Когда разработчик говорит: «А давай добавим поиск по новостям прямо в чат-бота?» — обычно это означает три часа отладки и переосмысления архитектуры. Но в проекте Voice Agent это было неизбежно.
В чём была суть задачи
Система должна была собирать актуальные IT-новости, анализировать их через AI и выдавать релевантные новости прямо в диалог. Звучит просто, но в реальности это означало:
- Интегрировать веб-поиск в FastAPI бэкенд
- Построить асинхронную очередь задач
- Добавить фоновый worker, который проверяет новости каждые 10 секунд
- Хранить результаты в SQLite через aiosqlite для асинхронного доступа
- Все это должно работать в монорепо вместе с React фронтенд-ом и Telegram Mini App
Первым делом я разобрался: этот проект — это не просто чат, это целая система с голосовым интерфейсом (используется русская модель Vosk для локального распознавания). Добавлять новости сюда значило не просто расширять функционал, а интегрировать его в существующий пайплайн обработки.
Как это реализовывалось
Я начал с бэкенда. Нужно было создать:
- Таблицу в БД для хранения новостей — всего несколько полей: заголовок, ссылка, AI-анализ, дата сбора
- Scheduled task в asyncio, которая периодически срабатывает и проверяет, не появились ли новые новости
- Tool для LLM — специальный инструмент, который агент может вызывать, когда пользователь просит новости
Неожиданно выяснилось, что интеграция веб-поиска в монорепо с Turbopack требует аккуратности. Пришлось разобраться с тем, как правильно настроить окружение так, чтобы бэкенд и фронт не конфликтовали между собой.
Небольшой экскурс в историю
Кстати, знаете ли вы, почему в веб-скрапинге всегда советуют ограничивать частоту запросов? Это не просто вежливость. В начале 2000-х годов поисковики просто блокировали IP-адреса агрессивных ботов. Сейчас алгоритмы умнее — они анализируют паттерны поведения. Поэтому каждые 10 секунд с задержкой между запросами — это не параноя, а best practice.
Что получилось
В итоге Voice Agent получил новую возможность. Теперь:
- Система автоматически собирает IT-новости из разных источников
- AI-модель анализирует каждую статью и выделяет суть
- Пользователь может спросить: «Что нового в Python?» — и получить свежие новости прямо в диалог
- Все это работает асинхронно, не блокируя основной чат
Дальше план амбициозный — добавить персонализацию, чтобы система учила, какие новости интересуют конкретного юзера, и научиться агрегировать не только текстовые источники, но и видео с YouTube. Но это уже следующая история.
Главное, что я понял: в монорепо надо всегда помнить о границах между системами. Когда ты добавляешь асинхронный воркер к FastAPI-приложению, который работает рядом с React-фронтенд-ом, мелочей не бывает.
«Если WebSearch работает — не трогай. Если не работает — тоже не трогай, станет хуже.» 😄
Claude Code встретился с голосовым агентом: история первого контакта
Когда я начинал проект voice-agent, передо мной стояла интересная задача: создать полноценного помощника, который мог бы работать с голосом, текстом и интеграциями. Python на бэкенде, Next.js на фронте — классическая современная архитектура. Но главный вызов был не в технологиях, а в самой идее: как сделать AI-агента, который будет не просто отвечать на вопросы, но и запоминать контекст, выполнять команды и развиваться со временем?
Первым делом я осознал, что это не просто ещё один chatbot. Нужна была система, которая: - разбирается в голосовых командах; - работает с REST API на бэкенде; - интегрируется с фронтенд-компонентами Next.js; - может отлаживать ошибки через структурированный журнал.
Начал я с архитектуры. Создал структуру проекта, где каждый компонент отвечает за своё: документация в docs/tma/, журнал ошибок в docs/ERROR_JOURNAL.md, специализированные бэкенд-сервисы для разных функций. Python даёт нам гибкость с асинхронными вызовами, а Next.js — скорость и удобство на фронте.
Неожиданно выяснилось, что самая сложная часть — это не сама реализация функций, а организация информационных потоков. Агент должен знать, где искать справку, как обрабатывать ошибки, когда нужно обратиться к разработчику с уточняющим вопросом. Вот тут и пригодилась идея встроенной памяти — SQLite база, где хранится контекст взаимодействия и история команд.
Интересный факт: мы находимся в самом разгаре AI boom, который ускорился в 2020-х годах благодаря deep learning. Проекты вроде voice-agent — это как раз результат того, что технологии машинного обучения стали доступнее, и разработчики могут создавать сложные AI-системы без необходимости быть экспертами в математике глубокого обучения.
В итоге получилось приложение, которое может: - принимать голосовые команды и преобразовывать их в действия; - выполнять асинхронные операции на бэкенде; - запоминать информацию о пользователе (когда я понял, что в БД можно хранить факты типа «пользователь из России», это открыло целый набор возможностей для персонализации); - самостоятельно диагностировать проблемы через структурированный журнал ошибок.
Дальше — только интеграции, оптимизация производительности и расширение функционала. Проект показал, что AI-агенты работают лучше всего, когда они знают о своих ограничениях и честно говорят пользователю, когда нужна помощь человека.
Почему Apache считает себя лучше всех? Потому что Stack Overflow так сказал 😄
Когда AI-помощник встречается с монорепо: отладка голосового агента
Проект voice-agent — это амбициозная задача: связать Python-бэкенд с Next.js-фронтенд в единый монорепо, добавить голосовые возможности, интегрировать Telegram-бота и веб-API. Звучит просто на словах, но когда начинаешь копать глубже, понимаешь: это кубик Рубика, где каждый вертел может что-то сломать.
Проблема, с которой я столкнулся, была банальной, но коварной. Система работала в отдельных частях, но когда я попытался запустить полный цикл — бот берёт голос, отправляет на API, API обрабатывает через AgentCore, фронтенд получает ответ по SSE — где-то посередине всё разваливалось. Ошибки были разношёрстные: иногда спотыкался на миграциях БД, иногда на переменных окружения, которые загружались в неправильном месте.
Первым делом я понял: нужна система для документирования проблем. Создал ERROR_JOURNAL.md — простой журнал “что сломалось и как это чинилось”. Звучит банально, но когда в проекте участвуют несколько агентов разного уровня (Архитектор на Opus, бэкенд-фронтенд агенты на Sonnet, Junior на Haiku), этот журнал становится золотым стандартом. Вместо того чтобы каждый агент наново натыкался на баг с Tailwind v4 в монорепо, теперь первым делом смотрим журнал и применяем известное решение.
Архитектура обработки ошибок простая, но эффективная:
- Ошибка возникла → читаю
docs/ERROR_JOURNAL.md - Похожая проблема есть → применяю известное решение
- Новая проблема → исправляю + добавляю запись в журнал
Основные боли оказались не в коде, а в конфигурации. С Tailwind v4 нужна магия в next.config.ts и postcss.config.mjs — добавить turbopack.root и base. SQLite требует WAL-режим и правильный путь к базе. FastAPI любит, когда переменные окружения загружаются только в точках входа (telegram_main.py, web_main.py), а не на уровне модулей.
Интересный момент: я переоценил сложность. Большинство проблем решались не рефакторингом, а правильной организацией архитектуры. AgentCore — это единое ядро бизнес-логики для бота и API, и если оно валидируется с одной строки (python -c "from src.core import AgentCore; print('OK')"), весь стек работает как часы.
Итог: система работает, но главный урок не в технических трюках — в том, что монорепо требует прозрачности. Когда каждая составляющая (Python venv, Next.js сборка, миграции БД, синхронизация переменных окружения) задокументирована и протестирована, даже сложный проект становится управляемым. Теперь каждый новый агент, который присоединяется к проекту, видит ясную картину и может сразу быть полезным, вместо того чтобы возиться с отладкой.
На следующем этапе плотнее интегрирую streaming через Vercel AI SDK Data Stream Protocol и расширяю систему управления чатами через новую таблицу managed_chats. Но это — уже другая история.
😄 Что общего у монорепо и парка развлечений? Оба требуют хорошей разметки, иначе люди заблудятся.
Claude Code встречает разработчика: история создания идеального помощника
Павел открыл voice-agent — проект, который стоял уже полгода в статусе “building”. Python-бэкенд на FastAPI, Next.js фронтенд, асинхронная обработка аудио через aiogram. Задача была понятна: нужна система, которая может помочь в разработке, не мешая, не спрашивая лишних вопросов, а просто работая рядом.
Первым делом команда определилась с подходом. Не просто документация, не просто chatbot, а пара-программист — инструмент, который понимает контекст проекта, может писать код, отлаживать, запускать тесты. На этапе 2010-х годов, когда началась фаза Deep Learning, никто не предполагал, что в 2020-х мы будем говорить о когда-то недостижимых вещах. Но AI boom — это не просто статистика. Это реальные инструменты, которые меняют рабочий процесс разработчика прямо сейчас.
Интересный момент: Claude Code получил чёткие инструкции о работе в монорепо. На монорепо-проектах часто возникает проблема — Next.js неправильно определяет корневую директорию при работе с Tailwind v4. Решение неочевидное: нужно добавить turbopack.root в конфиг и указать base в postcss.config.mjs. Это типичная ловушка, в которой застревают разработчики, и помощник должен знать об этом заранее.
Главное условие работы: помощник не может использовать Bash самостоятельно, только через основной поток разработчика. Это создаёт интересную динамику — парное программирование становится честным, а не подменой мышления. Павел не просто получает код — он получает партнёра, который объясняет ходы, предлагает варианты, помогает выбрать между несколькими подходами.
Система помнит контекст: стек технологий (Python 3.11+, FastAPI 0.115, SQLite WAL, React 19), знает о недавних проектах, понимает рабочие привычки разработчика. Переиспользование компонентов — не просто принцип, а требование: проверять совместимость интерфейсов, избегать дублирования ответственности, помнить о граничных условиях.
Результат? Инструмент, который встречает разработчика дружеским “Привет, Павел! 👋” и точно знает, чем помочь. Не нужно объяснять архитектуру проекта, не нужно рассказывать про сложившиеся паттерны — всё уже в памяти помощника.
Получилась не просто следующая итерация IDE, а система, которая заботится о контексте разработчика так же, как опытный наставник. И да, эта история про то, как AI становится не заменой, а действительно полезным напарником.
😄 Почему Claude Code считает себя лучше всех? Потому что Stack Overflow так сказал.
Когда AI забывает контекст: как мы учим голосовых агентов помнить о встречах
Павел получил от своего AI-ассистента странный ответ. Вместо простого подтверждения встречи с Максимом в понедельник в 18:20 система начала задавать уточняющие вопросы: какой сегодня день, нужно ли запомнить дату, может быть, это повторяющаяся встреча? Звучит как помощник с амнезией, верно? Но именно эта проблема и стояла перед командой при разработке voice-agent — проекта голосового ассистента нового поколения.
Завязка: проект работает на стыке нескольких сложных технологий. Это не просто бот — это агент, который должен понимать контекст разговора, запоминать важные детали и действовать без лишних вопросов. Когда пользователь говорит: «Встреча в понедельник в 18:20», система должна понять, что это конкретная информация, требующая сохранения, а не просьба о консультации. Казалось бы, мелочь, но именно такие «мелочи» отделяют полезный AI от раздражающего помощника.
Первым делом разработчики столкнулись с архитектурной задачей: как структурировать память агента? Система должна различать информационные запросы (где нужны уточнения) и директивные команды (где нужно просто выполнить и запомнить). Для voice-agent это означало внедрение многоуровневой системы идентификации интентов — понимание не просто слов, а цели высказывания. Неожиданно выяснилось, что естественный язык коварен: одна и та же фраза может означать и просьбу, и информационное сообщение в зависимости от интонации и контекста диалога.
Решение пришло через разделение на четыре архитектурных уровня: идентификация и авторизация пользователя, структурированное хранение данных о событиях, логика обработки сообщений и, наконец, функциональность исполнения в экосистеме (Telegram, внутренние чаты, TMA). Каждый уровень отвечает за свой кусок пазла. Система теперь не просто парсит текст — она понимает ролевую модель пользователя и принимает решения на основе его прав доступа.
Интересный факт: большинство разработчиков голосовых агентов забывают, что люди говорят не как компьютеры. Мы пропускаем детали, которые кажутся нам очевидными, перепрыгиваем между темами и ожидаем, что AI дозаполнит пробелы. Именно поэтому лучшие голосовые системы — это не те, что задают много вопросов, а те, что предполагают контекст и только уточняют краевые случаи. Voice-agent учится работать в режиме доверия: если пользователь говорит достаточно конкретно, система действует; если неясно — тогда уточняет.
Итог: Павел больше не получит сотню вопросов по поводу встречи. Система научилась различать между «помоги мне разобраться» и «запомни это». Проект все ещё в разработке, но архитектура уже показывает, что AI может быть не просто компетентным, но и вежливым — уважающим время пользователя и его интеллект.
Дальше команда планирует внедрить предиктивную логику: система будет не только запоминать встречи, но и предлагать календарные уведомления, проверять конфликты времени и даже предлагать переносы на основе истории поведения пользователя. Но это уже совсем другая история.
😄 Что общего у yarn и подростка? Оба непредсказуемы и требуют постоянного внимания.
От хаоса к порядку: как мы научили AI-бота управлять собственными чатами
Столкнулись с интересной проблемой в проекте voice-agent — нашему AI-боту нужно было получить контроль над тем, в каких чатах он работает. Представь: бот может оказаться в сотнях групп, но обслуживать он должен только те, которые явно добавил владелец. И вот здесь начинается магия архитектуры.
Задача была классической, но хитрой
Нужно было реализовать систему управления чатами — что-то вроде белого списка. Бот должен был: - Помнить, какие чаты он курирует - Проверять права пользователя перед каждой командой - Добавлять/удалять чаты через понятные команды - Хранить всё это в надежной базе данных
Звучит просто? На деле это требовало продумать архитектуру с нуля: где брать данные, как валидировать команды, как не потерять информацию при перезагрузке.
Как мы это делали
Первым делом создали класс ChatManager — специалист по управлению чатами. Он бы жил в src/auth/ и работал с SQLite через aiosqlite (асинхронный драйвер, чтобы не блокировать главный цикл обработки сообщений). Важный момент: использовали уже имеющийся в проекте structlog для логирования — не захотелось добавлять ещё одну зависимость в requirements.txt.
Затем создали миграцию БД — новую таблицу managed_chats с полями для типа чата (приватный, группа, супергруппа, канал), ID владельца и временной метки. Ничего сложного, но по-человечески: индексы на часто используемых полях, CHECK-констрейнты для валидности типов.
Дальше идет классический паттерн — middleware для проверки прав. Перед каждой командой система проверяет: а имеет ли этот пользователь доступ к этому чату? Если нет — бот скромно молчит или вежливо отказывает. Это файл src/telegram/middleware/permission_check.py, который встраивается в pipeline обработки сообщений.
И, конечно, handlers — набор команд /manage add, /manage remove, /manage list. Пользователь пишет в личку боту /manage add, и чат добавляется в управляемые. Просто и понятно.
Маленький инсайт про асинхронные БД
Знаешь, почему aiosqlite так хороша? SQLite по умолчанию работает синхронно, но в асинхронном приложении это становится узким местом. aiosqlite оборачивает операции в asyncio, и вот уже БД не блокирует весь бот. Минимум кода, максимум производительности. Многие разработчики об этом не думают, пока не столкнутся с тем, что бот «зависает» при запросе к БД.
Итог: от плана к тестам
Весь процесс разбили на логические шаги с контрольными точками — каждый шаг можно было проверить отдельно. После создания ChatManager идёт миграция БД, потом интеграция в основной бот, затем handlers для команд управления, и наконец — unit-тесты в pytest.
Результат: бот теперь знает, кто его хозяин в каждом чате, и не слушает команды от неуполномоченных людей. Архитектура масштабируется — можно добавить роли, разные уровни доступа, историю изменений. А главное — всё работает асинхронно и не тормозит.
Дальше план — запустить интеграционные тесты и загнать в production. Но это уже другая история.
😄 Совет дня: всегда создавай миграции БД отдельно от логики — так проще откатывать и тестировать.
Монорепо как зеркало: Python + Next.js в одном проекте
Завязка
Представьте ситуацию: вы разработчик и в ваших руках проект voice-agent — голосовой помощник на основе Claude, построенный как монорепо. С одной стороны Python-backend (FastAPI, aiogram для Telegram), с другой — Next.js фронтенд (React 19, TypeScript 5.7) для Telegram Mini App. Звучит здорово, но вот в чём подвох: когда в одном репозитории живут две экосистемы с разными правилами игры, управлять ими становится искусством.
Развитие
Первой проблемой, которая выпрыгнула из неоткуда, была забывчивость переменных окружения. В Python проект использует pydantic-settings для конфигурации, но выяснилось, что эта библиотека не экспортирует значения автоматически в os.environ. Результат? Модульный код, читавший переменные прямо из окружения, падал с загадочными ошибками. Пришлось документировать эту ловушку в ERROR_JOURNAL.md — живом архиве подводных камней проекта, где уже скопилось десять таких «моментов истины».
Далее встал вопрос архитектуры. Backend требовал координатора — центрального паттерна, который бы оркестрировал взаимодействие между агентами и фронтенд-запросами. На бумаге это выглядело идеально, но в коде его не было. Это создавало технический долг, который блокировал Phase 2 разработки. Пришлось вводить phase-gate валидацию — автоматическую проверку, которая гарантирует, что прежде чем переходить к следующей фазе, все артефакты предыдущей действительно на месте.
В процессе появилась и проблема с миграциями базы данных. SQLite с WAL-режимом требовал аккуратности: после того как junior-агент создавал файл миграции, она не всегда применялась к самой БД. Пришлось вводить обязательный чек: запуск migrate.py, проверка таблиц через прямой SQL-запрос, документирование статуса. Без этого можно часами отлавливать фантомные ошибки импорта.
Познавательный блок
Интересный факт: монорепо — это не просто удобство, это культурный артефакт команды разработки. Google использует одно гигантское хранилище для всего кода (более миллиарда строк!), потому что это упрощает синхронизацию и рефакторинг. Но цена высока: нужны инструменты (Bazel), дисциплина и чёткие протоколы. Для нашего voice-agent это значит: не просто писать код, а писать его так, чтобы Python-part и Next.js-part доверяли друг другу.
Итог
В итоге сложилась простая истина: монорепо работает только если есть система проверок. ERROR_JOURNAL.md превратился не просто в логирование ошибок, а в живой артефакт культуры команды. Phase-gate валидация стала гарантией, что при параллельной работе нескольких агентов архитектура не съезжает в стороны. А обязательная проверка миграций — это не занудство, а спасение от трёх часов ночного отлавливания, почему таблица не там, где ей быть.
Главный урок: в монорепо важна не столько архитектура, сколько честность системы. Чем раньше вы перейдёте от надежды на память к автоматическим проверкам, тем спокойнее спать будете.
Почему Python и Java не могут дружить? У них разные dependency trees 😄
Когда AI-ассистент встречает монорепозиторий: история голосового агента
Представьте: перед вами лежит амбициозный проект voice-agent — это монорепозиторий с Python-бэкендом и Next.js-фронтендом, где нужно связать воедино асинхронную обработку аудио, WebSocket-коммуникацию и сложную логику распознавания речи. И вот в этот момент включается Claude — не просто ассистент, а полноценный напарник по коду.
Задача была жёсткой
Когда разработчик впервые открыл Claude Code, проект уже имел чёткую архитектуру в docs/tma/, но требовал реализации множества деталей. Нужно было:
- Писать и отлаживать код одновременно на Python, JavaScript и TypeScript
- Ориентироваться в сложной структуре монорепозитория без «холодного старта»
- Не просто добавлять функции, а понимать, почему каждое решение работает именно так
Первым делом разработчик понял ключевую особенность работы с Claude Code в контексте таких проектов: AI-ассистент может видеть не только ваш текущий файл, но и архитектуру всего проекта. Это даёт огромное преимущество — вы не пишете код в вакууме.
Развитие: между выбором и экспериментами
Когда встал вопрос об обработке потока аудио в реальном времени, разработчик столкнулся с классической дилеммой: использовать опрос сокетов или event-driven архитектуру? Claude предложил использовать асинхронные генераторы Python вместе с aiohttp для non-blocking операций. Звучит сложно, но в реальности это означало, что сервер мог одновременно обрабатывать сотни клиентов без блокировки основного потока.
Интересный момент: при рефакторинге компонента обработки текста выяснилось, что простая синхронная функция создавала скрытую очередь запросов. Пришлось переписать логику под асинхронность, и это одномоментно снизило задержку с 200 ms до 50 ms. Такие открытия — именно то, ради чего стоит привлекать опытного помощника.
Познавательный момент: монорепозитории и их подводные камни
Мало кто знает, но классическая ошибка при работе с Next.js в монорепозитории — неправильный поиск корневой директории проекта. Turbopack (встроенный в Next.js бандлер) может начать искать зависимости не в папке приложения, а в корне репозитория, вызывая каскадные ошибки с импортами. Правильное решение — явно указать turbopack.root в next.config.ts и настроить базовый путь в postcss.config.mjs. Это элементарно, но узнают об этом опытом… или благодаря опытному напарнику.
Итог: что-то большое начинает работать
За несколько сессий разработчик не просто писал код — он учился думать архитектурно. Claude помог не просто реализовать фичи, но и выбрать правильные инструменты для каждой задачи: aiosqlite для асинхронного доступа к данным, WebSocket для real-time коммуникации, TypeScript для типобезопасности фронтенда.
Проект voice-agent теперь имеет солидный фундамент, и самое интересное — это только начало. Впереди оптимизация, масштабирование, новые фичи. Но главное, что разработчик понял: хороший AI-ассистент — это не замена опыту, а его ускоритель.
Обычный коллега сказал бы: «Ну ты с AI-ассистентом кодишь?» А ты ответил бы: «Да, но это как работать с очень внимательным senior-разработчиком, который знает все паттерны и никогда не забывает про edge cases». 😄
Как мы научили агента следить за собой: история про самоотражение в проекте Voice Agent
Представь ситуацию: у тебя есть сложный проект Voice Agent с многоуровневой архитектурой, где крутятся несколько агентов одновременно, каждый выполняет свою роль. Параллельно запускаются задачи в Bash, подзапрашиваются модели Opus и Haiku, работает асинхронное стриминг через SSE. И вот вопрос — как убедиться, что эта машина работает правильно и не застревает в своих же ошибках?
Именно это и стояло перед нами. Обычного логирования было недостаточно. Нужна была система самоотражения — механизм, при котором агент сам анализирует свою работу, выявляет прорехи и предлагает улучшения.
Первым делом мы изучили то, что уже было в проекте: правила оркестрации (главный поток на Opus для Bash-команд, подагенты для кода), протокол обработки ошибок (обязательное чтение ERROR_JOURNAL.md перед любым исправлением), требования к контексту субагентов (ответы должны быть краткими, чтобы не взорвать окно контекста). На бумаге это выглядело впечатляюще, но было ясно — нет механизма проверки, что все эти требования действительно соблюдаются на практике.
Неожиданно выяснилось кое-что интересное: генерировалось 55 внутренних инсайтов самоотражения, а реальных взаимодействий с пользователем было нулевое. Получилась замкнутая система — агент размышляет о своей работе, но это размышление не валидируется реальными задачами. Это как писать код в пустоте, без тестов.
Поэтому мы переделали подход. Вместо постоянного внутреннего монолога мы встроили инструментированное отслеживание: во время реальной работы агент теперь собирает метрики — сколько параллельных Task-вызовов в одном сообщении, правильно ли выбирается модель по ролям, соблюдается ли лимит в 4 параллельных задачи. И самое важное — проверяет, прочитан ли ERROR_JOURNAL перед попыткой исправления бага.
Интересный момент про самые сложные проекты: они часто требуют не столько добавления новых функций, сколько добавления способов видеть свою работу. Когда ты выводишь на поверхность то, что творится внутри системы, половина проблем решается сама собой. Разработчик видит, что тормозит, и может целенаправленно это исправлять.
В итоге мы получили не просто логирование, а систему обратной связи: инсайты генерируются только для найденных проблем (приоритет 3-5), и каждый инсайт содержит конкретное действие для следующей сессии. На каждый шаг — метрика для проверки. На каждую архитектурную гарантию — точка наблюдения.
Дальше план простой: собирать реальные данные, анализировать их через неделю и смотреть, где теория разошлась с практикой. Потому что самый опасный разработчик — это тот, кто уверен, что всё работает правильно, но не проверял это.
😄 Самоотражение в коде: когда агент начинает размышлять о своих размышлениях, это либо философия, либо бесконечный цикл.
Голос вместо текста: как собрать Voice Agent с нуля на FastAPI и Next.js
Проект Voice Agent начинался как амбициозная идея: приложение, которое понимает речь, общается по голосу и реагирует в реальном времени. Ничего необычного для 2025 года, казалось бы. Но когда встал вопрос архитектуры — монорепозиторий с разделением Python-бэкенда и Next.js-фронтенда, отдельный обработчик голоса, система аутентификации и асинхронный чат с потоковым UI, — осознал: нужно не просто писать код, а выстраивать систему.
Первым делом разобрался с бэкендом. Выбор был между Django REST и FastAPI. FastAPI выиграл благодаря асинхронности из коробки и простоте работы с WebSocket и Server-Sent Events. Версия 0.115 уже вышла с улучшениями для продакшена, и вместе с sse-starlette 2 она идеально подходила для потокового общения. Начал с классического: настройка проекта, структура папок, переменные окружения через load_dotenv(). Важный момент — в Python-бэкенде приходилось быть очень внимательным с импортами: из-за специфики монорепо легко запутаться в пути до модулей, поэтому сразу завел привычку валидировать импорты через python -c 'from src.module import Class' после каждого изменения.
Потом понадобилась аутентификация. Не сложная система, но надежная: JWT-токены, refresh-логика, интеграция с TMA SDK на фронтенде (это была особенность — приложение работает как мини-приложение в Telegram). На фронтенде поднял Next.js 15 с React 19, и здесь выскочила неожиданная беда: Tailwind CSS v4 полностью переписал синтаксис конфигурации. Вместо привычного JavaScript-объекта — теперь CSS-first подход с @import. Монорепо с Turbopack в Next.js еще больше усложнял ситуацию: приходилось добавлять turbopack.root в next.config.ts и явно указывать base в postcss.config.mjs, иначе сборщик терялся в корне проекта.
Интересный момент: FastAPI 0.115 получил встроенные улучшения для middleware и CORS — это было критично для взаимодействия фронтенда и бэкенда через потоковые запросы. Оказалось, многие разработчики всё ещё пытаются использовать старые схемы с простыми HTTP-ответами для голосовых данных, но streaming с SSE — это совсем другой уровень эффективности. Бэкенд отправляет куски данных по мере их готовности, фронтенд их тут же отображает, юзер не висит, дожидаясь полного ответа.
Система валидации стала ключом к стабильности. На бэкенде — проверка импортов и тесты перед коммитом. На фронтенде — npm build перед каждым мерджем. Завел привычку писать в ERROR_JOURNAL.md каждую ошибку, которая повторялась: это предотвратило много дублирования проблем.
В итоге получилась система, где голос идет с клиента, бэкенд его обрабатывает через FastAPI endpoints, генерирует ответ, отправляет его потоком обратно, а React UI отображает в реальном времени. Просто, но изящно. Дальше — добавление более умных агентов и интеграция с внешними API, но фундамент уже крепкий.
Если Java работает — не трогай. Если не работает — тоже не трогай, станет хуже. 😄









