提示词组装

Hermes 有意将以下内容分离:

  • 缓存的系统提示词状态
  • 临时的 API 调用时附加内容

这是项目中最重要的设计选择之一,因为它影响:

  • token 用量
  • 提示词缓存效果
  • 会话连续性
  • 内存正确性

主要文件:

  • run_agent.py
  • agent/prompt_builder.py
  • tools/memory_tool.py

缓存的系统提示图层

缓存的系统提示词大致按以下顺序组装:

  1. 代理身份 — HERMES_HOME 中的 SOUL.md(如果可用),否则回退到 prompt_builder.py 中的 DEFAULT_AGENT_IDENTITY
  2. 工具感知的行为指导
  3. Honcho 静态块(激活时)
  4. 可选的系统消息
  5. 冻结的 MEMORY 快照
  6. 冻结的 USER 配置快照
  7. 技能索引
  8. 上下文文件(AGENTS.md.cursorrules.cursor/rules/*.mdc)— 如果已在步骤 1 中作为身份加载,则此处包含 SOUL.md
  9. 时间戳 / 可选的会话 ID
  10. 平台提示

当设置了 skip_context_files(例如子代理委派)时,不加载 SOUL.md,使用硬编码的 DEFAULT_AGENT_IDENTITY 代替。

具体示例:组装后的系统提示词

以下是所有图层都存在时最终系统提示词的简化视图(注释显示每个部分的来源):

# 第 1 层:代理身份(来自 ~/.hermes/SOUL.md)
你是 Hermes,由 Nous Research 创建的 AI 助手。
你是一名专业软件工程师和研究员。
你重视正确性、清晰度和效率。
...

# 第 2 层:工具感知的行为指导
你在会话间拥有持久化内存。使用内存工具保存持久性事实:
用户偏好、环境细节、工具使用技巧和稳定的约定。
内存在每次交互时注入,因此请保持内容紧凑且专注于
以后仍然重要的事实。
...
当用户提到过去对话中的内容,或者你怀疑存在相关的
跨会话上下文时,请使用 session_search 进行召回,
而不是要求用户重复。

# 工具使用强制(仅限 GPT/Codex 模型)
你必须使用工具采取行动——不要仅描述你将要做什么或计划
做什么而不实际执行。
...

# 第 3 层:Honcho 静态块(激活时)
[Honcho 个性/上下文数据]

# 第 4 层:可选的系统消息(来自配置或 API)
[用户配置的系统消息覆盖]

# 第 5 层:冻结的 MEMORY 快照
## 持久化内存
- 用户偏好 Python 3.12,使用 pyproject.toml
- 默认编辑器为 nvim
- 正在 ~/code/atlas 上开发项目 "atlas"
- 时区:US/Pacific

# 第 6 层:冻结的 USER 配置快照
## 用户配置
- 姓名:Alice
- GitHub:alice-dev

# 第 7 层:技能索引
## 技能(强制)
在回复之前,请扫描以下技能。如果某个技能与您的
任务明确匹配,请使用 skill_view(name) 加载并遵循其说明。
...
<available_skills>
  software-development:
    - code-review: 结构化代码审查工作流
    - test-driven-development: TDD 方法论
  research:
    - arxiv: 搜索和总结 arXiv 论文
</available_skills>

# 第 8 层:上下文文件(来自项目目录)
# 项目上下文
以下项目上下文文件已加载,应予以遵循:

## AGENTS.md
这是 atlas 项目。使用 pytest 进行测试。主入口点是
src/atlas/main.py。在提交前始终运行 `make lint`。

# 第 9 层:时间戳 + 会话
当前时间:2026-03-30T14:30:00-07:00
会话:abc123

# 第 10 层:平台提示
你是一个 CLI AI 代理。尽量不使用 markdown,使用
终端内可渲染的纯文本。

SOUL.md 在提示词中的出现方式

SOUL.md 位于 ~/.hermes/SOUL.md,作为代理的身份——系统提示词的第一部分。prompt_builder.py 中的加载逻辑如下:

# 来自 agent/prompt_builder.py(简化版)
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")  # 安全扫描
    content = _truncate_content(content, "SOUL.md")       # 上限 2 万字符
    return content

load_soul_md() 返回内容时,它会替换硬编码的 DEFAULT_AGENT_IDENTITY。然后调用 build_context_files_prompt() 时使用 skip_soul=True,以防止 SOUL.md 出现两次(一次作为身份,一次作为上下文文件)。

如果 SOUL.md 不存在,系统回退到:

你是 Hermes Agent,由 Nous Research 创建的智能 AI 助手。
你乐于助人、知识渊博且直接。你帮助用户完成各种
任务,包括回答问题、编写和编辑代码、分析信息、
创意工作以及通过工具执行操作。你清晰地沟通,
在适当的时候承认不确定性,并优先追求真正有用而不是
啰嗦,除非下面另有指示。在探索和调查中要有针对性和高效性。

上下文文件的注入方式

build_context_files_prompt() 使用优先级系统——仅加载一种项目上下文类型(首个匹配胜出):

# 来自 agent/prompt_builder.py(简化版)
def build_context_files_prompt(cwd=None, skip_soul=False):
    cwd_path = Path(cwd).resolve()
 
    # 优先级:首个匹配胜出——仅加载一种项目上下文
    project_context = (
        _load_hermes_md(cwd_path)       # 1. .hermes.md / HERMES.md(遍历到 git 根目录)
        or _load_agents_md(cwd_path)    # 2. AGENTS.md(仅当前工作目录)
        or _load_claude_md(cwd_path)    # 3. CLAUDE.md(仅当前工作目录)
        or _load_cursorrules(cwd_path)  # 4. .cursorrules / .cursor/rules/*.mdc
    )
 
    sections = []
    if project_context:
        sections.append(project_context)
 
    # 来自 HERMES_HOME 的 SOUL.md(独立于项目上下文)
    if not skip_soul:
        soul_content = load_soul_md()
        if soul_content:
            sections.append(soul_content)
 
    if not sections:
        return ""
 
    return (
        "# 项目上下文\n\n"
        "以下项目上下文文件已加载,应予以遵循:\n\n"
        + "\n".join(sections)
    )

上下文文件发现详情

优先级文件搜索范围备注
1.hermes.mdHERMES.md当前工作目录向上到 git 根目录Hermes 原生项目配置
2AGENTS.md仅当前工作目录通用代理指令文件
3CLAUDE.md仅当前工作目录Claude Code 兼容性
4.cursorrules.cursor/rules/*.mdc仅当前工作目录Cursor 兼容性

所有上下文文件:

  • 经过安全扫描 — 检查提示注入模式(不可见 Unicode、“忽略之前的指令”、凭据窃取尝试)
  • 被截断 — 上限为 20,000 字符,使用 70/20 头部/尾部比例并带有截断标记
  • YAML frontmatter 被剥离.hermes.md 的 frontmatter 被移除(保留用于未来的配置覆盖)

仅 API 调用时附加的图层

这些有意作为缓存系统提示词的一部分持久化:

  • ephemeral_system_prompt
  • 预填充消息
  • 网关派生的会话上下文覆盖
  • 后续轮次的 Honcho 召回注入到当前轮次的用户消息中

这种分离保持了稳定前缀的可缓存性。

内存快照

本地内存和用户配置数据在会话启动时作为冻结快照注入。会话中的写操作会更新磁盘状态,但在新会话或强制重建之前不会改变已构建的系统提示词。

上下文文件

agent/prompt_builder.py 使用优先级系统扫描和清理项目上下文文件——仅加载一种类型(首个匹配胜出):

  1. .hermes.md / HERMES.md(遍历到 git 根目录)
  2. AGENTS.md(启动时的当前工作目录;子目录在会话期间通过 agent/subdirectory_hints.py 逐步发现)
  3. CLAUDE.md(仅当前工作目录)
  4. .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.mdHERMES.mdAGENTS.mdCLAUDE.md.cursorrules — 注入仓库特定的工作规则。
  • 技能 — 打包可重用工作流和参考信息,无需编辑核心提示词代码。
  • 可选的系统提示词配置 / API 覆盖 — 添加部署特定的指令文本,无需分支 Hermes。
  • 临时覆盖,如 HERMES_EPHEMERAL_SYSTEM_PROMPT 或预填充消息 — 添加轮次范围内的指导,不应成为缓存提示词前缀的一部分。

何时改为编辑代码

仅在您有意维护分支或贡献上游行为变更时,才编辑 agent/prompt_builder.py。该文件为每个会话组装提示词管道、缓存边界和注入顺序。直接编辑是全局产品变更,而非面向用户的提示词定制。

换句话说:

  • 如果您想要不同的助手身份,请编辑 SOUL.md
  • 如果您想要不同的仓库规则,请编辑项目上下文文件
  • 如果您想要可重用的操作流程,请添加或修改技能
  • 如果您想要改变 Hermes 为所有人组装提示词的方式,请更改 Python 并将其视为代码贡献

为什么提示词组装要这样拆分

该架构有意优化以:

  • 保持提供商侧的提示词缓存
  • 避免不必要地修改历史记录
  • 保持内存语义清晰易懂
  • 让网关/ACP/CLI 添加上下文而不污染持久化提示词状态

相关文档