Agent 实践

Hermes Agent Prompt 拼装逻辑与流程详解

文章目录
  1. 一、核心设计原则
  2. 二、完整 Prompt 结构
  3. 2.1 缓存系统提示词层(Cached System Prompt Layers)
  4. 2.2 API 调用时专属层(API-call-time-only layers)
  5. 三、组装流程详解
  6. 3.1 数据流总览
  7. 3.2 完整组装步骤
  8. 四、系统提示词(System Prompt)构建细节
  9. 4.1 SOUL.md(Agent Identity)
  10. 4.2 Memory 系统(MEMORY.md & USER.md)
  11. 4.3 Context Files(项目上下文)
  12. 4.4 Skills Index
  13. 4.5 完整组装示例
  14. 五、Provider Runtime Resolution
稳定指导、项目上下文和可变快照组合后再加入请求增量
图 1:缓存提示包含不同稳定性的内容,请求增量另行加入。

原文版本:2026-05-13;资料复核:2026-10-13。 项目明确匹配 NousResearch/hermes-agent,源码基线 427d605d。 官方文档部分示例仍保留旧层次或旧文件范围,本文涉及具体顺序时以该提交的实现为准,不把文档示意图当成实际请求捕获。


一、核心设计原则

  1. 缓存提示词与调用时内容分离:本地构建缓存避免每轮重做相同工作;provider 前缀缓存还取决于路由、内容字节、TTL 与命中条件,两者不是一回事。
  2. SOUL.md 是默认身份入口:通常位于首个身份块;成功加载时替代内置身份,跳过 context files 的子任务可使用默认身份。排在第一位不意味着它能覆盖宿主安全规则。
  3. 渐进式披露:Skills 目录与完整 SKILL.md 分开,可用 skill_view 按需载入;索引已存在时不必先调用一次 skills_list 才有能力使用技能。
  4. 项目上下文按类型选择:first match wins 指一个项目上下文类型,不等于永远只有一个文件。当前 AGENTS 类型可合并 git root 到 CWD 的目录链。
  5. 记忆是可重建的快照:写入可立即持久化,但已缓存提示词不会逐条原地更新;新会话、压缩后的重建等边界可刷新快照,不是必须等下次会话。

这些结论对应组装源码和上下文加载源码。


二、完整 Prompt 结构

2.1 缓存系统提示词层(Cached System Prompt Layers)

当前 build_system_prompt_parts() 返回三个 tier,最终按 stable → context → volatile 拼接:

Tier 当前主要内容
stable SOUL/默认身份、工具与模型指导、固定 pinned skills、编码操作指导
context 调用者 system_message、项目上下文、工作树相关信息等
volatile Skills 索引、内置 MEMORY/USER 快照、外部记忆/插件块、profile 与时间/模型/provider 信息、运行环境

是否有工作树等条件会影响部分尾部指导的归属。原文十层固定顺序已不适用于该实现;官方文档中“skills 属于 stable”的一句话也与同页列表和当前源码不一致。这里区分固定 pinned skill 内容与可变的技能目录,以代码为准。

volatile 仍属于已构建并缓存的 system prompt,不代表每轮重写。近期 Skills 目录变化可以通过一次性的 turn note 提醒,完整目录在重建边界收敛。官方 Prompt Assembly。

2.2 API 调用时专属层(API-call-time-only layers)

临时 system overlay、prefill、gateway 会话增量、外部 recall 与插件 pre_llm_call 返回的上下文,可能在请求准备阶段加入而不永久改写缓存提示词。不同内容的角色载体不同:例如当前插件上下文追加到该轮 user message,不等于取得新的高优先级系统权限。


三、组装流程详解

先解析路由与模型,再组装提示和适配协议后调用模型
图 2:有效路由参与请求与预算准备,工具结果按协议回填。

3.1 数据流总览

CLI / gateway / 其他入口
→ AIAgent 运行准备与有效 provider/模型解析
→ 构建或复用缓存 system prompt
→ 组装历史、当前输入与临时增量
→ 检查上下文压力,按当前策略压缩
→ provider 消息适配与缓存标记
→ 模型调用 ↔ 工具校验、执行与结果回填
→ 返回答案、保存会话,必要时更新记忆

这是职责概览。Provider 通常要在创建客户端、选择协议与上下文预算时参与,不能固定说“prompt_builder 完成后才解析 provider”。当前组装主逻辑在 agent/system_prompt.py,agent/prompt_builder.py 主要负责上下文、Skills 等帮助函数。

3.2 完整组装步骤

  1. 确定任务、会话、工作目录与 provider/model 等运行参数。
  2. 追加本次输入,并准备与当前请求匹配的历史。
  3. 复用缓存提示词,或按三层结构重建。
  4. 根据实际上下文预算、已报告 usage 与压缩配置判断是否压缩。
  5. 把内部消息转换为该 provider 的请求结构,加入临时内容。
  6. 在支持路径上应用缓存策略,发出可中断请求。
  7. 处理工具调用、追加结果,再进入下一次模型请求;无工具调用、达到运行限制或中断时结束。
  8. 按入口保存状态,必要时刷新记忆/提示词。

原文把“50% 必压缩”“总是循环到无工具调用”“最终回复后才检查压缩”写成统一行为,均过于绝对。


四、系统提示词(System Prompt)构建细节

选定上下文类型后,AGENTS 路径逐层选取并合并项目规则
图 3:first match 指类型选择;选中 AGENTS 类型后仍可合并目录链。

4.1 SOUL.md(Agent Identity)

通常从选定 profile 的 HERMES_HOME/SOUL.md 读取,不取项目 CWD 的同名文件。没有可用内容时采用内置身份;skip_context_files 等路径也可能直接用默认身份。

当前加载器还区分用户自写与 profile distribution 提供的 SOUL:前者命中扫描模式时警告后仍加载,后者可被阻断。不能把这项扫描说成“任何身份文件都已净化”。

截断上限也不再固定为 20k:默认会随模型上下文预算变化,有 20,000 字符下限和动态上界,显式 context_file_max_chars 优先。可概括为:

# 行为示意,不是可直接复制运行的完整实现
content = read_selected_profile_soul()
content = scan_with_source_trust(content)
content = truncate_to_effective_context_budget(content)
identity = content or DEFAULT_AGENT_IDENTITY

SOUL.md 是人格与行为输入,不是工具授权表。实际审批和文件/工具权限仍由宿主执行。加载器源码。

4.2 Memory 系统(MEMORY.md & USER.md)

文件 用途 默认字符预算
MEMORY.md 跨任务仍有价值的环境事实等笔记 2,200
USER.md 稳定用户资料与偏好 1,375

默认位置是所选 home 的 memories/。预算可配置,不能把字符数直接按固定比例换成 token,中文尤其不同。记忆工具源码。

Frozen Snapshot 的意义:

  • 当前缓存块保持稳定,减少无谓前缀变更。
  • memory 工具写入持久存储后,工具返回可以展示新状态,但不逐条原地改写缓存块。
  • invalidate_system_prompt() 在压缩后清除缓存并从磁盘重载,因此同一会话也能在重建时看到更新。
  • 保存到磁盘、快照出现和模型正确使用,仍是不同环节。

容量满时应整合或替换,不要把任务专属流程不断堆进常驻记忆;可复用任务经验更适合 Skills。

4.3 Context Files(项目上下文)

当前按第一个非空类型选择:

优先级 类型 当前范围
1 .hermes.md / HERMES.md CWD 向上到 git root,最近匹配
2 AGENTS 类型 git root 到 CWD 的目录链;非 git 项目只检查 CWD
3 CLAUDE.md / claude.md CWD
4 .cursorrules 与 .cursor/rules/*.mdc CWD,可组合多个规则文件

AGENTS 类型每层按首个非空 AGENTS.override.md / AGENTS.md / agents.md 选择,再合并不同目录的内容。因此“只加载一个项目上下文文件”和“AGENTS 只看 CWD”都已经不准确。 子目录 hint 的渐进发现是另一层机制,不替代启动时目录链。

所有这些文件都属于指令输入。扫描主要识别已知注入/隐藏字符/外传模式;项目文件命中时可能替换成 BLOCKED 标记,不能保证覆盖所有攻击,也可能误报。用户自写 SOUL 的告警后加载是另一信任路径,不要混为“扫描通过”。

4.4 Skills Index

通常先有紧凑索引,再按任务加载全文与参考资料:

已有索引或 skills_list()
→ skill_view(name)
→ skill_view(name, path)(需要具体参考时)

不是必须依次调用三次的固定流程,也没有永远约 3k token 的目录大小。目录由技能数量、描述、平台/应用资格、toolset 条件和预算决定。当前还有可明确固定加载的 pinned skills,所以“任何技能全文都绝不注入”也过于绝对。

常见 frontmatter:

---
name: my-skill
description: Brief task-specific procedure
---
# Skill Title
...

更复杂的资格字段须按安装版本的 Skills schema 检查,不能把示例当成所有字段均有效的证明。Skills 文档。

4.5 完整组装示例

以下按当前实现概括,不再复制旧十层模板:

[stable]
选定身份 → 通用工具/模型指导 → 固定技能与编码操作指导

[context]
调用者 system_message → 项目规则 → 工作树与相关操作信息

[volatile,仍在缓存 system prompt 中]
Skills 索引 → MEMORY / USER 快照 → 外部记忆与插件块
→ profile、时间/会话/模型信息 → 运行环境

[该次 API 请求另加]
当前输入、历史、工具结果、临时 overlay / recall

这些是缓存与组装顺序,不是安全优先级列表。system_message 是这里接收的一份输入,不等于必然替换整段身份或突破宿主规则。OpenAI 模型的角色权限由消息角色与指令层级定义,不能从 SOUL 在 slot #1 推出最高权限。OpenAI 官方角色说明。


五、Provider Runtime Resolution

5.1 支持的 Providers

项目提供 Nous、OpenRouter、Anthropic、OpenAI、Gemini 及其他托管/本地路由。具体 provider ID、授权方式、模型目录和功能以当前 resolver 与配置为准,不保留“200+ 模型”这样的动态数字,也不承诺任意 OpenAI-compatible endpoint 都完整支持工具、图片或压缩。

5.2 API Modes

Hermes 用 chat_completions、codex_responses、anthropic_messages 等内部模式名选择消息适配路径。codex_responses 是 Hermes 的内部路由名称,不是 OpenAI 官方另一个名为 Codex Responses 的 API 标准。

OpenAI Responses 使用 typed input/output items,工具调用与结果也有专门 item;不能把内部 role: tool 消息直接等同于最终 Responses 请求。Hermes Provider 文档、OpenAI Responses 迁移说明。

5.3 Resolution 优先级

显式运行参数、配置、环境变量、登录状态和 provider 默认值共同决定有效路由;具体模型覆盖和辅助调用各有规则。不再用一个四层列表概括所有入口。调试时应检查解析后的 provider、model、api mode 与有效上下文预算,不能只看配置文件里的模型名。


六、双重压缩系统

Hermes 有 gateway hygiene 与 agent 内上下文压缩两条防线,但当前还有原生/server-side 路径及模型特例,不能把“双层 50% / 85%”当固定契约。

6.1 Gateway Session Hygiene(高水位检查)

gateway 在 agent 开始前做粗略估算与保护,文档中的典型阈值是 85%。是否触发还取决于入口、预算与当前会话状态。

6.2 Agent ContextCompressor(可配置阈值)

compression.threshold 默认配置仍为 0.50,但当前实现/文档还有小窗口阈值下限、模型/provider 覆盖、原生压缩与证据门控。小于 512K 的窗口有 75% 阈值下限,部分路由有特例,因此不能写“一到一半必压缩”。

API usage 能提供较准确计数,但并不是每个时刻都有最新 usage;新工具结果、恢复历史等仍需估算。官方压缩说明。

6.3 压缩配置

compression:
  enabled: true
  threshold: 0.50
  target_ratio: 0.20
  protect_last_n: 20

这是局部配置示例。target_ratio 在 legacy 模式控制受保护尾部相对阈值预算的比例,不等于所有算法统一保留“完整窗口 20%”;当前 lean 等模式另有策略。

6.4 压缩算法(职责视图)

  1. 必要时缩短旧工具输出,但保持调用/结果配对和关键约束。
  2. 选择摘要与保护尾部边界,具体由 context engine 与配置决定。
  3. 调用摘要模型提炼目标、约束、进展、决定、文件与后续步骤。
  4. 将摘要、保留历史和当前请求组成可继续的输入;处理失败、重试和缓存重建。

原文的四阶段与结构化摘要可作为设计理解,不能据此断言每条旧工具输出超过 200 字符就必清空,或固定保留前 3 条。压缩有损,不保证旧偏好、工具细节或所有约束都保留。


七、Prompt Caching(Anthropic)

当前 agent/prompt_caching.py 仍管理 Anthropic cache-control,但默认布局已不只是旧的 system_and_3。

7.1 缓存断点策略

条件 当前布局
有匹配的 static system prefix 稳定系统前缀 + 完整系统提示尾部 + 最近两个可缓存的非系统消息
无匹配 static prefix 一个 system 断点 + 最近三个可缓存的非系统消息

工具 schema、native/代理路由和可承载 marker 的消息类型还会影响最终计划。不能直接把“倒数三条任意消息”当固定位置。缓存源码。

7.2 缓存标记格式

{"type": "ephemeral"}
{"type": "ephemeral", "ttl": "1h"}

这些是标记示例,具体 TTL、路由支持与费用由 provider 决定;本文没有验证账号实际命中或账单。

7.3 缓存感知设计模式

尽量保持前缀字节稳定;中间内容变化可能减少后续可复用长度。压缩后是否保住稳定前缀、多久重建命中,要看实际请求与缓存指标。原文的“约省 75%”“1-2 轮恢复”来自项目描述/经验,不是本文实测,也不是所有会话保证,因此不保留固定收益承诺。


八、API Mode 与消息格式

8.1 内部消息格式

内部常用兼容 Chat Completions 的角色结构:

{"role": "user", "content": "..."}
{"role": "assistant", "content": "...", "tool_calls": []}
{"role": "tool", "tool_call_id": "...", "content": "..."}

这不是最终 provider 请求的统一 schema。Responses items、Anthropic content blocks 等都需适配。

8.2 消息交替规则

运行时需维护工具调用/返回的有效结构,部分模型模板要求更严格的角色交替,适配器可能合并或规范化相邻消息。不能据此宣布所有 OpenAI/Anthropic/自定义 API 都禁止连续 user 或 assistant;这是 provider/模板兼容问题,不是通用消息角色定律。


九、关键源码文件

文件 用途
run_agent.py AIAgent 对外入口与运行协调
agent/system_prompt.py 三层系统提示组装、缓存失效与重建
agent/prompt_builder.py SOUL、项目文件、Skills 等加载帮助函数
agent/context_compressor.py 上下文压缩
agent/prompt_caching.py cache-control 计划与消息标记
tools/memory_tool.py 记忆工具与 home/预算解析
hermes_state.py 会话/状态持久化
gateway/run.py gateway 分发与运行协调

源码引用均锁定本次提交;文件名与方法可能继续变化。


十、与 OpenClaw 的关键差异

方面 Hermes OpenClaw
身份 通常 SOUL 作为首个身份块 workspace persona,载体按 harness 区分
Skills 索引、skill_view,另有 pinned skills 目录与按需 read,原生宿主有不同载体
项目上下文 先选类型,再可能合并目录链 多种 Bootstrap 与原生项目发现
Memory 缓存快照,可在压缩重建刷新 有界注入/按需工具/主动召回,按 harness 区分
压缩 gateway + context engine,含路由特例 内置/插件/native 路径,各有边界
缓存 本地 system 缓存与 provider 策略 稳定前缀、刷新与 provider/harness 缓存机制
Provider 协议 多种适配模式 同样不是只支持 chat completions
子代理 有独立上下文与运行配置 也可有模型/工具/上下文覆盖,不能简单说只继承父级

这里比较的是实现思路,不是功能排名;两个项目的版本和选用 harness 对结论影响很大。OpenClaw 官方 System Prompt。


十一、相关文档索引


2026-10-13 资料核对:已浏览官方文档并读取上述提交的 system_prompt、prompt_builder、memory_tool、prompt_caching 源码与压缩文档;OpenAI/Codex 相关先读本地 openai-docs 技能,再查官方角色和 Responses 资料。文档旧示例与源码冲突处已明确按源码修正。未运行 Hermes、provider API、压缩或费用测试。

记录到这里,判断留给实践。