目录

  1. Profile架构核心机制
  2. Profile隔离机制详解
  3. 多用户使用场景分析
  4. 多用户方案设计
  5. 方案对比与推荐
  6. 实施建议

一、Profile架构核心机制

1.1 核心设计理念

Hermes Agent的Profile机制基于环境变量隔离的轻量级设计,核心是通过HERMES_HOME环境变量实现完全独立的运行环境。

关键代码路径: hermes_constants.py

def get_hermes_home() -> Path:
    """Return the Hermes home directory (default: ~/.hermes)."""
    return Path(os.getenv("HERMES_HOME", Path.home() / ".hermes"))

1.2 Profile目录结构

每个Profile是一个完全独立的HERMES_HOME目录:

~/.hermes/                          # 默认Profile (default)
├── config.yaml                     # 模型、提供商、工具配置
├── .env                           # API密钥、Bot Token
├── SOUL.md                        # 个性设定
├── memories/                      # 记忆系统
│   ├── MEMORY.md                  # Agent笔记
│   └── USER.md                    # 用户画像
├── sessions/                      # 会话数据
├── skills/                        # 技能目录
├── state.db                       # SQLite数据库
├── home/                          # 子进程HOME目录(隔离git/ssh配置)
├── cron/                          # 定时任务
├── logs/                          # 日志
└── gateway.pid                    # Gateway进程ID

~/.hermes/profiles/                 # 命名Profile存储位置
├── coder/                         # coder profile
│   ├── config.yaml
│   ├── .env
│   ├── SOUL.md
│   └── ... (同上结构)
├── assistant/                     # assistant profile
└── work/                          # work profile

1.3 Profile核心组件

组件 隔离级别 说明
配置系统 完全隔离 独立的config.yaml, .env
记忆系统 完全隔离 独立的MEMORY.md, USER.md
会话系统 完全隔离 独立的state.db, sessions/
技能系统 完全隔离 独立的skills/目录
凭证池 完全隔离 独立的auth.json
Gateway服务 完全隔离 独立的进程、Bot Token
定时任务 完全隔离 独立的cron/目录
子进程环境 完全隔离 独立的home/目录 (git/ssh配置)

1.4 Profile操作机制

命令别名机制:

每个Profile自动在~/.local/bin/创建包装脚本:

# ~/.local/bin/coder
#!/bin/sh
exec hermes -p coder "$@"

切换机制:

方式 示例 说明
Flag指定 hermes -p coder chat 通过-p或–profile参数
别名调用 coder chat 通过Profile别名直接调用
粘性默认 hermes profile use coder 设置默认Profile,后续hermes命令自动使用

Profile管理命令:

hermes profile list              # 列出所有Profile
hermes profile create <name>     # 创建新Profile
hermes profile create <name> --clone     # 克隆配置
hermes profile create <name> --clone-all # 完全克隆
hermes profile delete <name>     # 删除Profile
hermes profile rename <old> <new> # 重命名
hermes profile export <name>     # 导出为tar.gz
hermes profile import <file>     # 导入
hermes profile use <name>        # 设置默认Profile

二、Profile隔离机制详解

2.1 路径解析隔离

所有119+个文件通过get_hermes_home()解析路径,自动实现隔离:

# 任何需要访问数据的地方
from hermes_constants import get_hermes_home
home = get_hermes_home()
config_path = home / "config.yaml"

关键实现:

  • 所有路径都基于HERMES_HOME动态计算
  • 切换Profile只需改变HERMES_HOME环境变量
  • 代码无需任何修改,自动适配当前Profile

2.2 进程级隔离

Gateway进程隔离:

coder gateway start      # 启动coder的Gateway (独立进程)
assistant gateway start  # 启动assistant的Gateway (独立进程)

每个Gateway是独立的Python进程,拥有自己的:

  • 进程ID (存储在各自的gateway.pid)
  • 端口监听
  • Bot Token连接

Bot Token安全锁:

如果两个Profile使用相同的Bot Token,第二个Gateway会被阻止启动,并显示明确的错误信息。支持的系统:

  • Telegram
  • Discord
  • Slack
  • WhatsApp
  • Signal

2.3 子进程HOME隔离

每个Profile有独立的home/目录,用于子进程工具配置隔离:

def get_subprocess_home() -> str | None:
    """Return a per-profile HOME directory for subprocesses."""
    hermes_home = os.getenv("HERMES_HOME")
    if not hermes_home:
        return None
    profile_home = os.path.join(hermes_home, "home")
    if os.path.isdir(profile_home):
        return profile_home
    return None

这确保每个Profile有独立的:

  • Git身份配置 (~/.gitconfig)
  • SSH密钥 (~/.ssh/)
  • GitHub CLI token (~/.config/gh/)
  • npm配置 (~/.npmrc)

Docker部署优势:

在Docker环境中,子进程HOME位于持久化卷内,确保工具配置在容器重启后保留。

2.4 会话隔离

SQLite数据库结构:

每个Profile有独立的state.db,包含:

说明
sessions 会话元数据(ID、来源、模型、标题、时间戳)
messages 完整消息历史(角色、内容、工具调用、token计数)
messages_fts FTS5全文搜索索引

Gateway会话追踪:

平台 会话Key格式 说明
Telegram DM agent:main:telegram:dm:<chat_id> 每个DM独立会话
Discord DM agent:main:discord:dm:<chat_id> 每个DM独立会话
群组聊天 agent:main:<platform>:group:<chat_id>:<user_id> 群组内按用户隔离
频道 agent:main:<platform>:channel:<chat_id>:<user_id> 频道内按用户隔离

配置选项:

# config.yaml
gateway:
  group_sessions_per_user: true   # 群组内按用户隔离会话
  session_reset_policy: idle      # 会话重置策略: idle/daily/both/none
  idle_reset_minutes: 60          # 60分钟无活动重置

2.5 凭证池隔离

每个Profile有独立的凭证池(auth.json),支持:

  • 多API密钥轮换
  • OAuth令牌管理
  • 自动速率限制恢复
  • 计费配额自动切换
# 查看凭证池
hermes auth list

# 添加凭证
hermes auth add openrouter --api-key sk-or-v1-xxx
hermes auth add anthropic --type oauth

三、多用户使用场景分析

3.1 场景1:单机多用户(不同OS用户)

现状评估:

项目 状态 说明
支持程度 ✅ 完全支持 每个OS用户有自己的~/.hermes
数据隔离 ✅ 天然隔离 不同home目录
共享机制 ❌ 不支持 无跨用户共享机制
管理成本 ⚠️ 较高 每用户需独立安装配置

适用场景:

  • 个人开发机多用户
  • 服务器多用户环境
  • 需要完全隔离的场景

3.2 场景2:单用户多Profile(不同用途Agent)

现状评估:

项目 状态 说明
支持程度 ✅ 完全支持 Profile机制的核心场景
数据隔离 ✅ 完全隔离 配置、记忆、会话、凭证全隔离
管理成本 ✅ 低 统一安装,Profile独立管理
资源占用 ✅ 低 空闲Profile不占用资源

典型用途:

Profile 用途 特点
coder 编程助手 技术文档、代码规范记忆
assistant 个人助理 日程、偏好记忆
research 研究助手 学术资源、文献记忆
work 工作专用 公司项目、流程记忆

3.3 场景3:团队共享(共享特定Profile)

现状评估:

项目 状态 说明
Profile迁移 ✅ 支持 export/import功能
实时共享 ❌ 不支持 无多用户并发访问控制
协作机制 ❌ 不支持 无协作编辑/同步

现有方案:

# 导出Profile
hermes profile export work ./work-backup.tar.gz

# 在另一台机器导入
hermes profile import ./work-backup.tar.gz work

3.4 场景4:多用户协作(同一Profile协作)

现状评估:

项目 状态 说明
多用户访问 ✅ 支持 Gateway模式支持多用户同时对话
会话隔离 ✅ 支持 会话按user_id自动隔离
记忆隔离 ❌ 不支持 记忆系统不区分用户
配置隔离 ❌ 不支持 配置对所有用户相同

Gateway多用户模式:

通过Telegram/Discord/Slack等消息平台,多用户可以:

  • 同时与同一个Agent对话
  • 各自的会话历史独立
  • 共享Agent的配置和记忆

限制:

  • 记忆系统共享(无法区分用户偏好)
  • SOUL.md对所有用户相同
  • 无法区分用户权限

四、多用户方案设计

4.1 方案A:基于现有Profile机制(推荐)

A-1: 单机多OS用户模式

架构图:

Linux Server
├── 用户 alice
│   └── ~/.hermes/                     # alice的Agent
│       ├── config.yaml
│       ├── .env (alice的API keys)
│       ├── memories/
│       └── profiles/
│           ├── work/
│           └── personal/
│
├── 用户 bob
│   └── ~/.hermes/                     # bob的Agent
│       ├── config.yaml
│       ├── .env (bob的API keys)
│       └── profiles/
│           └── dev/
│
└── 用户 shared (共享服务账户)
    └── ~/.hermes/                     # 团队共享Agent
        ├── config.yaml (团队配置)
        └── .env (团队共享凭证)

部署步骤:

# 1. 创建独立的OS用户
sudo useradd -m -s /bin/bash hermes-team
sudo useradd -m -s /bin/bash alice
sudo useradd -m -s /bin/bash bob

# 2. 为每个用户安装Hermes
sudo -u alice bash
cd ~alice
curl -fsSL https://raw.githubusercontent.com/nousresearch/hermes-agent/main/setup-hermes.sh | bash
exit

sudo -u bob bash
cd ~bob
curl -fsSL https://raw.githubusercontent.com/nousresearch/hermes-agent/main/setup-hermes.sh | bash
exit

# 3. 配置各自的API密钥
sudo -u alice hermes setup
sudo -u bob hermes setup
sudo -u hermes-team hermes setup

# 4. 启动各自的Gateway(如果需要)
sudo -u alice hermes gateway install   # systemd服务
sudo -u bob hermes gateway install
sudo -u hermes-team hermes gateway install

Systemd服务配置:

每个用户的Gateway会创建独立的systemd服务:

# alice的服务
~/.config/systemd/user/hermes-gateway-default.service

# bob的服务
~/.config/systemd/user/hermes-gateway-default.service

# hermes-team的服务
~/.config/systemd/user/hermes-gateway-default.service

优点:

  • ✅ 完全隔离,安全性最高
  • ✅ 无需代码修改
  • ✅ 每个用户完全控制自己的Agent

缺点:

  • ❌ 无共享机制
  • ❌ 管理成本高(每个用户需要独立安装)
A-2: Gateway多用户访问模式

架构图:

                    ┌─────────────────────────────────────┐
                    │      Hermes Gateway (shared)        │
                    │  ~/.hermes/                         │
                    │  ├── config.yaml                    │
                    │  ├── memories/ (团队共享记忆)        │
                    │  └── state.db                       │
                    └─────────────────────────────────────┘
                                     │
                    ┌────────────────┼────────────────┐
                    │                │                │
              ┌─────▼─────┐    ┌─────▼─────┐    ┌─────▼─────┐
              │  Alice    │    │   Bob     │    │   Carol   │
              │ Telegram  │    │  Discord  │    │   Slack   │
              │ DM/Group  │    │  Server   │    │ Workspace │
              └───────────┘    └───────────┘    └───────────┘

会话隔离机制:

Gateway自动按用户ID隔离会话:

平台 会话Key格式 说明
Telegram DM agent:main:telegram:dm:<chat_id> 每个DM独立会话
Discord DM agent:main:discord:dm:<chat_id> 每个DM独立会话
群组聊天 agent:main:<platform>:group:<chat_id>:<user_id> 群组内按用户隔离
频道 agent:main:<platform>:channel:<chat_id>:<user_id> 频道内按用户隔离

配置示例:

# ~/.hermes/config.yaml
gateway:
  group_sessions_per_user: true   # 群组内按用户隔离会话
  session_reset_policy: idle      # 会话重置策略
  idle_reset_minutes: 60          # 60分钟无活动重置

部署示例(Telegram):

# 1. 安装Hermes
curl -fsSL https://raw.githubusercontent.com/nousresearch/hermes-agent/main/setup-hermes.sh | bash

# 2. 配置
hermes setup
# 选择模型、输入API密钥

# 3. 配置Telegram Bot
# 访问 @BotFather 创建Bot,获取Token
hermes config set telegram.bot_token "123456:ABC-DEF..."

# 4. 启动Gateway
hermes gateway start

# 5. 团队成员添加Bot
# Alice、Bob、Carol各自在Telegram中搜索并添加Bot即可使用

优点:

  • ✅ 多用户可同时访问
  • ✅ 会话天然隔离
  • ✅ 无需额外配置
  • ✅ 跨平台支持(Telegram/Discord/Slack等)

缺点:

  • ⚠️ 记忆系统共享(不区分用户)
  • ⚠️ 配置共享(所有用户看到相同的SOUL.md)
  • ⚠️ 无法区分用户偏好
A-3: 混合方案(多Profile + Gateway)

为不同团队/用途创建独立Profile,每个Profile通过Gateway服务特定用户群。

架构图:

~/.hermes/profiles/
├── team-dev/                      # 开发团队Profile
│   ├── config.yaml
│   ├── .env (开发团队Bot Token)
│   ├── SOUL.md (开发团队个性)
│   └── memories/
│       └── MEMORY.md (开发团队知识)
│
├── team-support/                  # 支持团队Profile
│   ├── config.yaml
│   ├── .env (支持团队Bot Token)
│   ├── SOUL.md (支持团队个性)
│   └── memories/
│
└── personal-alice/                # Alice个人Profile
    ├── config.yaml
    ├── .env (Alice的Bot Token)
    └── memories/

运行方式:

# 启动开发团队Gateway(使用Telegram Dev Group Bot)
team-dev gateway start

# 启动支持团队Gateway(使用Discord Support Bot)
team-support gateway start

# Alice个人使用CLI
alice chat

团队Profile配置示例:

# 创建开发团队Profile
hermes profile create team-dev

# 配置开发团队专用设置
team-dev config set model.model anthropic/claude-sonnet-4
team-dev config set telegram.bot_token "DEV_TEAM_BOT_TOKEN"

# 设置开发团队个性
cat > ~/.hermes/profiles/team-dev/SOUL.md << 'EOF'
You are a coding assistant for the development team.
You have access to:
- GitHub repository: github.com/company/project
- CI/CD: Jenkins at ci.company.com
- Issue tracker: Jira at jira.company.com

Team conventions:
- Python code follows PEP8 with 120 char line limit
- Commit messages follow conventional commits
- All PRs require at least one review
EOF

# 启动服务
team-dev gateway install

优点:

  • ✅ 灵活性高,适应不同团队需求
  • ✅ 各团队完全隔离
  • ✅ 每个团队有自己的Agent个性
  • ✅ 凭证和配额独立管理

缺点:

  • ⚠️ 需要为每个Profile配置独立的Bot Token
  • ⚠️ 管理多个Profile有一定复杂度

4.2 方案B:增强型多用户支持(需开发)

如果需要更强的多用户支持(用户级记忆隔离、权限控制),需要开发增强功能。

B-1: 用户级记忆隔离

设计思路:

扩展记忆系统,支持按用户ID存储:

~/.hermes/memories/
├── MEMORY.md              # Agent公共记忆
├── USER.md                # 默认用户画像
└── users/
    ├── alice_12345/
    │   ├── MEMORY.md      # Alice专用记忆
    │   └── USER.md        # Alice画像
    ├── bob_67890/
    │   ├── MEMORY.md      # Bob专用记忆
    │   └── USER.md        # Bob画像
    └── shared/
        └── MEMORY.md      # 团队共享记忆

实现要点:

  1. 修改memory tool - 添加user_id参数
# tools/memory_tool.py (伪代码)
def memory(
    action: str, 
    target: str, 
    content: str = None, 
    old_text: str = None,
    user_id: str = None  # 新增参数
) -> dict:
    """Memory tool with user isolation support."""
    
    home = get_hermes_home()
    
    # 确定记忆文件路径
    if user_id:
        # 用户专用记忆
        memory_path = home / "memories" / "users" / user_id / f"{target}.md"
        memory_path.parent.mkdir(parents=True, exist_ok=True)
    else:
        # 公共记忆
        memory_path = home / "memories" / f"{target}.md"
    
    # 执行记忆操作
    if action == "add":
        return _add_memory(memory_path, content)
    elif action == "replace":
        return _replace_memory(memory_path, old_text, content)
    elif action == "remove":
        return _remove_memory(memory_path, old_text)
  1. Gateway传递user_id
# gateway/session.py (伪代码)
class GatewaySession:
    def get_memory_context(self) -> str:
        """Build memory context for system prompt."""
        user_id = self.get_user_id()  # 从消息来源获取
        
        # 加载公共记忆
        public_memory = load_memory("memory")
        public_user = load_memory("user")
        
        # 加载用户专用记忆
        user_memory = load_memory("memory", user_id=user_id)
        user_profile = load_memory("user", user_id=user_id)
        
        # 合并渲染
        return render_memory_block(
            public_memory, public_user, 
            user_memory, user_profile
        )
  1. 系统Prompt注入
══════════════════════════════════════════════
MEMORY (your personal notes) [67% — 1,474/2,200 chars]
══════════════════════════════════════════════
[公共记忆内容]
§
══════════════════════════════════════════════
USER MEMORY (alice_12345) [45% — 618/1,375 chars]
══════════════════════════════════════════════
[Alice的专用记忆]

配置选项:

# config.yaml
memory:
  user_isolation: true          # 启用用户级记忆隔离
  shared_memory_fallback: true  # 用户无专用记忆时使用公共记忆
B-2: 用户权限控制

设计思路:

添加权限配置,控制不同用户的访问范围:

# ~/.hermes/config.yaml
multi_user:
  enabled: true
  auth_method: telegram_id    # 或 discord_id, slack_id
  
  users:
    # 管理员 - 完全访问
    alice_12345:
      role: admin
      permissions: [chat, memory, skills, config, tools]
      
    # 普通用户 - 限制访问
    bob_67890:
      role: user
      permissions: [chat, memory]
      skills_allowed: [general, research]
      max_tokens_per_day: 100000
      
    # 访客 - 最小权限
    carol_11111:
      role: guest
      permissions: [chat]
      skills_allowed: [general]
      max_tokens_per_day: 20000
      
  # 默认权限(未配置的用户)
  default_role: guest

实现要点:

  1. 用户认证层
# gateway/auth.py (伪代码)
class UserAuthorizer:
    def __init__(self, config: dict):
        self.config = config.get("multi_user", {})
        
    def get_user_role(self, platform: str, user_id: str) -> str:
        """Get user role from config."""
        user_key = f"{platform}_{user_id}"
        users = self.config.get("users", {})
        
        if user_key in users:
            return users[user_key].get("role", "guest")
        return self.config.get("default_role", "guest")
    
    def check_permission(self, user_key: str, permission: str) -> bool:
        """Check if user has specific permission."""
        users = self.config.get("users", {})
        if user_key not in users:
            return permission in self.config.get("default_permissions", ["chat"])
        
        return permission in users[user_key].get("permissions", [])
    
    def check_skill_access(self, user_key: str, skill_name: str) -> bool:
        """Check if user can use a specific skill."""
        users = self.config.get("users", {})
        if user_key not in users:
            return skill_name in self.config.get("default_skills", ["general"])
        
        allowed = users[user_key].get("skills_allowed", ["general"])
        return skill_name in allowed or "all" in allowed
  1. 工具调用检查
# agent/tool_executor.py (伪代码)
async def execute_tool(tool_name: str, params: dict, context: dict):
    """Execute tool with permission check."""
    user_id = context.get("user_id")
    user_key = f"{context.get('platform')}_{user_id}"
    
    authorizer = context.get("authorizer")
    
    # 检查工具权限
    if not authorizer.check_permission(user_key, "tools"):
        return {"error": "You don't have permission to use tools"}
    
    # 检查技能访问(如果是技能调用)
    if tool_name == "skill":
        skill_name = params.get("skill")
        if not authorizer.check_skill_access(user_key, skill_name):
            return {"error": f"Access denied to skill: {skill_name}"}
    
    # 执行工具
    return await _do_execute_tool(tool_name, params)
  1. 配额管理
# agent/quota_manager.py (伪代码)
class QuotaManager:
    def __init__(self, db_path: str):
        self.db = sqlite3.connect(db_path)
        self._init_tables()
    
    def check_quota(self, user_key: str) -> bool:
        """Check if user has remaining quota for today."""
        today = datetime.now().date().isoformat()
        cursor = self.db.execute(
            "SELECT tokens_used FROM daily_quota WHERE user_key = ? AND date = ?",
            (user_key, today)
        )
        row = cursor.fetchone()
        used = row[0] if row else 0
        
        # 从config获取用户配额
        quota = self._get_user_quota(user_key)
        return used < quota
    
    def record_usage(self, user_key: str, tokens: int):
        """Record token usage."""
        today = datetime.now().date().isoformat()
        self.db.execute(
            """INSERT INTO daily_quota (user_key, date, tokens_used)
               VALUES (?, ?, ?)
               ON CONFLICT(user_key, date) 
               DO UPDATE SET tokens_used = tokens_used + ?""",
            (user_key, today, tokens, tokens)
        )
        self.db.commit()
B-3: 共享Profile机制

设计思路:

允许多用户共享特定Profile,支持读写权限控制:

# 创建共享Profile
hermes profile create team-dev --shared

# 设置共享权限
hermes profile share team-dev --add alice --permissions rw
hermes profile share team-dev --add bob --permissions r
hermes profile share team-dev --add carol --permissions r

# 查看共享状态
hermes profile show team-dev
# Output:
# Profile: team-dev
# Path: ~/.hermes/profiles/team-dev
# Shared with:
#   alice (rw)
#   bob (r)
#   carol (r)

实现要点:

  1. Profile存储位置调整
# hermes_cli/profiles.py (修改)

def _get_profiles_root() -> Path:
    """Return the directory where named profiles are stored."""
    # 检查是否是共享Profile
    shared_root = Path("/var/lib/hermes/profiles")
    if shared_root.exists():
        return shared_root
    return _get_default_hermes_home() / "profiles"

def get_shared_profile_dir(name: str) -> Path:
    """Get shared profile directory."""
    return Path("/var/lib/hermes/profiles") / name
  1. Unix Group权限控制
# 创建共享Profile时
sudo mkdir -p /var/lib/hermes/profiles/team-dev
sudo groupadd hermes-team-dev
sudo chgrp hermes-team-dev /var/lib/hermes/profiles/team-dev
sudo chmod 775 /var/lib/hermes/profiles/team-dev

# 添加用户到组
sudo usermod -aG hermes-team-dev alice
sudo usermod -aG hermes-team-dev bob

# 设置ACL实现读写分离
sudo setfacl -m u:alice:rwx /var/lib/hermes/profiles/team-dev
sudo setfacl -m u:bob:rx /var/lib/hermes/profiles/team-dev
  1. Profile锁机制
# hermes_cli/profiles.py (新增)
import fcntl

class ProfileLock:
    """File-based lock for shared profile access."""
    
    def __init__(self, profile_dir: Path):
        self.lock_file = profile_dir / ".profile.lock"
        self.lock_fd = None
    
    def acquire_read(self):
        """Acquire shared lock for reading."""
        self.lock_fd = open(self.lock_file, 'r')
        fcntl.flock(self.lock_fd.fileno(), fcntl.LOCK_SH)
    
    def acquire_write(self):
        """Acquire exclusive lock for writing."""
        self.lock_fd = open(self.lock_file, 'w')
        fcntl.flock(self.lock_fd.fileno(), fcntl.LOCK_EX)
    
    def release(self):
        """Release the lock."""
        if self.lock_fd:
            fcntl.flock(self.lock_fd.fileno(), fcntl.LOCK_UN)
            self.lock_fd.close()

4.3 方案C:企业级多租户方案(需开发)

适合企业部署,支持租户隔离、计费、审计。

C-1: 架构设计
Hermes Enterprise Gateway
│
├── Tenant Manager
│   ├── tenant_config.yaml          # 租户配置
│   ├── tenant_credentials.json     # 租户凭证池
│   └── tenant_billing.db           # 租户计费数据
│
├── Tenant Isolation Layer
│   ├── tenants/
│   │   ├── tenant_a/
│   │   │   ├── memories/
│   │   │   ├── sessions/
│   │   │   ├── state.db
│   │   │   └── config.yaml
│   │   ├── tenant_b/
│   │   │   ├── memories/
│   │   │   ├── sessions/
│   │   │   ├── state.db
│   │   │   └── config.yaml
│
└── Multi-Tenant Gateway
    ├── Telegram Bot (tenant_a_bot)
    ├── Discord Bot (tenant_b_bot)
    └── API Server (各租户独立endpoint)
C-2: 租户配置设计
# /etc/hermes/tenant_config.yaml
version: 1

tenants:
  tenant_a:
    name: "Acme Corporation"
    plan: enterprise
    created_at: "2026-01-01"
    
    # API密钥池
    credentials:
      anthropic:
        - sk-ant-api03-xxx
        - sk-ant-api03-yyy
      openrouter:
        - sk-or-v1-xxx
    
    # 配额限制
    quotas:
      max_tokens_per_month: 10_000_000
      max_users: 100
      max_sessions_per_user_per_day: 50
      rate_limit_requests_per_minute: 60
    
    # 功能权限
    features:
      - chat
      - memory
      - skills
      - tools
      - delegation
    
    # 用户映射
    users:
      telegram:
        "12345": { name: "Alice", role: admin }
        "67890": { name: "Bob", role: user }
      discord:
        "111222333": { name: "Carol", role: user }
    
    # 品牌定制
    branding:
      agent_name: "Acme Assistant"
      welcome_message: "Welcome to Acme's AI assistant!"
      response_style: professional
    
  tenant_b:
    name: "Beta Startup"
    plan: pro
    created_at: "2026-02-15"
    
    credentials:
      openrouter:
        - sk-or-v1-zzz
    
    quotas:
      max_tokens_per_month: 1_000_000
      max_users: 10
      rate_limit_requests_per_minute: 30
    
    features:
      - chat
      - memory
    
    users:
      telegram:
        "99999": { name: "Dave", role: admin }

# 全局设置
global:
  default_plan: free
  billing:
    provider: stripe
    plans:
      free:
        price: 0
        max_tokens_per_month: 100_000
      pro:
        price: 29
        max_tokens_per_month: 1_000_000
      enterprise:
        price: 299
        max_tokens_per_month: 10_000_000
C-3: 租户隔离实现
# gateway/tenant_manager.py
import os
from pathlib import Path
from contextlib import contextmanager
from typing import Optional

class TenantManager:
    """Manage multi-tenant isolation."""
    
    def __init__(self, config_path: str = "/etc/hermes/tenant_config.yaml"):
        self.config = self._load_config(config_path)
        self.tenants_root = Path("/var/lib/hermes/tenants")
    
    def get_tenant(self, tenant_id: str) -> Optional[dict]:
        """Get tenant configuration."""
        return self.config.get("tenants", {}).get(tenant_id)
    
    def get_tenant_dir(self, tenant_id: str) -> Path:
        """Get tenant data directory."""
        return self.tenants_root / tenant_id
    
    @contextmanager
    def tenant_context(self, tenant_id: str):
        """Context manager for tenant isolation."""
        tenant_dir = self.get_tenant_dir(tenant_id)
        
        # 保存原始HERMES_HOME
        original_home = os.environ.get("HERMES_HOME")
        
        try:
            # 设置租户专属HERMES_HOME
            os.environ["HERMES_HOME"] = str(tenant_dir)
            yield tenant_dir
        finally:
            # 恢复原始HERMES_HOME
            if original_home:
                os.environ["HERMES_HOME"] = original_home
            else:
                os.environ.pop("HERMES_HOME", None)
    
    def identify_tenant(self, platform: str, user_id: str) -> Optional[str]:
        """Identify tenant from platform user."""
        for tenant_id, tenant in self.config.get("tenants", {}).items():
            users = tenant.get("users", {}).get(platform, {})
            if user_id in users:
                return tenant_id
        return None
C-4: 多租户Gateway实现
# gateway/multi_tenant_server.py
from fastapi import FastAPI, Request, HTTPException, Header
from typing import Optional

app = FastAPI()
tenant_manager = TenantManager()

@app.post("/v1/chat")
async def chat(
    request: Request,
    x_tenant_id: Optional[str] = Header(None),
    x_user_id: Optional[str] = Header(None),
):
    """Multi-tenant chat endpoint."""
    
    # 1. 验证租户
    tenant_id = x_tenant_id
    if not tenant_id:
        raise HTTPException(401, "Missing tenant ID")
    
    tenant = tenant_manager.get_tenant(tenant_id)
    if not tenant:
        raise HTTPException(401, "Invalid tenant")
    
    # 2. 验证用户
    if not x_user_id:
        raise HTTPException(401, "Missing user ID")
    
    user_info = tenant.get("users", {}).get(x_user_id)
    if not user_info:
        raise HTTPException(401, "User not authorized for this tenant")
    
    # 3. 检查配额
    if not check_quota(tenant_id, x_user_id):
        raise HTTPException(429, "Quota exceeded")
    
    # 4. 检查速率限制
    if not check_rate_limit(tenant_id, x_user_id):
        raise HTTPException(429, "Rate limit exceeded")
    
    # 5. 在租户上下文中运行Agent
    body = await request.json()
    
    with tenant_manager.tenant_context(tenant_id):
        response = await run_agent(
            messages=body.get("messages", []),
            user_id=x_user_id,
            tenant_config=tenant
        )
    
    # 6. 记录使用
    record_usage(tenant_id, x_user_id, response.tokens_used)
    
    return response


async def run_agent(messages: list, user_id: str, tenant_config: dict):
    """Run agent in tenant context."""
    from run_agent import run as run_hermes
    
    # 加载租户配置
    model = tenant_config.get("model", "anthropic/claude-sonnet-4")
    
    # 运行Agent
    result = await run_hermes(
        messages=messages,
        model=model,
        user_context={"user_id": user_id}
    )
    
    return result
C-5: 计费系统
# billing/usage_tracker.py
import sqlite3
from datetime import datetime
from typing import Dict, List

class UsageTracker:
    """Track usage for billing."""
    
    def __init__(self, db_path: str = "/var/lib/hermes/billing.db"):
        self.db = sqlite3.connect(db_path)
        self._init_tables()
    
    def _init_tables(self):
        self.db.execute("""
            CREATE TABLE IF NOT EXISTS usage (
                id INTEGER PRIMARY KEY AUTOINCREMENT,
                tenant_id TEXT NOT NULL,
                user_id TEXT NOT NULL,
                timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
                input_tokens INTEGER,
                output_tokens INTEGER,
                model TEXT,
                request_type TEXT,
                metadata JSON
            )
        """)
        self.db.execute("""
            CREATE INDEX IF NOT EXISTS idx_tenant_timestamp 
            ON usage(tenant_id, timestamp)
        """)
        self.db.commit()
    
    def record_usage(
        self,
        tenant_id: str,
        user_id: str,
        input_tokens: int,
        output_tokens: int,
        model: str,
        request_type: str = "chat"
    ):
        """Record a usage event."""
        self.db.execute(
            """INSERT INTO usage 
               (tenant_id, user_id, input_tokens, output_tokens, model, request_type)
               VALUES (?, ?, ?, ?, ?, ?)""",
            (tenant_id, user_id, input_tokens, output_tokens, model, request_type)
        )
        self.db.commit()
    
    def get_monthly_usage(self, tenant_id: str, year: int, month: int) -> Dict:
        """Get usage summary for a month."""
        start = datetime(year, month, 1)
        if month == 12:
            end = datetime(year + 1, 1, 1)
        else:
            end = datetime(year, month + 1, 1)
        
        cursor = self.db.execute(
            """SELECT 
                 SUM(input_tokens) as total_input,
                 SUM(output_tokens) as total_output,
                 COUNT(*) as request_count
               FROM usage 
               WHERE tenant_id = ? AND timestamp >= ? AND timestamp < ?""",
            (tenant_id, start.isoformat(), end.isoformat())
        )
        row = cursor.fetchone()
        
        return {
            "tenant_id": tenant_id,
            "period": f"{year}-{month:02d}",
            "input_tokens": row[0] or 0,
            "output_tokens": row[1] or 0,
            "request_count": row[2] or 0,
        }
    
    def generate_invoice(self, tenant_id: str, year: int, month: int) -> Dict:
        """Generate invoice for a billing period."""
        usage = self.get_monthly_usage(tenant_id, year, month)
        tenant = tenant_manager.get_tenant(tenant_id)
        
        # 获取定价
        plan = tenant.get("plan", "free")
        pricing = BILLING_PLANS[plan]
        
        # 计算费用
        base_fee = pricing["price"]
        token_cost = 0
        
        # 超额计费
        total_tokens = usage["input_tokens"] + usage["output_tokens"]
        if total_tokens > pricing["max_tokens_per_month"]:
            overage = total_tokens - pricing["max_tokens_per_month"]
            token_cost = overage * 0.00001  # $0.00001 per token
        
        return {
            "tenant_id": tenant_id,
            "tenant_name": tenant["name"],
            "period": usage["period"],
            "base_fee": base_fee,
            "token_cost": token_cost,
            "total": base_fee + token_cost,
            "usage": usage
        }
C-6: 审计日志
# audit/logger.py
import json
import sqlite3
from datetime import datetime
from pathlib import Path

class AuditLogger:
    """Comprehensive audit logging for enterprise compliance."""
    
    def __init__(self, db_path: str = "/var/lib/hermes/audit.db"):
        self.db = sqlite3.connect(db_path)
        self._init_tables()
    
    def log_event(
        self,
        tenant_id: str,
        user_id: str,
        event_type: str,
        resource: str,
        action: str,
        details: dict = None,
        ip_address: str = None
    ):
        """Log an audit event."""
        self.db.execute(
            """INSERT INTO audit_log 
               (tenant_id, user_id, event_type, resource, action, details, ip_address, timestamp)
               VALUES (?, ?, ?, ?, ?, ?, ?, ?)""",
            (tenant_id, user_id, event_type, resource, action, 
             json.dumps(details) if details else None,
             ip_address, datetime.utcnow().isoformat())
        )
        self.db.commit()
    
    def query_events(
        self,
        tenant_id: str = None,
        user_id: str = None,
        event_type: str = None,
        start_time: datetime = None,
        end_time: datetime = None,
        limit: int = 100
    ) -> List[dict]:
        """Query audit events with filters."""
        query = "SELECT * FROM audit_log WHERE 1=1"
        params = []
        
        if tenant_id:
            query += " AND tenant_id = ?"
            params.append(tenant_id)
        if user_id:
            query += " AND user_id = ?"
            params.append(user_id)
        if event_type:
            query += " AND event_type = ?"
            params.append(event_type)
        if start_time:
            query += " AND timestamp >= ?"
            params.append(start_time.isoformat())
        if end_time:
            query += " AND timestamp < ?"
            params.append(end_time.isoformat())
        
        query += f" ORDER BY timestamp DESC LIMIT {limit}"
        
        cursor = self.db.execute(query, params)
        columns = [desc[0] for desc in cursor.description]
        
        return [dict(zip(columns, row)) for row in cursor.fetchall()]


# 使用示例
audit = AuditLogger()

# 记录事件
audit.log_event(
    tenant_id="tenant_a",
    user_id="alice_12345",
    event_type="authentication",
    resource="session",
    action="login",
    details={"method": "telegram"},
    ip_address=None
)

audit.log_event(
    tenant_id="tenant_a",
    user_id="alice_12345",
    event_type="data_access",
    resource="memory",
    action="write",
    details={"target": "memory", "content_length": 256}
)

# 查询事件
events = audit.query_events(
    tenant_id="tenant_a",
    event_type="data_access",
    start_time=datetime(2026, 1, 1)
)

五、方案对比与推荐

5.1 方案对比表

方案 适用场景 开发成本 部署复杂度 隔离程度 共享能力 推荐度
A-1: 多OS用户 个人/小团队,完全隔离 ⭐⭐⭐⭐⭐ ⭐⭐⭐⭐⭐
A-2: Gateway共享 团队协作,共享Agent ⭐⭐⭐ ✅ 会话级 ⭐⭐⭐⭐
A-3: 多Profile混合 不同团队不同Agent ⭐⭐⭐⭐ ✅ Profile级 ⭐⭐⭐⭐⭐
B-1: 用户级记忆 需要区分用户偏好 ⭐⭐⭐⭐ ✅ 记忆级 ⭐⭐⭐
B-2: 权限控制 需要访问控制 ⭐⭐⭐⭐ ✅ 功能级 ⭐⭐⭐
B-3: 共享Profile 多用户协作同一Agent ⭐⭐⭐ ✅ Profile级 ⭐⭐
C: 企业多租户 SaaS/企业部署 ⭐⭐⭐⭐⭐ ✅ 租户级 ⭐⭐

5.2 详细对比

隔离维度对比
隔离维度 A-1 多OS用户 A-2 Gateway A-3 多Profile B-1 用户记忆 B-2 权限 C 企业多租户
配置隔离 ✅ 完全 ❌ 共享 ✅ 完全 ❌ 共享 ❌ 共享 ✅ 完全
记忆隔离 ✅ 完全 ❌ 共享 ✅ 完全 ✅ 用户级 ❌ 共享 ✅ 完全
会话隔离 ✅ 完全 ✅ 自动 ✅ 完全 ✅ 完全 ✅ 完全 ✅ 完全
凭证隔离 ✅ 完全 ❌ 共享 ✅ 完全 ❌ 共享 ❌ 共享 ✅ 完全
进程隔离 ✅ 完全 ❌ 共享 ✅ 完全 ❌ 共享 ❌ 共享 ✅ 完全
功能维度对比
功能维度 A-1 多OS用户 A-2 Gateway A-3 多Profile B-1 用户记忆 B-2 权限 C 企业多租户
用户管理 OS级别 需开发 需开发 完整
权限控制 OS级别 需开发 完整
配额管理 需开发 完整
计费系统 完整
审计日志 OS级别 需开发 完整
品牌定制 ✅ SOUL.md 完整

5.3 推荐方案

小团队(< 5人)

推荐:方案A-1 或 A-3

  • 使用多OS用户或多Profile即可满足需求
  • 无需额外开发
  • 管理成本可接受

部署示例:

# 方案A-1: 每个团队成员一个OS用户
for user in alice bob carol; do
    sudo useradd -m -s /bin/bash $user
    sudo -u $user bash -c "curl -fsSL https://... | bash && hermes setup"
done

# 方案A-3: 每个团队成员一个Profile
hermes profile create alice --clone
hermes profile create bob --clone
hermes profile create carol --clone
中型团队(5-20人)

推荐:方案A-2 或 A-3

  • Gateway共享 + 多Profile组合
  • 开发团队、支持团队、管理团队各自Profile
  • 通过消息平台统一访问

部署示例:

# 为不同团队创建Profile
hermes profile create team-dev
hermes profile create team-support
hermes profile create team-management

# 配置各自的Bot
team-dev config set telegram.bot_token "DEV_BOT_TOKEN"
team-support config set discord.bot_token "SUPPORT_BOT_TOKEN"
team-management config set slack.bot_token "MGMT_BOT_TOKEN"

# 启动Gateway
team-dev gateway install
team-support gateway install
team-management gateway install
大型团队/企业(> 20人)

推荐:方案B-1 + B-2

  • 需要开发用户级记忆隔离
  • 需要权限控制
  • 基于现有Profile机制扩展

开发清单:

  1. 用户级记忆隔离

    • 修改 tools/memory_tool.py
    • 修改 agent/memory_manager.py
    • Gateway传递user_id
  2. 权限控制系统

    • 创建 gateway/auth.py
    • 修改工具调用检查
    • 配置schema扩展
  3. 配额管理

    • 创建 agent/quota_manager.py
    • 集成到Gateway
SaaS产品

推荐:方案C

  • 需要完整的多租户架构
  • 计费、审计、配额管理
  • 租户数据完全隔离

开发清单:

  1. 租户管理模块
  2. 多租户Gateway重构
  3. 计费系统集成
  4. 审计日志系统
  5. 管理后台

六、实施建议

6.1 立即可行(无需开发)

团队共享Agent部署

步骤1:创建共享账户

# 在Linux服务器上创建专用账户
sudo useradd -m -s /bin/bash hermes-team

# 切换到该账户
sudo -u hermes-team bash

步骤2:安装Hermes

cd ~
curl -fsSL https://raw.githubusercontent.com/nousresearch/hermes-agent/main/setup-hermes.sh | bash
source ~/.bashrc

步骤3:配置

# 运行设置向导
hermes setup

# 配置Telegram Bot(或Discord/Slack)
hermes config set telegram.bot_token "YOUR_BOT_TOKEN"

# 定制Agent个性
cat > ~/.hermes/SOUL.md << 'EOF'
You are the team assistant for [Team Name].

You help with:
- Code reviews and debugging
- Documentation
- Research and analysis
- Task management

Team conventions:
- [Add your conventions here]
EOF

# 添加团队记忆
hermes memory add memory "Team uses GitHub: github.com/org/repo"
hermes memory add memory "CI/CD: GitHub Actions"
hermes memory add user "Team prefers concise responses"

步骤4:启动服务

# 安装为系统服务
hermes gateway install

# 启动服务
hermes gateway start

# 查看状态
hermes gateway status

步骤5:团队成员使用

团队成员只需在各自的设备上:

  1. 打开Telegram(或Discord/Slack)
  2. 搜索Bot名称
  3. 发送消息开始使用
多团队独立Agent部署

步骤1:创建多个Profile

# 开发团队
hermes profile create team-dev
team-dev config set telegram.bot_token "DEV_BOT_TOKEN"
cat > ~/.hermes/profiles/team-dev/SOUL.md << 'EOF'
You are a coding assistant for the development team.
Focus on: code quality, architecture, debugging.
EOF

# 支持团队
hermes profile create team-support
team-support config set discord.bot_token "SUPPORT_BOT_TOKEN"
cat > ~/.hermes/profiles/team-support/SOUL.md << 'EOF'
You are a customer support assistant.
Focus on: user issues, documentation, quick solutions.
EOF

步骤2:启动多个Gateway

# 启动开发团队Gateway
team-dev gateway install
team-dev gateway start

# 启动支持团队Gateway
team-support gateway install
team-support gateway start

步骤3:验证

# 查看运行状态
hermes profile list

# 输出示例:
# Profile      Gateway    Model           Skills
# ────────────────────────────────────────────────
# default      running    claude-sonnet   15
# team-dev     running    claude-sonnet   12
# team-support running    claude-sonnet   8

6.2 需要开发(短期)

用户级记忆隔离实现

预估工时:2-3天

修改文件清单:

  1. tools/memory_tool.py - 添加user_id参数
  2. agent/memory_manager.py - 用户级记忆加载
  3. gateway/session.py - 传递user_id
  4. hermes_constants.py - 新增路径函数

测试要点:

  • 不同用户记忆隔离验证
  • 公共记忆 + 用户记忆合并验证
  • 系统prompt注入正确性验证

6.3 需要开发(长期)

企业多租户系统

预估工时:4-6周

开发阶段:

阶段 内容 工时
Phase 1 租户管理模块、数据隔离 1.5周
Phase 2 多租户Gateway重构 1周
Phase 3 权限控制、配额管理 1周
Phase 4 计费系统集成 0.5周
Phase 5 审计日志系统 0.5周
Phase 6 管理后台、文档 1.5周

技术选型建议:

  • API框架:FastAPI
  • 数据库:PostgreSQL(租户元数据)+ SQLite(租户数据)
  • 计费:Stripe API
  • 缓存:Redis(配额计数)
  • 部署:Docker + Kubernetes

附录

A. 相关代码文件索引

文件 功能 关键函数
hermes_constants.py 核心路径定义 get_hermes_home(), get_default_hermes_root()
hermes_cli/profiles.py Profile管理 create_profile(), delete_profile(), list_profiles()
tools/memory_tool.py 记忆工具 memory()
gateway/session.py Gateway会话管理 会话key生成、用户ID提取
agent/credential_pool.py 凭证池管理 API密钥轮换、错误恢复
hermes_cli/gateway.py Gateway服务管理 服务安装、启动、停止

B. 配置文件参考

Profile基础配置
# ~/.hermes/config.yaml
model:
  default: anthropic/claude-sonnet-4
  provider: openrouter

gateway:
  group_sessions_per_user: true
  session_reset_policy: idle
  idle_reset_minutes: 60

memory:
  memory_enabled: true
  user_profile_enabled: true
  memory_char_limit: 2200
  user_char_limit: 1375

credential_pool_strategies:
  openrouter: fill_first
  anthropic: least_used
多用户增强配置(方案B)
# ~/.hermes/config.yaml
multi_user:
  enabled: true
  auth_method: telegram_id
  
  users:
    alice_12345:
      role: admin
      permissions: [chat, memory, skills, config]
    
    bob_67890:
      role: user
      permissions: [chat, memory]
      skills_allowed: [general, research]
      max_tokens_per_day: 100000

memory:
  user_isolation: true
  shared_memory_fallback: true

C. 命令速查表

Profile管理
# 创建
hermes profile create <name>                  # 空白Profile
hermes profile create <name> --clone          # 克隆配置
hermes profile create <name> --clone-all      # 完全克隆

# 查看
hermes profile list                           # 列出所有
hermes profile show <name>                    # 详情

# 操作
hermes profile use <name>                     # 设置默认
hermes profile rename <old> <new>             # 重命名
hermes profile delete <name>                  # 删除

# 导入导出
hermes profile export <name> [file]           # 导出
hermes profile import <file> [name]           # 导入
Gateway管理
# 启动停止
hermes gateway start                          # 前台运行
hermes gateway stop                           # 停止
hermes gateway restart                        # 重启

# 服务管理
hermes gateway install                        # 安装系统服务
hermes gateway uninstall                      # 卸载系统服务
hermes gateway status                         # 查看状态
会话管理
# 列出
hermes sessions list                          # 最近会话
hermes sessions list --source telegram        # 按平台筛选

# 操作
hermes sessions rename <id> "title"           # 重命名
hermes sessions delete <id>                   # 删除
hermes sessions prune --older-than 30         # 清理旧会话

# 导出
hermes sessions export backup.jsonl           # 全部导出

文档结束

Logo

欢迎加入 MCP 技术社区!与志同道合者携手前行,一同解锁 MCP 技术的无限可能!

更多推荐