H繁中版
<!-- Source: https://hermesbible.com/docs/developer-guide/agent-loop -->

核心協調引擎是 run_agent.pyAIAgent 類別——一個大型檔案,處理從提示組裝到工具分派到供應商降級的所有事務。

核心職責

AIAgent 負責:

  • 透過 prompt_builder.py 組裝有效的系統提示和工具 schema
  • 選擇正確的供應商/API 模式(chat_completions、codex_responses、anthropic_messages)
  • 執行可中斷的模型呼叫,支援取消
  • 執行工具呼叫(透過執行緒池依序或並行)
  • 以 OpenAI 訊息格式維護對話歷史
  • 處理壓縮、重試和降級模型切換
  • 追蹤父代與子代 Agent 的迭代預算
  • 在上下文遺失前將持久化記憶刷新至磁碟

兩個進入點

# 簡單介面——回傳最終回應字串
response = agent.chat("Fix the bug in main.py")

# 完整介面——回傳包含 messages、metadata、usage stats 的字典
result = agent.run_conversation(
    user_message="Fix the bug in main.py",
    system_message=None,           # 若省略則自動建構
    conversation_history=None,      # 若省略則從會話自動載入
    task_id="task_abc123"
)

chat()run_conversation() 的薄包裝,從結果字典中提取 final_response 欄位。

API 模式

Hermes 支援三種 API 執行模式,根據供應商選擇、明確參數和基礎 URL 啟發式規則進行解析:

API 模式用途用戶端類型
chat_completionsOpenAI 相容端點(OpenRouter、自訂、大多數供應商)openai.OpenAI
codex_responsesOpenAI Codex / Responses APIopenai.OpenAI 搭配 Responses 格式
anthropic_messages原生 Anthropic Messages APIanthropic.Anthropic 透過適配器

模式決定了訊息的格式、工具呼叫的結構、回應的解析方式,以及快取/串流的運作方式。三種模式在 API 呼叫前後都收斂為相同的內部訊息格式(OpenAI 風格的 role/content/tool_calls 字典)。

模式解析順序:

  1. 明確的 api_mode 建構子參數(最高優先順序)
  2. 供應商特定偵測(例如 anthropic 供應商 → anthropic_messages
  3. 基礎 URL 啟發式規則(例如 api.anthropic.comanthropic_messages
  4. 預設:chat_completions

一輪生命週期

Agent 迴圈的每次迭代遵循以下序列:

run_conversation()
  1. 若未提供則產生 task_id
  2. 將使用者訊息附加至對話歷史
  3. 建構或重用快取的系統提示(prompt_builder.py)
  4. 檢查是否需要預飛壓縮(>50% 上下文)
  5. 從對話歷史建構 API 訊息
     - chat_completions:OpenAI 格式原樣使用
     - codex_responses:轉換為 Responses API 輸入項目
     - anthropic_messages:透過 anthropic_adapter.py 轉換
  6. 注入臨時提示層(預算警告、上下文壓力)
  7. 若使用 Anthropic 則套用提示快取標記
  8. 執行可中斷的 API 呼叫(_interruptible_api_call)
  9. 解析回應:
     - 若有 tool_calls:執行它們、附加結果、回到步驟 5
     - 若為文字回應:持久化會話、需要時刷新記憶、回傳

訊息格式

所有訊息在內部使用 OpenAI 相容格式:

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

推理內容(來自支援擴展思考的模型)儲存在 assistant_msg["reasoning"] 中,並可選擇透過 reasoning_callback 顯示。

訊息交替規則

Agent 迴圈強制嚴格的訊息角色交替:

  • 在系統訊息之後:User → Assistant → User → Assistant → ...
  • 在工具呼叫期間:Assistant(帶 tool_calls)→ Tool → Tool → ... → Assistant
  • 永遠不要連續兩則 assistant 訊息
  • 永遠不要連續兩則 user 訊息
  • 只有 tool 角色可以有連續項目(並行工具結果)

供應商會驗證這些序列,並拒絕格式不正確的歷史。

可中斷的 API 呼叫

API 請求被包裝在 _interruptible_api_call() 中,它在背景執行緒中執行實際的 HTTP 呼叫,同時監聽中斷事件:

┌────────────────────────────────────────────────────┐
│  Main thread                  API thread           │
│                                                    │
│   wait on:                     HTTP POST           │
│    - response ready     ───▶   to provider         │
│    - interrupt event                               │
│    - timeout                                       │
└────────────────────────────────────────────────────┘

當被中斷時(使用者傳送新訊息、/stop 命令或訊號):

  • API 執行緒被捨棄(回應被丟棄)
  • Agent 可以處理新輸入或乾淨地關閉
  • 不會有任何部分回應被注入對話歷史

工具執行

依序 vs 並行

當模型回傳工具呼叫時:

  • 單一工具呼叫 → 直接在主執行緒中執行
  • 多個工具呼叫 → 透過 ThreadPoolExecutor 並行執行
    • 例外:標記為互動式的工具(例如 clarify)強制依序執行
    • 結果按原始工具呼叫順序重新插入,不論完成順序

執行流程

for each tool_call in response.tool_calls:
    1. 從 tools/registry.py 解析處理器
    2. 觸發 pre_tool_call 外掛 hook
    3. 檢查是否為危險指令(tools/approval.py)
       - 若危險:呼叫 approval_callback,等待使用者
    4. 以 args + task_id 執行處理器
    5. 觸發 post_tool_call 外掛 hook
    6. 將 {"role": "tool", "content": result} 附加至歷史

Agent 層級工具

部分工具在到達 handle_function_call() 之前就被 run_agent.py 攔截:

工具攔截原因
todo讀寫 Agent 本地的任務狀態
memory寫入有字元限制的持久化記憶檔案
session_search透過 Agent 的會話資料庫查詢會話歷史
delegate_task以隔離的上下文產生子代理

這些工具直接修改 Agent 狀態,並在不經過註冊表的情況下回傳合成的工具結果。

回呼介面

AIAgent 支援平台特定的回呼,用於在 CLI、閘道器和 ACP 整合中提供即時進度:

回呼觸發時機使用者
tool_progress_callback每次工具執行的前後CLI 旋轉器、閘道器進度訊息
thinking_callback模型開始/停止思考時CLI「思考中...」指示器
reasoning_callback模型回傳推理內容時CLI 推理顯示、閘道器推理區塊
clarify_callbackclarify 工具被呼叫時CLI 輸入提示、閘道器互動訊息
step_callback每次完整 Agent 輪次結束後閘道器步驟追蹤、ACP 進度
stream_delta_callback每個串流 token(啟用時)CLI 串流顯示
tool_gen_callback工具呼叫從串流中被解析時CLI 在旋轉器中預覽工具
status_callback狀態變更(thinking、executing 等)ACP 狀態更新

預算與降級行為

迭代預算

Agent 透過 IterationBudget 追蹤迭代:

  • 預設:90 次迭代(可透過 agent.max_turns 設定)
  • 每個 Agent 有自己的預算。子代理獲得獨立的預算,上限為 delegation.max_iterations(預設 50)——父代與子代理的總迭代次數可能超過父代的上限
  • 達到 100% 時,Agent 停止並回傳已完成工作的摘要

降級模型

當主模型失敗時(429 速率限制、5xx 伺服器錯誤、401/403 認證錯誤):

  1. 檢查設定中的 fallback_providers 列表
  2. 按順序嘗試每個降級選項
  3. 成功後,使用新供應商繼續對話
  4. 遇到 401/403 時,嘗試刷新憑證後再降級

降級系統也獨立涵蓋輔助任務——視覺、壓縮和網頁提取各自有獨立的降級鏈,透過 auxiliary.* 設定區塊進行配置。

壓縮與持久化

壓縮何時觸發

  • 預飛(API 呼叫前):若對話超過模型上下文視窗的 50%
  • 閘道器自動壓縮:若對話超過 85%(更積極,在輪次之間執行)

壓縮期間發生的事

  1. 記憶首先被刷新至磁碟(防止資料遺失)
  2. 中間對話輪次被摘要為簡潔的摘要
  3. 最後 N 則訊息被完整保留(compression.protect_last_n,預設:20)
  4. 工具呼叫/結果訊息對保持在一起(永不拆分)
  5. 產生新的會話血緣 ID(壓縮建立「子」會話)

會話持久化

每次輪次後:

  • 訊息被儲存到會話儲存(透過 hermes_state.py 的 SQLite)
  • 記憶變更被刷新至 MEMORY.md / USER.md
  • 會話可透過 /resumehermes chat --resume 稍後恢復

關鍵原始碼檔案

檔案用途
run_agent.pyAIAgent 類別——完整的 Agent 迴圈
agent/prompt_builder.py從記憶、技能、上下文檔案、個性建構系統提示
agent/context_engine.pyContextEngine ABC——可插拔的上下文管理
agent/context_compressor.py預設引擎——有損摘要演算法
agent/prompt_caching.pyAnthropic 提示快取標記和快取指標
agent/auxiliary_client.py輔助 LLM 用戶端,處理副任務(視覺、摘要)
model_tools.py工具 schema 收集、handle_function_call() 分派

相關文件



提示組裝