hermes-agent-architecture
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseHermes Agent Architecture
Hermes Agent 架构
Skill by ara.so — Hermes Skills collection.
Hermes Agent is a production-grade LLM agent framework by Nous Research featuring advanced memory management, multi-agent orchestration, 18+ messaging platform integrations, and a sophisticated tool execution system. This skill covers internal architecture, extension patterns, and implementation strategies verified against source code.
由ara.so提供的技能——Hermes技能合集。
Hermes Agent是Nous Research推出的生产级LLM Agent框架,具备高级内存管理、多Agent编排、18+消息平台集成以及成熟的工具执行系统。本技能涵盖经源码验证的内部架构、扩展模式与实现策略。
Installation
安装
bash
undefinedbash
undefinedClone the repository
Clone the repository
git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
git clone https://github.com/NousResearch/hermes-agent.git
cd hermes-agent
Install dependencies
Install dependencies
pip install -e .
pip install -e .
Or with Poetry
Or with Poetry
poetry install
poetry install
Basic configuration
Basic configuration
cp config.example.yaml config.yaml
cp config.example.yaml config.yaml
Edit config.yaml with your API keys and preferences
Edit config.yaml with your API keys and preferences
undefinedundefinedCore Architecture Components
核心架构组件
Agent Loop and Execution
Agent循环与执行
The main agent loop is in :
hermes/agent.pypython
from hermes.agent import Agent
from hermes.config import Config主Agent循环位于中:
hermes/agent.pypython
from hermes.agent import Agent
from hermes.config import ConfigInitialize agent
Initialize agent
config = Config.load("config.yaml")
agent = Agent(config)
config = Config.load("config.yaml")
agent = Agent(config)
Run interactive session
Run interactive session
await agent.run()
await agent.run()
Programmatic execution
Programmatic execution
response = await agent.process_message(
"Analyze the repository structure",
context={"cwd": "/path/to/repo"}
)
**Key execution flow:**
1. `process_message()` → Prompt assembly
2. Model inference → Tool calls extraction
3. Tool dispatch via `ToolRegistry`
4. Result aggregation → Memory storage
5. Response generationresponse = await agent.process_message(
"Analyze the repository structure",
context={"cwd": "/path/to/repo"}
)
**核心执行流程:**
1. `process_message()` → 提示词组装
2. 模型推理 → 工具调用提取
3. 通过`ToolRegistry`调度工具
4. 结果聚合 → 内存存储
5. 响应生成Tool System Architecture
工具系统架构
Tools are registered centrally via decorators:
python
from hermes.tools.registry import tool_registry
from hermes.tools.base import ToolResult
@tool_registry.register(
name="custom_analyzer",
description="Analyze code patterns",
category="analysis",
parameters={
"file_path": {
"type": "string",
"description": "Path to file to analyze"
},
"pattern": {
"type": "string",
"description": "Pattern to search for"
}
}
)
async def custom_analyzer(file_path: str, pattern: str, **kwargs) -> ToolResult:
"""Custom code analysis tool."""
try:
with open(file_path, 'r') as f:
content = f.read()
matches = re.findall(pattern, content)
return ToolResult(
success=True,
data={"matches": matches, "count": len(matches)},
message=f"Found {len(matches)} matches"
)
except Exception as e:
return ToolResult(
success=False,
error=str(e)
)Toolset grouping (from ):
hermes/tools/toolsets.pypython
from hermes.tools.toolsets import Toolset, toolset_registry
@toolset_registry.register("code_analysis")
class CodeAnalysisToolset(Toolset):
"""Custom toolset for code analysis."""
def get_tools(self):
return [
"custom_analyzer",
"list_functions",
"complexity_check"
]
def get_description(self):
return "Tools for analyzing code structure and patterns"工具通过装饰器集中注册:
python
from hermes.tools.registry import tool_registry
from hermes.tools.base import ToolResult
@tool_registry.register(
name="custom_analyzer",
description="Analyze code patterns",
category="analysis",
parameters={
"file_path": {
"type": "string",
"description": "Path to file to analyze"
},
"pattern": {
"type": "string",
"description": "Pattern to search for"
}
}
)
async def custom_analyzer(file_path: str, pattern: str, **kwargs) -> ToolResult:
"""Custom code analysis tool."""
try:
with open(file_path, 'r') as f:
content = f.read()
matches = re.findall(pattern, content)
return ToolResult(
success=True,
data={"matches": matches, "count": len(matches)},
message=f"Found {len(matches)} matches"
)
except Exception as e:
return ToolResult(
success=False,
error=str(e)
)工具集分组(来自):
hermes/tools/toolsets.pypython
from hermes.tools.toolsets import Toolset, toolset_registry
@toolset_registry.register("code_analysis")
class CodeAnalysisToolset(Toolset):
"""Custom toolset for code analysis."""
def get_tools(self):
return [
"custom_analyzer",
"list_functions",
"complexity_check"
]
def get_description(self):
return "Tools for analyzing code structure and patterns"Memory System
内存系统
Three-layer architecture ():
hermes/memory/python
from hermes.memory.manager import MemoryManager
from hermes.memory.store import MemoryStore
from hermes.memory.provider import MemoryProvider三层架构():
hermes/memory/python
from hermes.memory.manager import MemoryManager
from hermes.memory.store import MemoryStore
from hermes.memory.provider import MemoryProviderInitialize memory system
Initialize memory system
store = MemoryStore(db_path="~/.hermes/memory.db")
manager = MemoryManager(store)
store = MemoryStore(db_path="~/.hermes/memory.db")
manager = MemoryManager(store)
Store interaction
Store interaction
await manager.add_message(
role="user",
content="Remember that I prefer functional programming",
session_id="current_session"
)
await manager.add_message(
role="user",
content="Remember that I prefer functional programming",
session_id="current_session"
)
Retrieve relevant memories
Retrieve relevant memories
memories = await manager.search_memories(
query="programming preferences",
limit=5
)
memories = await manager.search_memories(
query="programming preferences",
limit=5
)
Freeze snapshot for prompt caching
Freeze snapshot for prompt caching
snapshot = manager.freeze_snapshot()
snapshot = manager.freeze_snapshot()
This protects the prefix cache boundary
This protects the prefix cache boundary
**Session search with FTS5:**
```python
from hermes.memory.session_db import SessionDB
session_db = SessionDB(db_path="~/.hermes/sessions.db")
**基于FTS5的会话搜索:**
```python
from hermes.memory.session_db import SessionDB
session_db = SessionDB(db_path="~/.hermes/sessions.db")Search across sessions
Search across sessions
results = await session_db.search(
query="docker configuration",
limit=10
)
results = await session_db.search(
query="docker configuration",
limit=10
)
Get LLM summary of related sessions
Get LLM summary of related sessions
summary = await session_db.get_session_summary(
query="docker issues",
llm_client=auxiliary_client
)
undefinedsummary = await session_db.get_session_summary(
query="docker issues",
llm_client=auxiliary_client
)
undefinedContext Compression v3
上下文压缩v3
Automatic context management ():
hermes/compression/compressor.pypython
from hermes.compression.compressor import ContextCompressor
compressor = ContextCompressor(
model_client=client,
max_tokens=128000,
preserve_recent=5 # Keep last 5 messages uncompressed
)自动上下文管理():
hermes/compression/compressor.pypython
from hermes.compression.compressor import ContextCompressor
compressor = ContextCompressor(
model_client=client,
max_tokens=128000,
preserve_recent=5 # Keep last 5 messages uncompressed
)Three-stage preprocessing
Three-stage preprocessing
compressed = await compressor.compress(
messages=conversation_history,
strategies=[
"md5_dedup", # Remove duplicate tool results
"smart_collapse", # Collapse similar adjacent messages
"param_truncation" # Truncate large parameters
]
)
compressed = await compressor.compress(
messages=conversation_history,
strategies=[
"md5_dedup", # Remove duplicate tool results
"smart_collapse", # Collapse similar adjacent messages
"param_truncation" # Truncate large parameters
]
)
Structured summarization
Structured summarization
summary = await compressor.summarize_structured(
messages=old_messages,
format="bullet_points" # or "narrative"
)
undefinedsummary = await compressor.summarize_structured(
messages=old_messages,
format="bullet_points" # or "narrative"
)
undefinedSkills System
技能系统
Progressive disclosure with conditional activation ():
hermes/skills/python
from hermes.skills.manager import SkillsManager
skills_manager = SkillsManager(
skills_dir="~/.hermes/skills",
config=config
)带条件激活的渐进式披露():
hermes/skills/python
from hermes.skills.manager import SkillsManager
skills_manager = SkillsManager(
skills_dir="~/.hermes/skills",
config=config
)Skills are auto-discovered from markdown files
Skills are auto-discovered from markdown files
Triggered by keywords or explicit @skill references
Triggered by keywords or explicit @skill references
Conditional activation example in YAML frontmatter:
Conditional activation example in YAML frontmatter:
"""
name: docker-expert
triggers:
- docker
- container
- dockerfile conditions:
- file_exists: Dockerfile
- OR:
- file_exists: docker-compose.yml
- env_var: DOCKER_HOST credentials:
- DOCKER_API_KEY
"""
"""
name: docker-expert
triggers:
- docker
- container
- dockerfile conditions:
- file_exists: Dockerfile
- OR:
- file_exists: docker-compose.yml
- env_var: DOCKER_HOST credentials:
- DOCKER_API_KEY
"""
Plugin namespace skills (loaded from plugins)
Plugin namespace skills (loaded from plugins)
await skills_manager.load_plugin_skills(
plugin_name="custom_plugin",
skills_manifest=plugin.get_skills()
)
undefinedawait skills_manager.load_plugin_skills(
plugin_name="custom_plugin",
skills_manifest=plugin.get_skills()
)
undefinedMulti-Agent Architecture
多Agent架构
Four runtime mechanisms:
python
undefined四种运行机制:
python
undefined1. Task Delegation
1. Task Delegation
from hermes.tools.delegate import delegate_task
result = await delegate_task(
task="Research Python async patterns",
specialist_config={
"model": "claude-3-7-sonnet",
"toolsets": ["web_search", "code_analysis"]
}
)
from hermes.tools.delegate import delegate_task
result = await delegate_task(
task="Research Python async patterns",
specialist_config={
"model": "claude-3-7-sonnet",
"toolsets": ["web_search", "code_analysis"]
}
)
2. Mixture of Agents (MoA)
2. Mixture of Agents (MoA)
from hermes.multi_agent.moa import MixtureOfAgents
moa = MixtureOfAgents(
agents=[
{"name": "researcher", "model": "gpt-4"},
{"name": "critic", "model": "claude-3-opus"},
{"name": "synthesizer", "model": "claude-3-7-sonnet"}
]
)
consensus = await moa.deliberate(
question="What's the best architecture for this service?"
)
from hermes.multi_agent.moa import MixtureOfAgents
moa = MixtureOfAgents(
agents=[
{"name": "researcher", "model": "gpt-4"},
{"name": "critic", "model": "claude-3-opus"},
{"name": "synthesizer", "model": "claude-3-7-sonnet"}
]
)
consensus = await moa.deliberate(
question="What's the best architecture for this service?"
)
3. Background Review
3. Background Review
from hermes.multi_agent.reviewer import BackgroundReviewer
reviewer = BackgroundReviewer(model="gpt-4o")
review = await reviewer.review_conversation(
messages=conversation_history,
focus="security concerns"
)
from hermes.multi_agent.reviewer import BackgroundReviewer
reviewer = BackgroundReviewer(model="gpt-4o")
review = await reviewer.review_conversation(
messages=conversation_history,
focus="security concerns"
)
4. Direct Agent Messaging
4. Direct Agent Messaging
await agent.send_message(
to_agent="code_reviewer",
content="Please review the changes in PR #123"
)
undefinedawait agent.send_message(
to_agent="code_reviewer",
content="Please review the changes in PR #123"
)
undefinedBrowser Automation
浏览器自动化
Multi-backend architecture ():
hermes/tools/browser/python
from hermes.tools.browser import browser_navigate, browser_interact多后端架构():
hermes/tools/browser/python
from hermes.tools.browser import browser_navigate, browser_interactNavigate with accessibility tree extraction
Navigate with accessibility tree extraction
result = await browser_navigate(
url="https://github.com/trending",
extract_content=True,
backend="playwright" # or "selenium", "playwright_firefox"
)
result = await browser_navigate(
url="https://github.com/trending",
extract_content=True,
backend="playwright" # or "selenium", "playwright_firefox"
)
Interact with elements
Interact with elements
await browser_interact(
action="click",
selector="button[aria-label='Star']",
wait_for="networkidle"
)
await browser_interact(
action="click",
selector="button[aria-label='Star']",
wait_for="networkidle"
)
Three-layer security:
Three-layer security:
1. URL allowlist/blocklist
1. URL allowlist/blocklist
2. Content filtering
2. Content filtering
3. Sandboxed execution
3. Sandboxed execution
undefinedundefinedCode Execution Sandbox
代码执行沙箱
Secure Python execution ():
hermes/tools/code_exec/python
from hermes.tools.code_exec import execute_code
result = await execute_code(
code="""
import numpy as np
data = np.random.rand(100)
print(f"Mean: {data.mean()}")
""",
language="python",
timeout=30,
allowed_imports=["numpy", "pandas", "matplotlib"]
)安全Python执行():
hermes/tools/code_exec/python
from hermes.tools.code_exec import execute_code
result = await execute_code(
code="""
import numpy as np
data = np.random.rand(100)
print(f"Mean: {data.mean()}")
""",
language="python",
timeout=30,
allowed_imports=["numpy", "pandas", "matplotlib"]
)Sandbox restrictions:
Sandbox restrictions:
- No os.system, subprocess, eval
- No os.system, subprocess, eval
- Limited file system access
- Limited file system access
- Network requests blocked by default
- Network requests blocked by default
- Resource limits enforced
- Resource limits enforced
**Communication modes:**
```python
**通信模式:**
```python1. Unix Domain Socket (default)
1. Unix Domain Socket (default)
sandbox_config = {
"mode": "uds",
"socket_path": "/tmp/hermes_sandbox.sock"
}
sandbox_config = {
"mode": "uds",
"socket_path": "/tmp/hermes_sandbox.sock"
}
2. File RPC (Windows-compatible)
2. File RPC (Windows-compatible)
sandbox_config = {
"mode": "file_rpc",
"rpc_dir": "/tmp/hermes_rpc"
}
undefinedsandbox_config = {
"mode": "file_rpc",
"rpc_dir": "/tmp/hermes_rpc"
}
undefinedMessaging Gateway Integration
消息网关集成
Platform adapter plugin system ():
hermes/gateway/python
from hermes.gateway.platform_registry import platform_registry
from hermes.gateway.base import PlatformAdapter, PlatformMessage
@platform_registry.register("custom_chat")
class CustomChatAdapter(PlatformAdapter):
"""Custom messaging platform integration."""
platform_name = "custom_chat"
async def initialize(self):
"""Connect to platform API."""
self.client = CustomChatClient(
api_key=self.config.get("api_key")
)
await self.client.connect()
async def receive_messages(self):
"""Poll for new messages."""
async for raw_msg in self.client.stream_messages():
yield PlatformMessage(
platform="custom_chat",
channel_id=raw_msg.channel,
user_id=raw_msg.author_id,
username=raw_msg.author_name,
content=raw_msg.text,
message_id=raw_msg.id,
timestamp=raw_msg.created_at
)
async def send_message(self, channel_id: str, content: str, **kwargs):
"""Send response to platform."""
await self.client.send(
channel=channel_id,
text=content
)
def get_channel_prompt(self, channel_id: str) -> str:
"""Optional: platform-specific instructions."""
return "Respond in a friendly, casual tone suitable for chat."平台适配器插件系统():
hermes/gateway/python
from hermes.gateway.platform_registry import platform_registry
from hermes.gateway.base import PlatformAdapter, PlatformMessage
@platform_registry.register("custom_chat")
class CustomChatAdapter(PlatformAdapter):
"""Custom messaging platform integration."""
platform_name = "custom_chat"
async def initialize(self):
"""Connect to platform API."""
self.client = CustomChatClient(
api_key=self.config.get("api_key")
)
await self.client.connect()
async def receive_messages(self):
"""Poll for new messages."""
async for raw_msg in self.client.stream_messages():
yield PlatformMessage(
platform="custom_chat",
channel_id=raw_msg.channel,
user_id=raw_msg.author_id,
username=raw_msg.author_name,
content=raw_msg.text,
message_id=raw_msg.id,
timestamp=raw_msg.created_at
)
async def send_message(self, channel_id: str, content: str, **kwargs):
"""Send response to platform."""
await self.client.send(
channel=channel_id,
text=content
)
def get_channel_prompt(self, channel_id: str) -> str:
"""Optional: platform-specific instructions."""
return "Respond in a friendly, casual tone suitable for chat."Register and run
Register and run
gateway = MessagingGateway(config)
gateway.register_platform(CustomChatAdapter(config.platforms.custom_chat))
await gateway.run()
**Built-in platform adapters:**
- Discord, Slack, Telegram, IRC
- WeChat, QQ, DingTalk, WeCom (企业微信)
- WhatsApp, Signal, Matrix
- BlueBubbles (iMessage), SMS
- 腾讯元宝 (Tencent Yuanbao)gateway = MessagingGateway(config)
gateway.register_platform(CustomChatAdapter(config.platforms.custom_chat))
await gateway.run()
**内置平台适配器:**
- Discord、Slack、Telegram、IRC
- 微信、QQ、钉钉、企业微信
- WhatsApp、Signal、Matrix
- BlueBubbles(iMessage)、SMS
- 腾讯元宝Plugin System
插件系统
Dual hook architecture ():
hermes/plugins/python
from hermes.plugins.base import Plugin, plugin_registry
@plugin_registry.register
class DashboardPlugin(Plugin):
"""Web dashboard for monitoring agent activity."""
name = "dashboard"
version = "1.0.0"
async def initialize(self, agent):
"""Setup plugin."""
self.agent = agent
self.app = create_dashboard_app()
# Register custom commands
agent.register_command(
name="/dashboard",
handler=self.open_dashboard,
description="Open web dashboard"
)
# Hook into tool execution
agent.register_hook(
"before_tool_call",
self.log_tool_call
)
async def log_tool_call(self, tool_name, parameters):
"""Log tool executions to dashboard."""
await self.app.broadcast_event({
"type": "tool_call",
"tool": tool_name,
"params": parameters,
"timestamp": time.time()
})
async def open_dashboard(self, args):
"""Handle /dashboard command."""
url = await self.app.get_url()
return f"Dashboard: {url}"双钩子架构():
hermes/plugins/python
from hermes.plugins.base import Plugin, plugin_registry
@plugin_registry.register
class DashboardPlugin(Plugin):
"""Web dashboard for monitoring agent activity."""
name = "dashboard"
version = "1.0.0"
async def initialize(self, agent):
"""Setup plugin."""
self.agent = agent
self.app = create_dashboard_app()
# Register custom commands
agent.register_command(
name="/dashboard",
handler=self.open_dashboard,
description="Open web dashboard"
)
# Hook into tool execution
agent.register_hook(
"before_tool_call",
self.log_tool_call
)
async def log_tool_call(self, tool_name, parameters):
"""Log tool executions to dashboard."""
await self.app.broadcast_event({
"type": "tool_call",
"tool": tool_name,
"params": parameters,
"timestamp": time.time()
})
async def open_dashboard(self, args):
"""Handle /dashboard command."""
url = await self.app.get_url()
return f"Dashboard: {url}"Load plugins
Load plugins
await agent.load_plugins(plugins_dir="~/.hermes/plugins")
undefinedawait agent.load_plugins(plugins_dir="~/.hermes/plugins")
undefinedMCP (Model Context Protocol) Integration
MCP(Model Context Protocol)集成
python
from hermes.mcp.client import MCPClientpython
from hermes.mcp.client import MCPClientConnect to MCP server
Connect to MCP server
mcp = MCPClient(server_url="http://localhost:8000")
mcp = MCPClient(server_url="http://localhost:8000")
MCP tools automatically registered
MCP tools automatically registered
await mcp.connect()
mcp_tools = await mcp.list_tools()
await mcp.connect()
mcp_tools = await mcp.list_tools()
Tools appear in agent's tool registry
Tools appear in agent's tool registry
OAuth flows handled automatically for supported MCPs
OAuth flows handled automatically for supported MCPs
undefinedundefinedSmart Model Routing
智能模型路由
python
from hermes.routing.smart_router import SmartRouter
router = SmartRouter(
default_model="claude-3-7-sonnet",
short_message_model="claude-3-5-haiku",
short_message_threshold=100 # tokens
)python
from hermes.routing.smart_router import SmartRouter
router = SmartRouter(
default_model="claude-3-7-sonnet",
short_message_model="claude-3-5-haiku",
short_message_threshold=100 # tokens
)Automatic routing based on complexity
Automatic routing based on complexity
model = router.select_model(
messages=conversation,
task_type="code_generation" # or "chat", "analysis"
)
model = router.select_model(
messages=conversation,
task_type="code_generation" # or "chat", "analysis"
)
Provider-specific features
Provider-specific features
- AWS Bedrock with cross-region failover
- AWS Bedrock with cross-region failover
- Gemini with OAuth refresh
- Gemini with OAuth refresh
- Ollama Cloud distributed routing
- Ollama Cloud distributed routing
- Tool Gateway for model-specific tool schemas
- Tool Gateway for model-specific tool schemas
undefinedundefinedPrompt Caching Optimization
提示词缓存优化
python
from hermes.optimization.cache import CacheStrategypython
from hermes.optimization.cache import CacheStrategyFreeze memory snapshot to protect prefix
Freeze memory snapshot to protect prefix
cache_strategy = CacheStrategy(
enabled=True,
min_cache_size=2000, # tokens
freeze_system_prompt=True
)
cache_strategy = CacheStrategy(
enabled=True,
min_cache_size=2000, # tokens
freeze_system_prompt=True
)
Cache-aware message assembly
Cache-aware message assembly
messages = prompt_builder.build_messages(
system_prompt=frozen_system, # Cached
memory_snapshot=frozen_memory, # Cached
new_messages=recent_messages # Not cached
)
messages = prompt_builder.build_messages(
system_prompt=frozen_system, # Cached
memory_snapshot=frozen_memory, # Cached
new_messages=recent_messages # Not cached
)
Typical savings: 75% reduction in prompt processing costs
Typical savings: 75% reduction in prompt processing costs
undefinedundefinedSecurity & Safety
安全与防护
python
from hermes.security.approval import ApprovalSystempython
from hermes.security.approval import ApprovalSystemConfigure danger command approval
Configure danger command approval
approval = ApprovalSystem(
mode="smart", # or "manual", "off"
dangerous_patterns=[
r"rm -rf",
r"DROP TABLE",
r"chmod 777"
]
)
approval = ApprovalSystem(
mode="smart", # or "manual", "off"
dangerous_patterns=[
r"rm -rf",
r"DROP TABLE",
r"chmod 777"
]
)
Smart mode uses LLM to assess risk
Smart mode uses LLM to assess risk
if await approval.requires_approval(command):
user_confirmed = await approval.request_approval(
command=command,
risk_level="high",
explanation="This will delete system files"
)
if not user_confirmed:
return ToolResult(success=False, error="User rejected")
if await approval.requires_approval(command):
user_confirmed = await approval.request_approval(
command=command,
risk_level="high",
explanation="This will delete system files"
)
if not user_confirmed:
return ToolResult(success=False, error="User rejected")
Multi-layer defense:
Multi-layer defense:
1. Prompt injection guards
1. Prompt injection guards
2. Path traversal protection
2. Path traversal protection
3. Credential isolation
3. Credential isolation
4. PII detection/redaction (in gateway mode)
4. PII detection/redaction (in gateway mode)
undefinedundefinedError Handling & Fault Tolerance
错误处理与容错
python
from hermes.errors import HermesError, ToolExecutionError
from hermes.errors.classifier import ErrorClassifier
classifier = ErrorClassifier()
try:
result = await tool_function(**params)
except Exception as e:
# Structured error classification
error_info = classifier.classify(e)
if error_info.category == "rate_limit":
# Automatic retry with backoff
await asyncio.sleep(error_info.retry_after)
result = await tool_function(**params)
elif error_info.category == "auth_failure":
# Try fallback credentials
alt_creds = credential_pool.get_next()
result = await tool_function(**params, creds=alt_creds)
elif error_info.recoverable:
# Switch to fallback model
fallback_model = config.get_fallback_model()
result = await fallback_model.complete(...)
else:
# Propagate with context
raise HermesError(
message=f"Unrecoverable error in {tool_name}",
original_error=e,
context=error_info.context
)python
from hermes.errors import HermesError, ToolExecutionError
from hermes.errors.classifier import ErrorClassifier
classifier = ErrorClassifier()
try:
result = await tool_function(**params)
except Exception as e:
# Structured error classification
error_info = classifier.classify(e)
if error_info.category == "rate_limit":
# Automatic retry with backoff
await asyncio.sleep(error_info.retry_after)
result = await tool_function(**params)
elif error_info.category == "auth_failure":
# Try fallback credentials
alt_creds = credential_pool.get_next()
result = await tool_function(**params, creds=alt_creds)
elif error_info.recoverable:
# Switch to fallback model
fallback_model = config.get_fallback_model()
result = await fallback_model.complete(...)
else:
# Propagate with context
raise HermesError(
message=f"Unrecoverable error in {tool_name}",
original_error=e,
context=error_info.context
)Configuration Patterns
配置模式
Multi-Profile Setup
多配置文件设置
yaml
undefinedyaml
undefinedconfig.yaml
config.yaml
profiles:
default:
model: claude-3-7-sonnet-20250219
provider: anthropic
toolsets:
- filesystem
- web_search
- code_execution
memory:
enabled: true
compress_threshold: 50
code_assistant:
model: claude-3-7-sonnet-20250219
toolsets:
- filesystem
- git
- code_execution
- browser
skills:
- python-expert
- rust-expert
memory:
enabled: true
session_isolation: true
researcher:
model: gpt-4o
toolsets:
- web_search
- browser
- pdf_tools
auxiliary_model: gpt-4o-mini
memory:
compress_threshold: 30
profiles:
default:
model: claude-3-7-sonnet-20250219
provider: anthropic
toolsets:
- filesystem
- web_search
- code_execution
memory:
enabled: true
compress_threshold: 50
code_assistant:
model: claude-3-7-sonnet-20250219
toolsets:
- filesystem
- git
- code_execution
- browser
skills:
- python-expert
- rust-expert
memory:
enabled: true
session_isolation: true
researcher:
model: gpt-4o
toolsets:
- web_search
- browser
- pdf_tools
auxiliary_model: gpt-4o-mini
memory:
compress_threshold: 30
Load specific profile
Load specific profile
hermes --profile code_assistant
undefinedhermes --profile code_assistant
undefinedCredential Pool Management
凭证池管理
yaml
credentials:
anthropic:
pool:
- api_key: ${ANTHROPIC_KEY_1}
rate_limit: 1000
- api_key: ${ANTHROPIC_KEY_2}
rate_limit: 500
selection_strategy: round_robin # or least_used, weighted, failover
openai:
pool:
- api_key: ${OPENAI_KEY_MAIN}
organization: ${OPENAI_ORG}
- api_key: ${OPENAI_KEY_BACKUP}yaml
credentials:
anthropic:
pool:
- api_key: ${ANTHROPIC_KEY_1}
rate_limit: 1000
- api_key: ${ANTHROPIC_KEY_2}
rate_limit: 500
selection_strategy: round_robin # or least_used, weighted, failover
openai:
pool:
- api_key: ${OPENAI_KEY_MAIN}
organization: ${OPENAI_ORG}
- api_key: ${OPENAI_KEY_BACKUP}Gateway Configuration
网关配置
yaml
gateway:
enabled: true
platforms:
discord:
enabled: true
token: ${DISCORD_TOKEN}
allowed_channels:
- "1234567890"
admin_users:
- "user#1234"
channel_prompts:
"1234567890": "You are a helpful coding assistant."
slack:
enabled: true
token: ${SLACK_TOKEN}
signing_secret: ${SLACK_SIGNING_SECRET}
socket_mode: true
wechat:
enabled: true
auto_login: true
contact_whitelist:
- "friend_name"
session_management:
timeout: 3600 # seconds
max_per_user: 5
pii_redaction: trueyaml
gateway:
enabled: true
platforms:
discord:
enabled: true
token: ${DISCORD_TOKEN}
allowed_channels:
- "1234567890"
admin_users:
- "user#1234"
channel_prompts:
"1234567890": "You are a helpful coding assistant."
slack:
enabled: true
token: ${SLACK_TOKEN}
signing_secret: ${SLACK_SIGNING_SECRET}
socket_mode: true
wechat:
enabled: true
auto_login: true
contact_whitelist:
- "friend_name"
session_management:
timeout: 3600 # seconds
max_per_user: 5
pii_redaction: trueCLI Commands
CLI命令
bash
undefinedbash
undefinedInteractive mode
Interactive mode
hermes
hermes
One-shot command
One-shot command
hermes "Analyze the codebase structure"
hermes "Analyze the codebase structure"
With specific profile
With specific profile
hermes --profile researcher "Find recent papers on RAG"
hermes --profile researcher "Find recent papers on RAG"
Dump configuration/state
Dump configuration/state
hermes dump --format json --output state.json
hermes dump --format json --output state.json
Skill management
Skill management
hermes skills list
hermes skills reload
hermes --reload-skills # Reload during session
hermes skills list
hermes skills reload
hermes --reload-skills # Reload during session
Session management
Session management
hermes sessions list
hermes sessions search "docker configuration"
hermes sessions delete <session_id>
hermes sessions list
hermes sessions search "docker configuration"
hermes sessions delete <session_id>
Gateway mode
Gateway mode
hermes gateway --platforms discord,slack
hermes gateway --platforms discord,slack
Generate training data
Generate training data
hermes trajectory --output dataset/ --runs 100
undefinedhermes trajectory --output dataset/ --runs 100
undefinedSlash Commands (in interactive mode)
交互式模式下的斜杠命令
/exit or /quit - Exit session
/reset - Clear conversation
/dump - Export state
/models - List available models
/switch <model> - Switch model
/profile <name> - Switch profile
/tools - List active tools
/skills - List loaded skills
/reload-skills - Reload skill library
/memory search <query> - Search memories
/help - Show commands/exit or /quit - 退出会话
/reset - 清除对话记录
/dump - 导出状态
/models - 列出可用模型
/switch <model> - 切换模型
/profile <name> - 切换配置文件
/tools - 列出激活的工具
/skills - 列出已加载的技能
/reload-skills - 重新加载技能库
/memory search <query> - 搜索记忆内容
/help - 显示命令列表Development Patterns
开发模式
Custom Provider Transport
自定义Provider传输层
python
from hermes.providers.base import ProviderTransport
from hermes.providers.registry import provider_registry
@provider_registry.register("custom_llm")
class CustomLLMTransport(ProviderTransport):
"""Custom LLM provider integration."""
async def create_completion(self, messages, model, **kwargs):
"""Send completion request."""
response = await self.http_client.post(
f"{self.base_url}/v1/chat/completions",
json={
"model": model,
"messages": self._format_messages(messages),
"tools": self._format_tools(kwargs.get("tools", []))
},
headers={"Authorization": f"Bearer {self.api_key}"}
)
return self._parse_response(response)
async def stream_completion(self, messages, model, **kwargs):
"""Stream completion chunks."""
async with self.http_client.stream(
"POST",
f"{self.base_url}/v1/chat/completions",
json={"model": model, "messages": messages, "stream": True}
) as stream:
async for line in stream.aiter_lines():
if line.startswith("data: "):
yield self._parse_chunk(line)
def _format_tools(self, tools):
"""Convert Hermes tool schema to provider format."""
return [
{
"name": tool["name"],
"description": tool["description"],
"parameters": tool["parameters"]
}
for tool in tools
]python
from hermes.providers.base import ProviderTransport
from hermes.providers.registry import provider_registry
@provider_registry.register("custom_llm")
class CustomLLMTransport(ProviderTransport):
"""Custom LLM provider integration."""
async def create_completion(self, messages, model, **kwargs):
"""Send completion request."""
response = await self.http_client.post(
f"{self.base_url}/v1/chat/completions",
json={
"model": model,
"messages": self._format_messages(messages),
"tools": self._format_tools(kwargs.get("tools", []))
},
headers={"Authorization": f"Bearer {self.api_key}"}
)
return self._parse_response(response)
async def stream_completion(self, messages, model, **kwargs):
"""Stream completion chunks."""
async with self.http_client.stream(
"POST",
f"{self.base_url}/v1/chat/completions",
json={"model": model, "messages": messages, "stream": True}
) as stream:
async for line in stream.aiter_lines():
if line.startswith("data: "):
yield self._parse_chunk(line)
def _format_tools(self, tools):
"""Convert Hermes tool schema to provider format."""
return [
{
"name": tool["name"],
"description": tool["description"],
"parameters": tool["parameters"]
}
for tool in tools
]Context Reference System
上下文引用系统
python
from hermes.context.references import ContextReferenceParser
parser = ContextReferenceParser(
sandbox_root="/workspace",
max_file_size=100000 # bytes
)python
from hermes.context.references import ContextReferenceParser
parser = ContextReferenceParser(
sandbox_root="/workspace",
max_file_size=100000 # bytes
)Parse @references from user input
Parse @references from user input
content, references = await parser.parse(
"@file:src/main.py @url:https://docs.python.org/3/library/asyncio.html"
)
content, references = await parser.parse(
"@file:src/main.py @url:https://docs.python.org/3/library/asyncio.html"
)
Automatic injection into context
Automatic injection into context
context_additions = await parser.resolve_references(references)
context_additions = await parser.resolve_references(references)
Supported reference types:
Supported reference types:
@file:path/to/file
@file:path/to/file
@folder:path/to/dir
@folder:path/to/dir
@diff:branch1..branch2
@diff:branch1..branch2
@url:https://...
@url:https://...
@git:commit-hash
@git:commit-hash
undefinedundefinedParallel Tool Execution
并行工具执行
python
from hermes.tools.parallel import ParallelExecutor
executor = ParallelExecutor(max_workers=5)python
from hermes.tools.parallel import ParallelExecutor
executor = ParallelExecutor(max_workers=5)Automatic safety detection
Automatic safety detection
tool_calls = [
{"name": "search_web", "params": {"query": "Python async"}},
{"name": "search_web", "params": {"query": "Rust async"}},
{"name": "write_file", "params": {"path": "test.txt", "content": "x"}},
]
tool_calls = [
{"name": "search_web", "params": {"query": "Python async"}},
{"name": "search_web", "params": {"query": "Rust async"}},
{"name": "write_file", "params": {"path": "test.txt", "content": "x"}},
]
Intelligent batching (searches run parallel, write serialized)
Intelligent batching (searches run parallel, write serialized)
results = await executor.execute_batch(
tool_calls,
conflict_detection=True # Checks path overlaps
)
results = await executor.execute_batch(
tool_calls,
conflict_detection=True # Checks path overlaps
)
Three safety categories:
Three safety categories:
- read_only: Always safe to parallelize
- read_only: Always safe to parallelize
- stateless: Safe if parameters don't conflict
- stateless: Safe if parameters don't conflict
- stateful: Always serialize
- stateful: Always serialize
undefinedundefinedVoice Mode Integration
语音模式集成
python
from hermes.voice.stt import STTProvider
from hermes.voice.tts import TTSProviderpython
from hermes.voice.stt import STTProvider
from hermes.voice.tts import TTSProviderSpeech-to-Text (3 providers: OpenAI, Deepgram, AssemblyAI)
Speech-to-Text (3 providers: OpenAI, Deepgram, AssemblyAI)
stt = STTProvider(
provider="deepgram",
api_key="${DEEPGRAM_API_KEY}",
language="en"
)
transcript = await stt.transcribe_audio(
audio_file="recording.wav"
)
stt = STTProvider(
provider="deepgram",
api_key="${DEEPGRAM_API_KEY}",
language="en"
)
transcript = await stt.transcribe_audio(
audio_file="recording.wav"
)
Text-to-Speech (5 providers)
Text-to-Speech (5 providers)
tts = TTSProvider(
provider="gemini", # or openai, elevenlabs, kitten, xai
voice="alloy"
)
audio_data = await tts.synthesize(
text="Analysis complete. Found 3 issues.",
output_format="mp3"
)
tts = TTSProvider(
provider="gemini", # or openai, elevenlabs, kitten, xai
voice="alloy"
)
audio_data = await tts.synthesize(
text="Analysis complete. Found 3 issues.",
output_format="mp3"
)
Push-to-talk workflow
Push-to-talk workflow
from hermes.voice.ptt import PushToTalkSession
async with PushToTalkSession(stt, tts, agent) as session:
await session.run() # Handles recording, transcription, TTS
undefinedfrom hermes.voice.ptt import PushToTalkSession
async with PushToTalkSession(stt, tts, agent) as session:
await session.run() # Handles recording, transcription, TTS
undefinedTroubleshooting
故障排查
Memory Issues
内存相关问题
Problem: Context window exceeded despite compression.
python
undefined问题: 已启用压缩但仍超出上下文窗口。
python
undefinedSolution 1: Adjust compression threshold
解决方案1:调整压缩阈值
config.memory.compress_threshold = 30 # More aggressive
config.memory.compress_threshold = 30 # 更激进的压缩
Solution 2: Limit memory retrieval
解决方案2:限制内存检索数量
config.memory.max_memories_per_query = 3
config.memory.max_memories_per_query = 3
Solution 3: Use summarization
解决方案3:使用摘要功能
compressor.summarize_structured(
messages=old_messages[:-10],
format="bullet_points"
)
**Problem:** Memories not being recalled.
```pythoncompressor.summarize_structured(
messages=old_messages[:-10],
format="bullet_points"
)
**问题:** 记忆内容无法被召回。
```pythonCheck FTS5 index
检查FTS5索引
from hermes.memory.session_db import SessionDB
db = SessionDB()
await db.rebuild_fts_index()
from hermes.memory.session_db import SessionDB
db = SessionDB()
await db.rebuild_fts_index()
Verify embedding similarity threshold
验证嵌入相似度阈值
config.memory.similarity_threshold = 0.7 # Lower = more matches
undefinedconfig.memory.similarity_threshold = 0.7 # 值越低,匹配结果越多
undefinedTool Execution
工具执行问题
Problem: Tool results too large.
python
undefined问题: 工具返回结果过大。
python
undefinedThree-layer overflow protection active:
三层溢出保护已激活:
1. Tool-level truncation (automatic)
1. 工具级自动截断
2. Single result persistence (check ~/.hermes/tool_cache/)
2. 单结果持久化(检查~/.hermes/tool_cache/)
3. Round budget enforcement (configured in config.yaml)
3. 轮次预算限制(在config.yaml中配置)
config.tools.max_result_size = 50000 # bytes per tool
config.tools.round_token_budget = 100000 # total per round
**Problem:** Parallel execution conflicts.
```pythonconfig.tools.max_result_size = 50000 # 每个工具的结果最大字节数
config.tools.round_token_budget = 100000 # 每轮总预算
**问题:** 并行执行出现冲突。
```pythonEnable path conflict detection
启用路径冲突检测
from hermes.tools.parallel import PathConflictDetector
detector = PathConflictDetector()
conflicts = detector.find_conflicts([
("write_file", {"path": "src/main.py"}),
("read_file", {"path": "src/main.py"}) # Conflict!
])
from hermes.tools.parallel import PathConflictDetector
detector = PathConflictDetector()
conflicts = detector.find_conflicts([
("write_file", {"path": "src/main.py"}),
("read_file", {"path": "src/main.py"}) # 冲突!
])
Configure safety classification
配置安全分类
@tool_registry.register(safety_class="stateful") # Force serialization
async def my_stateful_tool(...):
...
undefined@tool_registry.register(safety_class="stateful") # 强制串行执行
async def my_stateful_tool(...):
...
undefinedGateway Issues
网关相关问题
Problem: Platform authentication failing.
python
undefined问题: 平台认证失败。
python
undefinedCheck credentials
检查凭证
hermes gateway --test-auth --platform discord
hermes gateway --test-auth --platform discord
For QR-code platforms (WeChat, DingTalk)
对于需要二维码登录的平台(微信、钉钉)
config.gateway.platforms.wechat.auto_login = true
config.gateway.platforms.dingtalk.use_qr = true
config.gateway.platforms.wechat.auto_login = true
config.gateway.platforms.dingtalk.use_qr = true
Verify webhook delivery (Slack, Discord)
验证Webhook投递(Slack、Discord)
config.gateway.platforms.slack.verify_signature = true
**Problem:** PII leaking in logs.
```pythonconfig.gateway.platforms.slack.verify_signature = true
**问题:** 日志中泄露个人身份信息(PII)。
```pythonEnable redaction
启用脱敏功能
config.gateway.pii_redaction = true
config.gateway.redact_patterns:
- r'\b\d{3}-\d{2}-\d{4}\b' # SSN
- r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Z|a-z]{2,}\b' # Email
undefinedconfig.gateway.pii_redaction = true
config.gateway.redact_patterns:
- r'\b\d{3}-\d{2}-\d{4}\b' # 社保号
- r'\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+.[A-Z|a-z]{2,}\b' # 邮箱
undefinedPerformance
性能问题
Problem: Slow response times.
python
undefined问题: 响应速度慢。
python
undefinedEnable prompt caching
启用提示词缓存
config.optimization.cache.enabled = true
config.optimization.cache.min_size = 2000
config.optimization.cache.enabled = true
config.optimization.cache.min_size = 2000
Use smart routing for simple queries
对简单查询使用智能路由
config.routing.short_message_model = "claude-3-5-haiku"
config.routing.threshold = 100
config.routing.short_message_model = "claude-3-5-haiku"
config.routing.threshold = 100
Parallel tool execution
启用并行工具执行
config.tools.parallel_execution = true
config.tools.max_parallel_workers = 5
**Problem:** High API costs.
```pythonconfig.tools.parallel_execution = true
config.tools.max_parallel_workers = 5
**问题:** API成本过高。
```pythonAggressive compression
启用激进压缩
config.memory.compress_threshold = 20
config.memory.compress_threshold = 20
Auxiliary model for non-critical tasks
对非关键任务使用辅助模型
config.auxiliary_model = "gpt-4o-mini"
config.auxiliary_model = "gpt-4o-mini"
Credential rotation to distribute load
轮换凭证分散负载
config.credentials.anthropic.selection_strategy = "round_robin"
undefinedconfig.credentials.anthropic.selection_strategy = "round_robin"
undefinedDebugging
调试
python
undefinedpython
undefinedEnable detailed logging
启用详细日志
import logging
logging.basicConfig(level=logging.DEBUG)
import logging
logging.basicConfig(level=logging.DEBUG)
Dump full state
导出完整状态
hermes dump --include-memory --include-tools --output debug.json
hermes dump --include-memory --include-tools --output debug.json
Trace tool execution
跟踪工具执行
config.debug.trace_tools = true
config.debug.trace_tools = true
Monitor with dashboard plugin
使用仪表盘插件监控
await agent.load_plugin("dashboard")
await agent.load_plugin("dashboard")
Access at http://localhost:7777
undefinedundefinedBest Practices
最佳实践
- Memory management: Use before each model call to maximize cache hits
freeze_snapshot() - Tool development: Always return with structured data, mark safety class correctly
ToolResult - Multi-agent: Prefer for focused sub-tasks, MoA for complex decisions
delegate_task - Gateway mode: Use for platform-specific behavior, enable PII redaction
channel_prompts - Skills: Write skills with clear triggers, use conditional activation to reduce noise
- Security: Enable danger command approval in production, use sandbox for code execution
- Performance: Enable prompt caching, use auxiliary models for simple tasks, parallelize read-only tools
- Extensions: Register via decorators, use hook system for cross-cutting concerns, follow plugin structure for complex additions
- 内存管理:每次模型调用前使用以最大化缓存命中率
freeze_snapshot() - 工具开发:始终返回带结构化数据的,正确标记安全类别
ToolResult - 多Agent:针对聚焦子任务优先使用,针对复杂决策使用MoA
delegate_task - 网关模式:使用实现平台特定行为,启用PII脱敏
channel_prompts - 技能开发:编写带有明确触发条件的技能,使用条件激活减少无效触发
- 安全防护:生产环境启用危险命令审批,使用沙箱执行代码
- 性能优化:启用提示词缓存,对简单任务使用辅助模型,并行执行只读工具
- 扩展开发:通过装饰器注册扩展,使用钩子系统处理横切关注点,复杂扩展遵循插件结构
Resources
资源
- Source code: https://github.com/NousResearch/hermes-agent
- Architecture wiki: https://github.com/cclank/Hermes-Wiki
- Discord community: Nous Research server
- Model: Hermes-3-Llama-3.1-405B optimized for tool use
- 源码:https://github.com/NousResearch/hermes-agent
- 架构Wiki:https://github.com/cclank/Hermes-Wiki
- Discord社区:Nous Research服务器
- 适配模型:Hermes-3-Llama-3.1-405B(针对工具使用优化)