Hermes Agent SOUL.md:3 層提示詞、14 個內置人格,從源碼看身份定製的完整設計

作者:術哥無界
日期:2026年6月3日 上午8:30
來源:WeChat 原文

整理版優先睇

速讀 5 個重點 高亮

Hermes Agent 用三層提示詞同 SOUL.md 實現身份與項目分離,確保 Agent 人格穩定統一

整理版摘要

呢篇文章由術哥撰寫,佢係專注 AI 編程同 Agent 技術嘅實踐者,透過分析 Hermes Agent 源碼同官方文檔,拆解 SOUL.md 人格系統嘅設計原理。文章主要想解決一個常見問題:點解同一個 AI Agent 喺唔同項目會有唔同風格?傳統做法將身份、風格、項目規範全部塞入 system prompt,改project 時好易搞亂 Agent 嘅說話方式。Hermes Agent 用一套三層提示詞架構(stable、context、volatile)將呢啲嘢分開,其中 SOUL.md 專門管理 Agent 嘅身份同溝通風格,唔受項目影響。

文章從源碼層面詳細解釋咗三層點樣運作:stable 層包含 SOUL.md 同埋工具引導等不變內容,擺喺最前面以利前綴緩存;context 層放用戶訊息同 AGENTS.md 等項目文件;volatile 層放每次對話都會變嘅記憶同時間戳。SOUL.md 只會從 $HERMES_HOME 加載,原樣注入 system prompt,唔加任何包裝,確保模型直接接收身份描述。另外仲有安全掃描同截斷機制,防止提示注入同過長內容。

整體結論係Hermes Agent 透過身份同項目嚴格分離,配合 /personality 命令嘅 overlay 機制,做到穩定嘅人格基線同時保留靈活切換。呢個設計比主流框架(如 Claude CodeCursor)多一層全局身份管理,代價係多維…

  • Hermes Agent 三層提示詞(stable/context/volatile)將不變嘅身份引導同變動嘅上下文分開,提升前綴緩存命中率,節省 API 成本。
  • SOUL.md 只從 $HERMES_HOME 加載,唔受工作目錄影響,確保人格跨項目一致;而 AGENTS.md 從項目目錄加載,管理項目級指令。
  • SOUL.md 原樣注入 system prompt,冇任何包裝文本,避免幹擾模型注意力;安全掃描會攔截提示注入,阻止惡意指令進入系統提示詞。
  • /personality 命令提供 14 個內置人格預設同自定義選項,以 overlay 方式疊加喺 SOUL.md 之上,唔係完全取代,可用 /personality none 恢復基線。
  • 最佳實踐:先用默認身份觀察回覆,記錄不滿之處,逐步調整 SOUL.mdSOUL.md 應包含跨上下文穩定嘅溝通偏好,唔好放項目指令或臨時風格。
值得記低
Prompt

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 avoid - 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

整理重點

三層提示詞:點解唔係一層?

Hermes 嘅系統提示詞唔係一舊過拼埋一齊嘅大字符串,而係分成三層:stable(穩定層)、context(上下文層)、volatile(易變層)。目的係為咗前綴緩存友好——將唔變嘅內容放喺前面,變嘅內容放後面,咁樣 API 提供商就可以重用已緩存嘅前綴,節省 token 計費。

stable 層包含 SOUL.md 身份、工具行為引導、技能提示、環境提示呢啲整個會話生命週期基本不變嘅內容

context 層放用戶傳入嘅 system_message 同 AGENTS.md 等上下文文件

volatile 層放記憶快照、USER.md 畫像、時間戳、會話 ID 呢啲每次都會變嘅嘢

  • stable 層總共有 14 個部分,SOUL.md 係第一個
  • SOUL.md 放第一個係因為後面嘅工具引導都以佢定義嘅身份為前提
  • SOUL.md 只從 HERMES_HOME 加載,確保 stable 層穩定,唔會搞亂緩存
整理重點

SOUL.md 加載流程:從文件到提示詞

SOUL.md 嘅加載鏈路由 load_soul_md() 函數執行,路徑寫死喺 get_hermes_home() / "SOUL.md",只認 ~/.hermes/SOUL.md,唔會從當前工作目錄揾。呢個設計同 AGENTS.md 相反——AGENTS.md 管項目,所以從 cwd 向上遍歷;SOUL.md 管人,人走到邊度身份都一樣。

位置鎖定確保人格唔會因為啟動目錄唔同而改變

如果 SOUL.md 唔存在或者內容為空,Hermes 會用硬編碼嘅 DEFAULT_AGENT_IDENTITY。首次運行時,_ensure_default_soul_md() 會自動播種默認內容到 ~/.hermes/SOUL.md,但唔會覆蓋你之後嘅修改。

load_soul_md() 核心邏輯 python
def load_soul_md() -> Optional[str]:
 ensure_hermes_home()
 soul_path = get_hermes_home() / "SOUL.md"
 if not soul_path.exists():
 return None
 content = soul_path.read_text(encoding="utf-8").strip()
 if not content:
 return None
 content = _scan_context_content(content, "SOUL.md")
 content = _truncate_content(content, "SOUL.md")
 return content

原樣注入:system_prompt.py 第 94 行直接 append _soul_content,冇任何前綴後綴或解釋性文字

測試 test_soul_md_has_no_wrapper_text 專門斷言包裝文本唔會出現

整理重點

/personality 命令:14 個人格預設 + 自定義

SOUL.md 係持久嘅人格基線,但有時你想臨時轉風格,例如 code review 時用嚴厲語氣,討論創意時用活潑語氣。呢個時候就可以用 /personality 命令。Hermes 內置咗 14 個人格預設,分實用型同趣味型兩大類。

  1. 1 實用型:helpful、concise、technical、creative、teacher
  2. 2 趣味型:kawaii、catgirl、pirate、shakespeare、surfer、noir、uwu
  3. 3 特殊型:philosopher、hype

/personality 嘅設計係 overlay(疊加層),唔係替換

Overlay 喺 context 層注入,位於 SOUL.md 之後。SOUL.md 定義你個 Agent 係邊個,/personality 定義佢今次對話用咩語氣。兩者共存。清除 personality 可以用 /personality none、/personality default 或 /personality neutral,都會恢復基線身份。

清除 personality 嘅方式係重置 system_prompt 配置項並觸發 Agent 重建

除咗內置預設,仲可以喺 config.yaml 自定義人格,支援簡單 string 格式同更細粒度嘅 dict 格式。

整理重點

SOUL.md vs AGENTS.md:咪放錯位

如果呢個特性應該跟你走,就放 SOUL.md;如果屬於一個 project,就放 AGENTS.md

SOUL.md 管身份、語氣、溝通風格,作用域係所有項目、所有會話,位置喺 $HERMES_HOME/SOUL.md,加載層係 stable(Slot #1)。AGENTS.md 管項目架構、編碼規範、工具偏好,作用域僅當前項目,位置喺 $CWD/AGENTS.md,加載層係 context 層。

常見錯誤:將項目級指令放 SOUL.md,例如「全部用英文回覆」會令個人項目都強制英文

Hermes 主動兼容 CLAUDE.md 同 .cursorrules,遷移時 project 配置無縫銜接

整理重點

最佳實踐:迭代優化你的 SOUL.md

SOUL.md 唔係寫一次就完事嘅。官方建議嘅特徵係「跨上下文穩定、足夠廣泛適用於多種對話、足夠具體能實質性塑造風格」。實際操作可以分幾步行:先用默認身份跑幾日,感受 Agent 嘅回覆風格;然後記錄唔滿意嘅地方(太囉嗦?太討好?);再喺 SOUL.md 有針對性地加規則,之後再試效果,重複呢個循環。

一條好嘅 SOUL.md 規則應該唔依賴特定項目或話題,而係描述一種溝通偏好

  • 唔好寫項目指令:用咩框架、跑咩 port、目錄結構——呢啲放 AGENTS.md
  • 唔好寫臨時風格:今日想佢活潑啲?用 /personality,唔好改 SOUL.md
  • 唔好寫敏感資訊:雖然有安全掃描,但唔好喺入面放 API Key 或密碼

與 /personality 配合使用:SOUL.md 定義基線,/personality 做臨時切換

例如 SOUL.md 定義核心風格偏好(直接、唔廢話、技術導向),日常對話用默認身份,code review 時用 /personality technical,腦力激盪時用 /personality creative。每次切完用 /personality none 自動返回基線。

🚩 2026 年「術哥無界」系列實戰文檔 X 篇原創計劃 第 129 篇,Hermes Agent  最佳實戰「2026」系列第 8 篇

大家好,歡迎來到 術哥無界 | ShugeX | 運維有術

我是術哥,一名專注於 AI 編程、AI 智能體、Agent Skills、MCP、雲原生、AIOps、Milvus 向量數據庫的技術實踐者與開源佈道者

Talk is cheap, let's explore。無界探索,有術而行。

封面圖
封面圖

圖 1:Hermes Agent SOUL.md 人格系統核心要點

說明:本文內容基於 Hermes Agent 源碼(NousResearch/hermes-agent)和官方文檔分析整理而成,源碼分析基於筆者本地倉庫版本。文中的配置模板和參數建議僅供參考,實際效果請以你的業務數據和環境測試結果為準。如果有實際使用經驗,歡迎在評論區分享交流。

你有沒有遇到過這樣的情況:同一個 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 是誰"這個問題單獨拎出來,給了專門的文件、專門的加載邏輯、專門的安全機制。

我翻了 Hermes 的源碼和官方文檔,發現這個設計比看起來要精細得多。下面從源碼層面把它拆開。

1. 三層提示詞:為什麼不是一層?

Hermes 的系統提示詞不是一坨拼在一起的大字符串,而是分成了三層:stable(穩定層)、context(上下文層)、volatile(易變層)。

這三層不是隨便分的。目的就一個:前綴緩存友好

源碼位置:agent/system_prompt.py 的 build_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 永遠在第一個位置。

三層提示詞架構圖
三層提示詞架構圖

圖 2:Hermes Agent 三層提示詞架構(stable / context / volatile)

stable 層裏面到底有什麼?

源碼位置:agent/system_prompt.py 的 build_system_prompt_parts()

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

  1. SOUL.md 內容(或 DEFAULT_AGENT_IDENTITY 回退)
  2. HERMES_AGENT_HELP_GUIDANCE — 引導用戶瞭解 Hermes 自身配置
  3. TASK_COMPLETION_GUIDANCE — 通用任務完成/反虛構引導
  4. 工具感知行為引導(按條件注入):記憶、搜索、技能、Kanban
  5. COMPUTER_USE_GUIDANCE — 計算機使用引導(macOS)
  6. Nous 訂閲提示
  7. TOOL_USE_ENFORCEMENT_GUIDANCE — 工具使用強制引導
  8. 模型特定操作引導(Google/OpenAI 模型)
  9. 技能系統提示
  10. 模型身份覆蓋(Alibaba 等特殊提供商)
  11. 環境提示(WSL、Termux 等)
  12. Python 工具鏈探針
  13. 活躍配置文件提示
  14. 平台特定格式提示

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.py 的 load_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
    ifnot soul_path.exists():
        returnNone
    
    # 4. 讀取並去除首尾空白
    content = soul_path.read_text(encoding="utf-8").strip()
    
    # 5. 空文件也返回 None
    ifnot content:
        returnNone
    
    # 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

官方文檔對這個設計有明確解釋:

If Hermes loaded SOUL.md from whatever directory you happened to launch it in, your personality could change unexpectedly between projects.

測試文件 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 <name> 從 self.personalities 字典中查找對應的人格
  2. 找到後,將 personality 文本寫入 self.system_prompt(即 agent.system_prompt 配置項)
  3. 設置 self.agent = None,強制 Agent 在下次對話時重新初始化
  4. 將選擇持久化到 config.yaml 的 agent.system_prompt 字段

關鍵點在第 3 步。設置 self.agent = None 不是重啓整個 Agent,而是讓它在下次需要時重新初始化。重新初始化時會重新組裝系統提示詞,此時新的 personality 就會被注入到 context 層。

清除 personality 也簡單:/personality none/personality default/personality neutral 都能清除 overlay,恢復 SOUL.md 的基準身份。清除的方式是重置 system_prompt 配置項並再次觸發 Agent 重建。

人格切換效果對比圖
人格切換效果對比圖

圖 3:/personality 命令 overlay 效果對比——疊加而非替換

在 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 對這兩個文件有非常明確的職責劃分。官方文檔的原話很直白:

If it should follow you everywhere, it belongs in SOUL.md. If it belongs to a project, it belongs in AGENTS.md.

一句話的判斷準則:這個東西是不是應該跟着你走?

維度
SOUL.md
AGENTS.md
身份、語氣、溝通風格
項目架構、編碼規範、工具偏好
作用域
所有項目、所有會話
僅當前項目
位置
$HERMES_HOME/SOUL.md$CWD/AGENTS.md
加載層
stable 層(Slot #1
context 層

SOUL.md 寫什麼:"Be direct." "Avoid 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/<name>/,擁有獨立的 SOUL.md、config.yaml、skills、cron、memories。源碼 hermes_cli/main.py 第 10835 行的輸出信息也確認了這一點:Edit {profile_dir_display}/SOUL.md for different personality

多 Profile 目錄結構圖
多 Profile 目錄結構圖

圖 4:Hermes Agent 多 Profile 目錄結構——每個 Profile 擁有獨立的 SOUL.md

這意味着你可以給工作、學習、個人項目各建一個 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 avoid
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 做臨時切換。一個合理的用法是:

  1. SOUL.md 定義你的核心風格偏好(直接、不廢話、技術導向)
  2. 日常對話用默認身份(走 SOUL.md)
  3. 代碼審查時切 /personality technical 獲得更嚴謹的分析
  4. 頭腦風暴時切 /personality creative 激發更多想法
  5. 每次切完不用手動恢復,/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 的這種"身份與項目分離"的設計,和你在用的工具有什麼不同?歡迎在評論區聊聊。

好啦,謝謝你觀看我的文章,如果喜歡可以點贊轉發給需要的朋友,我們下一期再見!敬請期待!