Newer
Older
AI_Lab_SCRUME_Co / skills / engineering / ai-data-perimeter / references / hermes-intercept.md

Принуждение на исходящем запросе в Hermes

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

Точки перехвата

Плагин регистрирует middleware из register(ctx); вызовы применяются в рантайме, а не в промпте:

Точка Что получает Что может Где применяется
tool_request tool_name, args, original_args заменить аргументы инструмента или отказать до выполнения до проверок доступности, guardrails и approval
llm_request request (полные kwargs провайдера, включая messages/input), original_request заменить запрос целиком; исключение прерывает вызов agent/turn_api_request.py → apply_llm_request_middleware
llm_execution request, next_call обернуть или заменить сам вызов провайдера вокруг исполнения

Порядок на каждый запрос: собрать kwargs → llm_request → наблюдатели pre_api_request → llm_execution → post_api_request. Регистрация: ctx.register_middleware("llm_request", fn) в hermes_cli/plugins.py.

Практический вывод: hooks/ — это наблюдатели, они ничего не меняют. Пустой hooks/ не означает «принуждения быть не может»; смотреть надо на зарегистрированные middleware (включённые плагины в config.yaml).

Три точки = три задачи

Точка Задача
tool_request на read_file, DOCX/PDF-парсер, OCR определить тип документа (имя файла, титул, штамп), сверить с ролью пользователя, поставить метку категории в сессии; при запрете — отказ до чтения, содержимое в модель не попадает
llm_request замаскировать по правилам категории из метки и записать строку в журнал
llm_execution вернуть реальные значения в ответе — иначе модель отвечает про [РОЛ_01] и ответ бесполезен

Категория — по типу документа и роли, не по шаблону

Шаблоны ПДн дают ложные срабатывания на техническом тексте: номера СП и ГОСТ, ИНН поставщика в спецификации, кадастровые в выписке. Поэтому решение принимается не по содержимому, а по типу документа (он известен до чтения) + роли пользователя. Шаблоны остаются подсказкой для автоклассификации; при сомнении тип подтверждает человек одним вопросом, ответ живёт в метке сессии — иначе одно и то же спрашивают десять раз за день и отвечают не глядя.

Политика — отдельный файл в профиле, правится без пересборки:

Категория Кому Что входит Режим
🟢 зелёный всем открытые нормативы, методики, обезличенные тексты без маски
🟡 жёлтый всем ТЗ, реестры замечаний, переписка, локальные сметы, ВОР маска + журнал
🔴 красный только выделенная роль (отдельная учётка) договоры, сводные сметы, акты, ИД, кадры, финансы остальным — отказ с подсказкой, к кому идти

Два ограничения, которые нельзя размывать:

  1. Роль не даёт права отправить красное в облако. Красное в облако не идёт никому; роль разрешает открыть документ агенту (например, чтобы снять структуру и сделать обезличенную выписку), но не отправку самого документа. Иначе светофор противоречит сам себе, и первый же вопрос «а почему им можно?» его ломает.
  2. Роль вешается на учётку, а не на флаг в текущем профиле. Переключатель в том же профиле сотрудник поставит себе сам, и контроль фиктивный.

Маскировать красное и отправлять нельзя: у договора маска убивает предмет — стороны, суммы, особые условия. Единственный корректный ответ для красного — не пускать.

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

Роли берутся из таблицы учёток организации (той же, где логины и лимиты), а policy.yaml генерируется из неё скриптом. Руками политику не править: два источника правды разъедутся на первой же кадровой замене, и узнается об этом на инциденте.

  • Роль — машинный код (engineer / contracts / admin), а не перечисление задач. «инженер ОВиК, ТЗ, ТУ, СТУ, проекты» не парсится и у каждого записано по-своему; человекочитаемое описание держать отдельной колонкой рядом с кодом.
  • root политику не обходит. Учётка со статусом root проходит те же проверки; отличие — только пометка admin в журнале. Иначе достаточно попросить root, и контроль отменён.
  • После записи перечитывать таблицу и сверять число строк и раскладку по ролям, а не только одну изменённую ячейку: пропущенная учётка = сотрудник без роли, и он либо блокирован, либо проходит как зелёный.

Порядок внедрения

  1. tool_request + политика + журнал в режиме «только запись»: ничего не маскируем, смотрим реальный поток и настраиваем правила.
  2. Включаем маску на жёлтом.
  3. Включаем демаскировку ответа (llm_execution).

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

Приёмка

  • Сотрудник без роли просит проверить договор → отказ до чтения, файл не открывается.
  • ТЗ у любого сотрудника → уходит маской, в журнале строка, ответ с реальными значениями.
  • 20 запросов без ПДн → ни одной маски и ни одной блокировки.
  • В журнале: пользователь, тип документа, категория, сколько замен, модель, время.

Чего перехват не закрывает

  • Картинки (vision_analyze) и вложения не маскируются.
  • PDF-сканы без текстового слоя требуют OCR до маски.
  • Путь «человек скопировал в браузер мимо агента» закрывается только шлюзом или DLP на периметре. Плагин закрывает свой участок, а не периметр целиком.