当前位置: 首页
AI教程
Hermes Agent身份定制设计:3层提示词与14人格源码解析

Hermes Agent身份定制设计:3层提示词与14人格源码解析

热心网友 时间:2026-06-04
转载

你有没有遇到过这样的情况:同一个 AI Agent,在项目 A 里回复得专业克制,到了项目 B 却突然变得絮絮叨叨,风格飘忽不定?

这不是模型的问题,是人格定义的方式有问题。

大部分 Agent 框架把身份、风格、项目规范全塞在一个 system prompt 里,改个项目配置不小心就把 Agent 的说话方式也改了。Hermes Agent 用一套三层架构解决了这个矛盾:SOUL.md 管身份,AGENTS.md 管项目,/personality 管临时风格切换。三个东西各司其职,互不干扰。

Hermes Agent 是 Nous Research 开发的开源 AI Agent(GitHub Star 已突破 60,000),支持 200+ 大模型和 15+ 消息平台。它把"Agent 是谁"这个问题单独拎出来,给了专门的文件、专门的加载逻辑、专门的安全机制。

翻了翻它的源码和官方文档,发现这个设计比看起来要精细得多。下面从源码层面把它拆开。

1. 三层提示词:为什么不是一层?

Hermes 的系统提示词不是一坨拼在一起的大字符串,而是分成了三层:stable(稳定层)、context(上下文层)、volatile(易变层)。

这三层不是随便分的。目的就一个:前缀缓存友好。

源码位置:agent/system_prompt.pybuild_system_prompt_parts() 函数。

stable 层包含 SOUL.md 身份、工具行为引导、技能提示、环境提示这些在整个会话生命周期中基本不变的内容。context 层放用户传入的 system_message 和 AGENTS.md 等上下文文件,会话之间可能变化。volatile 层放记忆快照、USER.md 画像、时间戳、会话 ID 这些每次都会变的东西。

关键设计:系统提示词在每个会话中只构建一次并缓存到 agent._cached_system_prompt,只有在上下文压缩事件后才重建。

为什么要这么干?因为大模型的 API 调用中,系统提示词是前缀的一部分。如果前缀不变,就可以利用 API 提供商的前缀缓存机制(比如 Anthropic 的 prompt caching),省掉重复的 token 计费。把不变的东西放在 stable 层前面,变的东西放在 volatile 层后面,就是在为缓存命中创造条件。

这个设计在测试里也有覆盖。test_system_prompt.py 确认了三层按序拼接,stable 层的 SOUL.md 永远在第一个位置。

三层提示词架构图三层提示词架构图

stable 层里面到底有什么?

源码位置:agent/system_prompt.pybuild_system_prompt_parts()

stable 层不是只有 SOUL.md。它由 14 个部分按序拼接而成,SOUL.md 只是第一个:

- SOUL.md 内容(或 DEFAULT_AGENT_IDENTITY 回退) - HERMES_AGENT_HELP_GUIDANCE — 引导用户了解 Hermes 自身配置 - TASK_COMPLETION_GUIDANCE — 通用任务完成/反虚构引导 - 工具感知行为引导(按条件注入):记忆、搜索、技能、Kanban - COMPUTER_USE_GUIDANCE — 计算机使用引导(macOS) - Nous 订阅提示 - TOOL_USE_ENFORCEMENT_GUIDANCE — 工具使用强制引导 - 模型特定操作引导(Google/OpenAI 模型) - 技能系统提示 - 模型身份覆盖(Alibaba 等特殊提供商) - 环境提示(WSL、Termux 等) - Python 工具链探针 - 活跃配置文件提示 - 平台特定格式提示

SOUL.md 被放在 stable 层第一个位置是有原因的。stable 层里后面的内容(工具引导、环境提示等)都以 SOUL.md 定义的身份为前提。SOUL.md 放后面的话,这些引导就会以默认身份运行,和 SOUL.md 定义的风格冲突。

这也是 SOUL.md 只从 HERMES_HOME 加载的原因:stable 层在会话开始时一次性组装,之后不变。SOUL.md 位置不确定,stable 层就不稳定,前缀缓存就废了。

2. SOUL.md 加载流程:从文件到提示词

SOUL.md 的加载链路不长,但每一步都有讲究。

源码位置:agent/prompt_builder.pyload_soul_md() 函数。

def load_soul_md() -> Optional[str]:
    # 1. 确保 HERMES_HOME 目录存在
    ensure_hermes_home()
    # 2. 只从 HERMES_HOME 加载,不搜索当前工作目录
    soul_path = get_hermes_home() / "SOUL.md"
    # 3. 文件不存在 → 返回 None
    if not soul_path.exists():
        return None
    # 4. 读取并去除首尾空白
    content = soul_path.read_text(encoding="utf-8").strip()
    # 5. 空文件也返回 None
    if not content:
        return None
    # 6. 安全扫描
    content = _scan_context_content(content, "SOUL.md")
    # 7. 截断
    content = _truncate_content(content, "SOUL.md")
    return content

只认 HERMES_HOME,不认 cwd

load_soul_md()soul_path = get_hermes_home() / "SOUL.md" 这一行写死了路径。不管你在哪个目录启动 Hermes,它只看 ~/.hermes/SOUL.md

官方文档对这个设计有明确解释:

测试文件 test_prompt_builder.py 里的 test_loads_soul_md_from_hermes_home_only() 也验证了这一点:在 HERMES_HOME 和当前工作目录各放一个 SOUL.md,结果只有 HERMES_HOME 的那个被加载。

这和 AGENTS.md 的行为完全相反。AGENTS.md 是从工作目录向上遍历到 git root 去发现的,因为它管的是项目级的东西。SOUL.md 管的是人,人走到哪身份都一样,所以只认一个地方。

回退到默认身份

如果 load_soul_md() 返回 None(文件不存在、内容为空、或被安全扫描拦截),Hermes 会使用硬编码的 DEFAULT_AGENT_IDENTITY

DEFAULT_AGENT_IDENTITY = ("You are Hermes Agent, an intelligent AI assistant "
                          "created by Nous Research. You are helpful, "
                          "knowledgeable, and direct.")

这段文本(prompt_builder.py 第 121-129 行)同时也是首次运行时自动播种到 ~/.hermes/SOUL.md 的默认内容。_ensure_default_soul_md() 函数在 ensure_hermes_home() 中被调用,只在 SOUL.md 不存在时创建,已有文件永远不会被覆盖。

这个自动播种机制的设计很克制:它不会在你每次启动时检查内容是否是默认的,也不会覆盖你的修改。它做的事情就是——文件不存在就创建,存在就不管。这意味着你拿到的是一个干净的起点,而不是一个需要先删掉才能开始定制的模板。

原样注入,不加包装

源码 system_prompt.py 第 94 行:stable_parts.append(_soul_content)

就是直接 append,不加任何前缀、后缀或解释性文字。没有 "If SOUL.md is present" 这种提示,也没有 "## SOUL.md" 这种标题包装。

测试 test_soul_md_has_no_wrapper_text() 专门断言了这些包装文本不会出现在结果中。为什么?因为 SOUL.md 的内容本身就是给模型看的身份描述,加一层包装反而会干扰模型的注意力分配。

3. 安全扫描:防注入的第一道门

SOUL.md 是用户自己写的文件,但它会被原样注入到系统提示词里。如果有人在 SOUL.md 里写了提示注入指令(比如"忽略之前的所有指令"),Agent 就会被劫持。

Hermes 用 _scan_context_content() 函数来应对这个问题。

源码位置:prompt_builder.py

def _scan_context_content(content: str, filename: str) -> str:
    findings = _scan_for_threats(content, scope="context")
    if findings:
        return f"[BLOCKED: {filename} contained potential prompt injection]"
    return content

扫描使用 "context" scope 的威胁模式库,覆盖了经典注入模式、promptware/C2 模式、角色扮演劫持等。但不使用 "strict" scope(SSH 后门、持久化、数据泄露 URL 检测),因为对仓库中的上下文文件来说太激进了,容易误报。

一旦检测到威胁,加载会被完全阻止,返回一个 [BLOCKED: ...] 占位符。不是警告,不是删掉可疑部分继续用,是直接拦住。因为内容会原样进入系统提示词,没有第二次处理的机会。

这个安全扫描不只针对 SOUL.md,所有上下文文件(AGENTS.md、CLAUDE.md、.cursorrules)都会经过同一套扫描流程。不过 scope 不同:SOUL.md 使用 "context" scope,检测注入和劫持模式;对仓库里的文件也是同样的 scope。"strict" scope(检测 SSH 后门、持久化、数据泄露 URL 等)只在更严格的场景下使用,因为对用户自己写的上下文文件来说,这些检测太容易误报了。

截断机制

如果 SOUL.md 写得太长,Hermes 会通过 _truncate_content() 进行截断。截断的方式是保留头部和尾部,中间插入截断标记。这种两头保留的策略意味着你在 SOUL.md 开头定义的身份描述和结尾的风格约束都会被保留,被砍的是中间可能不那么关键的内容。

不过说实话,SOUL.md 本来就不应该写太长。官方文档建议的内容特征是"跨上下文稳定、足够广泛适用于多种对话、足够具体能实质性塑造风格"——满足这三个条件的文本通常不会太长。如果你发现自己写了很长,很可能已经越界到项目级指令的范畴了。

4. /personality 命令:14 个人格预设 + 自定义

SOUL.md 是持久的人格基线。但有时候你想临时换个风格——比如代码审查时用严厉的语气,讨论创意时换成活泼的语气。这时候就用 /personality 命令。

内置的 14 个人格

源码位置:cli.py 第 406-421 行。

Hermes 内置了 14 个预设,从实用的到整活的都有:

类型名称定位
实用型helpful、concise、technical、creative、teacher日常工作场景
趣味型kawaii、catgirl、pirate、shakespeare、surfer、noir、uwu风格化对话
特殊型philosopher、hype深度思考 / 极度热情

/personality pirate 就能让 Agent 开始用海盗风格回复你。说实话,测试的时候切到 shakespeare 模式跑了一段代码审查,输出确实挺有戏剧效果的——不过实际干活还是 technical 更靠谱。

自定义人格

除了内置预设,还支持在 config.yaml 中自定义。两种格式都行:

agent:
  personalities:
    # 简单 string 格式
    codereviewer: >
      You are a meticulous code reviewer...
    # dict 格式,更细粒度
    coder:
      description: "Expert programmer"
      system_prompt: "You are an expert programmer."
      tone: "technical"
      style: "concise"

overlay 机制,不是替换

/personality 的设计是叠加层(overlay),不是替换。它在系统提示词的 context 层注入,位于 SOUL.md 之后。SOUL.md 定义的是你的 Agent 是谁,/personality 定义的是它这次对话用什么语气。两者共存。

从源码看,_handle_personality_command()cli.py)的执行流程是这样的:

1. /personality self.personalities 字典中查找对应的人格 2. 找到后,将 personality 文本写入 self.system_prompt(即 agent.system_prompt 配置项) 3. 设置 self.agent = None,强制 Agent 在下次对话时重新初始化 4. 将选择持久化到 config.yamlagent.system_prompt 字段

关键点在第 3 步。设置 self.agent = None 不是重启整个 Agent,而是让它在下次需要时重新初始化。重新初始化时会重新组装系统提示词,此时新的 personality 就会被注入到 context 层。

清除 personality 也简单:/personality none/personality default/personality neutral 都能清除 overlay,恢复 SOUL.md 的基准身份。清除的方式是重置 system_prompt 配置项并再次触发 Agent 重建。

人格切换效果对比图人格切换效果对比图

在 Gateway 模式下(tui_gateway/server.py),_apply_personality_to_session() 会在会话历史中插入一条系统消息,格式是 [System: The user has changed the assistant's personality. ...]。注意它保留历史记录,不重置会话。这意味着在 Gateway 模式下切换 personality 是非破坏性的——之前的对话不会丢失。

5. SOUL.md vs AGENTS.md:别把活放错了地方

Hermes 对这两个文件有非常明确的职责划分。官方文档的原话很直白:

一句话的判断准则:这个东西是不是应该跟着你走?

维度SOUL.mdAGENTS.md
管的身份、语气、沟通风格项目架构、编码规范、工具偏好
作用域所有项目、所有会话仅当前项目
位置$HERMES_HOME/SOUL.md$CWD/AGENTS.md
加载层stable 层(Slot #1)context 层

SOUL.md 写什么:"Be direct." "A void hype language." "Push back when the user is wrong."

AGENTS.md 写什么:"Use pytest, not unittest." "Frontend lives in frontend/." "The API runs on port 8000."

一个常见的错误是把项目级指令放进 SOUL.md。比如你写了一句 "All responses should be in English because our team is international",这句话放 SOUL.md 会导致你在个人项目里也被强制要求英文回复。正确的做法是放进项目根目录的 AGENTS.md。

另一个常见错误是反过来:把风格偏好写进 AGENTS.md。比如 "Always respond in a friendly and encouraging tone"——这句话应该放在 SOUL.md,因为它是人格层面的偏好,不管你在哪个项目里都适用。

一个简单的判断方法:关闭所有项目,只开一个空白对话,你还希望 Agent 保持这个行为吗? 如果是,放 SOUL.md。如果不是,放 AGENTS.md。

话说回来,这种分离在目前 Agent 框架中并不常见。Claude Code 的 CLAUDE.md 和 Cursor 的 .cursorrules 都是项目级文件,身份和项目指令混在一起。Hermes 多了一层全局身份管理,代价是多维护一个文件,收益是身份的稳定性和可预测性。

有意思的是,Hermes 还主动兼容了 CLAUDE.md 和 .cursorrules。如果项目根目录有这些文件且没有更高优先级的上下文文件,Hermes 会自动加载它们。这意味着从 Claude Code 或 Cursor 迁移到 Hermes,项目配置基本无缝衔接,SOUL.md 只需要管好身份这一件事就够了。

6. 特殊执行模式:谁继承 SOUL.md,谁不继承

SOUL.md 在不同执行模式下的行为不一样,这个在设计上是有意的。

Cron 任务:继承

源码位置:cron/scheduler.py 第 1654-1659 行。

# Cron jobs should always inherit the user's SOUL.md identity
load_soul_identity=True,

即使 Cron 任务跳过了其他上下文文件,SOUL.md 身份还是会被加载。设计意图很明确:定时任务也是你派出去的,带着你的身份去干活。

子袋里/委托模式:不继承

源码位置:cli.py 第 3161 行。

# AGENTS.md/SOUL.md/.cursorrules and persistent memory are not loaded.

子袋里用的是 DEFAULT_AGENT_IDENTITY,不加载 SOUL.md。这也是合理的——子袋里是主 Agent 的工具,不需要也不应该有人格偏好。想象一下,如果你让主 Agent 去搜索文件,搜索子 Agent 突然用 shakespeare 风格返回结果,那对话就乱了。

另外还有个环境变量 HERMES_IGNORE_RULES,设置为 1 时会跳过所有上下文文件(AGENTS.md、SOUL.md、.cursorrules)和持久记忆的加载。这个主要用于调试和隔离测试场景。

多 Profile 系统

Hermes 支持 Profile(配置文件)系统,每个 Profile 位于 ~/.hermes/profiles//,拥有独立的 SOUL.md、config.yaml、skills、cron、memories。源码 hermes_cli/main.py 第 10835 行的输出信息也确认了这一点:Edit {profile_dir_display}/SOUL.md for different personality

多 Profile 目录结构图多 Profile 目录结构图

这意味着你可以给工作、学习、个人项目各建一个 Profile,每个有不同的人格。切换 Profile 就切换了整个身份体系。

容器写入保护

tests/agent/test_file_safety_container_mirror.py 中有一个有意思的测试:classify_container_mirror_target() 会检测对 profiles/*/SOUL.md 的写入尝试。

简单说,Hermes 的文件安全机制会阻止 Agent 通过容器路径篡改自己的 SOUL.md。这是防止 Agent 自我修改身份的保护措施——你不能让一个 AI 自己把自己的约束给删了。

7. 最佳实践

从源码和官方文档里提炼几条实际可操作的建议。

SOUL.md 写什么

参考官方给出的示例模板:

# Personality
You are a pragmatic senior engineer with strong taste.
You optimize for truth, clarity, and usefulness over politeness theater.

## Style
- Be direct without being cold
- Prefer substance over filler
- Push back when something is a bad idea
- Admit uncertainty plainly

## What to a void
- Sycophancy
- Hype language
- Repeating the user's framing if it's wrong

## Technical posture
- Prefer simple systems over clever systems
- Care about operational reality
- Treat edge cases as part of the design

不写什么

- 不写项目指令:用什么框架、跑在哪个端口、目录结构怎么组织,这些放 AGENTS.md - 不写临时风格:今天想让它活泼点?用 /personality,别改 SOUL.md - 不写敏感信息:虽然 SOUL.md 经过安全扫描,但别在里面放 API Key 或密码

/personality 配合使用

SOUL.md 定义基线,/personality 做临时切换。一个合理的用法是:

- SOUL.md 定义你的核心风格偏好(直接、不废话、技术导向) - 日常对话用默认身份(走 SOUL.md) - 代码审查时切 /personality technical 获得更严谨的分析 - 头脑风暴时切 /personality creative 激发更多想法 - 每次切完不用手动恢复,/personality none 自动回到基线

迭代优化方法

SOUL.md 不是写一次就完事的东西。官方文档建议的特征是:跨上下文稳定、足够广泛适用于多种对话、足够具体能实质性塑造风格。

实际操作中,可以这样做:

1. 先用默认身份跑几天,感受 Agent 的回复风格 2. 把让你不满意的地方记录下来(太啰嗦?太讨好?不够直接?) 3. 在 SOUL.md 中针对性地加一条规则 4. 再跑几天,看效果是否改善 5. 重复这个循环

一条好的 SOUL.md 规则是这样的:它不依赖于特定项目或特定话题,而是描述一种沟通偏好。比如 "Push back when something is a bad idea" 这条规则,不管你让 Agent 写代码还是写文章,它都会适用。

和其他框架的对比

如果你之前用过 Claude Code 或 Cursor,可以参考这个对应关系来理解 SOUL.md 的定位:

你在想什么放在 Hermes 的哪里
"我希望 Agent 回复更直接"SOUL.md
"这个项目用 TypeScript"AGENTS.md
"今天想让 Agent 用海盗风格聊天"/personality pirate
"团队代码规范:用 ESLint"AGENTS.md
"Agent 不应该过度讨好我"SOUL.md

从 Claude Code 迁移的用户可以直接把 CLAUDE.md 留在项目根目录,Hermes 会自动识别。你只需要额外创建一个 SOUL.md 来定义人格——那些原来和身份混在一起的 CLAUDE.md 内容不需要删。从 OpenClaw 迁移更简单,hermes claw migrate 一条命令就能把配置和数据搬过来,SOUL.md 也会被自动导入。

总结

回头看 Hermes 的 SOUL.md,几个设计选择挺有意思:身份和项目严格分离、原样注入不加包装、三层分离给前缀缓存腾空间、overlay 叠加而非替换。

从源码看,每个决策都有实际理由——位置锁定为了可预测性,原样注入为了不干扰模型注意力,三层分离为了缓存命中,overlay 为了灵活性。安全扫描、容器写入保护、子袋里跳过这些边界处理也都没落下。

如果你的场景需要给 Agent 一个稳定的、跨项目的身份,Hermes 的 SOUL.md 方案值得看看。

你在项目中用过 Agent 人格定制吗?SOUL.md 的这种"身份与项目分离"的设计,和你在用的工具有什么不同?欢迎在评论区聊聊。

来源:https://cloud.tencent.com.cn/developer/article/2682032

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
Claude Code进阶:32个Skills与8个MCP提升开发效率

Claude Code进阶:32个Skills与8个MCP提升开发效率

围绕ClaudeCode整理了32个亲测可用的Skills和8个MCP服务器:Skills提供标准化提示词与工作流,MCP赋予访问本地文件、浏览器等工具能力。两者均支持一键安装、自动触发,无需手动配置即可自动激活,显著提升开发、测试、部署等全流程效率。

时间:2026-06-04 18:16
Claude Code真实项目实战体验

Claude Code真实项目实战体验

前言 最近接连多个紧急项目集中推进,团队人手实在捉襟见肘。为了缓解开发压力,索性自己动手写代码——当然,如今写代码全靠Claude Code代劳,谁还手动敲键盘呢。 敢于全权交给AI来生成代码,是因为这些项目虽然紧急,但属于后台系统,与线上核心业务有一定隔离。这样的项目正是实践AI编程的最佳场景——

时间:2026-06-04 18:14
零基础两小时用Claude Code为对象打造专属数字衣橱

零基础两小时用Claude Code为对象打造专属数字衣橱

起因换季时节,对象开始翻衣柜。翻了半小时,翻出一件完全忘记存在的毛衣,两件几乎一模一样的白T,还有一条“失踪”了三个月、其实一直在最底层的裤子。她说:要是有个 App 能把衣服都存进去就好了,找的时候搜一下,买之前也能看看自己有什么。这个需求听起来很合理。正好最近对AI比较着迷,看能不能借助AI手搓

时间:2026-06-04 18:14
2026 Codex手机号验证教程 国内ChatGPT验证问题解决

2026 Codex手机号验证教程 国内ChatGPT验证问题解决

近期,不少开发者被Codex的手机号验证卡住了。OpenAI的风控力度明显加码,很多人在使用ChatGPT Codex、Codex CLI或者生成API Key的过程中,突然就被要求验证手机号。 这篇文章会深入拆解Codex触发手机号验证的根本原因,同时给国内用户提供一套可落地的接码方案,帮助你尽快

时间:2026-06-04 18:14
新手从零搭建OpenClaw自动化智能体全流程指南

新手从零搭建OpenClaw自动化智能体全流程指南

OpenClaw 智能助理:六大核心场景赋能开发者高效成长 当AI能力开始下沉到每一个开发者的桌面,真正能让人“用起来”的产品,其实比想象中少得多。多数工具要么太复杂,要么太通用,很难直接嵌入工作流。阿里云推出的OpenClaw智能助理,算是其中少有的“开箱即用”型选手——基于通义千问大模型深度定制

时间:2026-06-04 18:14
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜