- Hermes Agent๋ Nous Research๊ฐ ๋ง๋ ์๊ฐ ๊ฐ์ (self-improving) AI ์์ด์ ํธ์ด์ MIT ๋ผ์ด์ ์ค ์คํ์์ค ํ๋ก์ ํธ
- ๊ฒฝํ์์ ์คํฌ์ ๋ง๋ค๊ณ ์ฌ์ฉ ์ค์ ๊ทธ ์คํฌ์ ๊ฐ์ ํ๋ ๋ด์ฅ ํ์ต ๋ฃจํ(built-in learning loop)๋ฅผ ๊ฐ์ง ์์ด์ ํธ
- ๋ ธํธ๋ถ์ ๋ฌถ์ด์ง ์๊ณ $5 VPSยทGPU ํด๋ฌ์คํฐยท์๋ฒ๋ฆฌ์ค ์ธํ๋ผ์์ ์์ ๋์ํ๋ ์ ํ ํธ์คํ ์์จ ์์ด์ ํธ
ํด๋น ๊ฐ๋ ์ด ํ์ํ ์ด์
- ์ปจํ ์คํธ ํผ๋ก(Context Fatigue): ์ผ๋ฐ ์ฑ๋ด์ ์ธ์ ์ด ๋๋๋ฉด ๋ค ์์ด๋ฒ๋ ค ๋งค๋ฒ ์ค๋ช ์ ๋ฐ๋ณตํด์ผ ํจ โ ์์ ๋ฉ๋ชจ๋ฆฌ๋ก ํด๊ฒฐ
- ์ง์ ์์ค(Knowledge Loss): ์ด๋ ต๊ฒ ํผ ๋ฌธ์ ์ ํด๋ฒ์ด ์ฌ๋ผ์ง โ ์๋์ผ๋ก ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ ์คํฌ ๋ฌธ์(SKILL.md)๋ก ์ ์ฅ
- ํ๋ซํผ ํํธํ: ๋๊ตฌ๋ง๋ค ํฉ์ด์ง ๋ํ โ TelegramยทDiscordยทSlackยทWhatsAppยทSignalยทCLI๋ฅผ ๋จ์ผ ๊ฒ์ดํธ์จ์ด๋ก ํตํฉ
- ๋ชจ๋ธ ์ข
์(Lock-in): ํน์ LLM์ ๋ฌถ์ โ
hermes model๋ก 200+ ๋ชจ๋ธ์ ์ฝ๋ ๋ณ๊ฒฝ ์์ด ๊ต์ฒด - ๋ฐ๋ณต ์์ : ์๋ ๋ฐ๋ณต โ ์์ฐ์ด cron ์ค์ผ์ค๋ฌ๋ก ๋ฌด์ธ ์๋ํ
AS-IS (์ผ๋ฐ ์ฑ๋ด/์ฝํ์ผ๋ฟ)
sequenceDiagram autonumber participant U as ์ฌ์ฉ์ participant Bot as ์ฑ๋ด (stateless) U->>Bot: ์ง๋ฌธ & ๋ฐฐ๊ฒฝ ์ค๋ช Bot-->>U: ๋ต๋ณ Note over Bot: ์ธ์ ์ข ๋ฃ โ ๊ธฐ์ต ์๋ฉธ U->>Bot: ๋ค์ ์ธ์ , ์ฒ์๋ถํฐ ๋ค์ ์ค๋ช Note over U,Bot: ๋ ธํธ๋ถ์ ๋ฌถ์, ํ์ต ์์
TO-BE (Hermes Agent)
sequenceDiagram autonumber participant U as ์ฌ์ฉ์ (Telegram/CLI ๋ฑ) participant A as Hermes Agent (ํด๋ผ์ฐ๋ ์์ฃผ) participant M as ๋ฉ๋ชจ๋ฆฌ / ์คํฌ ์ ์ฅ์ U->>A: ์์ ์์ฒญ A->>A: ๋๊ตฌ ์คํ & ์์ ์ํ A->>M: ๊ฒฐ๊ณผ๋ฅผ ์คํฌ(SKILL.md)ยท๋ฉ๋ชจ๋ฆฌ๋ก ์ ์ฅ A->>M: ๊ณผ๊ฑฐ ๋ํ ๊ฒ์(FTS5)์ผ๋ก ๋งฅ๋ฝ ํ์ A-->>U: ๊ฒฐ๊ณผ (์ด๋ค ํ๋ซํผ์์๋ ์ด์ด์) Note over A,M: ์ธ์๋ก ์ฌ์ฉ์ ๋ชจ๋ธ์ด ๊น์ด์ง๋ ํ์ต ๋ฃจํ
ํต์ฌ ํน์ง 6๊ฐ์ง
- ์ง์ง ํฐ๋ฏธ๋ ์ธํฐํ์ด์ค(TUI): ๋ฉํฐ๋ผ์ธ ํธ์ง, ์ฌ๋์ ๋ช ๋ น ์๋์์ฑ, ๋ํ ํ์คํ ๋ฆฌ, ์์ ์ค๋จยท์ฌ์ง์, ์คํธ๋ฆฌ๋ฐ ๋๊ตฌ ์ถ๋ ฅ
- ์ฌ์ฉ์๊ฐ ์๋ ๊ณณ์์ ๋์: 6๊ฐ ๋ฉ์ ์ + CLI๋ฅผ ๋จ์ผ ๊ฒ์ดํธ์จ์ด ํ๋ก์ธ์ค๋ก. ์์ฑ ๋ฉ๋ชจ ์ ์ฌ, ํ๋ซํผ ๊ฐ ๋ํ ์ฐ์์ฑ
- ๋ซํ ํ์ต ๋ฃจํ(Closed Learning Loop): ์ฃผ๊ธฐ์ ๋ฉ๋ชจ๋ฆฌ ๋ณด์กด ๋์ง, ๋ณต์กํ ์์ ํ ์๋ ์คํฌ ์์ฑ, ์ฌ์ฉ ์ค ์คํฌ ์๊ธฐ ๊ฐ์ , FTS5 ์ธ์ ๊ฒ์ + LLM ์์ฝ
- ์ค์ผ์ค ์๋ํ: ํ๋ซํผ ์ ์ก์ด ๊ฐ๋ฅํ ๋ด์ฅ cron. ์ผ์ผ ๋ฆฌํฌํธยท์ผ๊ฐ ๋ฐฑ์ ยท์ฃผ๊ฐ ๊ฐ์ฌ๋ฅผ ์์ฐ์ด๋ก
- ์์๊ณผ ๋ณ๋ ฌํ: ๊ฒฉ๋ฆฌ๋ ์๋ธ์์ด์ ํธ๋ฅผ ๋์ ๋ณ๋ ฌ ์์ . RPC๋ก ๋๊ตฌ๋ฅผ ํธ์ถํ๋ ํ์ด์ฌ ์คํฌ๋ฆฝํธ๋ก ๋ค๋จ๊ณ ํ์ดํ๋ผ์ธ์ ๋ฌด๋งฅ๋ฝ ๋น์ฉ ํด์ผ๋ก ์์ถ
- ์ด๋์๋ ์คํ: 6๊ฐ ํฐ๋ฏธ๋ ๋ฐฑ์๋(localยทDockerยทSSHยทSingularityยทModalยทDaytona). Modal/Daytona๋ ์ ํด ์ ํด๋ฉดํ๋ ์๋ฒ๋ฆฌ์ค ์์์ฑ
์ํคํ ์ฒ ๊ตฌ์ฑ์์
์ค์ ์ ์ฅ์ ๋๋ ํ ๋ฆฌ ๊ตฌ์กฐ์ ๋์ํ๋ค.
| ๊ตฌ์ฑ์์ | ๋๋ ํ ๋ฆฌ | ์ญํ |
|---|---|---|
| Agent ์ฝ์ด | run_agent.py, agent/ | ์์ฌ๊ฒฐ์ ๋ฃจํ + ๋๊ตฌ ์คํ (AIAgent ํด๋์ค) |
| Gateway | gateway/ | 20+ ๋ฉ์ ์ ๋ฅผ ์๋ ํตํฉ ๋ฉ์์ง ์ธํฐํ์ด์ค |
| CLI / TUI | hermes_cli/, ui-tui/ | ํฐ๋ฏธ๋ ์ง์ ์ ๊ณผ UI |
| Skills | skills/, optional-skills/ | ์ ์ฐจ์ ๋ฉ๋ชจ๋ฆฌ, agentskills.io ํ์ค ํธํ |
| Tools | tools/ | ์น ๊ฒ์ยท์ด๋ฏธ์ง ์์ฑยท์ฝ๋ ์คํยทํด๋ผ์ฐ๋ ๋ธ๋ผ์ฐ์ ๋ฑ 70+ |
| Cron | cron/ | ์ค์ผ์ค ์๋ํ |
| Providers | providers/ | LLM ๊ณต๊ธ์ ์ถ์ํ(Nous Portal, OpenRouter ๋ฑ) |
| State | hermes_state.py | SQLite ์ธ์
์ ์ฅ์(~/.hermes/state.db) |
ํ์ต ๋ฃจํ๊ฐ ์๋ํ๋ ๋ฐฉ์ (๊ฐ๋ฐ์ ๊ด์ )
Hermes๊ฐ โ์๊ฐ ๊ฐ์ (self-improving)โ์ด๋ผ ๋ถ๋ฆฌ๋ ํต์ฌ์ด๋ค. ๋จ์ํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ์ฅํ๋ ๊ฒ ์๋๋ผ, ๋งค ํด ํ ์์ด์ ํธ๊ฐ ์๊ธฐ ์์ ์ ํฌํฌ(fork)ํด์ โ์ด๋ฒ ๋ํ์์ ๊ธฐ์ตํ๊ฑฐ๋ ์คํฌ๋ก ๋ง๋ค ๊ฒ ์๋?โ๋ฅผ ์ค์ค๋ก ํ๊ฐํ๋ ๊ตฌ์กฐ๋ค. ์๋ 5๊ฐ ๋ฉ์ปค๋์ฆ์ด ๋ง๋ฌผ๋ ค ๋๋ค.
1. ์์ด์ ํธ ํด ๋ฃจํ (AIAgent.run_conversation)
๋ชจ๋ ๊ฒ์ ์ค์ฌ์ run_agent.py์ AIAgent ํด๋์ค๋ค. ํ ํด์ ๋ค์ ์์๋ก ์ฒ๋ฆฌ๋๋ค.
run_conversation()
1. task_id ์์ฑ (์์ผ๋ฉด)
2. ์ฌ์ฉ์ ๋ฉ์์ง๋ฅผ ๋ํ ํ์คํ ๋ฆฌ์ ์ถ๊ฐ
3. ์์คํ
ํ๋กฌํํธ ๋น๋ ๋๋ ์บ์ ์ฌ์ฌ์ฉ (prompt_builder.py)
4. ํ๋ฆฌํ๋ผ์ดํธ ์์ถ ํ์ ์ฌ๋ถ ํ์ธ (์ปจํ
์คํธ >50%)
5. ๋ํ ํ์คํ ๋ฆฌ๋ก API ๋ฉ์์ง ๊ตฌ์ฑ (api_mode๋ณ ๋ณํ)
6. ephemeral ํ๋กฌํํธ ๋ ์ด์ด ์ฃผ์
(์์ฐ ๊ฒฝ๊ณ , ์ปจํ
์คํธ ์๋ฐ)
7. Anthropic์ด๋ฉด ํ๋กฌํํธ ์บ์ฑ ๋ง์ปค ์ ์ฉ
8. ์ค๋จ ๊ฐ๋ฅํ(interruptible) API ํธ์ถ
9. ์๋ต ํ์ฑ:
- tool_calls ์์ผ๋ฉด โ ์คํ ํ ๊ฒฐ๊ณผ append โ step 5๋ก ๋ฃจํ๋ฐฑ
- ํ
์คํธ ์๋ต์ด๋ฉด โ ์ธ์
์์ํ, ํ์ ์ ๋ฉ๋ชจ๋ฆฌ flush, ๋ฐํ๋ฉ์์ง๋ ๋ด๋ถ์ ์ผ๋ก ํญ์ OpenAI ํธํ ํฌ๋งท(role/content/tool_calls)์ผ๋ก ํต์ผ๋๋ฉฐ, chat_completionsยทcodex_responsesยทanthropic_messages ์ธ ๊ฐ์ง API ๋ชจ๋๊ฐ ๋ชจ๋ ์ด ํฌ๋งท์ผ๋ก ์๋ ดํ๋ค.
์์ด์ ํธ ๋ ๋ฒจ ๋๊ตฌ
์ผ๋ถ ๋๊ตฌ๋ ์ผ๋ฐ ๋ ์ง์คํธ๋ฆฌ(tools/registry.py)๋ฅผ ๊ฑฐ์น์ง ์๊ณ run_agent.py๊ฐ ์ง์ ๊ฐ๋ก์ฑ์ ์์ด์ ํธ ์ํ๋ฅผ ๋ฐ๊พผ๋ค. ํ์ต ๋ฃจํ์ ์
๊ตฌ๊ฐ ์ฌ๊ธฐ๋ค.
| ๋๊ตฌ | ์ญํ |
|---|---|
memory | ์์ ๋ฉ๋ชจ๋ฆฌ ํ์ผ์ ๊ธ์ ์ ์ ํ๊ณผ ํจ๊ป ๊ธฐ๋ก |
session_search | ์ธ์ DB์์ ๊ณผ๊ฑฐ ๋ํ ๊ฒ์ |
delegate_task | ๊ฒฉ๋ฆฌ๋ ์ปจํ ์คํธ๋ก ์๋ธ์์ด์ ํธ ์คํฐ |
todo | ์์ด์ ํธ ๋ก์ปฌ ์์ ์ํ |
2. ๋ฐฑ๊ทธ๋ผ์ด๋ ์๊ฐ ๊ฐ์ ๋ฆฌ๋ทฐ (agent/background_review.py) โ ๋ฃจํ์ ์ฌ์ฅ
ํด์ด ๋๋๋ฉด run_conversation์ด spawn_background_review_thread๋ฅผ ํธ์ถํด ๋ฐ๋ชฌ ์ค๋ ๋๋ฅผ ๋์ด๋ค. ์ด ์ค๋ ๋์ ๋์์ด Hermes ํ์ต ๋ฃจํ์ ๋ณธ์ง์ด๋ค.
- ๋ํ ์ค๋
์ท์ **ํฌํฌ๋
AIAgent**์์ **์ฌ์(replay)**ํ๋ฉฐ ์ค์ค๋ก์๊ฒ ๋ฌป๋๋ค: โ์ ์ฅํ๊ฑฐ๋ ๊ฐฑ์ ํ ์คํฌ/๋ฉ๋ชจ๋ฆฌ๊ฐ ์๋๊ฐ?โ - ์ด ํฌํฌ๋ ๋ฉ๋ชจ๋ฆฌยท์คํฌ ๊ด๋ฆฌ ๋๊ตฌ๋ง ํ์ดํธ๋ฆฌ์คํธ๋ก ํ์ฉํ๋ค. ๊ทธ ์ธ ๋ชจ๋ ๋๊ตฌ๋ ๋ฐํ์์์ ๊ฑฐ๋ถ๋๋ค (์์ ์ฅ์น).
- ๊ฒฐ๊ณผ ์ฐ๊ธฐ๋ ๋ฉ๋ชจ๋ฆฌยท์คํฌ ์ ์ฅ์๋ก ์งํํ๋ค.
- ๋ฉ์ธ ๋ํ์ ํ๋กฌํํธ ์บ์๋ ์ ๋ ๊ฑด๋๋ฆฌ์ง ์๋๋ค โ ์ฌ์ฉ์ ํฅ ์๋ต ์๋์ ์บ์ ์ ์ค๋ฅ ์ ๋ณด์กดํ๊ธฐ ์ํ ํต์ฌ ๋ถ๋ณ์(invariant)์ด๋ค.
- ํฌํฌ๋ ๋ถ๋ชจ์ ๋ฐํ์(providerยทmodelยทbase_urlยทcredentialsยท์บ์๋ ์์คํ ํ๋กฌํํธ)์ ๊ทธ๋๋ก ์์ โ ๋์ผํ prefix ์บ์์ ์ ์ค โ ์ ๋ ดํ ์บ์ ์ฝ๊ธฐ.
auxiliary.background_review.{provider,model}๋ก ๋ ์ผ ๋ชจ๋ธ์ ๋ฆฌ๋ทฐ๋ฅผ ์์ํ ์ ์๋ค(๋ฒค์น๋งํฌ ~3โ5ร ์ ๊ฐ). ๋ค๋ฅธ ๋ชจ๋ธ์ ๋ฉ์ธ ์บ์๋ฅผ ๋ชป ์ฐ๋ฏ๋ก, ์ ์ฒด ํธ๋์คํฌ๋ฆฝํธ ๋์ ์์ถ digest(์ต๊ทผ ํด ์๋ฌธ + ์ ํด ์์ฝ)๋ฅผ ์ฌ์ํ๋ค.
sequenceDiagram autonumber participant U as ์ฌ์ฉ์ participant Main as ๋ฉ์ธ AIAgent participant Fork as ํฌํฌ AIAgent (๋ฐ๋ชฌ ์ค๋ ๋) participant Store as ๋ฉ๋ชจ๋ฆฌ/์คํฌ ์ ์ฅ์ U->>Main: ๋ฉ์์ง Main->>Main: ๋๊ตฌ ์คํ & ์๋ต ์์ฑ Main-->>U: ์๋ต (์ฆ์) Main->>Fork: spawn_background_review_thread(๋ํ ์ค๋ ์ท) Note over Fork: ๋๊ตฌ ํ์ดํธ๋ฆฌ์คํธ<br/>= memory + skill ๊ด๋ฆฌ ์ ์ฉ Fork->>Fork: ๋ํ ์ฌ์ โ "๊ธฐ์ต/์คํฌ๋ก ๋ง๋ค ๊ฒ ์๋?" Fork->>Store: memory.add / skill_manage.createยทpatch Note over Main,Fork: ๋ฉ์ธ ๋ํยทํ๋กฌํํธ ์บ์๋<br/>์ ๋ ๊ฑด๋๋ฆฌ์ง ์์
์ด ๋ฆฌ๋ทฐ๊ฐ ๋ง๋ ๋ฉ๋ชจ๋ฆฌ/์คํฌ์ ๋ค์ ์ธ์ ์ ์์คํ ํ๋กฌํํธ๋ก ํ๋ฌ ๋ค์ด๊ฐ ๋ค์ ๋ํ๋ฅผ ๋ ๋๋ํ๊ฒ ๋ง๋ ๋ค. ์ด๊ฒ์ด โ๋ซํ ๋ฃจํโ๊ฐ ๋ซํ๋ ์ง์ ์ด๋ค.
3. ๋ฉ๋ชจ๋ฆฌ: frozen snapshot ํจํด
์์ ๋ฉ๋ชจ๋ฆฌ๋ ~/.hermes/memories/์ ๋งํฌ๋ค์ด ๋ ํ์ผ๋ก ๊ตฌ์ฑ๋๋ค.
| ํ์ผ | ์ฉ๋ | ๊ธ์ ์ ํ |
|---|---|---|
| MEMORY.md | ์์ด์ ํธ์ ๊ฐ์ธ ๋ ธํธ โ ํ๊ฒฝ ์ฌ์ค, ์ปจ๋ฒค์ , ํ์ตํ ๊ฒ | 2,200์ (~800 ํ ํฐ) |
| USER.md | ์ฌ์ฉ์ ํ๋กํ โ ์ ํธ, ์ปค๋ฎค๋์ผ์ด์ ์คํ์ผ, ๊ธฐ๋ | 1,375์ (~500 ํ ํฐ) |
ํต์ฌ์ frozen snapshot ํจํด์ด๋ค.
- ์ธ์
์์ ์ ๋์คํฌ์์ ๋ก๋๋์ด ์์คํ
ํ๋กฌํํธ์ ๊ณ ์ ๋ธ๋ก์ผ๋ก ์ฃผ์
๋๋ค (๊ฐ ํญ๋ชฉ์
ยง๋ก ๊ตฌ๋ถ). - ์ธ์
๋์ค
memory๋๊ตฌ๋ก ์ถ๊ฐ/๊ต์ฒด/์ญ์ ํ๋ฉด ๋์คํฌ์๋ ์ฆ์ ๋ฐ์๋์ง๋ง, ์์คํ ํ๋กฌํํธ์๋ ๋ค์ ์ธ์ ๋ถํฐ ๋ํ๋๋ค. โ LLM prefix ์บ์๋ฅผ ๊นจ์ง ์๊ธฐ ์ํจ. memory๋๊ตฌ ์ก์ :add/replace/remove(์ฝ๊ธฐ ์ก์ ์ ์์ โ ์ด๋ฏธ ํ๋กฌํํธ์ ์์ผ๋ฏ๋ก).replaceยทremove๋ ์งง์ ๊ณ ์ substring ๋งค์นญ ์ฌ์ฉ.- ๊ธ์ ์ ํ์ ๋๊ธฐ๋ฉด ์กฐ์ฉํ ๋ฒ๋ฆฌ์ง ์๊ณ ์๋ฌ๋ฅผ ๋ฐํ โ ์์ด์ ํธ๊ฐ ๊ฐ์ ํด์์ ํญ๋ชฉ์ ํตํฉยท์ญ์ ํ ๋ค ์ฌ์๋.
- ์ฃผ์ ์ ๋ณด์ ์ค์บ(ํ๋กฌํํธ ์ธ์ ์ ยท์๊ฒฉ์ฆ๋ช ํ์ทจยทinvisible Unicode)์ ๊ฑฐ์น๋ค.
4. ์คํฌ: progressive disclosure
์คํฌ์ ~/.hermes/skills/์ SKILL.md(YAML frontmatter + ๋งํฌ๋ค์ด)๋ก ์ ์ฅ๋๋ฉฐ, agentskills.io ์คํ ํ์ค๊ณผ ํธํ๋๋ค. ํ ํฐ ์ ์ฝ์ ์ํด **์ ์ง์ ๊ณต๊ฐ(progressive disclosure)**๋ก ๋ก๋ํ๋ค.
Level 0: skills_list() โ [{name, description, category}, ...] (~3k ํ ํฐ)
Level 1: skill_view(name) โ ์ ์ฒด ๋ด์ฉ + ๋ฉํ๋ฐ์ดํฐ
Level 2: skill_view(name, path) โ ํน์ reference ํ์ผ- ์๋ ์์ฑ: ๋ณต์กํ ์์
(5+ ๋๊ตฌ ํธ์ถ), ์๋ฌ ๋ฐ์, ๋น์๋ช
ํ ์ํฌํ๋ก ๋ฐ๊ฒฌ ํ
skill_manage๋๊ตฌ๋ก ์์ฑ. ์ก์ ์create/patch/edit/delete/write_file. - ์กฐ๊ฑด๋ถ ํ์ฑํ:
fallback_for_toolsets(ํด๋น toolset ์์ ๋๋ง ๋ ธ์ถ),requires_toolsets(์์ ๋๋ง ๋ ธ์ถ). - ์๊ธฐ ๊ฐ์ : ์ฌ์ฉ ์ค ๋ฐ๊ฒฌํ ๊ฐ์ ์ ์
patch๋ก ๋ฐ์(ํ ํฐ ํจ์จ์ ). - ๋ชจ๋ ์ฌ๋์ ๋ช
๋ น(
/skill-name)์ผ๋ก ํธ์ถ ๊ฐ๋ฅ. ์ค์น ์คํฌ์ ๋ณด์ ์ค์บ + ์ ๋ขฐ ๋ ๋ฒจ(builtin/official/trusted/community) ๋ถ์ฌ.
5. ์ธ์ ๊ฒ์ (FTS5)
๋ฉ๋ชจ๋ฆฌ๊ฐ โํญ์ ๋ค๊ณ ๋ค๋๋ ํต์ฌ ์ฌ์คโ์ด๋ผ๋ฉด, ์ธ์ ๊ฒ์์ โ์ง๋์ฃผ์ ๊ทธ๊ฑฐ ์๊ธฐํ์๋?โ๋ฅผ ์ํ ๋๊ตฌ๋ค.
- ๋ชจ๋ CLIยท๋ฉ์ ์ ์ธ์
์ด SQLite(
~/.hermes/state.db)์ ์ ์ฅ๋๊ณ ,messages_fts๊ฐ์ ํ ์ด๋ธ๋ก FTS5 ์ ๋ฌธ ๊ฒ์. session_search๋๊ตฌ๋ ์ค์ ๋ฉ์์ง๋ฅผ ๊ทธ๋๋ก ๋ฐํ โ LLM ์์ฝยทtruncation ์์.- ~20ms, LLM ํธ์ถ 0ํ(๋ฌด๋ฃ), ์ฉ๋ ๋ฌด์ ํ. ๋ฉ์ธ ์ปจํ ์คํธ๋ฅผ ์๋นํ์ง ์๊ณ ๊ณผ๊ฑฐ๋ฅผ ํ์.
| ๋น๊ต | ์์ ๋ฉ๋ชจ๋ฆฌ | ์ธ์ ๊ฒ์ |
|---|---|---|
| ์ฉ๋ | ~1,300 ํ ํฐ | ๋ฌด์ ํ |
| ์๋ | ์ฆ์(ํ๋กฌํํธ ๋ด) | ~20ms FTS5 |
| ๋น์ฉ | ๋งค ํ๋กฌํํธ ํ ํฐ | ๋ฌด๋ฃ |
| ๊ด๋ฆฌ | ์์ด์ ํธ๊ฐ ํ๋ ์ด์ | ์๋(์ ์ธ์ ์ ์ฅ) |
๋์ ๊ฒ์ดํธ (write_approval)
๋ฐฑ๊ทธ๋ผ์ด๋ ๋ฆฌ๋ทฐ์ ์๋ ์ฐ๊ธฐ๊ฐ ๋ถ๋ด์ค๋ฝ๋ค๋ฉด memory.write_approval: true / skills.write_approval: true๋ก ์ผค ์ ์๋ค. ์ผ๋ฉด ํฌ๊ทธ๋ผ์ด๋/๋ฐฑ๊ทธ๋ผ์ด๋ ์ฐ๊ธฐ๊ฐ ๋ชจ๋ ์คํ
์ด์ง๋์ด /memory pendingยท/skills pending์์ ์น์ธ ํ์๋ง ๋ฐ์๋๋ค. ๊ฒ์ดํธ์จ์ด ์ฑํ
์๋ ๐พ Memory updated ๊ฐ์ ์๋ฆผ์ด ๋ฌ๋ค(display.memory_notifications๋ก ์ ์ด).
Gateway / ๋ฉํฐํ๋ซํผ (์ฌํ)
๊ฒ์ดํธ์จ์ด๋ Hermes๋ฅผ 20+ ์ธ๋ถ ๋ฉ์์ง ํ๋ซํผ์ ์๋ ์ฅ๊ธฐ ์คํ ํ๋ก์ธ์ค๋ค. ๋ณธ์ง์ ๋ฉํฐ ์ด๋ํฐ ๋ผ์ฐํฐ(multi-adapter router) โ ์ ๊ฐ๊ฐ์ธ ํ๋ซํผ API๋ฅผ ๋จ์ผ ์์ด์ ํธ ์ธํฐํ์ด์ค๋ก ์ ๊ทํํ๋ค. ํต์ฌ ์ค๊ณ๋ ํ๋์ AIAgent ํด๋์ค๊ฐ CLIยทgatewayยทACPยทbatchยทAPI๋ฅผ ๋ชจ๋ ์ฒ๋ฆฌํ๊ณ , ํ๋ซํผ ์ฐจ์ด๋ ์ง์
์ (์ด๋ํฐ)์๋ง ๊ฐ๋๋ค๋ ๊ฒ์ด๋ค.
sequenceDiagram autonumber participant P as ํ๋ซํผ (Telegram ๋ฑ) participant Ad as Platform Adapter participant GR as GatewayRunner._handle_message participant SS as SessionStore (SQLite) participant A as AIAgent P->>Ad: raw event Ad->>Ad: MessageEvent๋ก ์ ๊ทํ + ํ์ฑ ์ธ์ ๊ฐ๋ ํ์ธ Ad->>GR: ์ด๋ฒคํธ ์ ๋ฌ GR->>GR: ์ธ์ ํค ์์ฑ + ์ธ๊ฐ(authorization) ํ์ธ alt ์ฌ๋์ ๋ช ๋ น GR->>GR: ์ปค๋งจ๋ ํธ๋ค๋ฌ๋ก ๋์คํจ์น else ์ผ๋ฐ ๋ฉ์์ง GR->>A: AIAgent ์์ฑ ํ run_conversation A->>SS: ๋ํ ์์ํ A-->>GR: ์๋ต end GR->>Ad: send_message Ad-->>P: ์๋ต ์ ์ก
๋ฉ์์ง ํ๋ฆ๊ณผ ๋ํ ์ฐ์์ฑ
- ํ๋ซํผ ์ด๋ํฐ๊ฐ raw ์ด๋ฒคํธ๋ฅผ ๋ฐ์
MessageEvent๋ก ์ ๊ทํ (on_message()). - ์ธ์
ํค๋ก ๋ผ์ฐํ
์ปจํ
์คํธ๋ฅผ ์ธ์ฝ๋ฉ:
agent:main:{platform}:{chat_type}:{chat_id}(์:agent:main:telegram:private:123456789). ํค๋ ๋ฐ๋์build_session_key()๋ก ์์ฑ. ์ด per-chat ์ธ์ ์คํ ์ด ๋๋ถ์ ๋ฉ์์ง๋ฅผ ๋์ด ๋ํ๊ฐ ์ด์ด์ง๋ค(์ผ์ผ ์๊ฐ ๋๋ idle ํ์์์ ์ ์ฑ ์ ๊น์ง). - ์ธ๊ฐ: per-platform allow-all โ ํ๋ซํผ allowlist โ DM ํ์ด๋ง โ ๊ธ๋ก๋ฒ allow-all โ ๊ธฐ๋ณธ ๊ฑฐ๋ถ ์์ผ๋ก ํ๊ฐ.
- ์ฌ๋์ ๋ช
๋ น์ด๋ฉด ์ปค๋งจ๋ ํธ๋ค๋ฌ๋ก, ์๋๋ฉด
AIAgent์ธ์คํด์ค๋ฅผ ๋ง๋ค์ด ๋ํ ์คํ.
2๋จ๊ณ ๋ฉ์์ง ๊ฐ๋ (์ค๋จยท์ฌ์ง์)
์์ด์ ํธ๊ฐ ์คํ ์ค์ผ ๋ ๋ค์ด์ค๋ ๋ฉ์์ง๋ ๋ ๋จ๊ณ ๊ฐ๋๋ฅผ ๊ฑฐ์น๋ค.
- Level 1 โ ๋ฒ ์ด์ค ์ด๋ํฐ(
gateway/platforms/base.py):_active_sessionsํ์ธ. ํ์ฑ์ด๋ฉด_pending_messages์ ํ์ํ๊ณ interrupt ์ด๋ฒคํธ set โ ๊ฒ์ดํธ์จ์ด ๋ฌ๋ ๋๋ฌ ์ ์ ์ก์. - Level 2 โ ๊ฒ์ดํธ์จ์ด ๋ฌ๋(
gateway/run.py):_running_agentsํ์ธ./stopยท/newยท/queueยท/statusยท/approveยท/deny๋ ํน์ ์ฒ๋ฆฌ, ๊ทธ ์ธ๋interrupt()ํธ๋ฆฌ๊ฑฐ./approve๋ฑ์ race๋ฅผ ํผํ๋ ค ์ธ๋ผ์ธ ๋์คํจ์น.
์ด๋ํฐ ๊ตฌ์กฐ์ ๋ถ๊ฐ ๋ฉ์ปค๋์ฆ
- ๋๋ถ๋ถ์ ํ๋ซํผ์
plugins/platforms/<name>/adapter.pyํ๋ฌ๊ทธ์ธ ์ด๋ํฐ, ์ผ๋ถ ๋ ๊ฑฐ์๋gateway/platforms/์ ์ง์ . ๋ชจ๋BasePlatformAdapter๋ฅผ ์์ํ๊ณconnect()/disconnect()/send_message()/on_message()๋ฅผ ๊ตฌํ. - ํ ํฐ ๋ฝ(
acquire_scoped_lock): ๋ ํ๋กํ์ด ๊ฐ์ ๋ด ํ ํฐ์ ๋์์ ์ฐ์ง ๋ชปํ๊ฒ ๋ง์. - Silence ํ ํฐ: ์๋ต์ด ์ ํํ
[SILENT]/SILENT/NO_REPLY๋ฉด ์ ์ก์ ์ต์ ํ๋ ํด์ ์ธ์ ํ์คํ ๋ฆฌ์ ๋ณด์กด. - ๋ฐฑ๊ทธ๋ผ์ด๋ ์ ์ง๋ณด์: cron ํฑ(์ค์ผ์ค ์ ๊ฒ), ์ธ์ ๋ง๋ฃ ์ ๋ฆฌ, ๋ง๋ฃ ์ ๋ฉ๋ชจ๋ฆฌ flush, ๋ชจ๋ธ ๋ชฉ๋ก ์บ์ ๊ฐฑ์ .
- ํ๋ก์ธ์ค ๊ด๋ฆฌ: ์ฅ๊ธฐ ์คํ ํ๋ก์ธ์ค๋ก systemd(Linux)/launchd(macOS) ์๋น์ค ๋ฑ๋ก, PID ํ์ผ(
~/.hermes/gateway.pid)์ ํ๋กํ ์ค์ฝํ.
์์ํ๊ธฐ
# ์ค์น (Linux/macOS/WSL2/Termux)
curl -fsSL https://hermes-agent.nousresearch.com/install.sh | bash
hermes # ๋ํํ CLI ์์
hermes model # LLM ๊ณต๊ธ์ยท๋ชจ๋ธ ์ ํ
hermes tools # ํ์ฑํํ ๋๊ตฌ ์ค์
hermes gateway # ๋ฉ์ ์ ๊ฒ์ดํธ์จ์ด ์์ (Telegram, Discord ๋ฑ)
hermes setup # ์ ์ฒด ์ค์ ๋ง๋ฒ์ฌ
hermes doctor # ๋ฌธ์ ์ง๋จ์ฐธ๊ณ ๋ฌธ์
- Hermes Agent - GitHub (NousResearch)
- ๊ณต์ ๋ฌธ์
- Agent Loop Internals
- Gateway Internals
- Persistent Memory
- Skills System
- agentskills.io - ์คํฌ ์คํ ํ์ค
- ๋ก์ปฌ ์์ค:
run_agent.py,agent/background_review.py,hermes_state.py,gateway/run.py