За последние полгода вышли сотни материалов об ИИ-агентах. Особенно много говорят про 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), вебхук или любое другое событие, которое код умеет ловить.
Компоновка запроса
После срабатывания триггера система формирует первый запрос к модели. Он состоит из двух ключевых частей:
- Контекст: история переписки (если она есть), системный промт (правила поведения) и новые данные из триггера (например, текст входящего письма).
- Описание инструментов (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-ключ. Обязательно сохраните его, и желательно не на стикере, а в надежном месте, например защищенном менеджере паролей.

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

В рамках этого руководства мы не будем настраивать SSH-ключ — просто скопируем сгенерированный пароль и нажмем кнопку Создать сервер.
После создания сервера откроется страница с его параметрами. Здесь доступны вкладки управления, а также настройки, с помощью которых можно выключить или заморозить сервер.
Заморозка полезна, если нужно временно остановить сервер, чтобы не переплачивать за простой, но при этом сохранить все данные. В таком режиме вы платите только за диски и публичные IP-адреса. В любой момент сервер можно разморозить, и вам не придется настраивать виртуальную машину заново.
На панели также доступны кнопки перезагрузки и другие опции управления. Еще одно преимущество облака: в любой момент можно изменить конфигурацию, добавив или уменьшив ресурсы. Это займет всего пару минут, так как система автоматически мигрирует на другой хост.
Если вы решите расширить свой проект, в Selectel можно создать полноценную инфраструктуру благодаря экосистеме сервисов – например, развернуть облачные базы данных, кластеры Kubernetes, подключить объектное хранилище, сеть доставки контента и многое другое в рамках одного провайдера.
Подключение к серверу
Чтобы подключиться к серверу из терминала на локальном компьютере, перейдем во вкладку Порты и скопируем публичный IP-адрес — он нужен для подключения к серверу из терминала на нашем компьютере.

Откроем терминал на macOS/Linux или командную строку на Windows и введем команду подключения в формате ssh root@<IP-адрес>.
ssh root@178.72.165.128
При первом подключении SSH-клиент спросит, доверяете ли вы этому серверу, так как его ключ еще не сохранен на вашем компьютере. Введем yes, и при следующих подключениях этот вопрос уже не появится.

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

Пользоваться сервером можно практически сразу благодаря автоматической установке операционной системы — вы получаете готовую и настроенную среду.
Развертывание и запуск агента
Подготавливаем среду выполнения одной командой в консоли сервера:
apt update && apt upgrade -y && curl -fsSL https://deb.nodesource.com/setup_22.x | bash - && apt install -y nodejs
Эта команда обновит пакетную базу, подключит официальный репозиторий Node.js 22-й версии и установит ее на сервер.
На данном этапе мы будем работать под пользователем root. Это самый быстрый путь для настройки прототипа, однако помните, что root обладает неограниченными правами в системе. Для сервера, где кроме этого бота ничего нет, это осознанный компромисс. Про альтернативу скажу чуть позже.
Теперь перенесем файлы проекта с локального компьютера на удаленный сервер. Открываем новый терминал на локальной машине и выполняем команду scp (замените IP-адрес на адрес вашего облачного сервера):
scp -r /Users/arseniypomazkov/Desktop/custom-agent-6 root@178.72.165.128:~/

Команда скопирует всю директорию custom-agent-6 в домашний каталог пользователя root на сервере.
Проверяем появление папки на сервере:
root@ai-agent:~# ls
custom-agent-6 ← папка появилась
Далее заходим в папку и запускаем агента, два действия одной командой:
cd ~/custom-agent-6 && node agent.js
В консоли должна появиться знакомая строка: Слушаю Telegram.
root@ai-agent:~/custom-agent-6# node agent.js
Слушаю телеграм…
Настало время настроить утренний дайджест. Отправляем нашему Telegram-боту подробную инструкцию:
Каждое утро в 7 утра по Москве я хочу получать самые актуальные новости из мира ИИ за за последние сутки. Меня интересуют только те новости, которые произошли за последние 24 часа и которые важны для индустрии и для меня как для разработчика. Мне неинтересно получать новости о каких-то минорных запусках open-source моделей, релизах на Hugging Face или иных вещах, которые мало обсуждаются или мало влияют на индустрию. Важны новости, которые связаны с ИИ, его интеграцией в какие-то новые сферы, с выпуском frontier моделей, инструментов, технологий, самых громких новостях о ИИ-стартапах.
Реализуй этот workflow и протестируй его сейчас.

Агент успешно принимает задачу, регистрирует периодическое задание в 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 && systemctl enable --now agent
Проверить статус работы службы вы можете стандартной командой:
systemctl status agent

Если вы видите в выводе зеленый маркер active (running), значит, все настроили верно. Теперь можно смело закрывать терминал — бот продолжит работу в фоне и пришлет свежие новости точно к утреннему кофе.
Идеи для самостоятельного развития
В качестве практики попробуйте расширить функциональность вашего агента самостоятельно:
- добавьте поддержку форматирования Markdown в Telegram (жирный шрифт, курсив, интерактивные гиперссылки);
- научите бота распознавать голосовые сообщения;
- создайте инструмент, позволяющий агенту безопасно редактировать собственные файлы конфигурации;
- спроектируйте более сложную систему долгосрочной памяти на базе векторной базы данных.
Главное преимущество этой концепции в том, что разработка строится вокруг создания удобной инфраструктуры и инструментов для ИИ. Не обязательно писать весь код вручную, но важно оставаться тем, кто направляет, контролирует и управляет архитектурой системы.