23 KiB
Hermes Agent — Улучшения и Паттерны
Agentic Memory Update
Как лучше обновлять доки/память агента из истории бесед.
Основные паттерны
1. Async post-session (доминирующий) — разделить живой чат и консолидацию памяти. После завершения сессии / по расписанию агент читает транскрипт, извлекает инсайты, пишет в canonical store. Никакой задержки в живом чате.
2. Three-memory model:
- Episodic — история сессий (summary что обсуждали)
- Semantic — факты, предпочтения, решения
- Procedural — воркфлоу, скиллы, подходы
Чем запускают
- Cron (2–4 AM) — самый простой и надёжный
- Webhook после завершения сессии
- LangMem
ReflectionExecutor— фоновый тред прямо во время чата
Инструменты
| Инструмент | Плюсы | Минусы |
|---|---|---|
| LangMem | Нативная интеграция с LangGraph | p95 latency = 60s в продакшне |
| Mem0 | Граф с conflict detection, лучшая производительность | Проприетарный |
| Custom agents | Полный контроль, пишет в git/docs | Надо делать самому |
Eagle использует custom agents — текущий подход.
Главные правила
- Обрабатывать один раз в конце сессии, не после каждого сообщения
- Дешёвые модели для memory ops, дорогие — для разговора
- Guard: «обновлять только при значимой новой информации»
- Temporal decay — чтобы память не росла бесконечно
Пробелы в текущей системе
Vault root не обрабатывается
Файлы попадают в корень vault через мобильный sync (Obsidian iOS) — нет хэндлера.
vault-enrichment— не перемещает (запрещено в промпте)inbox-sort— сканирует только staging-папки (family/sort/,personal/inbox/)
Fix: расширить inbox-sort, чтобы сканировал vault root и перемещал файлы по классификатору (food/recipes → family/documents/, etc.)
Нет renaming agent
Никто не переименовывает файлы. Мобильный sync создаёт файлы с произвольными именами, они остаются как есть.
Fix: добавить логику нормализации имён в inbox-sort или отдельный препроцессор.
Нет post-session memory agent
Сессии пишутся в ~/.hermes/sessions/, но memory.md и vault обновляются только вручную или через vault-enrichment (раз в неделю).
Fix: cron 02:00 AM ежедневно — читает свежие сессии, обновляет memory.md и personal/projects/. Вписывается в слот между inbox-sort (01:00) и vault-enrichment (03:00 вс).
Бэклог из обзора рынка ИИ-агентов (2026-09-02)
Полный разбор: ai-agent-landscape-2026. Вывод: смена фреймворка нецелесообразна (Hermes — #1 по объёму работы на OpenRouter в нише self-hosted перс.агента; альтернативы не перекрывают кастомизации). Из трендов, применимых к конфигу, растут следующие потенциальные улучшения (в порядке ценности):
- Event-driven проактивность поверх timer-driven cron — триггеры на изменение vault / новые файлы / сигналы, а не только по расписанию. Точка роста: сейчас проактивность только cron/watchdog.
- Confidence scoring + temporal decay для semantic-tier памяти — сейчас MEMORY.md overflow есть, но нет явного скоринга/устаревания фактов (паттерн Mem0/Letta/LangMem). Позже, кандидат на апгрейд semantic-tier сторонним движком (Letta/Mem0).
- Аудит скиллов до установки — урок из ClawHub supply-chain poisoning (341 вредоносный скилл) и CVE-2026-48710 (Hermes v0.16). Касается Skills Hub / установки сторонних скиллов.
- Модельная маршрутизация — самый дешёвый рычаг снижения токен-расхода (спред 100× между open-weight и фронтиром).
Статус каждого: не начато / потенциально — это research-findings, не подтверждённый план. Пересмотреть при планировании следующего спринта улучшений.
Вынос хардкода промптов в файлы
Статус: Реализовано ✅ (будет активно после перезапуска webhook)
Мотивация
В Hermes Whale все stable-блоки system prompt (identity, guidance, enforcement) были захардкожены в agent/prompt_builder.py как Python-константы. Невозможно изменить их без редактирования исходного кода Hermes Agent.
Решение
Вынести каждый блок в отдельный .md файл, добавить маппинг в config.yaml: agent.prompt_overrides, модифицировать agent/system_prompt.py, чтобы он читал файлы вместо констант.
Изменяемые файлы
1. agent/system_prompt.py — замена констант на file-load
Добавлена функция _load_prompt_block(agent, block_name, default_text) — строки 51-71 в /Users/admin/.hermes/hermes-agent/agent/system_prompt.py:
- Читает
agent._prompt_overrides(берётся из конфига на старте) - Если для
block_nameуказан путь — читает файл, возвращает его содержимое - Иначе возвращает
default_text
Заменены все 7 прямых ссылок на константы в build_system_prompt_parts() на вызовы _load_prompt_block().
Добавлены импорты: import logging, import os, from pathlib import Path, logger = logging.getLogger(__name__).
Константы, которые заменяются (7 блоков):
| Блок | Константа | Вставляется при условии |
|---|---|---|
hermes_help |
HERMES_AGENT_HELP_GUIDANCE |
всегда |
task_completion |
TASK_COMPLETION_GUIDANCE |
всегда |
memory_guidance |
MEMORY_GUIDANCE |
когда есть tool "memory" |
session_search_guidance |
SESSION_SEARCH_GUIDANCE |
когда есть tool "session_search" |
skills_guidance |
SKILLS_GUIDANCE |
когда есть tool "skill_manage" |
tool_use_enforcement |
TOOL_USE_ENFORCEMENT_GUIDANCE |
зависит от модели |
execution_discipline |
OPENAI_MODEL_EXECUTION_GUIDANCE |
зависит от модели |
Не заменяется (остаётся в коде):
DEFAULT_AGENT_IDENTITY— это fallback когда нет SOUL.md (у нас есть SOUL.md, не нужно)GOOGLE_MODEL_OPERATIONAL_GUIDANCE— Google-specific, неактуально для WhaleCOMPUTER_USE_GUIDANCE— нет toolsetKANBAN_GUIDANCE— нет kanbanPLATFORM_HINTS— platform-specific, другая логика
2. agent/system_prompt.py — функция загрузки
def _load_prompt_block(agent, block_name: str, default: str) -> str:
"""Load a prompt block from a file if configured, else return default."""
overrides = getattr(agent, "_prompt_overrides", None) or {}
path = overrides.get(block_name)
if path:
try:
resolved = os.path.expanduser(path)
content = Path(resolved).read_text(encoding="utf-8").strip()
if content:
return content
except Exception:
logger.debug("Could not load prompt override '%s' from %s", block_name, path)
return default
3. agent/agent_init.py — пробросить конфиг
После загрузки _agent_cfg (строка ~1058) добавлено чтение agent.prompt_overrides:
agent._prompt_overrides = {}
try:
_po = _agent_cfg.get("agent", {}).get("prompt_overrides", {})
if isinstance(_po, dict):
agent._prompt_overrides = _po
except Exception:
pass
4. Конфиг Whale — config.yaml
Добавлена секция:
agent:
prompt_overrides:
hermes_help: ~/.hermes/hermes-whale/review/hermes_help.md
task_completion: ~/.hermes/hermes-whale/review/task_completion.md
memory_guidance: ~/.hermes/hermes-whale/review/memory_guidance.md
session_search_guidance: ~/.hermes/hermes-whale/review/session_search_guidance.md
skills_guidance: ~/.hermes/hermes-whale/review/skills_guidance.md
tool_use_enforcement: ~/.hermes/hermes-whale/review/tool_use_enforcement.md
execution_discipline: ~/.hermes/hermes-whale/review/execution_discipline.md
5. Файлы блоков
Созданы 7 файлов в ~/.hermes/hermes-whale/review/:
hermes_help.md— содержимое константыHERMES_AGENT_HELP_GUIDANCEtask_completion.md— содержимоеTASK_COMPLETION_GUIDANCEmemory_guidance.md— содержимоеMEMORY_GUIDANCEsession_search_guidance.md— содержимоеSESSION_SEARCH_GUIDANCEskills_guidance.md— содержимоеSKILLS_GUIDANCEtool_use_enforcement.md— содержимоеTOOL_USE_ENFORCEMENT_GUIDANCEexecution_discipline.md— содержимоеOPENAI_MODEL_EXECUTION_GUIDANCE
Обратная совместимость
Если prompt_overrides не задан или файл не найден — используется хардкод. Никакой код не ломается для других профилей/пользователей.
Порядок выполнения
- ✅ Создать 7 файлов блоков в
~/.hermes/hermes-whale/review/ - ✅ Пропатчить
agent/system_prompt.py— добавить_load_prompt_block()и заменить 7 констант - ✅ Пропатчить
agent/agent_init.py— проброситьprompt_overridesиз конфига - ✅ Обновить
config.yaml— добавитьagent.prompt_overrides(через копию, т.к. patch блокирован TIRITH) - ⏸️ Перезапустить webhook (ждёт команды)
- ⏸️ Обновить Obsidian docs (этот шаг — выполнен)
Проверка
После изменений system prompt должен содержать те же блоки, что и раньше, но загруженные из файлов. При изменении файла и рестарте сессии — новый текст. При удалении файла — fallback на хардкод.
Pitfalls
- TIRITH блокирует patch/config.yaml —
config.yamlпод защитой TIRITH, patch и write_file отказываются писать в него. Решение:cpв/tmp/, отредактировать там,cpобратно (с аппрувом). - sed не подходит для YAML конфигов — сложные многострочные замены с вложенными отступами и escape-символами (
~,/) ломаются в sed. Лучше patch. - Конфиг всё равно просит аппрув — при
cpобратно TIRITH запрашивает подтверждение (overwrite project env/config file). Это нормально, нужно подтвердить. - SOUL.md уже существует — в Whale он лежит в
/Users/admin/.hermes/hermes-whale/SOUL.md. Он НЕ выносится через prompt_overrides, т.к. уже является файлом и загружается отдельно черезload_soul_md(). - webhook не в PLATFORM_HINTS — webhook нет в словаре
PLATFORM_HINTSвprompt_builder.py, поэтому блок platform hints пустой. Это не менялось.
Анализ вынесенных prompt-блоков
Все 7 файлов лежат в ~/.hermes/hermes-whale/review/ и подключаются через config.yaml → agent.prompt_overrides.
1. SOUL.md — Identity (не выносился, уже файл)
Путь: ~/.hermes/hermes-whale/SOUL.md
33 строки — определяет личность Кит (Whale), правила работы с Obsidian, инструментами, TIRITH, jq.
Структура:
- Identity + run location
- Core Rules (Obsidian first, vault namespaces, no external APIs, no
python3 -c "import json", TIRITH, jq) - Absolute rules (стоп — zero actions)
- Hermes self-reference (дока в приоритете над skill_view)
Наблюдения:
- ⚠️ Дублирование с
hermes_help.md— SOUL.md строка 34+ («AGAIN. ALWAYS check Obsidian first...») иhermes_help.md(Hermes Agent docs) пересекаются. Hermes help ссылается на docs.nousresearch.com, а SOUL напоминает про Obsidian MCP. Это complementary, а не конфликт — одно про внешнюю доку, другое про внутреннюю. Но стоит явно разделить: SOUL = who you ARE, hermes_help = что делать с Hermes как продуктом. - ✅ jq-правило (строка 22-23) удачно помещено именно сюда — это Whale-specific constraint.
- ✅
respond in the language you're addressed in— хорошее мягкое правило, сохраняет билингвальность. - ❌ Нет guard: после обновления доков — проверить, нет ли сломанных ссылок/дубликатов.
2. execution_discipline.md — 48 строк, самый большой блок
Структура XML-тэги:
<tool_persistence>— не останавливаться рано, retry, verify<mandatory_tool_use>— не отвечать по памяти: math, hashes, system state, git, web<act_dont_ask>— очевидные интерпретации — действовать сразу<prerequisite_checks>— проверять зависимости перед действием<verification>— корректность, grounding, формат, safety<missing_context>— не гадать, использовать lookup, только потом спросить
Наблюдения:
- ✅ Отличная структура: секции-запреты с чёткими примерами уменьшают ambiguity.
- ⚠️
<verification>пункт «Safety: if the next step has side effects... confirm scope before executing» — мягко противоречит<act_dont_ask>, которое велит не спрашивать. Вhermes_whalesystem prompt поверх есть «NEVER REMOVE/KILL WITHOUT CONFIRMATION», так что extra safety здесь не лишняя, но формулировка «confirm scope» может спровоцировать лишний вопрос. - ✅
<mandatory_tool_use>— самое важное: запрещает LLM-галлюцинации фактов внешнего мира. - ❌ Нет секции про batch/parallel execution — при multi-file операциях агент может делать последовательно то, что можно параллельно.
- ❌ Нет секции про отношение к ошибкам — если инструмент вернул ошибку, нужно ли retry с другим подходом (записано в
<tool_persistence>) или сообщить пользователю.
3. task_completion.md — 3 строки
Суть: не останавливаться на плане/стабе — доводить до работающего артефакта. Не фабриковать результаты при блокере.
Наблюдения:
- ✅ Критически важный guard против premature stopping.
- ⚠️ Не покрывает ситуацию: «задача сделана, но пользователь не проверил» — должен ли агент спросить «проверить?» или просто отчитаться?
- ❌ Не упоминает сценарий partial failure: часть задачи выполнена, часть провалилась — как подавать результат?
4. hermes_help.md — 1 строка
Суть: docs.nousresearch.com как authoritative reference, skill_view('hermes-agent') для guidance.
Наблюдения:
- ✅ Лаконично.
- ❌ Не упоминает куда писать issue / как апдейтить самому.
- ⚠️ Несовпадение с реальностью: дока не всегда полная (есть расхождения с реальным API). Skill часто актуальнее.
5. memory_guidance.md — 1 строка, 1441 символ (самая длинная строка)
Суть: compact facts, what to save (preferences, corrections, env), what NOT to save (task progress, PRs, stale artifacts). Imperative phrasing bad. Sessions for recall, skills for procedures.
Наблюдения:
- ✅ Отличный negative list (не сохранять PR numbers, commit SHAs, "Phase N done").
- ✅ Важный паттерн: declarative facts vs instructions — записана разница с примерами.
- ⚠️ «Write memories as declarative facts, not instructions to yourself» — полезно, но не всегда практично: некоторые memory entries работают лучше как правила (например, «Allways back up before editing» vs «User prefers backups before edits»).
- ❌ Нет про conditional memory — «если X, то запомни Y». Например, при ошибке сети — не запоминать «нет соединения», это transient.
6. session_search_guidance.md — 1 строка
Суть: прежде чем спрашивать пользователя — поищи в истории сессий.
Наблюдения:
- ✅ Одно чёткое правило, минимум слов.
- ❌ Не хватает: когда НЕ надо искать (например, если вопрос про current OS state — не искать, а сразу
uname).
7. skills_guidance.md — 1 строка
Суть: после сложной задачи — сохранить как skill; outdated skill — patch сразу.
Наблюдения:
- ✅ Лаконично.
- ❌ Не хватает: критерии «сложности» (5+ tool calls — триггер). И что делать с zombie skills (которые больше не нужны).
8. tool_use_enforcement.md — 2 строки
Суть: MUST use tools, не описывать планы без экзекьюшена. Каждый response = tool calls или final result.
Наблюдения:
- ✅ Самый жёсткий enforcement блок. Правильно.
- ❌ Не хватает: что делать когда tools не доступны (tool_use_enforcement не может быть выполнен).
Cross-cutting observations
- Размеры файлов несбалансированы:
execution_discipline(48 строк) vssession_search_guidance(1 строка). Это ОК — разные блоки разной сложности. - XML vs Markdown:
execution_disciplineиспользует XML-тэги как semantic sections — интересно, работает ли это для модели как структурный сигнал? Вhermes_whalesystem prompt есть ещё# Headersкак разделители. Два стиля в одном system prompt — возможно, снижают эффективность. - Нет ordering гарантий: блоки вставляются в разном порядке в
build_system_prompt_parts()— сначала task_completion, потом hermes_help, потом execution_discipline. Но модель читает слева направо. Если execution_discipline должен быть последним (как enforcement override) — его позиция в сборке не гарантирует этого. - Нет cross-reference между файлами: например,
execution_disciplineне ссылается наtask_completionили наоборот. Агент может воспринимать их как независимые, несмотря на overlap. - Нет версионирования блоков: если поменять
execution_discipline.md, нет способа отследить «было / стало» без диффа гита. - Potential prompt compression issue: при длинных system prompts модель может терять середину (lost-in-the-middle).
execution_discipline(2.7KB) — самый тяжёлый блок. Возможно, стоит сократить примеры в<mandatory_tool_use>(все 11 пунктов проверять не надо — достаточно 4-5).
Рекомендации
- Добавить ordering guard — execution_discipline и tool_use_enforcement должны быть последними в system prompt (как override rules).
- Консолидировать XML-стиль — либо все блоки в XML-тэгах, либо все в Markdown headers.
- Добавить conditional session_search — правило: для state-вопросов (time, OS, memory) — не session_search, сразу tool.
- Добавить partial failure protocol в task_completion.
- Ввести дайджест prompt-блоков — при изменении любого .md файла в
review/логировать diff.