← Лендинг Hermes Agent

Опубликовано

Профиль на проект: как перестать кричать на агента, что он опять натворил

Автор: Гусев Николай [портфолио]

Обновлено

Темы: hermes, profiles, skills, projects

Джилл кричит на кучу смятой одежды

Сложность: средняя

Ситуация, знакомая каждому, кто работает с агентом не первый месяц. Ты ставишь задачу, отходишь, возвращаешься, а агент за это время переименовал каталог, поменял настройки и применил не тот способ доступа. Начинаешь разбираться и понимаешь: он не ошибся. Он работал не с тем. Креды, модель, скиллы, привычки доступа - всё это были чужие, потому что у проекта не было ни своего профиля, ни своего проекта внутри него. Был один агент на всё, а значит, ни одно из решений не было его собственный.

Тезис

Один проект - один профиль агента. Всё, чего в этом профиле нет, для этого проекта чужое.

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

Главный риск - контаминация

Вот ради чего всё затевается. Не "удобнее", не "чище". Риск один, и он тихий.

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

Дальше начинается то, что выглядит как ошибка агента, но на самом деле ошибка архитектуры.

Способ доступа. Проект требует идти напрямую, а агент идёт через SOCKS5-прокси, потому что вчера через него ходил и получилось. Что он видит на выходе: обрывы TLS, несуществующие дефекты, завышенное время отклика. Я на этом ловил аудит внешнего сайта: пять из шести запросов "умирали", задержка первого байта 4131 мс, и всё это выглядело как блокер хостинга. Напрямую тот же сайт отдавал 20 запросов из 20 с кодом 200 и задержкой 0.16-0.25 с. В отчёте это потом стояло как вывод о нерабочем сайте, и вывод был ложным. Прокси не был дефектом. Прокси был привычкой из соседней задачи.

Сетевой контур. Проекту ходить без VPN, агент поднимает туннель - или наоборот, проект без VPN, а агент пускает всё через внешнюю ноду. Идёт, получает чужие ответы, другой IP в логах, другая картина, и выводы по позициям в поиске делаются не по тому региону, о котором ты спрашивал.

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

Способы управления. Один проект разворачивается через systemd, другой - через контейнеры, третий - ansible. Список команд в голове агента один, и он в общем профиле смешан. На проекте, где нужен один способ, он применяет другой - и получает отказ там, где всё должно было пройти.

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

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

Как это выглядит на практике

Изоляция двухуровневая. Профиль отвечает за роль и креды, проект внутри него - за содержание.

Схема выглядит так:

профиль (роль)
├── общие скиллы и инструменты
├── свои креды, своя модель
└── проекты
    ├── проект А
    │   ├── рабочая папка
    │   ├── HERMES.md: идея + правила
    │   └── свои наработки как сущности в базе знаний
    ├── проект Б
    │   ├── своя рабочая папка
    │   ├── свой HERMES.md
    │   └── свои наработки в базе знаний
    └── проект В
        └── ...

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

hermes project create "Название" C:\Work\projects\first --use
hermes project use "Название"       # переключиться на другой проект
hermes project add-folder "Название" C:\Work\projects\second
hermes project list

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

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

Содержание проекта живёт в трёх местах:

  1. Рабочие папки. Имя проекта связано с путём на диске, первая папка считается основной, остальные можно добавить. Агент не угадывает путь и не приносит путь из соседнего проекта.

  2. Файл HERMES.md в папке проекта. Он читается на старте сессии, и в нём две вещи: что мы делаем (идея, цель, что считается готовым) и как мы это делаем (правила, соглашения, что выполнять нельзя). Это контекстный файл с наивысшим приоритетом, и он загружается автоматически. Если папка внутри git-репозитория, Hermes читает такие файлы по всей цепочке от корня репозитория до текущей папки, причём более специфичные читаются последними, то есть имеют приоритет. Уровень вложенности даёт естественную иерархию правил.

Есть ещё один файл, который вы получаете бесплатно при создании проекта из карточки в приложении. Когда заполняете поле "О чём этот проект?" и жмёте создать, приложение само пишет этот текст в файл IDEA.md в основной папке проекта. Отдельная кнопка с кубиком умеет сгенерировать идею за вас. Удобно, но есть тонкость, о которой стоит знать: IDEA.md не контекстный файл. В официальном списке таких файлов его нет, агент не читает его в промпт сам и не знает, что файл существует, пока вы не попросите или он случайно не наткнётся. В командной строке у команды создания проекта вообще нет флага для идеи, только описание, так что файл появляется именно из карточки.

Отсюда практический вывод. Если идея и правила должны работать на автомате, кладите их в HERMES.md - он попадёт в промпт без всяких просьб. IDEA.md оставьте как запись о том, зачем проект вообще заведён, сверху от рабочих документов: он полезен человеку и пригодится, когда будете разбираться в старом проекте. Смешивать две сущности в одном файле не надо: правила должны быть там, где агент их видит без подсказки.

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

  2. Свои скиллы на уровне роли. Часть общих, часть узких, часть одноразовая - но лежит в том профиле, к которому относится. Скилл про рецепты промптов для картинки в профиле для пресейла - мусор, в профиле для рисования - второй рабочий инструмент. Между проектами одного профиля они и делятся: принадлежат роли, а не проекту.

  3. Свои доступы и модели на уровне роли. Файл .env профиля задаёт ключи, которыми пользуется этот агент, и больше нигде. И своя модель, потому что задачи разные и требования к модели тоже.

Вот как это выглядит на одной машине, где несколько проектов живут параллельно:

профиль              скиллов   задач по расписанию   модель
издание                120      6                     средний класс
инженерный             310      9                     средний класс
рисование               45      3                     бесплатная
дайджест новостей       38      4                     бесплатная
демо для вебинара        24      2                     локальная

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

Когда скиллы надо переносить, а когда не надо

Ключевой момент, который экономит больше всего нервов: ничего не нужно копировать, если скилл не про этот проект.

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

Что работает без молчаливых дублей - один каталог-хранилище общих скиллов и симлинки на нужное в каталоге скиллов профиля:

mklink /J %PROFILE%\skills\content\writer C:\Work\agents\shared-skills\content\writer

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

Два других пути, чем это решается:

/export, /import                    профиль целиком в архив, ключи вырезаются
                                    автоматически, получатель получает живого
                                    агента со всеми наработками
hermes profile install <git-url>    профиль как git-репозиторий с манифестом,
                                    обновление через hermes profile update,
                                    память и сессии получателя не трогаются

Разница принципиальная: экспорт - это разовая передача коллеге, установка из репозитория - это сопровождение агента как продукта, у которого есть версии.

Не всем проектам нужна самая дорогая модель

Модель - это параметр профиля, а не всего агента целиком, и профили этим пользуются. Задача, где агент пишет промпт и смотрит на картинку, отлично идёт на бесплатной модели. Разбор чужой архитектуры - уже другая история, там цена ошибки другая. А разница в цене умножается на объём: профиль, который гоняет сотни задач в день на дорогой модели, обходится в разы дороже профиля, который там же сидит на бесплатной и справляется.

Грабли, на которые я наступил

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

Флаг описания - это --text, а не --description. Второго не существует, команда падает.

Путь профиля - только строчные латинские буквы, цифры и дефис, пробелы не допускаются.

Создание проекта внутри профиля требует указания папки. Без пути команда не создаёт ничего, и проект потом не находится в списке.

Новый профиль не появляется в ростере, пока не перезагрузишь плагины в приложении.

Один профиль - один агент. Два процесса на одной папке профиля будут конфликтовать за память, и это прямое предупреждение в документации.

Файлы инструкций в папке проекта приоритетны, как и SOUL.md. Если рядом оказался чужой HERMES.md, он перебьёт привычные правила оформления текста. Файл личности в профиле тоже один на все проекты внутри, поэтому "личность, подстроенная под один проект" - это уже профиль под один проект, и тогда стоит завести отдельный.

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

Джилл перед гардеробом, где всё развешено и сложено по порядку

Итог

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

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

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

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