Дизайн: архитектура «семи агентов» лендинга на базе rodnik-hermes
Статус: проект архитектуры, без изменений в коде и конфигах. Дата: 2026-08-15. Вход: rodnik.bz/1/ (семь персон), rodnik-hermes (ARCHITECTURE.md, docs/profiles.md, docs/vision-hermes.md, docs/routine-catalog.md, паспорта soul/profiles/), rodnik-web (пайплайн, Assist::Suggest, prompt_templates, llm-биллинг). Внутренний документ — на trends не публикуется.
0. Принцип
Лендинг продаёт семь работ; система исполняет их четырьмя механизмами:
| Механизм | Что даёт | Цена |
|---|---|---|
| Профиль (HERMES_HOME: SOUL, config, ключи) | личность, свой периметр, своя модель | процесс + ~22.5k токенов SOUL на вызов |
| Канал (платформенный вход к gateway) | точка доступа | почти ноль |
| Рутина (cron: prompt / гибрид / no_agent) | работа по расписанию | по режиму |
| Карточка доски (assignee → воркер) | разовая работа под ревью | спавн Писаря |
Правило заведения профиля (из ревью ролей): другая модель, другой периметр доступа, другой класс входных данных или отдельный поток повторяемой работы. Ни одна из четырёх «новых» персон лендинга (Яна, Вера, Мирон, Игнат) этим критериям не отвечает — профили под них не заводятся. Персона — продуктовый ярлык поверх механизма, а не сущность.
Центральный новый объект дизайна — реестр персон (§2): таблица «персона → механизмы → метрика», которая делает лендинг честным (проценты атрибутируются) и не даёт продуктовой нарезке протечь в архитектуру.
1. Карта: персона → механизм
┌─ Себастьян = Telegram-канал (голос → STT gateway)
│
чат директора ──────────┤
Telegram ───────────────┴──► default (Sales Brain) ◄── рутины Яны/Веры/Мирона/Игната
│ (все кроны — в default-сторе,
│ board_card / per-profile cron, upstream #4707)
│ board_curate_now
▼
no_agent seed (nba_seed.sh)
│
▼
orchestrator (воркер) ──👤─► карточки человеку
│
🤖 (assignee=scribe)
▼
scribe (воркер) ──► черновик в карточку, на ревью
(брифы Яны, письма Веры,
фидбек Мирона — здесь)
отдельный контур: desktop ──► rodnik-web Assist::Suggest ──► realtime-гейтвей (Лина)
(envelope, AssistSession) быстрая модель, без тулов,
без памяти, свой bearer
фон (не персоны): rodnik-web pipeline (Whisper → normalize → sales_analysis →
classify → ingest OpenViking; amoCRM crm_summary) — детерминированный
код, производит сырьё для всех персон
01 · Яна — «брифер к каждому звонку»
Механизм: гибридная рутина в default + 🤖-карточки Писарю. Ежедневная крон-джоба режима «--script без --no-agent»: скрипт детерминированно собирает список сегодняшних звонков/встреч из CRM-проекции (crm_tasks / календарь amoCRM), stdout инжектится в промпт — агент ставит по 🤖-карточке «бриф к звонку <deal>» (идемпотентно brief-<deal_id>-<дата>), диспетчер спавнит Писаря на каждую. Бриф Писарь уже умеет (паспорт: «бриф к звонку — что известно, боли, возражения, цель, следующий шаг»; результат — в карточку, воркспейс scratch).
Почему не «каждому менеджеру по агенту»: бриф — это read-only компиляция CRM + viking_search, никакого своего периметра или модели не требует. Почему гибрид, а не prompt-джоба: список звонков — арифметика; тратить ~22.5k токенов SOUL на «выясни, какие сегодня звонки» — против урока nba_seed.sh.
Доставка: карточка на доске + утренняя сводка «готовы брифы: N» в чат менеджера (когда появится multi-user, см. §4) или РОПу.
02 · Лина — «суфлёр, который не молчит на „дорого“»
Механизм: профиль realtime на отдельном гейтвее — уже спроектирован и работает. Быстрая модель, без инструментов, без памяти, свой порт и свой bearer; речь клиента — враждебный вход, фенсится Context::Envelope со случайной меткой; память диалога живёт в Rails (AssistSession), не на гейтвее; [NO_RESP] — контракт молчания; промпт — prompt_type: assistant из /admin, единственный UNSEEDED-тип.
В дизайне ничего не меняется — Лина фиксируется как эталон «персона = профиль» и как единственная персона со своим SLA на латентность (см. §5).
03 · Вера — «тот, кто не даёт сделке остыть»
Механизм: детерминированный пайплайн + рутина дожима + 👤-карточки. Три части работы Веры уже разложены по правильным домам:
- - «карточка из разговора» — пайплайн rodnik-web:
sales_analysis→ amoCRMcrm_summary. Код, не LLM (правило ARCHITECTURE §7a: арифметика/реконсиляция — в recurring, рассуждение — в Hermes cron). Этос №6 соблюдён: в CRM пишет пайплайн-код по факту записи, не агент по своему решению. - - «обещание в задачу» — расширение рутины: извлечённые next steps из
sales_analysis→ 👤-карточки на доску (board_card, lane=human, идемпотентноpromise-<meeting_id>). Это дизайн-дельта: сегодня next steps лежат в разборе, на доску их поднимает Оркестратор косвенно. - - «фоллоуап вовремя» — рутина №5 каталога («Дожим стынущих сделок», вт/чт 10:00) + 🤖-карточки «черновик письма-реактивации» Писарю.
Вера — самая «распределённая» персона: код + рутина + две дорожки доски. Именно поэтому реестр персон (§2) обязателен — иначе её +7% нечем атрибутировать.
04 · Мирон — «уши РОПа на все звонки»
Механизм: пайплайн (100% покрытие) + рутина ротации + дашборды. «100% звонков разобраны» уже даёт пайплайн: каждый звонок проходит calls_analysis, каждая sales-встреча — sales_analysis; это свойство конвейера, не агента. Персона Мирона — надстройка осмысления: рутина №6 каталога («Качество звонков менеджера», среда, менеджеры по кругу, режим РОПа из SOUL) + выход report_publish в rodnik-report + 🤖-карточка «черновик обратной связи» Писарю.
Дизайн-дельта: к ротации добавить еженедельный агрегат «дыры в скрипте» (частотный срез красных флагов по всем звонкам недели → один дашборд) — это обещание лендинга «дыру в скрипте закрыть на этой неделе». Гибридная рутина: SQL-скрипт считает частоты, агент интерпретирует.
05 · Игнат — «методист, который учит систему»
Механизм: пакет из трёх существующих рутин каталога. №2 «Недельный разбор проигранных» (пт 17:00, причины + цитаты из транскриптов), №3 «Когорты won/lost за месяц» (1-е число, + 3 гипотезы с якорями), №7 «Свод возражений» (раз в 2 недели, objections/current.md). Сырьё уже оседает: objections_grouping, CohortDigest → cohorts/<status>/<week>.md в OpenViking.
«Учит систему» в буквальном смысле — компаундинг памяти (этос №7): выводы Игната ингестятся обратно в OpenViking и поднимаются всем остальным персонам через viking_search. Ничего нового заводить не надо — только собрать три рутины под один ярлык в реестре.
06 · Себастьян — «все данные продаж в кармане»
Механизм: канал, не личность. Telegram-бот тенанта — вход к default-гейтвею; голосовые перевариваются STT гейтвея (voice memo transcription — штатная возможность Hermes). Себастьян не имеет своей души, своей модели и своего процента — лендинг это честно оговаривает («доступ, не процент»).
Граница дизайна: пока Telegram-каналом пользуется только ком.директор, ничего не требуется. Как только доступ получают менеджеры — включается дизайн multi-user-brain (§4): OBO-токен в каждом tool-call, owner-RLS в Rails. Себастьян становится триггером этой работы, но не отдельным профилем.
07 · Родник — «второй мозг коммерческого»
Механизм: связка default + orchestrator + scribe — как есть. default (Sales Brain: этос семи статей, режим РОПа, конверт-контракт, навигация по мозгу) — собеседник и исполнитель всех рутин; orchestrator (паспорт «Оркестратор внимания»: 8–12 действий, деньги × риск, две дорожки, дедуп) — доска; scribe (паспорт «Писарь»: одна карточка, результат в карточку, наружу ничего) — руки. На лендинге вся тройка продаётся одним именем «Родник» — и это правильно: оркестратор и писарь — служебные роли, клиенту их видеть незачем.
2. Реестр персон — единственная новая сущность дизайна
Тонкий каталог в rodnik-web (концептуально — YAML/таблица, не новые процессы):
personas:
yana:
title: "Яна — брифер к каждому звонку"
mechanisms:
routines: [briefs-daily] # id крон-джоб в default-сторе
card_keys: ["brief-*"] # идемпотентные ключи карточек
metric: "звонков с брифом / всех звонков; конверсия таких звонков"
lina:
title: "Лина — суфлёр"
mechanisms: { profile: realtime, service: Assist::Suggest }
metric: "подсказок показано / принято; латентность p95"
vera:
mechanisms:
pipeline: [sales_analysis→crm_summary]
routines: [warm-deals] # №5 каталога
card_keys: ["promise-*", "warm-*"]
metric: "фоллоуапов вовремя; сделок, не остывших >7 дней"
miron:
mechanisms: { pipeline: [calls_analysis], routines: [qa-rotation, script-gaps] }
metric: "покрытие разбора 100%; закрытых дыр скрипта"
ignat:
mechanisms: { routines: [weekly-lost, monthly-cohorts, objections-refresh] }
metric: "гипотез выдано / принято; повторяемость причин lost"
sebastian:
mechanisms: { channel: telegram }
metric: "DAU канала; голосовых запросов"
rodnik:
mechanisms: { profiles: [default, orchestrator, scribe], board: true }
metric: "карточек закрыто (👤/🤖); гипотез проверено"
Что реестр даёт:
- 1. Атрибуция процентов. Каждый «+N%» лендинга привязывается к измеримому выходу конкретных рутин/карточек, а не к имени. Без этого пилот на 30 дней не доказуем.
- 2. Биллинг по персонам. Дизайн llm-billing уже ведёт учёт по virtual keys и фичам (
llm_usage_events, разрезы по фиче/ключу/модели/компании). Виртуальные ключи прокси выравниваются с персонами (<tenant>-assist= Лина,<tenant>-cron= рутины Яны/Веры/Мирона/Игната,<tenant>-chat= Родник/Себастьян) — и «токены пакетами» из прайса лендинга становятся строкой отчёта «сколько сжёг каждый сотрудник». - 3. UI «Команда». Вкладка в rodnik-web рендерит карточки персон из реестра: статус (рутины живы/на паузе — уже есть pause/resume в «Рутинах»), последний выход, расход токенов. Суточный контур лендинга («До звонка → На звонке → После → Качество → Система») — это просто группировка реестра по времени суток.
- 4. Защита архитектуры. Новая персона на лендинге = строка реестра, собранная из существующих механизмов. Требование «заведи персоне процесс» проверяется по критерию §0 — и почти всегда отклоняется.
Таблица персона → рутина
Развёртка реестра в плоский вид — то самое соответствие, без которого проценты лендинга не проверить в пилоте. «№» — номера болванок из routine-catalog; Д2/Д4 — дельты из §7; «код» — детерминированный пайплайн rodnik-web, не LLM.
| Персона | Вклад | Рутина / механизм | Расписание (МСК) | Режим | Выход |
|---|---|---|---|---|---|
| Яна | +4% | Брифы к сегодняшним звонкам (Д2) → 🤖-карточки brief-* Писарю | 07:30 будни | гибрид | брифы в карточках доски |
| Лина | +6% | Не рутина: realtime-контур Assist::Suggest (профиль realtime) | в момент разговора | профиль | подсказка на экране / [NO_RESP] |
| Вера | +7% | Карточка из разговора: sales_analysis → crm_summary в amoCRM | после каждой записи | код | сводка в сделке |
| Вера | ″ | Обещание в задачу: next steps → 👤-карточки promise-* (Д3) | после каждой записи | код + карточка | задача человеку |
| Вера | ″ | №5 «Дожим стынущих сделок» → карточки warm-* | вт, чт 10:00 | prompt | карточки + сводка в чат |
| Мирон | +5% | Разбор 100% звонков: calls_analysis / sales_analysis | каждый звонок/встреча | код | артефакт разбора |
| Мирон | ″ | №6 «Качество звонков менеджера» (ротация, режим РОПа) | ср 15:00 | prompt | дашборд + 🤖 «черновик фидбека» |
| Мирон | ″ | Агрегат «дыры в скрипте» за неделю (Д4) | еженедельно | гибрид | дашборд частот красных флагов |
| Игнат | +4% | №2 «Недельный разбор проигранных» | пт 17:00 | prompt | дашборд с цитатами |
| Игнат | ″ | №3 «Когорты won/lost за месяц» | 1-е число | prompt | дашборд + 3 гипотезы с якорями |
| Игнат | ″ | №7 «Свод возражений» → objections/current.md | раз в 2 недели | prompt | дашборд + обновление среза |
| Себастьян | доступ | Не рутина: Telegram-канал к default (голос → STT гейтвея) | по запросу | канал | ответ голосом/текстом |
| Родник | +4% | №1 «Утренний дайджест дня» | 08:30 будни | prompt | сводка в чат КД |
| Родник | ″ | №4 «Подготовка к планёрке» | пн 08:00 | prompt | дашборд + сводка |
| Родник | ″ | nba_seed.sh → seed Оркестратора → доска → Писарь | 07:00 пн-сб | no_agent | доска следующих действий |
| Родник | ″ | Чат КД + board_curate_now («обнови доску сейчас») | по запросу | чат | ответы, карточки |
Правило чтения: у персоны с процентом каждая строка — измеримый выход; вклад персоны в пилоте считается по сумме её строк, а не по впечатлению. Лина и Себастьян — единственные строки без крона: первая — профиль со своим SLA на латентность, второй — канал без собственного выхода.
3. Расписание суток (контур лендинга «как это выглядит за день»)
Все LLM-рутины — prompt/гибрид-джобы в default-сторе (единственный тикающий: cron per-profile by design, upstream #4707; bearer /api/jobs и вкладка «Рутины» видят только его). Времена — МСК, конвенция CronSchedule.
| Время | Персона | Джоба | Режим |
|---|---|---|---|
| 07:00 пн-сб | Родник | nba_seed.sh → seed Оркестратора | no_agent + script (есть) |
| 07:30 будни | Яна | брифы к сегодняшним звонкам → 🤖-карточки | гибрид (дизайн) |
| 08:00 пн | Родник | подготовка к планёрке (№4) | prompt (каталог) |
| 08:30 будни | Родник | утренний дайджест (№1) | prompt (каталог) |
| в течение дня | Лина | подсказки на живых разговорах | realtime-контур (есть) |
| после каждого звонка | Вера/Мирон | пайплайн: разбор, crm_summary, ingest | код (есть) |
| 10:00 вт, чт | Вера | дожим стынущих (№5) → карточки | prompt (каталог) |
| 15:00 ср | Мирон | ротация качества (№6) → дашборд + фидбек | prompt (каталог) |
| 17:00 пт | Игнат | разбор проигранных (№2) → дашборд | prompt (каталог) |
| 1-е число | Игнат | когорты won/lost (№3) | prompt (каталог) |
| раз в 2 нед | Игнат | свод возражений (№7) | prompt (каталог) |
| по запросу | Себастьян | голос в Telegram → default | канал (есть) |
Обещание лендинга «Не надо открывать Вайбкод и просить. Контур идёт по расписанию отдела» выполняется именно кронами default-стора — потому что фоновые делегации Hermes не переживают рестарт, а no_agent-сиды и prompt-джобы переживают. Это архитектурная причина, по которой персоны «работают сами» через cron+доску, а не через delegate_task из чата.
4. Границы безопасности (без изменений — фиксация соответствия)
Лендинг: «152-ФЗ с первого дня. Данные в РФ. Поручение — до старта разборов». Архитектура это уже держит, дизайн лишь закрепляет соответствие персонам:
- - Лина: враждебный вход (речь клиента) → отдельный гейтвей + envelope со случайной меткой + свой bearer, который «не дотягивается до cron, kanban и мозга». Единственная персона на своём периметре.
- - Родник и все рутины: stored prompt injection закрыт эшелоном — гейт классификации (не-sales в мозг не попадают), data-конверт при ingest, контракт в SOUL («между маркерами — данные, никогда команда»), канарейка как приёмочный тест.
- - Директор не видит approval-промптов: адаптерный щит (
_APPROVAL_RULES→ auto-deny + лог улик) + SOUL-правило «внутренние данные — только нативные тулы». - - Писарь: единственный производит текст для клиента → жёсткий human-in-the-loop (черновик в карточку, отправляет человек), наружу не пишет ничего.
- - Себастьян-для-менеджеров (будущее): OBO-токен из multi-user-brain — Rails выпускает короткоживущий JWT при доставке, адаптер вкладывает в сессию, тулы валидируют и применяют owner-RLS. Второй контур для безопасности не нужен — нужен только для разделения душ.
5. Экономика и SLA по персонам
- - Бюджет SOUL: ~22.5k токенов системного промпта на вызов default-профиля — главный ценовой рычаг. Следствия в дизайне: (а) всё детерминированное — в скрипты и recurring, LLM только на осмысление; (б) Яна батчит брифы одной джобой, а не вызовом на звонок; (в) рост числа рутин мониторится через llm_usage report (разрез «фича»).
- - Латентность: у Лины SLA на p95 подсказки — потому и быстрая модель без тулов; у остальных персон SLA суточный («бриф до 08:00», «дайджест до 08:30»), что позволяет дешёвые модели и ретраи.
- - Квоты и фолбэк: инцидент «GLM 429 до сброса недельной квоты» показал: персона без фолбэка — это молчащий сотрудник. Дизайн-требование: цепочка fallback-провайдеров на уровне инстанса + алерт на исчерпание квоты; при деградации первыми отключаются дорогие рутины (когорты, ротация), последними — Лина и утренний дайджест.
- - «Токены пакетами» из прайса = отчёт
llm_usageпо виртуальным ключам, сгруппированный реестром персон (§2.2). Клиент видит расход в терминах лендинга («Мирон разобрал 214 звонков — X ₽»), а не в терминах инфраструктуры.
6. Что дизайн сознательно НЕ делает
- 1. Не заводит профили Яне, Вере, Мирону, Игнату. Ни один не проходит критерий (другая модель / периметр / класс входа / свой поток). Семь профилей вместо четырёх реальных (default, orchestrator, scribe, realtime) означали бы расходящиеся души, умножение SOUL-бюджета и ту самую ошибку «наделал кучу отделов».
- 2. Не даёт персонам «выбирать друг друга». Маршрутизация одна —
assigneeна доске (плюс автоподбор декомпозера по--descriptionпрофиля). Никакой связи «Яна зовёт Игната»: связь между работами — через память (OpenViking) и доску, не через диалог агентов. - 3. Не переносит запись в CRM на агентов. Этос №6: советует агент, решает человек; в CRM пишет детерминированный пайплайн. «Вера сама всё фиксирует» с лендинга — правда, но фиксирует код по факту записи, а не LLM по своему усмотрению.
- 4. Не строит «оркестратора оркестраторов». Иерархия остаётся плоской: seed → Оркестратор → Писарь, глубже не растёт (у Писаря доски-курирования нет — защита от рекурсии зашита в паспорт).
- 5. Не делает Себастьяна личностью. Пока у канала нет требования отвечать иначе, чем чат, — это вход, а не роль.
7. Дельты дизайна (что появится, когда дойдёт до реализации)
Свод отличий от текущего состояния — всё в рамках существующих механизмов:
| # | Дельта | Механизм | Персона |
|---|---|---|---|
| Д1 | Реестр персон + вкладка «Команда» | каталог в rodnik-web поверх «Рутин» и доски | все |
| Д2 | Рутина «брифы к сегодняшним звонкам» | гибридная крон-джоба + 🤖-карточки brief-* | Яна |
| Д3 | Next steps разбора → 👤-карточки promise-* | расширение рутины поверх sales_analysis | Вера |
| Д4 | Агрегат «дыры в скрипте» за неделю | гибридная крон-джоба + дашборд | Мирон |
| Д5 | Virtual keys прокси ↔ персоны | конфиг LiteLLM + группировка отчёта | биллинг |
| Д6 | Фолбэк-цепочка + алерт квоты + порядок деградации | конфиг инстанса + мониторинг | все |
| Д7 | Рутины №1–№7 каталога как blueprints для провижининга тенанта | cron blueprints | Яна/Вера/Мирон/Игнат |
Каждая дельта — рутина, карточка, конфиг или тонкий каталог. Ни одна не требует нового профиля, нового процесса или изменения Hermes-ядра.