Сборка промпта
Гермес целенаправленно разделяет:
- закэшированное состояние системного промпта
- эфемерные дополнения, добавляемые во время вызова API
Это одно из самых важных проектных решений в проекте, так как оно влияет на:
- использование токенов
- эффективность кэширования промпта
- непрерывность сессии
- корректность памяти
Основные файлы:
run_agent.pyагент/prompt_builder.pyинструменты/memory_tool.py
Закэшированные слои системного промпта
Закэшированный системный запрос собирается примерно в таком порядке:
- идентичность агента —
SOUL.mdизHERMES_HOME, если доступен; иначе используетсяDEFAULT_AGENT_IDENTITYизprompt_builder.py - Инструкция поведения с учётом инструмента
- статический блок Honcho (если активирован)
- опциональное системное сообщение
- замороженный слепок ПАМЯТЬ
- замороженный слепок профиля USER
- индекс навыков
- Контекстные файлы (
AGENTS.md,.cursorrules,.cursor/rules/*.mdc) — SOUL.md не включается сюда, если он уже был загружен как идентичность на шаге 1 - метка времени / опциональный идентификатор сессии
- подсказка платформы
Когда установлен skip_context_files (например, при гуглении субагента), SOUL.md не загружается, и вместо него используется дележ жёстко заданный DEFAULT_AGENT_IDENTITY.
Конкретный пример: собранный системный запрос
Вот упрощённый вид конечного системного приглашения, когда все части присутствуют (комментарии показывают источник каждого раздела):
# Layer 1: Agent Identity (from ~/.hermes/SOUL.md)
You are Hermes, an AI assistant created by Nous Research.
You are an expert software engineer and researcher.
You value correctness, clarity, and efficiency....
# Layer 2: Tool-aware behavior guidance
You have persistent memory across sessions. Save durable facts using
the memory tool: user preferences, environment details, tool quirks,
and stable conventions. Memory is injected into every turn, so keep
it compact and focused on facts that will still matter later....
When the user references something from a past conversation or you
suspect relevant cross-session context exists, use session_search
to recall it before asking them to repeat themselves.
# Tool-use enforcement (for GPT/Codex models only)
You MUST use your tools to take action — do not describe what you
would do or plan to do without actually doing it....
# Layer 3: Honcho static block (when active)
[Honcho personality/context data]
# Layer 4: Optional system message (from config or API)
[User-configured system message override]
# Layer 5: Frozen MEMORY snapshot
## Persistent Memory
- User prefers Python 3.12, uses pyproject.toml
- Default editor is nvim
- Working on project "atlas" in ~/code/atlas
- Timezone: US/Pacific
# Layer 6: Frozen USER profile snapshot
## User Profile
- Name: Alice
- GitHub: alice-dev
# Layer 7: Skills index
## Skills (mandatory)
Before replying, scan the skills below. If one clearly matches
your task, load it with skill_view(name) and follow its instructions....
<available_skills>
software-development:
- code-review: Structured code review workflow
- test-driven-development: TDD methodology
research:
- arxiv: Search and summarize arXiv papers
</available_skills>
# Layer 8: Context files (from project directory)
# Project Context
The following project context files have been loaded and should be followed:
## AGENTS.md
This is the atlas project. Use pytest for testing. The main
entry point is src/atlas/main.py. Always run `make lint` before
committing.
# Layer 9: Timestamp + session
Current time: 2026-03-30T14:30:00-07:00
Session: abc123
# Layer 10: Platform hint
You are a CLI AI Agent. Try not to use markdown but simple text
renderable inside a terminal.
Как SOUL.md появился быстро
SOUL.md находится в ~/.hermes/SOUL.md и служит агенту идентичности — самой первой секцией системного промпта. Логика загрузки в prompt_builder.py работает следующим образом:
# From agent/prompt_builder.py (simplified)
def load_soul_md() -> Optional[str]:
soul_path = get_hermes_home() / "SOUL.md"
if not soul_path.exists():
return None
content = soul_path.read_text(encoding="utf-8").strip()
content = _scan_context_content(content, "SOUL.md") # Security scan
content = _truncate_content(content, "SOUL.md") # Cap at 20k chars
return content
Когда load_soul_md() загружает настройки, оно заменяет жёстко заданный DEFAULT_AGENT_IDENTITY. Функция build_context_files_prompt() возникает с skip_soul=True, чтобы SOUL.md не появлялся дважды (один раз как идентичность, второй раз как контекстный файл).
Если SOUL.md не существует, система использует запасной вариант:
You are Hermes Agent, an intelligent AI assistant created by Nous Research.
You are helpful, knowledgeable, and direct. You assist users with a wide
range of tasks including answering questions, writing and editing code,
analyzing information, creative work, and executing actions via your tools.
You communicate clearly, admit uncertainty when appropriate, and prioritize
being genuinely useful over being verbose unless otherwise directed below.
Be targeted and efficient in your exploration and investigations.
Как внедряются контекстные файлы
build_context_files_prompt() использует системные приоритеты — загружается только один тип контекста проекта (первый подходящий):
# From agent/prompt_builder.py (simplified)
def build_context_files_prompt(cwd=None, skip_soul=False):
cwd_path = Path(cwd).resolve()
# Priority: first match wins — only ONE project context loaded
project_context = (
_load_hermes_md(cwd_path) # 1..hermes.md / HERMES.md (walks to git root)
or _load_agents_md(cwd_path) # 2. AGENTS.md (cwd only)
or _load_claude_md(cwd_path) # 3. CLAUDE.md (cwd only)
or _load_cursorrules(cwd_path) # 4..cursorrules /.cursor/rules/*.mdc
)
sections = []
if project_context:
sections.append(project_context)
# SOUL.md from HERMES_HOME (independent of project context)
if not skip_soul:
soul_content = load_soul_md()
if soul_content:
sections.append(soul_content)
if not sections:
return ""
return (
"# Project Context\n\n"
"The following project context files have been loaded "
"and should be followed:\n\n"
+ "\n".join(sections)
)
Детали обнаружения контекстных файлов
| Приоритет | Файлы | Область поиска | Примечания |
|---|---|---|---|
| 1 | .hermes.md, HERMES.md |
Текущая директория до корня git | Родная конфигурация проекта Hermes |
| 2 | AGENTS.md |
Только текущая директория | Распространённый файл инструкций агента |
| 3 | CLAUDE.md |
Только текущая директория | Совместимость с Claude Code |
| 4 | .cursorrules, .cursor/rules/*.mdc |
Только текущая директория | Совместимость с Cursor |
Все контекстные файлы проходят:
- Проверку безопасности — проверяются на наличие паттернов внедрения промптов (невидимый юникод, «игнорируй предыдущие инструкции», попытки кражи учётных данных)
- Усечение — ограничены 20 000 символов с соотношением head/tail 70/20 и маркером усечения
- Удаление YAML frontmatter — frontmatter
.hermes.mdудаляется (зарезервирован для будущих переопределений конфигурации)
Слои, добавляемые только во время вызова API
Эти слои намеренно не сохраняются как часть закэшированного системного промпта:
ephemeral_system_prompt- предзаполненные сообщения
- наложения контекста сессии от шлюза
- информация от Honcho, внедрённая в пользовательское сообщение текущего витка
Такое разделение сохраняет стабильный префикс для кэширования.
Слепки памяти
Локальная память и профиль пользователя внедряются как замороженные слепки при запуске сессии. Записи в середине сессии обновляют состояние на диске, но не изменяют уже собранный системный промпт до начала новой сессии или принудительной перестройки.
Контекстные файлы
agent/prompt_builder.py сканирует и проверяет контекстные файлы проекта, используя систему приоритетов — загружается только один тип (первый подходящий):
.hermes.md/HERMES.md(обход до корня git)AGENTS.md(текущая директория при запуске; поддиректории обнаруживаются постепенно в течение сессии черезagent/subdirectory_hints.py)CLAUDE.md(только текущая директория).cursorrules/.cursor/rules/*.mdc(только текущая директория)
SOUL.md загружается отдельно через load_soul_md() для слоя идентичности. При успешной загрузке build_context_files_prompt(skip_soul=True) предотвращает его появление дважды.
Длинные файлы усекаются перед внедрением.
Индекс навыков
Система навыков добавляет компактный индекс навыков в промпт, когда соответствующая функциональность доступна.
Поддерживаемые точки настройки промпта
Большинству пользователей следует рассматривать agent/prompt_builder.py как внутренний код, а не как поверхность для конфигурации. Поддерживаемый путь настройки — изменять входные данные, которые Hermes уже загружает, а не редактировать шаблоны Python напрямую.
Используйте эти поверхности в первую очередь
~/.hermes/SOUL.md— замените встроенный блок идентичности по умолчанию на собственную персону агента и постоянное поведение.~/.hermes/MEMORY.mdи~/.hermes/USER.md— предоставьте долговременные факты и данные профиля пользователя между сессиями, которые должны попадать в новые сессии.- Контекстные файлы проекта, такие как
.hermes.md,HERMES.md,AGENTS.md,CLAUDE.mdили.cursorrules— внедряйте правила работы, специфичные для репозитория. - Навыки — упаковывайте повторно используемые рабочие процессы и ссылки без редактирования основного кода промпта.
- Опциональная конфигурация системного промпта / переопределения API — добавляйте инструкции, специфичные для развёртывания, без форка Hermes.
- Эфемерные наложения, такие как
HERMES_EPHEMERAL_SYSTEM_PROMPTили предзаполненные сообщения — добавляйте руководство на уровне витка, которое не должно становиться частью закэшированного префикса промпта.
Когда вместо этого редактировать код
Редактируйте agent/prompt_builder.py только в том случае, если вы целенаправленно поддерживаете форк или вносите изменения в основную ветку. Этот файл отвечает за сборку промпта, границы кэша и порядок внедрения для каждой сессии. Прямые правки там — это глобальные изменения продукта, а не настройка промпта для конкретного пользователя.
Иными словами:
- если вам нужна другая идентичность ассистента, редактируйте
SOUL.md - если вам нужны другие правила репозитория, редактируйте контекстные файлы проекта
- если вам нужны повторно используемые операционные процедуры, добавьте или измените навыки
- если вы хотите изменить способ, которым Hermes собирает промпты для всех, меняйте Python и рассматривайте это как вклад в код
Почему сборка промпта разделена именно так
Архитектура намеренно оптимизирована для:
- сохранения кэширования промпта на стороне провайдера
- избежания ненужных мутаций истории
- обеспечения понятной семантики памяти
- возможности шлюзу/ACP/CLI добавлять контекст, не загрязняя постоянное состояние промпта