コンテンツにスキップ

Hermes Agent 内部構造ノート

Hermes Agent (NousResearch)内部実装を読むための勉強メモ。手を動かしながら確認するハンズオン側は README.md

このノートのスタンス: - 「会話ループ」「永続メモリ」「自動スキル生成」「MCP」「Gateway」の 5 つの中核機構をMermaid + 3 層解説で紐解く - 行レベルの工夫が肝になるところは実ファイル名・行番号を併記する(agent/conversation_loop.py:558-587 のような形式) - 「LLM がやっていること」と「Python コードがやっていること」を明確に分けて書く


1. 全体像: 4 つの責務を 1 プロセスで抱える

Hermes Agent は単一の hermes プロセスが4 つの責務を担う:

flowchart TB
    User[ユーザー]
    subgraph HermesProcess["hermes プロセス(単一)"]
        REPL[CLI REPL<br/>cli.py: HermesCLI]
        Loop[会話ループ<br/>agent/conversation_loop.py: run_conversation]
        Tools[ツール群<br/>tools/ + tools/registry.py]
        BG[background review<br/>fork した AIAgent]
    end
    subgraph Storage["~/.hermes/ 配下"]
        DB[(state.db<br/>SQLite + FTS5)]
        Mem[memories/<br/>MEMORY.md / USER.md]
        Skills[skills/<br/>SKILL.md 群]
        Cfg[config.yaml]
    end
    subgraph External["外部"]
        LLM[LLM プロバイダ<br/>OpenAI / Anthropic / OpenRouter / ...]
        MCP[MCP サーバ群]
        GW[Gateway adapter<br/>Telegram / Discord / Slack / ...]
    end

    User -->|stdin| REPL
    REPL --> Loop
    Loop -->|chat.completions| LLM
    Loop -->|tool_call| Tools
    Tools --> MCP
    Loop -->|persist| DB
    Loop --> BG
    BG -->|write| Skills
    BG -->|write| Mem
    GW <-->|websocket / http| Loop

1-1. ディレクトリ構造(要点だけ)

パス 役割
cli.py 対話 CLI 本体(HermesCLI クラス、Rich + prompt_toolkit ベース TUI)
run_agent.py AIAgent クラス本体。会話ループの「親」
agent/conversation_loop.py run_conversation() の中身(ここが心臓部
agent/agent_init.py AIAgent.__init__ の中身(60+ 引数を整理)
agent/memory_manager.py メモリプロバイダ統括
agent/curator.py 長期メンテ(archive / consolidate)
agent/background_review.py 各ターン後のスキル/メモリ自動レビュー
tools/ 個別ツール(60+)。registry.py 経由で自動登録
hermes_state.py SQLite + FTS5 のセッションストア (SessionDB)
hermes_constants.py ~/.hermes 解決 (get_hermes_home())
gateway/run.py Gateway エントリ
gateway/platforms/ Telegram / Discord / Slack / WhatsApp 他のアダプタ
plugins/memory/ 外部メモリプロバイダ (honcho / hindsight / mem0 等)
skills/ 同梱の built-in skill

HERMES_HOME 環境変数で ~/.hermes を別パスに移せる(hermes_constants.py:42)。


2. AIAgent の会話ループ

agent/conversation_loop.py:run_conversation() がエージェントの心臓。LLM とのやり取りを ツール呼び出しが無くなるまで 回し続ける。

2-1. 動的フローチャート

flowchart TD
    Start([ユーザー入力到着])
    SP[システムプロンプト構築<br/>prompt_builder.py + skills + MEMORY.md/USER.md snapshot]
    PF[memory provider prefetch<br/>memory_manager.prefetch_all]
    Loop{api_call_count < max_iterations<br/>かつ interrupt 未要求?}
    API[client.chat.completions.create<br/>messages + tool_schemas]
    Stream[stream 受信 + think タグ除去<br/>think_scrubber.py]
    TC{tool_calls あり?}
    Exec[handle_function_call<br/>tools/registry 経由でディスパッチ]
    Append[messages に tool_result を追加]
    Persist[messages を SQLite + FTS5 に書く]
    BR[spawn_background_review_thread<br/>fork した AIAgent で memory/skill review]
    Done([最終応答を返す])

    Start --> SP --> PF --> Loop
    Loop -->|Yes| API --> Stream --> TC
    TC -->|Yes| Exec --> Append --> Loop
    TC -->|No| Persist --> BR --> Done
    Loop -->|No| Done

2-2. コード本体(要約)

実コードを簡略化すると、こうなっている(agent/conversation_loop.py):

while (api_call_count < self.max_iterations
       and self.iteration_budget.remaining > 0) \
      or self._budget_grace_call:
    if self._interrupt_requested:
        break

    response = client.chat.completions.create(
        model=model,
        messages=messages,
        tools=tool_schemas,
    )

    if response.tool_calls:
        for tool_call in response.tool_calls:
            result = handle_function_call(
                tool_call.name, tool_call.args, task_id
            )
            messages.append(tool_result_message(result))
        api_call_count += 1
    else:
        return response.content

ここで押さえるべき行レベルの工夫:

  1. iteration_budget.remaining — 1 ターンで使えるツール呼び出し回数の上限。暴走防止。
  2. _budget_grace_call — 上限ギリギリで 1 回だけ「最終応答」のためのチャンスを与える。
  3. _interrupt_requested — ユーザーが Ctrl+C を押すと立つフラグ。次のループで break する。
  4. streamclient.chat.completions.create(stream=True) で受け取り、think_scrubber<think>...</think> を即座に除去(モデルが reasoning を出すタイプ用)。
  5. messages の永続化は最終応答後だけ — ループ中はメモリ上、応答が確定してから一括で SQLite に書き込む(書き込み 1 回で済むのは FTS5 トリガーのコストを抑えるため)。

2-3. プロバイダ抽象化

LLM プロバイダごとの差異は agent/*_adapter.py に押し込まれている:

アダプタ 役割
agent/anthropic_adapter.py Anthropic 直叩き(tool_use / tool_result の形式変換)
agent/bedrock_adapter.py AWS Bedrock
agent/gemini_*.py Google Gemini(OpenAI 互換でない部分のラッパ)
agent/codex_responses_adapter.py OpenAI Codex
agent/azure_identity_adapter.py Azure OpenAI (Entra ID 認証)

会話ループ自体は OpenAI 形式({role, content, tool_calls})で書かれていて、各 adapter が往復で形式変換する設計。


3. 永続メモリの 3 層

「永続メモリ」と一言で言っても、Hermes Agent には3 つの異なるレイヤがある。混乱しがちなので明示的に分ける:

レイヤ 保存場所 何を プロンプトへの注入
MEMORY.md / USER.md ~/.hermes/memories/*.md エージェントの個人ノート + ユーザーモデル セッション開始時に system prompt にfrozen snapshot として焼き込む
Session DB ~/.hermes/state.db 全セッションの message + metadata セッション内は履歴として、横断検索は session_search ツール経由
External memory provider(任意 1 つ) プロバイダ次第 ユーザーモデル・知識グラフ等 各ターン前に prefetch(query) で注入

3-1. SQLite + FTS5 のスキーマ

hermes_state.py:186-310SCHEMA_SQL から要点だけ:

CREATE TABLE sessions (
    id TEXT PRIMARY KEY,
    source TEXT NOT NULL,           -- 'cli' | 'telegram' | 'discord' | 'cron' | ...
    user_id TEXT,
    model TEXT,
    system_prompt TEXT,
    parent_session_id TEXT,         -- 圧縮で分割した親セッション
    started_at REAL NOT NULL,
    ended_at REAL,
    message_count INTEGER DEFAULT 0,
    input_tokens INTEGER DEFAULT 0,
    output_tokens INTEGER DEFAULT 0,
    cache_read_tokens INTEGER DEFAULT 0,    -- プロンプトキャッシュのヒット計測
    cache_write_tokens INTEGER DEFAULT 0,
    estimated_cost_usd REAL,
    title TEXT,
    -- ...
);

CREATE TABLE messages (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    session_id TEXT NOT NULL REFERENCES sessions(id),
    role TEXT NOT NULL,             -- system | user | assistant | tool
    content TEXT,
    tool_call_id TEXT,
    tool_calls TEXT,                -- JSON 配列
    tool_name TEXT,
    timestamp REAL NOT NULL,
    -- ...
);

-- FTS5 仮想テーブル + triggers で自動同期
CREATE VIRTUAL TABLE messages_fts USING fts5(content);
CREATE TRIGGER messages_fts_insert AFTER INSERT ON messages BEGIN
    INSERT INTO messages_fts(rowid, content) VALUES (
        new.id,
        COALESCE(new.content, '') || ' ' ||
        COALESCE(new.tool_name, '') || ' ' ||
        COALESCE(new.tool_calls, '')
    );
END;

-- CJK / 日本語の部分一致用に trigram tokenizer も別途
CREATE VIRTUAL TABLE messages_fts_trigram USING fts5(
    content, tokenize='trigram'
);

3-2. なぜ FTS5 を採用したか

  • 横断検索が高速: 何万ターンの過去ログでも ms オーダーで全文検索可能
  • LLM 不要: 検索パスに LLM 呼び出しが入らない(コスト 0、レイテンシ ms)
  • CJK 対応: 既定の tokenizer は欧米語向けだが、trigram tokenizer 用に 別テーブル を持つことで日本語/中国語の部分一致を実現
  • WAL モード: 読み取りは並列、書き込みは排他。CLI ↔ Gateway の同時アクセスを想定

3-3. session_search ツールの 3 モード

tools/session_search_tool.py:1-30。1 つのツールで 3 つの呼び出しモードを引数で判別:

モード トリガ 動作
DISCOVERY query= を渡す FTS5 で検索 → セッション系統で dedupe → 各ヒットの ±5 メッセージウィンドウ + bookend (先頭/末尾 3 ユーザー+アシスタント) を返す
SCROLL session_id + around_message_id 前後 ±window をめくる
BROWSE 引数なし db.list_sessions_rich() で時系列に最近のセッションを返す

全部 SQL/FTS5 から実メッセージを返すので LLM 呼び出しは発生しない。エージェント側は「過去ログを覚えていなくてもツールで思い出せる」前提で動く。

3-4. MEMORY.md / USER.md の frozen snapshot パターン

tools/memory_tool.py:1-30。これが面白いので別途解説する:

sequenceDiagram
    participant U as ユーザー
    participant A as AIAgent (新セッション)
    participant M as MEMORY.md / USER.md
    participant SP as system_prompt (frozen)

    M->>SP: セッション開始時に snapshot を焼き込む
    U->>A: 「私の名前は山本健」
    A->>M: memory_tool(action=add, ...)
    Note over M: ファイルには追記されるが<br/>当該セッションの system_prompt は変わらない
    U->>A: 「次の質問」
    A->>SP: 同じ snapshot を使い続ける<br/>(プレフィックスキャッシュ温存)
    Note over A: ─── /quit ───
    M->>SP: 新セッションで再 snapshot<br/>新しい内容が反映される

なぜこの設計?: - プロンプトキャッシュを温存するため。同じセッション中に system_prompt が変わるとキャッシュが無効化されてコストが跳ねる - 次セッションから反映なので、即時性は犠牲にしている - 即時に思い出させたいなら memory ツールで action=read を呼べばその場で読める

実装の安全装置: - 書き込みは tempfile + os.replace で原子的 - fcntl / msvcrt ロックで並行書き込みを防ぐ - 内容は tools/threat_patterns.py の strict スコープでプロンプトインジェクション検査(system prompt にそのまま入るので)

3-5. 外部メモリプロバイダ

agent/memory_provider.py の ABC を実装すれば追加可能。同梱プラグイン:

プラグイン
honcho dialectic user modeling(会話から user representation を作る)
hindsight knowledge graph + entity resolution(cloud / local embedded / local external)
mem0 mem0.ai
supermemory, byterover, holographic, openviking, retaindb その他

MemoryManager外部プロバイダを同時に 1 つだけ許可(ツールスキーマ肥大化と挙動衝突防止)。設定は ~/.hermes/config.yamlmemory.provider

ライフサイクルフック: - initialize(session_id, hermes_home, platform, ...) — 起動時 - system_prompt_block() — system prompt 静的部分 - prefetch(query) — 各ターン前 - sync_turn(user_msg, assistant_response) — 各ターン後(async write) - get_tool_schemas() / handle_tool_call() — モデル向けに memory ツールを公開


4. スキル自動生成の 3 経路

「成功体験から再利用可能 skill を作る」の実体は 3 系統:

flowchart LR
    subgraph Sources["生成源"]
        BR[background_review<br/>各ターン後の自動レビュー]
        CR[curator<br/>長期メンテ・整理]
        User[ユーザー手動<br/>~/.hermes/skills/ に直接書く]
    end
    subgraph Storage["~/.hermes/skills/"]
        SK[my-skill/<br/>├ SKILL.md<br/>├ references/<br/>├ templates/<br/>├ scripts/<br/>└ assets/]
    end
    subgraph Activation["呼び出し経路"]
        Slash[/skill-name で明示ロード/]
        List[skills_list + skill_view<br/>段階的開示]
        Bundle[/bundle-name/ で複数一括/]
    end

    BR --> SK
    CR --> SK
    User --> SK
    SK --> Slash
    SK --> List
    SK --> Bundle

4-1. ターン後の background review(自動生成の主役)

agent/background_review.py:558-587。仕掛けが秀逸なので展開する:

  1. fork した AIAgent を daemon thread で起動
  2. fork は親と同じ provider・model・base_url・credential を継承 → プロンプトキャッシュにヒット
  3. fork は memory + skill 管理ツールだけ許可(ホワイトリスト方式)
  4. ユーザーメッセージとして _SKILL_REVIEW_PROMPT を投入
  5. fork が skill_manage ツールで skill 作成/編集/新ファイル追加を実行

_SKILL_REVIEW_PROMPT の要点(agent/background_review.py:46-):

  • ターゲットは「クラスレベル」の skill(umbrella + references/ で構造化、一発限りの粒度は避ける)
  • 反応するシグナル:
  • ユーザーがスタイル/手順/工程を修正した
  • 新しいテクニックが出現した
  • 既存 skill が間違っていた
  • ユーザーが「remember this」と言った
  • フラストレーション表現(「stop doing X」「too verbose」)
  • 行動順序:
  • すでにロード済の skill を patch
  • 既存 umbrella skill を update
  • 既存 umbrella の下に support file (references/<topic>.md, templates/<name>.<ext>, scripts/<name>.<ext>) を追加
  • それでも合うものがなければ 新規クラスレベル skill を作成
  • 「何もしないターン」は中立ではなく学習機会の損失と定義(積極的に生成させる文化)

4-2. スキル形式

tools/skills_tool.py:6-66。YAML frontmatter + Markdown:

---
name: skill-name              # 必須、64 文字以下
description: Brief description  # 必須、1024 文字以下
version: 1.0.0                # 任意
license: MIT                  # 任意 (agentskills.io)
platforms: [macos]            # 任意 — macos / linux / windows
prerequisites:                # 任意 — 必要 env var / コマンド
  env_vars: [API_KEY]
  commands: [curl, jq]
metadata:                     # agentskills.io 互換
  hermes:
    tags: [fine-tuning, llm]
    related_skills: [peft, lora]
---

# Skill Title

実際の手順や知識…

ディレクトリ構造:

~/.hermes/skills/
├── my-skill/
│   ├── SKILL.md       # 本体(必須)
│   ├── references/    # 補足ドキュメント(調査メモ、エラートランスクリプト)
│   ├── templates/     # 雛形ファイル
│   ├── scripts/       # 再実行可能なスクリプト
│   └── assets/        # その他
└── category-name/
    └── another-skill/
        └── SKILL.md

4-3. Curator: 長期メンテナンス

agent/curator.py:1-25background_review とは別の機構:

項目 background_review curator
起動 各ターン後(即時) inactivity-triggered(7 日アイドル)
役割 新規 skill 作成・既存 patch lifecycle 自動遷移(active → stale → archived)
対象 全 skill agent-created skill のみ(user / hub / bundled は不可侵)
削除 しない archive 止まり(auto-delete なし、復元可能)

寿命設定: - DEFAULT_STALE_AFTER_DAYS = 30 - DEFAULT_ARCHIVE_AFTER_DAYS = 90

実行コマンド:

hermes curator status
hermes curator run --dry-run

4-4. 呼び出しの 3 経路

  1. スラッシュコマンド/skill-name で明示ロード。SKILL.md がユーザーメッセージとして注入される(system prompt ではない理由はプロンプトキャッシュ温存)
  2. skills_list / skill_view — モデルが skills_list で利用可能 skill のメタデータ(name + description)だけを progressive disclosure 第 1 段として確認し、必要なら skill_view で本体を読む
  3. Skill bundle~/.hermes/skill-bundles/<name>.yaml で複数 skill を 1 つの slash command にまとめる。/<bundle-name> で全部一括ロード

4-5. usage telemetry

tools/skill_usage.py:1-30~/.hermes/skills/.usage.json に skill 名キーで使用回数・最終使用時刻を記録。skill_view / skill_manage がインクリメント。curator が読んで lifecycle 判定。

原子的書き込み(tempfile + os.replace)で並行アクセス安全。


5. MCP 対応

5-1. 設定

~/.hermes/config.yamlmcp_servers キー(tools/mcp_tool.py:1-30):

mcp_servers:
  filesystem:
    command: "npx"
    args: ["-y", "@modelcontextprotocol/server-filesystem", "/tmp"]
    env: {}
    timeout: 120
    connect_timeout: 60

  github:
    command: "npx"
    args: ["-y", "@modelcontextprotocol/server-github"]
    env:
      GITHUB_PERSONAL_ACCESS_TOKEN: "ghp_..."
    supports_parallel_tool_calls: true

  remote_api:
    url: "https://my-mcp.example.com/mcp"
    headers:
      Authorization: "Bearer sk-..."
    timeout: 180

  searxng:
    url: "http://localhost:8000/sse"
    transport: sse
    sampling:                # サーバから LLM 逆呼び出しを許可
      enabled: true
      model: "gemini-3-flash"
      max_tokens_cap: 4096

5-2. アーキテクチャ

flowchart LR
    subgraph HermesProcess["hermes プロセス"]
        Loop[会話ループ]
        Reg[tools/registry.py]
        MCPLoop[_mcp_loop<br/>専用 daemon thread]
    end
    subgraph MCPServers["MCP サーバ群"]
        S1[filesystem<br/>stdio: npx]
        S2[github<br/>stdio: npx]
        S3[remote_api<br/>HTTP]
        S4[searxng<br/>SSE]
    end

    Loop -->|tool_call| Reg
    Reg -->|run_coroutine_threadsafe| MCPLoop
    MCPLoop <-->|asyncio Task| S1
    MCPLoop <-->|asyncio Task| S2
    MCPLoop <-->|HTTP| S3
    MCPLoop <-->|SSE stream| S4

ポイント: - 専用バックグラウンド event loop を daemon thread で 1 つ持ち、各 MCP サーバを長寿命 asyncio Task として起動 - ツール呼び出しは run_coroutine_threadsafe() で同期 → 非同期の橋渡し - 自動再接続: 指数バックオフで最大 5 回 - credential ストリッピング: エラーメッセージから API キーを削除して LLM に返す - 自動 discovery: 接続後、MCP サーバが宣言しているツールを tools/registry.py に登録 → エージェントは組み込みツールと区別なく呼べる

5-3. 3 つのトランスポート

方式 設定キー 用途
stdio command + args ローカルプロセス(npx ... が定番)
HTTP / Streamable HTTP url(http/https) リモート MCP サーバ
SSE url + transport: sse Server-Sent Events 専用サーバ

5-4. Sampling

MCP サーバから LLM を逆呼び出しできる機能(MCP プロトコルの sampling/createMessage)。tools/mcp_tool.py で許可リスト形式で制御:

sampling:
  enabled: true
  model: "gemini-3-flash"
  max_tokens_cap: 4096
  timeout: 30
  max_rpm: 10          # rate limit
  allowed_models: []   # 空ならクライアント側で固定
  max_tool_rounds: 5

6. Gateway: マルチプラットフォーム対応

gateway/run.py:start_gateway()。CLI と同じ AIAgent / 同じ DB / 同じ skill 群を共有する別エントリポイント。

6-1. アーキテクチャ

flowchart LR
    subgraph User["外部"]
        TG[Telegram User]
        DC[Discord User]
        SL[Slack User]
    end
    subgraph Gateway["hermes gateway start"]
        TGA[TelegramAdapter]
        DCA[DiscordAdapter]
        SLA[SlackAdapter]
        Router[ChatRouter<br/>session_id を解決]
        Agent[AIAgent インスタンス]
    end
    subgraph Storage["~/.hermes/state.db"]
        DB[(sessions<br/>messages)]
    end

    TG -->|webhook/poll| TGA
    DC -->|websocket| DCA
    SL -->|websocket| SLA
    TGA --> Router
    DCA --> Router
    SLA --> Router
    Router --> Agent
    Agent --> DB

6-2. プラットフォーム一覧

gateway/platforms/ 配下(組み込み):

カテゴリ プラットフォーム
メッセンジャー Telegram, Discord, Slack, WhatsApp, Signal, Matrix, Line, Feishu, WeCom, WeChat
ビジネス DingTalk, MS Graph (Teams), QQ Bot, Yuanbao
その他 Email, SMS, BlueBubbles (iMessage), HomeAssistant, webhook 汎用, REST API server

プラグイン側にもさらに line, irc, teams, google_chat などがある。

6-3. プラットフォーム追加方法

gateway/platforms/ADDING_A_PLATFORM.md に詳しい。BasePlatformAdapter を継承して以下を実装:

メソッド 役割
connect() 接続確立
disconnect() 切断
send(chat_id, content) テキスト送信
send_typing(chat_id) typing インジケータ
send_image(chat_id, image) 画像送信
get_chat_info(chat_id) チャットメタデータ取得

セッション管理は Gateway 側が自動で行う。Adapter は「メッセージを受け取って Router に渡す」「Router から渡されたものを送信する」だけに集中。

6-4. クロスプラットフォーム検索

すべてのプラットフォームが同じ state.db に書き込むため、session_search ツール一つで Telegram の会話と CLI の会話を横断検索できる:

SELECT id, source, title FROM sessions WHERE source IN ('telegram', 'cli')
ORDER BY started_at DESC;

7. 対応 LLM プロバイダ

35+ プロバイダ。代表例:

provider 認証 備考
openrouter OPENROUTER_API_KEY 万能、推奨デフォルト
nous hermes login (OAuth) Nous Portal サブスク。Tool Gateway 込み
nous-api NOUS_API_KEY Nous Portal API
anthropic ANTHROPIC_API_KEY pip install .[anthropic]
openai-codex hermes auth OpenAI Codex
gemini GOOGLE_API_KEY Google AI Studio OpenAI 互換
copilot GITHUB_TOKEN GitHub Models / Copilot
azure-foundry API key or Entra ID Azure OpenAI
custom (= ollama / vllm / llamacpp) 任意 base_url 手書き
lmstudio 任意 http://127.0.0.1:1234/v1

auto を指定すると認証情報から自動推測。

設定ファイル: ~/.hermes/config.yaml:

model:
  default: "anthropic/claude-sonnet-4.5"
  provider: "openrouter"
  base_url: "https://openrouter.ai/api/v1"
  context_length: 200000
  max_tokens: 8192

hermes model で対話的に切替可能。


8. プロンプトキャッシュとコスト管理

Hermes Agent はあちこちで プロンプトキャッシュを死守する設計になっている。なぜなら長セッション + 多ツールでトークン数が膨れ上がるため、キャッシュなしでは API コストが爆発する:

設計判断 キャッシュ保護の意図
MEMORY.md / USER.md は frozen snapshot セッション中に system_prompt を変えない
skill は user message として注入 system_prompt を変えない
background_review の fork は親と同じ provider/credential キャッシュキー共有
session_search は LLM 不要 キャッシュを汚さずに過去を引ける
context_compressor.py で長セッションを圧縮 キャッシュ可能サイズに収める

sessions テーブルの cache_read_tokens / cache_write_tokens カラムでセッション単位の効率を計測できる:

SELECT
  id, title,
  cache_read_tokens, cache_write_tokens,
  ROUND(cast(cache_read_tokens as float) / NULLIF(cache_read_tokens + cache_write_tokens, 0), 2) AS hit_ratio
FROM sessions ORDER BY started_at DESC LIMIT 10;

9. 実ファイル参照早見表

ノートを書きながら原典に当たりたい人向け:

トピック ファイル + 関数
CLI エントリ hermes_cli/main.py
対話 REPL 本体 cli.py:HermesCLI
AIAgent クラス run_agent.py:327 (class AIAgent)
__init__ 詳細 agent/agent_init.py:init_agent
会話ループ agent/conversation_loop.py:run_conversation
ツール登録 tools/registry.py, model_tools.py:handle_function_call
SQLite + FTS5 スキーマ hermes_state.py:186-310
セッション検索 tools/session_search_tool.py:1-30
MEMORY.md / USER.md tools/memory_tool.py:1-100
メモリプロバイダ ABC agent/memory_provider.py:1-100
自動スキル生成 agent/background_review.py:558-587
Skill review プロンプト agent/background_review.py:46-120
Curator agent/curator.py
Skill 形式 tools/skills_tool.py:1-66
Skill 作成ツール tools/skill_manager_tool.py:1-37
MCP クライアント tools/mcp_tool.py:1-90
Gateway エントリ gateway/run.py:start_gateway
BasePlatformAdapter gateway/platforms/base.py
プラットフォーム追加方法 gateway/platforms/ADDING_A_PLATFORM.md
プロバイダ一覧 cli-config.yaml.example (model.provider のコメント)
環境変数一覧 .env.example
ホーム解決 hermes_constants.py:42
Setup wizard hermes_cli/setup.py:1-50
Install スクリプト scripts/install.sh, setup-hermes.sh

10. 連載コードとの比較

連載で扱ったツール群と Hermes Agent の対応表:

機能 連載で扱った例 Hermes Agent の該当
ReAct エージェント 第 11 回 (create_react_agent) agent/conversation_loop.py:run_conversation
マルチエージェント (Supervisor) 第 23 回 tools/delegate_tool.py + sub-agent spawning
共有メモリ + TODO 第 24 回 (Claude Code 風文章執筆) ~/.hermes/memories/ + tools/todo_tool.py
MCP サーバ/クライアント 第 19, 20 回 tools/mcp_tool.py
LangGraph Functional API 第 21, 22 回 (対応物なし。Hermes はワンパスループに寄せた設計)
プロンプト最適化 第 25-28 回 (DSPy) (Hermes は LLM 自己レビューで近似。DSPy のような optimizer は無い)
Middleware 第 29, 31 回 (LangChain v1) tools/registry.py のディスパッチ + adapter 層

「LangGraph で組むより一発で動くものが欲しい」場合の選択肢。逆にフローを細かく制御したいなら LangGraph / DSPy の方が向く。


まとめ: Hermes Agent の設計上の主張

  1. 学習ループは中央集権でなくバックグラウンド分散: メインの会話に介入せず、別スレッドの fork が自律的にメモリ/スキルを更新する
  2. 永続化は SQLite 一本化: マイクロサービス的に分けず、state.db 一つに全プラットフォーム・全セッション・全ツール呼び出しを集める
  3. プロンプトキャッシュ最優先: frozen snapshot, user-message injection, fork sharing 等、あらゆる設計判断がキャッシュヒット率を守る方向
  4. プロバイダ非依存: adapter 層で OpenAI 形式に統一、35+ プロバイダを差し替え可能に
  5. 拡張は MCP / Plugin / Skill の 3 層: 動的(MCP)/ Python コード(Plugin)/ 知識(Skill)の使い分け

これらを踏まえた上で、ハンズオン側(README.md)に戻って実体験するのが理解の近道。


作成: 2026-05-27 / 最終更新: 2026-05-27