架构概览¶
HermesX 的系统设计、两种运行模式和 SaaS 多租户架构。
两种运行模式¶
Hermes 支持两种独立的运行模式:
| 模式 | 命令 | 用途 | 存储 |
|---|---|---|---|
| CLI 模式 | hermes |
本地交互式 Agent | SQLite / 文件系统 |
| SaaS 模式 | hermes saas-api |
多租户 HTTP API 服务 | PostgreSQL |
两种模式共享 LLM 集成层和 Skills 系统,但网络层、存储层和认证体系完全独立。
SaaS 模式架构¶
┌─────────────────────────────────────────────────┐
│ HTTP 请求 │
└───────────────────────┬─────────────────────────┘
│
┌───────────────────────▼─────────────────────────┐
│ CORS Middleware │
│ (SAAS_ALLOWED_ORIGINS 配置) │
└───────────────────────┬─────────────────────────┘
│
┌────▼────┐
│ SPA 路由 │ ←── 静态文件(index.html, admin.html)
└────┬────┘
│
┌───────────────────────▼─────────────────────────┐
│ 9 层中间件栈(固定顺序) │
│ │
│ Tracing → Metrics → RequestID → Auth → Tenant │
│ → Logging → Audit → RBAC → RateLimit → Handler │
└───────────────────────┬─────────────────────────┘
│
┌─────────────▼─────────────┐
│ 路由分发 │
│ │
│ /health/* → 公开 │
│ /metrics → Prometheus │
│ /v1/tenants → Admin │
│ /v1/api-keys → Admin │
│ /v1/chat/* → User │
│ /v1/me → User │
└─────────┬─────────────────┘
│
┌──────────────▼──────────────┐
│ Store 层 │
│ PostgreSQL(多租户隔离) │
└─────────────────────────────┘
中间件栈¶
中间件按固定顺序执行,由 middleware.MiddlewareStack 强制保证:
Tracing → Metrics → RequestID → Auth → Tenant → Logging → Audit → RBAC → RateLimit → Handler
| 层 | 职责 | 源文件 |
|---|---|---|
| Tracing | OpenTelemetry span 创建与传播 | internal/observability/tracer.go |
| Metrics | Prometheus 请求计数、延迟、并发量 | internal/middleware/metrics.go |
| RequestID | 生成或提取 X-Request-ID |
internal/middleware/requestid.go |
| Auth | 链式认证(Static Token → API Key → JWT) | internal/auth/extractor.go |
| Tenant | 从 AuthContext 提取 tenant_id 写入 Context | internal/middleware/tenant.go |
| Logging | 注入 tenant_id 和 request_id 到 slog Logger | internal/observability/logger.go |
| Audit | 记录所有认证请求到 audit_logs 表 | internal/middleware/audit.go |
| RBAC | 基于路径前缀的角色访问控制 | internal/middleware/rbac.go |
| RateLimit | 按租户维度限流(分布式 + 本地 LRU 降级) | internal/middleware/ratelimit.go |
设计要点:
- Logging 层位于 Auth + Tenant 之后,确保日志自动包含 tenant_id
- Auth 错误使用 ContextLogger 降级(slog.Default + request_id)
- 所有中间件槽位可为 nil(passthrough),便于测试和按需启用
多租户模型¶
租户隔离¶
Hermes 使用数据库级租户隔离:
- tenant_id 派生自凭证:永远不从请求头读取,防止租户伪造
- 所有表 FK 到 tenants:9 张业务表均包含
tenant_id UUID NOT NULL REFERENCES tenants(id) - 查询自动过滤:所有 Store 方法按 tenant_id 过滤数据
AuthContext.TenantID(从凭证派生)
│
▼
┌──────────────┐
│ Context 传播 │ ← Tenant 中间件写入
└──────┬───────┘
│
▼
┌──────────────┐
│ Store 查询 │ ← WHERE tenant_id = $1
└──────────────┘
默认租户¶
首次启动时自动创建默认租户:
- ID:
00000000-0000-0000-0000-000000000001 - Name:
Default Tenant - Plan:
pro - Rate Limit: 120 RPM
- Max Sessions: 10
Static Token 认证自动映射到此租户。
Store 架构¶
接口抽象¶
store.Store 接口定义统一的数据访问层,支持多种后端实现:
type Store interface {
Tenants() TenantStore
Sessions() SessionStore
Messages() MessageStore
Users() UserStore
AuditLogs() AuditLogStore
APIKeys() APIKeyStore
CronJobs() CronJobStore
Memories() MemoryStore
UserProfiles() UserProfileStore
Roles() RoleStore
PricingRules() PricingRuleStore
}
存储后端¶
| 后端 | 用途 | 包路径 |
|---|---|---|
| PostgreSQL | SaaS 模式(多租户) | internal/store/pg/ |
| SQLite | CLI 模式(单用户) | internal/store/sqlite/ |
PostgreSQL 后端在启动时自动执行 70+ 个 migration(含 RLS policies、pricing_rules、sandbox_policy 等)。
LLM 集成¶
可插拔 Transport¶
LLM 调用通过 Transport 接口抽象,支持多种提供商:
请求 → FallbackRouter → RetryTransport → CircuitBreaker → Provider Transport → LLM API
支持的提供商: - OpenAI(openai 协议) - Anthropic(anthropic 协议,含 prompt caching) - 自动检测(根据 API URL 和 Key 格式推断)
弹性机制¶
| 组件 | 职责 | 包路径 |
|---|---|---|
| FallbackRouter | 主 Provider 故障时自动切换到备用 | internal/llm/fallback_router.go |
| RetryTransport | 指数退避重试 + ±25% 抖动 | internal/llm/retry_transport.go |
| Circuit Breaker | 按模型独立断路,Prometheus 指标 | internal/llm/breaker.go |
| Model Catalog | 热重载模型注册表,能力元数据 | internal/llm/model_catalog.go |
| Multimodal Router | 图片/音频/视频按 Provider 能力分发 | internal/agent/multimodal.go |
配置¶
| 环境变量 | 说明 |
|---|---|
LLM_API_URL |
LLM API 端点 |
LLM_API_KEY |
API 认证密钥 |
LLM_MODEL |
默认模型名称 |
LLM_FALLBACK_API_URL |
备用 Provider 端点 |
LLM_FALLBACK_API_KEY |
备用 Provider 密钥 |
OIDC_ISSUER_URL |
OIDC Provider URL(设置后激活 SSO) |
Chat 请求流程¶
一次完整的 /v1/chat/completions 请求经历以下路径:
1. HTTP 请求到达
2. CORS 检查(如果配置了 SAAS_ALLOWED_ORIGINS)
3. Tracing:创建 span
4. Metrics:记录请求开始
5. RequestID:生成唯一请求标识
6. Auth:链式认证,生成 AuthContext
7. Tenant:从 AuthContext 提取 tenant_id
8. Logging:注入 tenant_id 到 logger
9. Audit:记录审计日志(action、status_code、latency_ms)
10. RBAC:检查 "user" 角色权限
11. RateLimit:检查租户 RPM 配额
12. Handler:
a. 解析 ChatCompletionRequest
b. 获取或创建 Session(按 tenant_id 隔离)
c. 调用 LLM API(通过 Transport)
d. 存储 Message(关联 tenant_id)
e. 返回 ChatCompletionResponse
HTTP 服务器配置¶
| 参数 | 值 | 说明 |
|---|---|---|
| Read Timeout | 30s | 读取请求体超时 |
| Write Timeout | 60s | 写入响应超时(LLM 调用可能较慢) |
| Idle Timeout | 120s | Keep-Alive 空闲超时 |
| Listen Address | 0.0.0.0:{port} |
监听所有网卡 |
项目结构¶
hermesx/
├── cmd/hermes/
│ ├── main.go # CLI 入口
│ └── saas.go # SaaS API 入口(hermes saas-api)
├── internal/
│ ├── api/ # HTTP handlers 和路由
│ │ ├── server.go # APIServer、路由注册、中间件组装
│ │ ├── tenants.go # 租户 CRUD
│ │ ├── apikeys.go # API Key 管理
│ │ ├── mockchat.go # Chat completions + session store
│ │ ├── health.go # 健康探针
│ │ └── gdpr.go # GDPR 数据导出/删除
│ ├── auth/ # 认证链
│ │ ├── context.go # AuthContext 定义
│ │ ├── extractor.go # ExtractorChain 接口
│ │ ├── static.go # Static Token 认证
│ │ ├── apikey.go # API Key 认证
│ │ └── jwt.go # JWT 认证(预留)
│ ├── middleware/ # HTTP 中间件
│ │ ├── chain.go # 固定顺序中间件栈
│ │ ├── rbac.go # 角色访问控制
│ │ ├── ratelimit.go # 速率限制
│ │ ├── metrics.go # Prometheus 指标
│ │ └── audit.go # 审计日志
│ ├── store/ # 数据存储抽象
│ │ ├── types.go # 数据模型定义
│ │ ├── pg/ # PostgreSQL 实现
│ │ └── sqlite/ # SQLite 实现
│ ├── skills/ # Skills 系统
│ │ ├── hub.go # Skills Hub 发现与安装
│ │ ├── scanner.go # 安全扫描
│ │ └── loader.go # 本地加载
│ ├── observability/ # 可观测性
│ │ ├── tracer.go # OpenTelemetry 初始化
│ │ └── logger.go # Context-enriched 日志
│ ├── objstore/ # MinIO/S3 对象存储
│ ├── gateway/ # CLI 模式 Gateway, media dispatch, lifecycle hooks
│ │ └── platforms/ # 15 platform adapters + registry
│ ├── config/ # 配置管理
│ └── dashboard/ # 管理面板静态文件
│ └── static/ # HTML/CSS/JS
├── skills/ # 81 个内置 Skills
├── deploy/ # 部署配置
│ ├── helm/ # Helm Chart
│ └── kind/ # Kind 本地 K8s
├── scripts/ # 测试和工具脚本
└── docs/ # 文档
v1.4.0 新增模块(上游 v2026.4.30 吸收)¶
Agent 层¶
| 模块 | 职责 | 源文件 |
|---|---|---|
| Memory Curator | 自主去重、LLM 合并、过期清理 | internal/agent/curator.go |
| Self-improvement | 定期 LLM 对话自评 + 洞察持久化 | internal/agent/self_improve.go |
| Multimodal Router | 图片/音频/视频请求按提供商能力分发 | internal/agent/multimodal.go |
| Compress | 上下文压缩(接近 token 限制时自动摘要) | internal/agent/compress.go |
Gateway 层¶
| 模块 | 职责 | 源文件 |
|---|---|---|
| Media Dispatcher | 感知平台能力的媒体路由 + 降级链 | internal/gateway/media_dispatch.go |
| Lifecycle Hooks | 优先级排序事件钩子(RWMutex 并发安全) | internal/gateway/lifecycle_hooks.go |
| Platform Registry | 平台注册与能力声明 | internal/gateway/registry.go |
LLM 层¶
| 模块 | 职责 | 源文件 |
|---|---|---|
| Model Catalog | 支持热重载的模型注册表 + 能力元数据 | internal/llm/model_catalog.go |
Store 层¶
| 模块 | 职责 | 源文件 |
|---|---|---|
| Trigram Search | pg_trgm CJK 模糊搜索 | internal/store/pg/trigram_search.go |