Архитектура ИИ-агентов | Как собрать своего бота

Разбираемся в ИИ-агентах: от архитектуры OpenClaw до деплоя в облако

Тирекс
Тирекс Самый зубастый автор
7 сентября 2026

Зачем ИИ-агентам миллионы строк кода, если их базовый цикл занимает 100 строк? Разбираем инженерную обвязку OpenClaw и Hermes, создаем кастомного Telegram-помощника на Node.js и запускаем его в облачной инфраструктуре.

Изображение записи

За последние полгода вышли сотни материалов об ИИ-агентах. Особенно много говорят про OpenClaw и Hermes. Я изучил, пожалуй, добрую половину из них, протестировал сам и хочу поделиться выводами.

Статью написал Арсений Помазков, Senior Software Engineer и автор канала Pomazkov.js.

Сначала у меня сложилось впечатление, что это очередной раздутый пузырь бездумного хайпа. Каждый второй обещает личного цифрового сотрудника, который сам разбирает почту, ведет задачи и работает на вас 24/7, пока вы спите. Но досматривая такие видео и дочитывая статьи до конца, я раз за разом задавался вопросом: а где конкретно агент поменял автору жизнь? В чем революция? И, судя, по обсуждениям в сети, я в этом недоумении не одинок.

Давайте признаем: полезных кейсов применения сейчас действительно немного, денег вся эта инфраструктура ест прилично, а половину демонстрируемых функций проще вызвать в обычном чате с ИИ. И это вполне валидные претензии к OpenClaw как к готовому продукту. Вот только рассматривать его исключительно как потребительский продукт — ошибка. Когда я это понял, мой взгляд на технологию кардинально изменился. Революция действительно произошла, но не там, где ее привыкли искать.

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

Эта идея уже проваливалась три года назад

Давайте вернемся в март 2023 года, когда появился прародитель OpenClaw — AutoGPT. Базовая схема была той же: цикл, регулярные обращения к нейросети, вызов внешних инструментов и решение задач по шагам. Проект тогда выстрелил, набрав более 100 000 звезд на GitHub за несколько недель, а следом за ним появился BabyAGI. Резонанс был огромным, хотя и не таким громким, как этой зимой.

Но почему же тогда все заглохло?

Главная причина крылась в возможностях самих ИИ-моделей. На тот момент флагманом была GPT-4, которая плохо удерживала длинные цепочки действий: она теряла контекст, повторялась, вызывала неподходящие инструменты и забывала конечную цель. Вся внешняя обвязка (код вокруг модели) была написана корректно, но системе не хватало достаточно умных «мозгов». В итоге AutoGPT окрестили бесполезным, и интерес к теме угас.

Качественный сдвиг произошел зимой 2026 года, когда сошлись сразу несколько факторов: к готовой обвязке добавились гораздо более продвинутые модели — Claude 4.5 (Opus и Sonnet), GPT-5.1, DeepSeek V3.2 и другие. Прежняя архитектура наконец раскрылась и начала доводить задачи до конца благодаря появлению тех самых новых «мозгов».

Однако узкое место не исчезло, а лишь сместилось. Теперь, когда модели научились справляться с длинными цепочками действий, на первый план вышли новые вызовы: интеграции, права доступа и стоимость инфраструктуры. Агенты все еще не могут платить, получать доступ к многим сервисам и безопасно работать с секретами.

Мне не нужно посылать агента смотреть погоду — я вполне могу сделать это сам, и выйдет даже быстрее. А вот задача «подобрать продукты в магазине по рецепту, оплатить их и оформить доставку» — это именно то, что хочется делегировать автоматическому помощнику. Но сейчас этот процесс вызывает много трудностей: веб-сайты магазинов не адаптированы под API-агентов, платежных шлюзов для ИИ не существует, а безопасная работа с секретами и авторизацией вызывает много вопросов.

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

Поэтому я предлагаю рассматривать OpenClaw или AutoGPT не как готовые продукты, а как инженерную обвязку — удобный фреймворк с циклами, памятью и интеграциями, построенный вокруг вызова ИИ. Революция в том, что появился новый способ соединить нейросеть с реальным миром и сделать его более автономным. Подобный подход будет становиться все популярнее с каждым обновлением моделей. Крупные IT-компании уже строят необходимую инфраструктуру, и именно нам, разработчикам, предстоит с этим работать: создавать специализированных агентов под узкие бизнес-задачи и проектировать среду для них.

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

Как работает ИИ-агент

Схема работы и логики базового цикла ИИ-агента.

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

Вход в цикл

Агент не запускается сам по себе. Чтобы запустить процесс, нужен внешний импульс. Это может быть сообщение пользователя в Telegram, сработавший по расписанию планировщик (cron), вебхук или любое другое событие, которое код умеет ловить.

Компоновка запроса

После срабатывания триггера система формирует первый запрос к модели. Он состоит из двух ключевых частей:

  1. Контекст: история переписки (если она есть), системный промт (правила поведения) и новые данные из триггера (например, текст входящего письма).
  2. Описание инструментов (tools): их названия, текстовое описание назначения на человеческом языке и схема ожидаемых параметров.

Запрос упаковывается в формат JSON и отправляется по API в нейросеть.

Ответ от ИИ

Модель анализирует запрос и возвращает ответ, также в формате JSON. В нем содержатся две основные сущности: текстовое сообщение для пользователя (например, «Изучаю логи сервера» или финальный ответ на задачу) и

указание на вызов конкретного инструмента с нужными параметрами (функции).

Также в ответе есть служебные поля (например, finish_reason), по которым система понимает текущий статус выполнения задачи.

Обработка ответа и вызов инструментов

Наша управляющая программа (диспетчер) принимает JSON от модели. Если модель решила вызвать инструмент, программа выполняет соответствующую функцию на локальной машине с переданными параметрами, фиксирует результат и добавляет его в историю диалога. Затем цикл повторяется: система снова компонует запрос к агенту, но теперь он видит и результат работы инструмента. С каждым шагом контекст удлиняется, и модель получает все больше фактов о проделанной работе.

Выход из цикла

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

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

Описание инструмента – тоже часть программирования.

Поясню, что имею в виду. Раньше, чтобы решить, выполнять сценарий А или Б, мы писали конструкцию if или else. Условие лежало в коде, мы придумывали его заранее и оно было жестким.

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

Рассмотрим пример из реального кода OpenClaw. Вот как выглядит описание инструмента планировщика задач:


      description: `Gateway scheduler: reminders, delayed self-wakeups,
loops, recurring work, event watchers.
Never exec sleep/poll as timer.`   // ← запрет обычным предложением

Фраза `Never exec sleep/poll as timer` («Никогда не используй sleep в качестве таймера») — это не проверка и не жесткое ограничение прав в коде, а текстовая инструкция. Она снижает вероятность неправильного выбора, но ничего не гарантирует на 100%. В том же файле далее содержится указание не переводить время в UTC и приводится пример корректного часового пояса. Описание инструмента здесь — это одновременно документация для модели и подсказка против типичной ошибки.

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

Как устроена память у агентов


В Hermes работа с памятью — это одна из главных фишек. Агент способен накапливать опыт и преобразовывать повторяющиеся действия в навыки. Память делится на три слоя:

  • Два локальных текстовых файла, которые агент подгружает при каждом запуске: один содержит информацию о проекте, другой — сведения о пользователе (его предпочтения, ToV общения).
  • База данных с архивом прошлых диалогов: модель не читает его целиком, но осуществляет по нему семантический поиск по мере необходимости.
  • Каталог навыков: успешные цепочки действий агент сохраняет в виде отдельных сценариев и использует их при решении похожих задач.

Откуда берется большая кодовая база

Если базовый цикл ИИ-агента можно уместить всего в сотню строк кода, то почему репозиторий OpenClaw содержит почти три миллиона?

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

В итоге перед нами не «скрытый второй интеллект», а большой объем обычной инженерной работы, появившийся в ходе множества итераций тестирования и ошибок.

OpenClaw VS. Hermes

Если внутри у них работает один и тот же цикл, то чем они тогда отличаются?

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

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

Откуда берется риск

В контекст модели попадает не только ваш запрос, но и любые внешние данные, которые агент прочитал из файла, веб-страницы или письма. Хотя в запросе эти данные четко разделены (команда пришла от пользователя, а текст — от инструмента), для LLM эта граница не будет совсем непреодолимой. Внешний текст, содержащий скрытые инструкции (так называемые атаки класса Prompt Injection), может повлиять на последующие действия модели.

Поэтому запускать агента в одной среде с конфиденциальными файлами, рабочими API-ключами или коммерческими проектами категорически не рекомендуется. Ниже мы разберем практический пример и покажем, как это работает.

Как создать своего ИИ агента

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

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

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

Промпт

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

Напиши ИИ-агента на Node.js. Чистый JS, ESM, без фреймворков и внешних
библиотек.

## Что собираем
Личный ассистент, упрощенный аналог OpenClaw, с которым я переписываюсь в телеграме. Это постоянно
работающий процесс: он непрерывно слушает мои сообщения и отвечает на них,
умеет сам выполнять задачи по расписанию (cron). Что делать в каждый
момент — решает модель, выбирая инструменты.

## Файлы
– tools.js — инструменты: их описания и реализации.
– agent.js — ядро: цикл и точка входа. Импортирует из tools.js только нужное.
– .env – файл с ключами, токенами и секретами

## Модель и настройки (.env)
К модели ходи по протоколу OpenAI: POST на {BASE_URL}/chat/completions.
Настройки — BASE_URL, API_KEY, MODEL и токены телеграма — агент подгружает из файла .env рядом с собой при старте (process.loadEnvFile() или простой парсер), а не из экспортированных переменных шелла.
Создай .env: внеси значения BASE_URL (https://api.selectel.ru/aig/v1) и MODEL (deepseek/deepseek-v4-flash-0731), секреты (API_KEY, TELEGRAM_TOKEN) оставь пустыми. Поле TELEGRAM_CHAT_ID тоже оставь пустым – агент впишет его сам.

## tools.js — инструменты и диспетчер
1. TOOLS — массив описаний инструментов. У каждого: имя, описание обычным
   текстом и параметры в JSON Schema. Инструменты:
   - search_web(query) — ищет в вебе, возвращает заголовки и ссылки
   - fetch_url(url) — скачивает текст страницы, чтобы прочитать ее целиком
   - remember(note) — дописывает заметку в файл notes.md
   - schedule(cron, task) — ставит себе периодическую задачу в cron (реальная запись, а не строка в файле), которая запускает этого же агента
   - list_schedules() — показывает уже поставленные периодические задачи из cron
  (расписание + текст задачи), чтобы видеть, что запланировано
   - unschedule(task) — удаляет ранее поставленную задачу из cron по её тексту
  (чтобы не плодить дубли)


2. execute(name, args) — диспетчер: по имени находит нужную функцию и
   запускает её. Ошибку инструмента возвращает модели текстом, не роняя
   весь процесс.

## agent.js — цикл и запуск
3. loop(task) — цикл. Отправляем модели историю сообщений и описания
   инструментов. Если пришла просьба вызвать инструмент — выполняем через
   execute, результат дописываем в историю, повторяем. Если просьб больше
   нет — выходим и возвращаем этот текст: он и есть ответ пользователю
   (отдельного инструмента отправки у модели нет, доставляет его main).
   Пустой или обрезанный ответ без вызовов финалом не считается — это
   ошибка, пустоту не отправляем. Ограничь число кругов — не больше 25
   проходок, чтобы цикл не крутился вечно.

4. main() — берёт задачу одним из двух способов: из аргумента командной
   строки (так её запускает cron) или из нового сообщения в телеграме.
   В режиме телеграма main() не завершается после одного сообщения, а
   работает постоянно: в цикле ждёт новые сообщения (long polling) и
   обрабатывает их по мере прихода, пока процесс не остановят вручную.
   В режиме cron (задача пришла аргументом) — наоборот, выполняет одну
   задачу и выходит. Отвечает агент только своему владельцу, но ID вручную не
   вписываем: при первом входящем сообщении, если TELEGRAM_CHAT_ID в .env
   пуст, агент запоминает chat_id отправителя, дописывает его в .env и
   дальше работает только с ним, а сообщения с любого другого chat_id молча
   игнорирует. Этот же сохранённый chat_id — адрес, куда слать ответ, когда
   задачу приносит cron (там входящего сообщения нет). Перед стартом читает
   notes.md и кладёт заметки в контекст. Финальный текст цикла отправляет
   мне в телеграм.

## Системный промпт
Ты мой личный ассистент с инструментами: выполняй задачу, учитывай мои
заметки из notes.md, когда всё сделано — ответь текстом без вызовов.
В начало подставляй текущие дату и время сервера, чтобы у «сегодня» и
«сейчас» было верное значение. Для всего, что зависит от актуальности, опирайся на
результаты инструментов, а не на собственные знания: чего нет в свежих
данных — не выдумывай, если данных нет, скажи, что не нашёл.
Ответы уходят в телеграм, где markdown не отображается, — пиши простым
текстом без разметки (никаких ****, ##, [текст](url), обратных
кавычек): заголовки — обычной строкой с эмодзи, пункты — через тире или
эмодзи, ссылки — голым URL (телеграм сам сделает их кликабельными).

## Обвязка и стиль
Минимальная, с базовой подстраховкой:
- на сетевых вызовах таймаут и пара повторов с паузой на временные сбои
  (проблемы с сетью, таймаут, 429, 5xx) — и для модели, и для инструментов;
- длинные сообщения в телеграм режь под лимит;
- телеграм читай по offset, чтобы одно сообщение не обработать дважды.
Каждый инструмент — минимальная рабочая реализация: где можно, публичные
API без ключей. Без лишних абстракций и слоёв. Пиши компактно, но читаемо.
В ключевых местах оставь комментарии по-русски.

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

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

Запускаем промт в ИИ-ассистенте и, пока пишется код, получим необходимые доступы. Но сначала здесь нужно сделать важное уточнение.

Никогда не публикуйте файлы .env или файлы конфигурации с реальными ключами в публичные репозитории на GitHub или другие платформы. Всегда добавляйте .env в .gitignore вашего проекта. Если вам необходимо развернуть приложение в продакшене, используйте переменные окружения сервера или специализированные менеджеры секретов. Обратите внимание: все API-ключи и токены, используемые далее в примерах кода и на скриншотах, приведены исключительно в демонстрационных целях и на момент публикации этой статьи полностью аннулированы. В коде мы будем использовать безопасные заглушки в формате YOUR_API_KEY и YOUR_TELEGRAM_TOKEN.

Вот теперь точно можно получать данные. С токеном для бота в Telegram все достаточно просто, его получаем от BotFather.

Далее API-ключ. В качестве провайдера для подключения к ИИ я буду использовать Selectel: у них запущен удобный ИИ-роутер, который позволяет обращаться к моделям DeepSeek, OpenAI, Anthropic и другим через единый интерфейс. Регистрируемся в панели управления Selectel, переходим в раздел ИИ-роутер, нажимаем Создать ИИ-роутер и копируем полученный API-ключ. Обязательно сохраните его, и желательно не на стикере, а в надежном месте, например защищенном менеджере паролей.

Окно создания ИИ-роутера с сгенерированным API-ключом.

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

Файл agent.js

Основная логика ядра — это функция цикла loop:


      export async function loop(task, notes = '') {
  const messages = [
    { role: 'system', content: systemPrompt(notes) },
    { role: 'user', content: task },
  ]; // Собираем историю сообщений
  const tools = TOOLS.map((t) => ({
    type: 'function',
    function: { name: t.name, description: t.description, parameters: t.parameters },
  })); // Формируем массив инструментов с названием + описанием + параметрами каждого, но БЕЗ самого кода

  for (let round = 0; round < MAX_ROUNDS; round++) {
    const data = await callModel(messages, tools); // Обращаемся к ИИ
    const choice = data.choices?.[0] || {};
    const msg = choice.message || {}; // Разбираем ответ от ИИ
    messages.push(msg); // Ответ ИИ всегда кладём в историю

    // Далее развилка: если есть указание вызвать инструменты — выполняем и продолжаем круг.
    if (msg.tool_calls?.length) {
      for (const tc of msg.tool_calls) {
        let args = {};
        try { args = JSON.parse(tc.function.arguments || '{}'); } catch { /* ничего не делаем */ }
        const result = await execute(tc.function.name, args);
        messages.push({ role: 'tool', tool_call_id: tc.id, content: String(result) });
      }
      continue;
    }

    // Если указаний нет — это кандидат на выход из цикла.
    const text = (msg.content || '').trim();
    // Пустой или обрезанный ответ финалом не считаем — просим завершить.
    if (!text || choice.finish_reason === 'length') {
      messages.push({ role: 'user', content: 'Ответ пустой или обрезан. Заверши задачу и дай полный текстовый ответ.' });
      continue;
    }
    return text; // Это и есть ответ пользователю
  }
  throw new Error('Достигнут лимит кругов без финального ответа'); // Защита на случай, если модель уйдет в бесконечный цикл. У нас это 25 циклов, но для сложных задач этого будет недостаточно и придется поднимать, опираясь на метод проб и ошибок.
}

Кстати, сам этот цикл можно теперь даже не писать руками — Anthropic выложила его готовой библиотекой Claude Agent SDK. Но я все равно попросил ИИ написать цикл самостоятельно, чтобы вы увидели, что находится внутри.

Помимо цикла в agent.js содержатся:

  • импорты инструментов (tools);
  • код загрузки конфигурации из .env;
  • системный промт;
  • функция вызова API ИИ-роутера;
  • интеграция с Telegram (получение обновлений, отправка ответов, user ID);
  • функция main(), запускающая бота в режиме ожидания сообщений или выполнения cron-задачи.

Файл tools.js

В этом файле находится логика работы инструментов и диспетчер вызовов. Функция-диспетчер execute сопоставляет текстовое имя инструмента с реальной JS-функцией:


      // execute находит инструмент по имени и запускает его
export async function execute(name, args) {
  const fn = IMPL[name];
  if (!fn) return `Неизвестный инструмент: ${name}`; // Если инструмента нет, возвращаем соответствующую ошибку в ИИ
  try {
    return await fn(args || {});
  } catch (e) {
    return `Ошибка инструмента ${name}: ${e.message}`; // Если вызов не удался, также сообщаем об этом ИИ
  }
}

А вот пример реализации инструмента fetch_url, который загружает веб-страницу и очищает ее от лишнего HTML-мусора для экономии токенов:


      async function fetch_url({ url }) {
  const res = await fetchWithRetry(url, { headers: { 'user-agent': 'Mozilla/5.0' } }); // Запрашиваем данные страницы
  const html = await res.text(); // Превращаем ответ в обычный текст
  const text = html
    .replace(/<script[\s\S]*?/gi, ' ')
    .replace(/<style[\s\S]*?/gi, ' ')
    .replace(/]+>/g, ' '); // Удаляем скрипты
  return decode(text).replace(/\s+/g, ' ').trim().slice(0, 4000); // Приводим страницу к чистому компактному тексту и обрезаем до разумного размера, чтобы не раздувать контекст и не жечь токены
}

Файл .env

Заполняем файл конфигурации секретами, подставляя ранее полученные токены:


      BASE_URL=https://api.selectel.ru/aig/v1
MODEL=deepseek/deepseek-v4-flash-0731
API_KEY=YOUR_API_KEY
TELEGRAM_TOKEN=YOUR_TELEGRAM_TOKEN

TELEGRAM_CHAT_ID=

Если используете другого ИИ провайдера или модель, укажите это сразу в промпте, и тогда данные в BASE_URL и MODEL уже не придется менять. TELEGRAM_CHAT_ID оставляем пустым, он будет добавлен самим агентом, когда мы впервые ему напишем.

Для локального тестирования запускаем бота командой:


      node agent.js

В терминале отобразится сообщение Слушаю Telegram…, указывающее на успешный запуск. Отправляем тестовый запрос в чат — бот отвечает без задержек.

Приветственный ответ Telegram-бота с перечнем доступных функций.

Развертывание ИИ-агента на сервере

У агента есть доступ к моим файлам, он может выходить в интернет и умеет коммуницировать в Telegram. И теперь работать он должен без моего надзора (иначе какой смысл в новостной сводке к семи утра). Держать агента запущенным на рабочем ноутбуке, мягко скажем, нецелесообразно. Во-первых, компьютер должен быть всегда включен, а во-вторых, запускать агента с доступом к файловой системе рядом с вашими конфиденциальными рабочими файлами, ключами и паролями — это серьезный риск информационной безопасности.

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

Настройка сервера

Для развертывания создадим облачный сервер в панели управления Selectel.

Чтобы зарегистрироваться или войти в панель управления, переходим на my.selectel.ru. Выбираем Продукты, открываем раздел Облачные серверы в верхней панели, и затем в панели справа нажимаем Создать сервер и задаем его параметры:

  • Имя сервера: ai-agent
  • Регион: Санкт-Петербург
  • Пул: ru-3b
  • Источник: любой дистрибутив Linux — Ubuntu, Debian, CentOS, Fedora и другие. В нашем случае — Ubuntu 22.04 LTS 64-bit
  • Конфигурация: В зависимости от ваших требований можно выбрать целое ядро (Standard Line) или воспользоваться тарифом Shared Line. Shared Line — выгодное решение для небольших скриптов: вы арендуете долю ядра (например, 10%, 20% или 50%) и платите только за фактически потребляемые ресурсы, что обходится значительно дешевле. При этом, если получится так, что на сервере нет других арендаторов, все 100% мощности сервера переходят нам без доплат. Сейчас рассмотрим вариант с арендой целого сервера с процессором 1vCPU 1 ГБ RAM и базовым SSD на 5 ГБ.

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

Опция выбора прерываемого виртуального сервера в панели Selectel.

В рамках этого руководства мы не будем настраивать SSH-ключ — просто скопируем сгенерированный пароль и нажмем кнопку Создать сервер.

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

Заморозка полезна, если нужно временно остановить сервер, чтобы не переплачивать за простой, но при этом сохранить все данные. В таком режиме вы платите только за диски и публичные IP-адреса. В любой момент сервер можно разморозить, и вам не придется настраивать виртуальную машину заново.

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

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

Подключение к серверу

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

Вкладка «Порты» в панели Selectel с публичным IP-адресом сервера.

Откроем терминал на macOS/Linux или командную строку на Windows и введем команду подключения в формате ssh root@<IP-адрес>.


      ssh root@178.72.165.128

При первом подключении SSH-клиент спросит, доверяете ли вы этому серверу, так как его ключ еще не сохранен на вашем компьютере. Введем yes, и при следующих подключениях этот вопрос уже не появится. 

Первое SSH-подключение к облачному серверу через терминал.

Далее введем скопированный ранее пароль. Подключение установлено, видим такой результат:

Успешное подключение к серверу по SSH и приветствие Ubuntu.

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

Развертывание и запуск агента

Подготавливаем среду выполнения одной командой в консоли сервера:


      apt update &amp;&amp; apt upgrade -y &amp;&amp; curl -fsSL https://deb.nodesource.com/setup_22.x | bash - &amp;&amp; apt install -y nodejs

Эта команда обновит пакетную базу, подключит официальный репозиторий Node.js 22-й версии и установит ее на сервер.

На данном этапе мы будем работать под пользователем root. Это самый быстрый путь для настройки прототипа, однако помните, что root обладает неограниченными правами в системе. Для сервера, где кроме этого бота ничего нет, это осознанный компромисс. Про альтернативу скажу чуть позже.

Теперь перенесем файлы проекта с локального компьютера на удаленный сервер. Открываем новый терминал на локальной машине и выполняем команду scp (замените IP-адрес на адрес вашего облачного сервера):


      scp -r /Users/arseniypomazkov/Desktop/custom-agent-6 root@178.72.165.128:~/
Копирование файлов проекта с локального компьютера на сервер через scp.

Команда скопирует всю директорию custom-agent-6 в домашний каталог пользователя root на сервере.

Проверяем появление папки на сервере:


      root@ai-agent:~# ls
custom-agent-6 ← папка появилась

Далее заходим в папку и запускаем агента, два действия одной командой:


      cd ~/custom-agent-6 &amp;&amp; node agent.js

В консоли должна появиться знакомая строка: Слушаю Telegram.


      root@ai-agent:~/custom-agent-6# node agent.js
Слушаю телеграм…

Настало время настроить утренний дайджест. Отправляем нашему Telegram-боту подробную инструкцию:

Каждое утро в 7 утра по Москве я хочу получать самые актуальные новости из мира ИИ за за последние сутки. Меня интересуют только те новости, которые произошли за последние 24 часа и которые важны для индустрии и для меня как для разработчика. Мне неинтересно получать новости о каких-то минорных запусках open-source моделей, релизах на Hugging Face или иных вещах, которые мало обсуждаются или мало влияют на индустрию. Важны новости, которые связаны с ИИ, его интеграцией в какие-то новые сферы, с выпуском frontier моделей, инструментов, технологий, самых громких новостях о ИИ-стартапах.
Реализуй этот workflow и протестируй его сейчас.

Настройка cron-задачи и тестовый запуск утреннего дайджеста новостей.

Агент успешно принимает задачу, регистрирует периодическое задание в cron сервера и сразу же присылает тестовый дайджест. Все инструменты, включая поиск в сети и чтение веб-страниц, отработали корректно. Проверим поиск дополнительной информации: 

Уточнение деталей по запросу пользователя через поиск информации в сети.

Также без ошибок. Комбинацией Ctrl + C остановим процесс node, он был нужен нам для теста.

Осталось сделать так, чтобы агент работал в фоновом режиме и автоматически перезапускался при сбоях или перезагрузке сервера. Для этого настроем системную службу с помощью менеджера служб systemd.

Создаем файл конфигурации службы:


      nano /etc/systemd/system/agent.service

После этой команды будет создан файл и автоматически откроется редактор nano, вставляем туда следующие строки:


      [Unit]
Description=News agent
After=network.target

[Service]
WorkingDirectory=/root/custom-agent-6
ExecStart=/usr/bin/node /root/custom-agent-6/agent.js
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

Сохраняем файл (нажав Ctrl+X, затем Y и Enter) и активируем службу:


      systemctl daemon-reload &amp;&amp; systemctl enable --now agent

Проверить статус работы службы вы можете стандартной командой:


      systemctl status agent
Проверка статуса службы systemd с активным состоянием агента.

Если вы видите в выводе зеленый маркер active (running), значит, все настроили верно. Теперь можно смело закрывать терминал — бот продолжит работу в фоне и пришлет свежие новости точно к утреннему кофе.

Идеи для самостоятельного развития

В качестве практики попробуйте расширить функциональность вашего агента самостоятельно:

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

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