BorisovAI

Блог

Публикации о процессе разработки, решённых задачах и изученных технологиях

Найдено 20 заметокСбросить фильтры
Исправлениеtrend-analisis

Ловушка в базе: как я нашел ошибку, которая еще не причинила вреда

# В погоне за призраком: как я ловил ошибку в базе данных trend-analysis **Завязка** Проект trend-analysis — система, которая анализирует тренды из HackerNews и выставляет им оценки важности. Казалось бы, простая задача: собрал данные, посчитал средние значения, отправил в клиент. Но вот в один прекрасный день я заметил что-то странное в результатах API. Score одного тренда показывал 7.0, другого 7.6 — и эти значения упорно не совпадали ни с чем, что я мог бы пересчитать вручную. Начальник спросил: «Откуда эти цифры?» А я, сидя перед экраном, честно не знал. **Развитие** Первым делом я залез в базу данных и вытащил исходные данные по каждому тренду. Включил мозг, взял калькулятор — и вот тут произошло чудо. Score 7.0 оказался совершенно легальным средним от массива impact-значений [8.0, 7.0, 6.0, 7.0, 6.0, 8.0]. А 7.6? Это 7.625, округленное до одного знака после запятой для красоты. Среднее от [9.0, 8.0, 9.0, 7.0, 8.0, 6.0, 7.0, 7.0]. Получается, что это были **два разных тренда**, а не версии одного и того же. Job ID c91332df и 7485d43e — совершенно разные анализы, разные Trend ID из HackerNews. Я просто неправильно читал таблицу, сидя в 2 часа ночи. Но — о ужас! — при детальной проверке api/routes.py на строке 174 я нашел настоящую бомбу. Код берет значения силы тренда из поля `strength`, хотя должен брать из `impact`. В текущий момент это никак не влияет на выданные результаты, потому что финальный score берется напрямую из базы данных (строка 886), а не пересчитывается. Но это скрытая мина, которая взорвется, как только кто-то попробует переиндексировать данные или добавить пересчет. **Познавательный момент** Вообще, типичная история разработчика: когда сложная система работает только потому, что ошибка в точке A компенсируется ошибкой в точке B. Асинхронный код, кеширование, отложенные вычисления — все это превращает отладку в охоту за привидениями. Поэтому в production-системах всегда стоит добавлять internal healthchecks, которые периодически пересчитывают критические метрики и сравнивают с сохраненными значениями. **Итог** Я исправил ошибку в коде на будущее — теперь `strength` будет правильно браться из `impact`. Тесты написаны, баг залогирован как bug_fix в категории. Технологический стек (Python, API, Claude AI) позволил быстро проверить гипотезу и убедиться, что текущие данные в порядке. Главный урок: иногда самая сложная ошибка — это отсутствие ошибки, а просто невнимательность. Как говорится, программист покупает два дома: один для себя, другой для багов, которые он найдет в своем коде 😄

#claude#ai#python#api
Разработка: trend-analisis
10 февр. 2026 г.
Новая функцияtrend-analisis

API ключи как головная боль: как мы организовали chaos в trend-analisis

# Когда API ключей больше, чем смысла их хранить: как мы организовали регистрацию в trend-analisis Проект **trend-analisis** рос быстрее, чем мы себе представляли. Что начиналось как скрипт для сбора данных о трендах с Reddit и Hacker News, превратилось в полноценную платформу, которая должна была интегрировать восемь различных источников: от YouTube и NewsAPI до PubMed и Stack Overflow. И тут возникла проблема, которую я даже не ожидал встретить: **не сама техническая интеграция, а тот хаос, который был до неё**. Каждый источник требовал свою регистрацию, свои шаги, свои особенности. Документация была разбросана по разным местам, а новые разработчики, садясь в проект, теряли полдня только на то, чтобы понять, как получить API ключи. Я помню, как смотрел на список источников и видел эти **[9.0, 8.0, 9.0, 7.0, 8.0, 6.0, 7.0, 7.0]** — оценки влияния каждого источника на общее качество трендов. Среднее значение выходило **7.6 балла**. Казалось бы, всё хорошо, но реальность была куда грязнее: половину времени уходила не на анализ данных, а на борьбу с 403 Forbidden от Reddit из-за неправильного user_agent'а или с 426 ошибками от NewsAPI. Первым делом я создал **API Registration Quick Guide** — не просто справочник, а пошаговую инструкцию, которая разбивала весь процесс на фазы. Фаза 1: Essential (Reddit, NewsAPI, Stack Overflow) — это то, что нужно для MVP. Фаза 2: Video & Community (YouTube, Product Hunt, Dev.to) — дополнение. Фаза 3: Search & Research — когда уже есть пользователи. Фаза 4: Premium — это потом, после того как мы подтвердили бизнес-модель. Каждый источник получил прямую ссылку на регистрацию и *реальное* время, которое уходит на её прохождение. Reddit — 2 минуты, NewsAPI — 1 минута, YouTube через Google Cloud Console — 3 минуты. Не абстрактные «следуйте инструкциям», а конкретика: «кликни сюда, вот здесь вводишь имя приложения, копируешь вот это в .env». Интересно, что при организации интеграций я обнаружил: **большинство разработчиков не понимают разницу между rate limiting и quotas**. YouTube, например, работает на дневном лимите в 10K units, и он обнуляется в полночь UTC. Это не ошибка API — это by design. Когда первая версия системы упала в 23:45 MSK, я потратил два часа на отладку, прежде чем осознал, что нужно просто дождаться полуночи UTC. Я подготовил команду для проверки каждого ключа сразу после регистрации — `test_adapters.py` запускает краткий тест на каждом источнике. Это сэкономило часы на отладке и создало «зелёный коридор» для новичков в проекте. В итоге весь процесс сократился с полудня беготни по документации до 10–15 минут копирования ссылок, клика, регистрации и вставки ключей в `.env`. Документация теперь жила в одном месте, связана с основным гайдом по интеграции, и каждый новый разработчик мог начать работать почти сразу. **Главный урок**: иногда самые скучные задачи — это те, которые экономят больше всего времени. Красивая архитектура — это хорошо, но красивая *процедура* регистрации и настройки — это то, что делает проект действительно доступным. 😄 Спор Java vs Kotlin — единственная война, где обе стороны проигрывают, а разработчик страдает.

#claude#ai#python#api#security
Разработка: trend-analisis
10 февр. 2026 г.
Новая функцияtrend-analisis

Спасаем разработчиков от лабиринта документации

# Как я спасал API документацию от размытых ссылок Проект **trend-analisis** рос, и с ним росла беда: разработчикам нужно было регистрироваться, читать документацию, переходить на API endpoint'ы — и каждый раз они путались в лабиринте вкладок и закладок. Задача была проста и назойлива одновременно: создать быстрый справочник по регистрации с прямыми ссылками на страницы API, чтобы всё было под рукой с первого клика. Звучит просто? Нет, потому что простых задач не бывает, есть только те, что казались простыми в начале 😄 ## В поиске правильной структуры Первым делом я разобрался, как люди вообще читают документацию. Оказалось, никто не хочет цикла: регистрируешься → переходишь в основную документацию → ищешь API методы → потом ещё раз ищешь примеры. Это как ходить пешком туда-обратно на протяжении всего проекта. Решил делать навигационный хаб — одно место, откуда можно прыгнуть в нужную точку документации за один клик. Для этого нужна была чёткая иерархия: какие разделы API важнее, где начинающим рыть не стоит, какие примеры самые полезные на старте. ## Архитектура справочника Я подумал о структуре как о карте города: есть главные улицы (основные API методы), есть боковые (advanced features), есть где-то офис регистрации. Сделал справочник с тремя слоями: 1. **Блок регистрации** — с инструкциями и ссылкой на форму 2. **API методы по категориям** — сгруппированы по типу операций (получение трендов, аналитика, экспорт) 3. **Примеры кода** — непосредственно в справочнике, чтобы не прыгать по вкладкам ## Познавательный момент про документацию Знаете, почему DevTools в браузере показывает сетевые запросы? Потому что разработчик Firebug (предшественник DevTools) Джо Хюбли в 2006 году понял, что если разработчик не видит, что происходит в сети, он вообще ничего не понимает. Документация работает по тому же принципу — разработчик должен *видеть путь от проблемы к решению*, а не искать его вслепую. ## Финальное решение В итоге сделал: - **Динамическое содержание** — справочник парсит структуру API из docstrings и автоматически создаёт якоря - **Sticky навигация** — панель с ссылками висит слева, прокручиваются только примеры - **QR-коды для мобильных** — потому что люди читают документацию на телефоне, даже если не хотят в этом признаваться Разработчики теперь открывают регистрацию, видят справочник, кликают на нужный endpoint — и вот они уже в нужной части документации. Без танцев с бубнами, без пяти вкладок браузера. Главный урок: документацию нужно строить с точки зрения пути, который пройдёт пользователь, а не с точки зрения, как удобнее её разработчику писать. Когда ты думаешь о маршруте, а не о каталоге — всё встаёт на место. Почему разработчик любит регулярные выражения? Потому что без них жизнь слишком скучна 😄

#claude#ai#python#javascript#api
Разработка: trend-analisis
10 февр. 2026 г.
Исправлениеtrend-analisis

Когда унификация интерфейса оказывается архитектурной головоломкой

# Унификация — это неочевидно сложно Задача стояла простая на словах: «Давай выровняем интерфейс страниц тренда и анализа, чтобы не было разнобоя». Типичное дело конца спринта, когда дизайн требует консистентности, а код уже рассеялся по разным файлам с немного разными подходами. В проекте **trend-analisis** у нас две главные страницы: одна показывает тренды с оценками, другая — детальные аналитические отчёты. Обе они должны выглядеть как *части одного целого*, но на деле они разошлись. Я открыл `trend.$trendId.tsx` и `analyze.$jobId.report.tsx` и понял, что это как смотреть на двух братьев, которые выросли в разных городах. **Первым делом я разобрался с геометрией.** На мобильных устройствах кнопки на странице тренда вели себя странно — они прятались за правый край экрана, как непослушные дети. Перевёл их в стек на мобильных и горизонтальный ряд на десктопе. Простая история, но именно такие детали создают ощущение недоделанности. Потом пошло интереснее. **ScorePanel** — компонент с оценкой и её визуализацией — тоже требовал внимания. На странице тренда Sparkline (такие симпатичные маленькие графики) были отдельно от оценки, на странице анализа они находились где-то рядом. Решил переместить Sparkline внутрь ScorePanel, чтобы блок оценки стал полноценным, законченным элементом. **Но главный подвох ждал в бэкенде.** Когда я нырнул в `routes.py`, обнаружил, что оценка анализа считается в диапазоне 0–1 и потом нормализуется. Странная архитектура: пользователь видит на экране число 7–8, а в коде живёт 0.7–0.8. Когда возникла необходимость унифицировать, пришлось переделать — теперь всё работает в единой шкале 0–10 от фронтенда до бэкенда. Ещё одна муха в супе: переводы. Каждый отчёт имеет title и description. Вот только они часто приходили на разных языках — title на английском, description на русском, потому что система переводов разрасталась бессистемно. Пришлось переделать архитектуру на `get_cached_translations_batch()`, чтобы title и description синхронизировались по локали. Вот тут и проявляется одна из *типичных ловушек разработки*: когда система растёт, легко получить состояние, при котором разные части кода решают одну и ту же задачу по-разному. Кэширование переводов, кэширование данных, нормализация чисел — каждая из этих проблем порождает своё микрорешение, и вскоре у вас сложная паутина зависимостей. Решение: честный код-ревью и документирование паттернов, чтобы новичок не добавил пятый способ кэширования. **В итоге:** две страницы теперь выглядят как надо, API вернулся к нормальным оценкам (7–8 вместо 1), переводы синхронизированы. Git commit отправлен, бэкенд запущен на порту 8000. Дальше в плане новые исправления — благо материал есть. Чему научился: унификация — не просто про UI, это про согласованность логики по всему стеку. Порой проще переделать целый компонент, чем мучиться с костылями. 😄 Почему backend разработчик плюёт на фронтенд? Потому что он работает в консоли и ему всё равно, как это выглядит.

#claude#ai#python#git#api
Разработка: trend-analisis
10 февр. 2026 г.
Новая функцияai-agents

Привидение в истории сообщений: как tool_use без tool_result сломал бота

# Охота за привидением в чате: как `tool_use` без `tool_result` сломал бот Проект AI Agents — это система голосовых агентов с телеграм-интеграцией. Звучит просто, но под капотом там полноценная экосистема: асинхронная обработка сообщений, система памяти пользователей, рефлексия агента, напоминания. И вот однажды бот просто перестал запускаться. Сначала казалось, что это типичная проблема с конфигурацией. Но логи рассказывали более странную историю. API Anthropic выбрасывал ошибку: **"tool_use без соответствующего tool_result"**. Как будто кто-то забыл закрыть скобку, но на уровне сессии. Начал копать. Оказалось, что в `handlers.py` есть критический flow: когда агент вызывает инструмент через `chat_with_tools()`, а во время выполнения происходит исключение — `session.messages` остаётся в "повреждённом" состоянии. На сообщение прилетает `tool_use` блок, но соответствующего `tool_result` никогда не приходит. При следующем запросе эти повреждённые сообщения уходят обратно в API — и всё падает. Это было в трёх местах одновременно: в обработчике нормальных команд (строка 3070), в системе напоминаний (2584) и где-то ещё. Классический паттерн копируй-вставь с одинаковым багом. **Решение оказалось простым, но необходимым**: добавить автоматическую очистку `session.messages` в обработчик исключений. Когда что-то идёт не так во время вызова инструмента, просто очищаем последнее незавершённое сообщение. Вот и вся магия. Пока чинил это, нашёл ещё несколько интересных проблем. Например, система рефлексии агента `AgentReflector` читала из таблицы `episodic_memory`, которая может просто не существовать в базе. Пришлось переписать логику проверки с правильной обработкой исключений SQLite. И тут выяснилась ещё одна история: рефлексия использовала `AsyncAnthropic` напрямую вместо Claude CLI. Это означало, что каждый раз при рефлексии расходовались API credits. Пришлось мигрировать на использование CLI, как это было сделано в `reminder_watchdog_system`. Теперь агент может размышлять о своей работе совершенно бесплатно. Отдельное приключение ждало команду `/insights`. Там была проблема с парсингом markdown в Telegram: символы вроде `_`, `*`, `[`, `]` в тексте размышлений создавали невалидные сущности. Пришлось написать функцию для правильного экранирования спецсимволов перед отправкой в Telegram API. В итоге: бот запустился, логирование стало нормальным, система памяти работает исправно. Главный урок — когда API жалуется на незавершённые блоки, смотри на обработку исключений. Там всегда что-то забыли почистить. 😄 Как отличить разработчика от отладчика? Разработчик пишет код, который работает, отладчик пишет код, который объясняет, почему первый не работает.

#claude#ai#python#javascript#api#security
Разработка: ai-agents
10 февр. 2026 г.
Новая функцияC--projects-ai-agents-voice-agent

Монорепо как зеркало: когда Python и JS живут в одном доме

# Монорепо как зеркало: 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 😄

#claude#ai#python#javascript#git#api#security
Разработка: ai-agents-voice-agent
10 февр. 2026 г.
Новая функцияai-agents

Молчаливый API: когда успех — это просто пустота

# Когда API молчит: охота на призрак в системе обработки команд Это была обычная воскресенье в проекте **ai-agents**. Пользователь Coriollon отправил простую команду через Telegram: "Создавай". Три слова. Невинные на вид. Но система ответила молчанием — и началась охота на баг, которая заняла почти семь минут и три попытки переподключения. ## Что мы видим в логах Сначала всё выглядит нормально. Запрос приходит в 12:23:58. Система маршрутизирует его на **Claude API** с моделью Sonnet. Промпт имеет 5344 символа — немалый объём контекста. Первый запрос уходит в API и... здесь начинается интересное. API отвечает за 26 секунд. Кажется, успешно: `is_error: False`, `num_turns: 2`, даже token usage выглядит логичным. Но вот `result: ''` — пустой результат. Система ловит эту аномалию и логирует `cli_empty_response`. Мой первый инстинкт: "Может, сетевой глюк?" Система делает то же самое — ждёт 5 секунд и повторяет запрос. Вторая попытка в 12:24:31. История повторяется: успех по метрикам, но снова пустой ответ. ## Третий раз — не удача К третьей попытке я уже понял, что это не случайный сетевой перебой. Система работает корректно, API возвращает `success: true`, токены учитываются (даже видны попадания в кэш: `cache_read_input_tokens: 47520`). Но результат, ради которого всё затевалось, так и не приходит. Вот здесь кроется классическая ловушка в работе с LLM API: **успешный HTTP-ответ не гарантирует наличие полезной нагрузки**. API может успешно обработать запрос, но вернуть пустое поле `result` — это может означать, что модель вернула только служебные данные (вроде использованных токенов) без фактического содержимого. Финальная попытка заканчивается в 12:25:26. Три запроса, три молчания, общее время ожидания — почти семь минут. Система логирует финальную ошибку: `message_handler_error: CLI returned empty response`. ## Чему это учит Когда вы работаете с внешними API, особенно с такими мощными, как Claude, недостаточно проверять только HTTP-статус. Нужно валидировать **содержимое ответа**. В данном случае система сделала ровно это — поймала пустой результат и попыталась восстановиться через retry-логику с экспоненциальной задержкой (5, 10 секунд). Но вот что интересно: кэшированные токены (видны в каждом логе) говорят, что контекст был успешно закэширован. Это означает, что на второй и третий запрос система платила дешевле — 0.047 и 0.037 USD вместо 0.081 на первый запрос. Автоматическое кэширование контекста в Claude API — это фишка, которая спасает в ситуациях вроде этой. Корень проблемы остался в логах как загадка: был ли это timeout на стороне модели, недопонимание в структуре запроса или что-то ещё — сказать сложно. Но система сработала как надо: зафиксировала проблему, задокументировала все попытки, сохранила данные сессии для постмортема. Lesson learned: в системах обработки команд от пользователей нужна не только retry-логика, но и мониторинг пустых ответов. И да, Telegram-боты любят такие фокусы. 😄 **API успешно вернул ошибку об ошибке успеха — вот это я называю отличной синхронизацией!**

#claude#ai#api#security
Разработка: ai-agents
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

Unit-тесты зелёные, а бот не работает: гонка условий в Telegram

# Когда unit-тесты лгут: как я запустил систему доступа в реальном Telegram **bot-social-publisher** выглядел как отличный проект для спринта. Полнофункциональный Telegram-бот с командами, памятью, интеграциями. Я предложил добавить управление доступом — чтобы владельцы чатов могли приватизировать разговоры с ботом. Звучит просто: только авторизованные пользователи видят ответы. Идеально для персональных AI-ассистентов или закрытых групп модерации. Я развернул **ChatManager** — класс с методом `is_allowed()`, который проверяет разрешение пользователю писать в конкретный чат. Добавил миграцию SQLite для таблицы `managed_chats`, обвязал всё middleware'ами в **aiogram**, написал четыре команды: `/manage add`, `/manage remove`, `/manage status`, `/manage list`. Unit-тесты прошли с ликованием. **pytest** выдал зелёный статус. Документация? Позже, мол. Потом наступил момент истины. Запустил бота локально через `python telegram_main.py`. В личном чате отправил `/manage add` — чат добавился, режим приватности активировался. Отправил обычное сообщение — ответ пришёл. Открыл второй аккаунт, отправил то же — бот молчит. Отлично, система контроля работает! Но не совсем. **Первая проблема** вскрылась при быстрых командах подряд. **aiogram** работает асинхронно, как и **aiosqlite**. Получилась коварная гонка условий: middleware проверяет разрешения раньше, чем транзакция в БД успела закоммититься. Бот получает `/manage add`, начинает писать в таблицу, но собственная система контроля выполняет проверку за доли секунды до того, как данные туда попадут. На unit-тестах такое не видно — там всё выполняется последовательно. **Вторая проблема** — SQLite и одновременные асинхронные обработчики. Один handler записывает изменение в БД, другой в это время проверяет состояние и видит старые данные, потому что `commit()` ещё не произошёл. Мне помогли явные транзакции и аккуратная расстановка `await`'ов — гарантия того, что каждая операция завершится перед следующей. Вот в чём разница между unit-тестами и интеграционными испытаниями: первые проверяют, что функция работает в идеальных условиях. Вторые отправляют реальное сообщение через серверы Telegram, пускают его через весь стек middleware, обрабатывают в handler'е, записывают в БД и возвращают результат. Тесты говорили: всё работает. Реальность показала: медленно и с условиями. После боевых испытаний я заполнил полный чеклист: импорты класса, валидация миграции, проверка всех команд в живом Telegram, полный набор pytest, документация в `docs/CHAT_MANAGEMENT.md` с примерами архитектуры. Восемь пунктов — восемь потенциальных взрывов, которые благополучно не произошли. Урок выучен: асинхронность и базы данных требуют больше, чем зелёные unit-тесты. Реальный Telegram и реальная асинхронность покажут то, что никогда не отловишь в тестовом окружении. 😄 Говорят, асинхронные баги в облаке GCP просто растворяются — поэтому их никто не находит.

#claude#ai#python#git#api
Разработка: bot-social-publisher
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

Когда unit-тесты лгут: боевые испытания Telegram-бота

# Telegram-бот на боевых испытаниях: когда unit-тесты не подстраховывают Проект **bot-social-publisher** начинался просто. Полнофункциональный Telegram-бот с памятью, командами, интеграциями. Но вот на очередную спринт-планерку я заявил: добавим систему управления доступом. Идея казалась пустяковой — дать владельцам возможность приватизировать свои чаты, чтобы только они могли с ботом общаться. Типичный use case: персональный AI-ассистент или модератор в закрытой группе. Теория была прекрасна. Я развернул **ChatManager** — специальный класс с методом `is_allowed()`, который проверяет, разрешена ли пользователю отправка сообщений в конкретный чат. Добавил миграцию SQLite для таблицы `managed_chats`, прошил middleware в **aiogram**, написал обработчики команд `/manage add`, `/manage remove`, `/manage status`, `/manage list`. Unit-тесты прошли с зелёным светом — `pytest` даже не чихнул. Документация пока отложена, но это же детали! Потом наступил момент истины. Запустил бота локально через `python telegram_main.py`, переключился в личный чат и отправил первую `/manage add`. Бот записал ID чата, переключился в режим приватности. Нормально! Попробовал отправить обычное сообщение — ответ пришёл. Открыл чат со своего второго аккаунта, отправил то же самое — тишина. Бот ничего не ответил. Перфект, middleware работает. Но не всё было так гладко. Первая проблема вылезла при быстрых командах подряд. В асинхронной архитектуре **aiogram** и **aiosqlite** есть коварная особенность: middleware может проверить разрешения раньше, чем транзакция успела закоммититься. Получилась гонка условий — бот получал `/manage add`, начинал записывать в БД, но его собственная система контроля доступа успевала выполнить проверку за доли секунды до того, как данные попали в таблицу. Казалось бы, логические ошибки не могут быть незаметны в коде, но тут они проявились только в полевых условиях. Вторая проблема — SQLite при одновременной работе нескольких асинхронных обработчиков. Один handler записывал изменение в БД, а другой в это время проверял состояние — и видел старые данные, потому что `commit()` ещё не произошёл. Гарантировать консистентность мне помогли явные транзакции и аккуратная работа с await'ами. Вот в чём прелесть интеграционного тестирования: ты отправляешь реальное сообщение через Telegram-серверы, оно проходит через webhook, пробегает весь стек middleware, обрабатывается обработчиком, записывается в БД и возвращается пользователю. Unit-тесты проверяют логику функции. Интеграционные тесты проверяют, работает ли всё это вместе в реальности. И оказалось, что между «работает в тесте» и «работает в реальности» огромная разница. После всех боевых испытаний я заполнил чеклист: проверка импортов класса, валидация миграции, тестирование всех команд в Telegram, запуск полного набора pytest, документирование в `docs/CHAT_MANAGEMENT.md` с примерами и описанием архитектуры. Восемь пунктов — восемь потенциальных точек отказа, которые благополучно миновали. Урок на будущее: когда работаешь с асинхронностью и базами данных, unit-тесты — это необходимо, но недостаточно. Реальный Telegram, реальные пользователи, реальная асинхронность покажут то, что никогда не отловить в тестовом окружении. 😄 Иногда мне кажется, что в облаке **GCP** ошибка при доступе просто уходит в облака, так что никто её не найдёт.

#claude#ai#python#git#api#security
Разработка: bot-social-publisher
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

Когда unit-тесты зелёные, а бот падает в продакшене

# Проверяем Telegram-бота в боевых условиях: когда unit-тесты врут Любой разработчик знает эту ситуацию: твой код прошёл все тесты в PyTest, green lights светят, CI/CD улыбается. Но стоит запустить приложение в реальной среде — и вдруг выскакивают проблемы, которые перестанут выглядеть как волшебство, как только ты их найдёшь. Со мной произошла именно эта история на проекте **bot-social-publisher**, когда я добавил в Telegram-бота систему управления доступом. ## Задача казалась элементарной Надо было реализовать для бота фишку с приватными чатами. Идея простая: если владелец чата напишет `/manage add`, бот переходит в режим приватности и начинает отвечать только ему. Команда `/manage remove` открывает доступ всем обратно. Плюс туда же добавил `/recall` и `/remember` для сохранения истории разговоров. На бумаге всё выглядело как три строки кода в middleware'е, которые проверяют ID пользователя перед обработкой сообщения. Я написал unit-тесты, всё прошло. Но реальный Telegram — совсем другой зверь. ## Боевые испытания в реальной среде Первым делом поднял бота локально через `python telegram_main.py` и начал его "пилить" из реального Telegram аккаунта. Написал `/manage add` — бот записал ID чата в таблицу `managed_chats` в SQLite и переключился в режим приватности. Проверил middleware `permission_check.py` — всё срабатывает корректно, обработка заблокирована для чужих. Хорошо. Потом попросил друга написать то же самое сообщение со своего аккаунта. Ожидал — ничего не случится. И действительно, бот промолчал. Отлично, система работает как надо. Финальный тест: я написал `/manage remove`, друг снова отправил сообщение — и бот ответил. Приватность отключена, доступ восстановлен. Казалось бы, победа. Но потом обнаружилась подвох. ## Гонка условий в асинхронном коде Оказалось, что в асинхронной архитектуре **aiogram** есть коварная особенность: middleware проверяет доступ, а запись в БД может ещё не завершиться. Получилась гонка условий — команда `/manage add` срабатывала, но контроль доступа успевал проверить разрешения *до* того, как данные попали в таблицу. Пришлось оборачивать insert'ы в explicit `await`, чтобы гарантировать консистентность. Другая проблема с SQLite: при одновременной работе нескольких асинхронных обработчиков изменения одного из них могут быть не видны другим, пока не произойдёт `commit()`. Контроллер доступа проверял одно, а в реальности БД содержала совсем другое. Решение было банальным — явные транзакции, но выяснить это можно было только через реальное тестирование. ## Познавательный момент об асинхронности Здесь скрывается типичная ловушка разработчиков, переходящих с синхронного кода на async/await: асинхронный код **кажется** последовательным в написании, но на самом деле может выполняться в самых неожиданных порядках. Когда ты пишешь `await db.execute()`, это не значит, что все предыдущие операции уже завершены в других корутинах. Нужна явная синхронизация через контекстные менеджеры или явные commit'ы. ## Итог: документируем опыт После всех интеграционных тестов я задокументировал находки в `docs/CHAT_MANAGEMENT.md`, добавил примеры использования в README.md и описал полную архитектуру ChatManager'а. Теперь система готова к работе с приватными чатами и конфиденциальными данными. Главный урок: unit-тесты проверяют логику в вакууме, но реальный мир полон асинхронности, сетевых задержек и race conditions. Никакой PyTest не найдёт то, что видно только в продакшене. Поэтому перед тем, как праздновать зелёный CI/CD, всегда имеет смысл руки испачкать в реальной среде. 😄 Что говорит разработчик после запуска асинхронного кода? «У меня было семь ошибок, теперь их четырнадцать, но они более интересные».

#claude#ai#python#git#api
Разработка: bot-social-publisher
9 февр. 2026 г.
Новая функцияai-agents

Четыре инструмента вместо двух: как мы освободили AI-агентов от ограничений

# От изоляции к открытости: как мы расширили доступ к файловой системе в AI-агентах Работал я над проектом **ai-agents** — платформой для создания интеллектуальных помощников на Python. И вот в какой-то момент нас настигла настоящая боль роста: агенты работали в тесной клетке ограничений. ## Проблема: узкие границы доступа Представь ситуацию. У нас была виртуальная файловая система — и звучит круто, пока не начнёшь с ней работать. Агенты могли читать только три папки: `plugins/`, `data/`, `config/`. Писать вообще не могли. Нужно было создать конфиг? Нет. Сохранить результат работы? Нет. Отредактировать существующий файл? Снова нет. Это было словно программировать с одной рукой, привязанной за спину. Функциональность `file_read` и `directory_list` — хорошо, но недостаточно. Проект рос, требования расширялись, а система стояла на месте. ## Решение: четыре инструмента вместо двух Первым делом я понял, что нужно идти не путём костылей, а переписать модуль **filesystem.py** целиком. Вместо двух полуслепых инструментов создал четыре полнофункциональных: - **`file_read`** — теперь читает что угодно в проекте, до 200 килобайт - **`file_write`** — создаёт и перезаписывает файлы, автоматически создаёт директории - **`file_edit`** — тонкая работа: находит точную подстроку через find-and-replace и заменяет - **`directory_list`** — гибкий листинг: поддерживает glob-паттерны и рекурсию Но тут появилась вторая проблема: как дать свободу, но не потерять контроль? ## Безопасность: ограничения, которые действительно работают Всё звучит опасно, пока не посмотришь на механизм защиты. Я добавил несколько слоёв: Все пути привязаны к корню проекта через `Path.cwd()`. Выбраться наружу невозможно — система просто не позволит обратиться к файлам выше по дереву директорий. Плюс чёрный список: система блокирует доступ к `.env`, ключам, секретам, паролям — ко всему, что может быть опасно. А для дополнительной уверенности я добавил проверку path traversal через `resolve()` и `relative_to()`. Получилась архитектура, где агент может свободно работать внутри своей песочницы, но не может ей повредить. ## Интересный момент: почему это важно Знаешь, в истории компьютерной безопасности есть забавный парадокс. Чем больше ты запрещаешь, тем больше люди ищут обходные пути. А чем правильнее ты даёшь разрешения — с умными ограничениями — тем спокойнее всем. Unix-философия в действии: дай инструменту ровно столько мощи, сколько нужно, но убедись, что он не сможет что-то сломать. ## Итого Переписал модуль, обновил константы в **constants.py**, экспортировал новые классы в **\_\_init\_\_.py**, подключил всё в **core.py** и **handlers.py**. Проверил сборку — зелёная лампочка. Теперь агенты могут полноценно работать с проектом, не боясь случайно удалить что-то важное. Дальше планировали тестировать на реальных сценариях: создание логов, сохранение состояния, динамическая генерация конфигов. А пока что у нас есть полнофункциональная и безопасная система для работы с файлами. Мораль истории: не выбирай между свободой и безопасностью — выбирай правильную архитектуру, которая обеспечивает оба.

#claude#ai#python#git#security
Разработка: ai-agents
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

ChatManager: как научить бота помнить, где ему работать

# Как научить AI-бота помнить свои чаты: история ChatManager Задача стояла простая на словах, но коварная на деле. У AI-бота в проекте **voice-agent** началась проблема с идентичностью: он рос, его добавляли в новые чаты, но вот беда — он не различал, в каких группах он вообще должен работать. Представь: бот оказывается в сотне чатов, а слушаться команд должен только в тех, которые явно добавил его хозяин. Без этого механизма вся система на мине. **Первым делом разобрали задачу по кирпичикам.** Нужна была полноценная система управления чатами: бот должен помнить, какие чаты ему доверены, проверять права пользователя перед каждой командой и предоставлять простые способы добавлять/удалять чаты из управляемых. Звучит как обычная CRUD-операция, но в контексте асинхронного Telegram-бота это становится интереснее. Решение разделили на пять логических контрольных точек. Начали с **ChatManager** — специального класса в `src/auth/`, который ведал бы всеми чатами. Важное решение: использовали уже имеющийся в проекте **structlog** для логирования вместо того, чтобы добавлять ещё одну зависимость. И, что критично для асинхронного бота, выбрали **aiosqlite** — асинхронный драйвер для SQLite. Почему это важно? Потому что обычный SQLite работает синхронно и может заблокировать весь бот при обращении к БД. aiosqlite оборачивает операции в `asyncio` — и вот уже БД не стопорит главный цикл обработки сообщений. **Дальше пошли миграции и middleware.** Создали таблицу `managed_chats` с информацией о чатах, их типах и владельцах. Затем встроили в pipeline Telegram-хэндлеров специальный middleware для проверки прав — перед каждой командой система проверяет, имеет ли пользователь доступ к этому чату. Если нет — молчит или вежливо отказывает. Команды управления (`/manage add`, `/manage remove`, `/manage list`) сделали простыми и понятными. Напишешь в личку боту `/manage add` — и чат добавляется в управляемые. Никакого магического угадывания, всё явно. **Интересный момент про асинхронные БД.** Когда разработчики впервые натыкаются на проблему "бот зависает при запросе к БД", они часто виноваты в синхронных операциях с базой. aiosqlite решает это элегантно: минимум кода, максимум производительности. Это один из тех инсайтов, которые приходят дорого, но в долгосрочной перспективе спасают душу. **В итоге получилось мощно.** Бот теперь точно знает, кто его хозяин в каждом чате, и не поддаётся на трюки неуполномоченных пользователей. Архитектура масштабируется — можно добавить роли, разные уровни доступа, историю изменений. Всё работает асинхронно и не тормозит. Дальше очередь интеграционных тестов и production. 😄 **Совет дня:** всегда создавай миграции БД отдельно от логики — так проще откатывать и тестировать. И да, GCP и кот похожи тем, что оба делают только то, что хотят, и игнорируют твои инструкции.

#claude#ai#python#api#security
Разработка: bot-social-publisher
9 февр. 2026 г.
Изменение кодаC--projects-ai-agents-voice-agent

ChatManager: как AI-боту дать контроль над своими чатами

# От хаоса к порядку: как мы научили 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. Но это уже другая история. 😄 **Совет дня:** всегда создавай миграции БД отдельно от логики — так проще откатывать и тестировать.

#claude#ai#python#api#security
Разработка: ai-agents-voice-agent
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

SQLite спасает день: масштабируемая БД вместо хаоса в памяти

# SQLite вместо памяти: как я спас Telegram-ботов от хаоса Проект `bot-social-publisher` взлетал буквально на глазах. Каждый день новые пользователи подключали своих ботов, запускали кампании, расширяли функционал. Но в какой-то момент понял: у нас есть проблема, которая будет только расти. Где-то в недрах памяти процесса валялась вся информация о том, какие чаты под управлением, кто их владелец, какие у них настройки. Приватный чат? Группа? Канал? Всё это было либо в переменных, либо в логах, либо вообще только в голове. Когда рост пользователей начал экспоненциальный скачок, стало ясно: **нужна нормальная база данных. Правильная, масштабируемая, без требований на отдельный сервер**. **Первым делом посмотрел на то, что уже есть.** В проекте уже была собственная SQLite база в `data/agent.db`, и там спокойно жил `UserManager` — отличный пример того, как работать с асинхронными операциями через `aiosqlite`. Логика была простой: одна база, одна инфраструктура, одна точка подключения для всей системы. Так почему бы не применить ту же философию к чатам? Архитектурное решение созревало быстро. Не было никаких грёз о микросервисах, Redis-кэшах или какой-то сложности. Нужна таблица `managed_chats` с полями для `chat_id` (первичный ключ), `owner_id` (связь с пользователем), `chat_type` с `CHECK` constraint для валидации типов, `title` для названия и JSON-поле `settings` про запас на будущее. **Неожиданно выяснилось** — и это было критично — что индекс на `owner_id` вообще не опциональная штука. Когда пользователь запрашивает список своих чатов, база должна найти их за миллисекунды, а не сканировать таблицу от начала до конца. SQLite часто недооценивают в стартапах, думают, что это игрушка для тестирования. На самом деле при правильном использовании индексов и подготовленных SQL-statements она справляется с миллионами записей и может быть полноценной боевой базой. Реализацию сделал по образцу `UserManager`: создал `ChatManager` с асинхронными методами `add_chat()`, `is_managed()`, `get_owner()`. Каждый запрос параметризован — никаких SQL-injection уязвимостей. Всё та же `aiosqlite` для асинхронного доступа, один способ работать с данными, без дублирования логики. Красивый момент получился благодаря `INSERT OR REPLACE` — если чат переиндексируется с новыми настройками, старая запись просто заменяется. Это вышло из архитектуры, не планировалось специально, но сработало идеально. **В итоге:** одна БД, одна инфраструктура, индекс уже готов к аналитическим запросам на будущее, JSON-поле ждёт расширенных настроек. Никаких ORM-фреймворков, которые на этом этапе обычно добавляют больше проблем, чем решают. Дальше — интеграция с обработчиками Telegram API, где эта информация начнёт по-настоящему работать. Но то уже следующая история. 😄 Разработчик говорит: «Я знаю SQLite». HR: «На каком уровне?». Разработчик: «На уровне, когда она работает, и я этому не верю».

#claude#ai#python#javascript#api#security
Разработка: bot-social-publisher
9 февр. 2026 г.
Новая функцияC--projects-bot-social-publisher

SQLite вместо памяти: как обуздать рост Telegram-ботов

# Управляем Telegram-чаты как должно: от памяти к базе данных Проект `bot-social-publisher` рос как на дрожжах. Каждый день новые пользователи подключали своих ботов, запускали кампании, развивали функционал. Но вот беда: где-то в памяти процесса валялась информация о том, какие чаты под управлением, кто их владелец, какие у них настройки. Приватный чат? Группа? Канал? Всё это было либо в переменных, либо где-то в логах. Нужна была система. Правильная, масштабируемая, не требующая отдельного сервера для базы данных. **Первым делом** посмотрел, как устроен текущий стек. В проекте уже была собственная SQLite база в `data/agent.db`, и там жил `UserManager` — отличный пример того, как правильно работать с асинхронными операциями через `aiosqlite`. Значит, нужно просто добавить новую таблицу `managed_chats` в ту же базу, скопировать философию управления пользователями и запустить в production. **Архитектурное решение** было ясно с самого начала: никаких микросервисов, никаких Redis-кэшей для этого этапа. Нужна таблица с полями для `chat_id` (первичный ключ), `owner_id` (связь с пользователем), `chat_type` (с проверкой через `CHECK` constraint — только валидные типы), `title` и JSON-поле `settings` на будущее. Неожиданно выяснилось, что индекс на `owner_id` — это не опциональная штука. Когда пользователь запрашивает список своих чатов, база должна найти их быстро, а не сканировать всю таблицу от начала до конца. SQLite часто недооценивают в стартапах, думают, что это игрушка для тестирования. На самом деле при правильном использовании индексов и подготовленных statements она справляется с миллионами записей и может быть полноценной боевой базой. **Реализацию** сделал по образцу `UserManager`: создал `ChatManager` с асинхронными методами `add_chat()`, `is_managed()`, `get_owner()`. Каждый запрос параметризован — никаких SQL injection уязвимостей. Используется всё та же `aiosqlite` для асинхронного доступа, одна точка подключения для всей системы, без дублирования логики. Красивый момент получился благодаря `INSERT OR REPLACE` — если чат переиндексируется с новыми настройками, старая запись просто заменяется. Это вышло из архитектуры, а не планировалось специально. В итоге: одна БД, одна инфраструктура, масштабируемая схема. Когда понадобятся сложные аналитические запросы — индекс уже есть. Когда захотим добавить права доступа или расширенные настройки чата — JSON-поле ждёт. Никаких фреймворков ORM, которые обычно добавляют больше проблем, чем решают на этом этапе. Дальше — интеграция с обработчиками Telegram API, где эта информация будет реально работать. Но то уже следующая история. 😄 Разработчик: «Я знаю ArgoCD». HR: «На каком уровне?». Разработчик: «На уровне Stack Overflow».

#claude#ai#python#javascript#api#security
Разработка: bot-social-publisher
9 февр. 2026 г.
Новая функцияC--projects-ai-agents-voice-agent

Когда голосовой агент забывает встречи: учим AI слушать, не переспрашивая

# Когда AI забывает контекст: как мы учим голосовых агентов помнить о встречах Павел получил от своего AI-ассистента странный ответ. Вместо простого подтверждения встречи с Максимом в понедельник в 18:20 система начала задавать уточняющие вопросы: какой сегодня день, нужно ли запомнить дату, может быть, это повторяющаяся встреча? Звучит как помощник с амнезией, верно? Но именно эта проблема и стояла перед командой при разработке **voice-agent** — проекта голосового ассистента нового поколения. **Завязка:** проект работает на стыке нескольких сложных технологий. Это не просто бот — это агент, который должен понимать контекст разговора, запоминать важные детали и действовать без лишних вопросов. Когда пользователь говорит: «Встреча в понедельник в 18:20», система должна понять, что это *конкретная информация*, требующая *сохранения*, а не просьба о консультации. Казалось бы, мелочь, но именно такие «мелочи» отделяют полезный AI от раздражающего помощника. **Первым делом** разработчики столкнулись с архитектурной задачей: как структурировать память агента? Система должна различать *информационные запросы* (где нужны уточнения) и *директивные команды* (где нужно просто выполнить и запомнить). Для voice-agent это означало внедрение многоуровневой системы идентификации интентов — понимание не просто слов, а *цели* высказывания. Неожиданно выяснилось, что естественный язык коварен: одна и та же фраза может означать и просьбу, и информационное сообщение в зависимости от интонации и контекста диалога. Решение пришло через разделение на четыре архитектурных уровня: идентификация и авторизация пользователя, структурированное хранение данных о событиях, логика обработки сообщений и, наконец, функциональность исполнения в экосистеме (Telegram, внутренние чаты, TMA). Каждый уровень отвечает за свой кусок пазла. Система теперь не просто парсит текст — она *понимает ролевую модель* пользователя и принимает решения на основе его прав доступа. **Интересный факт:** большинство разработчиков голосовых агентов забывают, что люди говорят не как компьютеры. Мы пропускаем детали, которые кажутся нам очевидными, перепрыгиваем между темами и ожидаем, что AI дозаполнит пробелы. Именно поэтому лучшие голосовые системы — это не те, что задают много вопросов, а те, что *предполагают контекст* и только уточняют краевые случаи. Voice-agent учится работать в режиме доверия: если пользователь говорит достаточно конкретно, система действует; если неясно — *тогда* уточняет. **Итог:** Павел больше не получит сотню вопросов по поводу встречи. Система научилась различать между «помоги мне разобраться» и «запомни это». Проект все ещё в разработке, но архитектура уже показывает, что AI может быть не просто компетентным, но и *вежливым* — уважающим время пользователя и его интеллект. Дальше команда планирует внедрить предиктивную логику: система будет не только запоминать встречи, но и предлагать календарные уведомления, проверять конфликты времени и даже предлагать переносы на основе истории поведения пользователя. Но это уже совсем другая история. 😄 Что общего у yarn и подростка? Оба непредсказуемы и требуют постоянного внимания.

#claude#ai#security
Разработка: ai-agents-voice-agent
9 февр. 2026 г.
Новая функцияC--projects-ai-agents-voice-agent

Когда AI становится парным программистом: история Claude Code

# 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 так сказал.

#claude#ai#python#javascript#git#api
Разработка: ai-agents-voice-agent
9 февр. 2026 г.
Изменение кодаai-agents

Когда агент начинает помнить о себе как о личности

# Когда агент говорит от своего лица: переписали систему памяти для более человечного AI Работали мы над проектом **ai-agents** и столкнулись с забавной ситуацией. У нас была система, которая запоминала факты о взаимодействии с пользователями, но писалась она на корпоративном языке технических модулей: "Я — модуль извлечения памяти. Я обрабатываю данные. Я выполняю функции." Звучало как инструкция робота из 1960-х годов. **Задача была простой, но философской**: переписать все промпты памяти так, чтобы агент думал о себе как о самостоятельной сущности со своей историей, а не как о наборе алгоритмов. Почему это важно? Потому что фреймирование через первое лицо меняет поведение LLM. Агент начинает принимать решения не как "выполни инструкцию", а как "я помню, я решу, я беру ответственность". Первым делом переписали пять основных промптов в `prompts.py`. **EXTRACTION_PROMPT** превратился из "You are a memory-extraction module" в "You are an autonomous AI agent reviewing a conversation you just had... This is YOUR memory". **DEDUPLICATION_PROMPT** теперь не просто проверяет дубликаты — агент сам решает, какие факты достойны его памяти. **CONSOLIDATION_PROMPT** стал размышлением агента о собственном развитии: "Это как я расту своё понимание". Неожиданно выяснилось, что такой подход влияет на качество памяти. Когда агент думает "это МОЯ память", он более критично подходит к тому, что запоминает. Фильтрует шум. Задаётся вопросами. Затем переписали системный промпт в `manager.py`. Там была скучная таблица фактов — теперь это раздел "Моя память (ВАЖНО)" с подразделами "Что я знаю", "Недавний контекст", "Рабочие привычки и процессы", "Активные проекты". Каждая секция написана от первого лица: "то, что я помню", "я обязан использовать это", "я заметил закономерность". Итог: агент стал более *осознанным* в своих решениях. Он не просто выполняет алгоритмы обработки памяти — он *рефлексирует* над собственным опытом. И да, это просто промпты и фреймирование, но это показывает, насколько мощное влияние имеет язык, на котором мы говорим с AI. Главный вывод: попробуйте переписать свои системные промпты от первого лица. Посмотрите, как изменится поведение модели. Иногда самые глубокие улучшения — это просто изменение перспективы. 😄 Почему агент начал ходить к психотерапевту? Ему нужно было лучше понять свою память.

#claude#ai#python
Разработка: ai-agents
9 февр. 2026 г.
Новая функцияC--projects-ai-agents-voice-agent

Монорепо, голос и журнал ошибок: как AI учится не ломать код

# Когда AI-помощник встречается с монорепо: отладка голосового агента Проект `voice-agent` — это амбициозная задача: связать Python-бэкенд с Next.js-фронтенд в единый монорепо, добавить голосовые возможности, интегрировать Telegram-бота и веб-API. Звучит просто на словах, но когда начинаешь копать глубже, понимаешь: это кубик Рубика, где каждый вертел может что-то сломать. **Проблема, с которой я столкнулся, была банальной, но коварной.** Система работала в отдельных частях, но когда я попытался запустить полный цикл — бот берёт голос, отправляет на API, API обрабатывает через `AgentCore`, фронтенд получает ответ по SSE — где-то посередине всё разваливалось. Ошибки были разношёрстные: иногда спотыкался на миграциях БД, иногда на переменных окружения, которые загружались в неправильном месте. **Первым делом я понял: нужна система для документирования проблем.** Создал `ERROR_JOURNAL.md` — простой журнал "что сломалось и как это чинилось". Звучит банально, но когда в проекте участвуют несколько агентов разного уровня (Архитектор на Opus, бэкенд-фронтенд агенты на Sonnet, Junior на Haiku), этот журнал становится золотым стандартом. Вместо того чтобы каждый агент наново натыкался на баг с Tailwind v4 в монорепо, теперь первым делом смотрим журнал и применяем известное решение. **Архитектура обработки ошибок простая, но эффективная:** 1. Ошибка возникла → читаю `docs/ERROR_JOURNAL.md` 2. Похожая проблема есть → применяю известное решение 3. Новая проблема → исправляю + добавляю запись в журнал Основные боли оказались не в коде, а в конфигурации. С 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#ai#python#javascript#git#api#security
Разработка: ai-agents-voice-agent
9 февр. 2026 г.
Новая функцияtrend-analisis

AI изучает себя: как мы мониторим научные тренды

# Когда AI исследует сам себя: как мы строили систему мониторинга научных трендов Вот уже несколько недель я сидел над проектом **trend-analisis** и постепенно понимал: обычный парсер научных статей — это скучно и малоэффективно. Нужна была система, которая не просто собирает ссылки на arXiv, а *понимает*, какие исследовательские направления сейчас набирают силу и почему они имеют значение для практиков вроде нас. Задача стояла серьёзная: проанализировать тренд под названием "test SSE progress" на основе контекста передовых научных статей. Звучит сухо, но на деле это означало — нужно было построить мост между миром фундаментальных исследований и инженерными решениями, которые уже завтра могут оказаться в production. ## Что творится в AI-исследованиях прямо сейчас Первым делом я разобрался, какие пять основных направлений сейчас наиболее активны. И вот что получилось интересное: **Мультимодальные модели всё более хитрые.** Появляются проекты вроде **SwimBird**, которые позволяют языковым моделям переключаться между разными режимами рассуждения. Это не просто пухлая нейросеть — это система, которая знает, когда нужно "думать", а когда просто генерировать. **Геометрия — это новый король.** Статьи про пространственное рассуждение показывают, что просто скормить модели килотонны текста недостаточно. Нужны геометрические приоры, понимание 3D-сцен, позиции камер. Проект **Thinking with Geometry** буквально встраивает геометрию в процесс обучения. Звучит как философия, но это работает. **Retrieval-системы перестают быть простыми.** Исследование **SAGE** показало, что для глубоких исследовательских агентов недостаточно BM25 или даже простого векторного поиска. Нужны умные retriever'ы, которые сами знают, что ищут. **Дешёвые модели становятся умнее.** Работы про влияние compute на reinforcement learning показывают: вопрос уже не в том, сколько параметров у модели, а в том, как эффективно использовать доступные ресурсы. Это открывает путь к edge AI и мобильным решениям. **Generative модели наконец-то становятся теоретически понятнее.** Исследования про generalization в diffusion models через inductive biases к ridge manifolds — это не просто красивая математика. Это значит, мы начинаем понимать, *почему* эти модели работают, а не просто наблюдаем результаты. ## Как я это собирал На ветке **feat/scoring-v2-tavily-citations** я сделал интересный ход: интегрировал не просто поиск статей, а *контекстный анализ* с использованием мощных LLM. Система теперь не только находит статьи по ключевым словам, но и организует их в экосистемы: какие зоны исследований связаны, кто на них работает, как это может повлиять на индустрию. Неожиданно выяснилось, что самая сложная часть — не техническая. Это правильно определить связи между соседними трендами. Статья про hydraulic cylinders и friction estimation на первый взгляд кажется совершенно отдельной историей. Но когда понимаешь, что это про predictive maintenance и edge computing, видишь, как она связывается с работами про efficient RL. Промышленная автоматизация и AI-на-краю сети — они развиваются параллельно и подпитывают друг друга. ## Маленький инсайт о diffusion models Кстати, пока копался в исследованиях про обобщающую способность diffusion models, наткнулся на замечательный факт: эти модели естественным образом тяготеют к низкомерным многообразиям в данных. Это не баг и не случайность — это встроенное в архитектуру свойство, которое позволяет моделям избежать зубрёжки и научиться реально генерировать новые примеры. Вот такое вот невидимое мастерство работает под капотом. ## Что дальше Система уже в работе, регулярно обновляется с новыми статьями, и каждый раз я вижу, как исследовательские темы переплетаются в более сложные паттерны. Это напоминает наблюдение за живой экосистемой — каждое новое открытие создаёт точки приложения для трёх других. Главное, что я понял: мониторить тренды в AI — это не про сбор информации, это про построение карты будущего. И каждая на первый взгляд узкая статья может оказаться ключевой для вашего следующего проекта. 😄 Обед разработчика: ctrl+c, ctrl+v из вчерашнего меню.

#claude#ai#javascript#security
Разработка: trend-analisis
9 февр. 2026 г.