chore: initial import

This commit is contained in:
phamnazage-jpg
2026-05-12 17:47:32 +08:00
commit fc54ba84b2
104 changed files with 11575 additions and 0 deletions

175
tech/DEPLOYMENT.md Normal file
View File

@@ -0,0 +1,175 @@
# AI-Ops 部署设计
> 版本v1.0 | 状态:初稿
---
## 1. 部署架构
### 1.1 总体架构
```
├── Load Balancer (Nginx / 云 CLB)
├── AI-Ops API Server x 2 (主备)
│ │
│ ├── HTTP API (标准库 net/http)
│ └── WebSocket (告警推送)
├── AI-Ops Worker x 2 (后台任务)
│ │
│ ├── 指标采集器
│ ├── 告警评估器
│ ├── 自愈执行器
│ └── 审计清理器
└── 共享层
├── PostgreSQL 15+ (主库 + 备库)
├── Redis (缓存 + 会话 + 锁)
├── Prometheus (时序数据)
└── Grafana (监控可视化)
```
### 1.2 容器化部署
使用 Docker Compose 或 Kubernetes
```yaml
# docker-compose.yml 抽象
services:
ai-ops-api:
image: ai-ops:latest
command: ["./ai-ops", "api"]
replicas: 2
ports:
- "8080:8080"
environment:
- DB_HOST=postgres
- REDIS_HOST=redis
- PROMETHEUS_HOST=prometheus
ai-ops-worker:
image: ai-ops:latest
command: ["./ai-ops", "worker"]
replicas: 2
environment:
- DB_HOST=postgres
- REDIS_HOST=redis
- PROMETHEUS_HOST=prometheus
postgres:
image: postgres:15
volumes:
- pg_data:/var/lib/postgresql/data
redis:
image: redis:7
prometheus:
image: prom/prometheus:latest
volumes:
- ./prometheus.yml:/etc/prometheus/prometheus.yml
grafana:
image: grafana/grafana:latest
```
---
## 2. 资源需求
### 2.1 API Server
| 资源 | 需求 | 说明 |
|------|------|------|
| CPU | 2 核 | Go 服务主要为 IO 密集型 |
| 内存 | 1 GB | 含连接池缓存 |
| 存储 | 无 | 状态外部化 |
| 网络 | 内网 100Mbps | 调用内部服务 |
### 2.2 Worker
| 资源 | 需求 | 说明 |
|------|------|------|
| CPU | 1 核 | 定时任务CPU 需求低 |
| 内存 | 512 MB | |
| 存储 | 无 | |
### 2.3 数据库
| 资源 | 需求 | 说明 |
|------|------|------|
| CPU | 2 核 | |
| 内存 | 4 GB | 索引与缓冲 |
| 存储 | 200 GB | 90 天审计日志 + 时序数据 |
| 网络 | 内网 1Gbps | |
### 2.4 Prometheus
| 资源 | 需求 | 说明 |
|------|------|------|
| CPU | 1 核 | |
| 内存 | 2 GB | |
| 存储 | 100 GB | 时序数据保留 90 天 |
---
## 3. 监控与运维钩子
### 3.1 健康检查
| 端点 | 路径 | 预期响应 | 失败行为 |
|------|------|----------|---------|
| 存活检查 | `/actuator/health/live` | HTTP 200 | 容器重启 |
| 就绪检查 | `/actuator/health/ready` | HTTP 200 | 从负载均衡移除 |
| 综合检查 | `/actuator/health` | HTTP 200 + JSON | 触发告警 |
### 3.2 启动/关闭顺序
**启动顺序**:
1. PostgreSQL 启动完成
2. Redis 启动完成
3. Prometheus 启动完成
4. Worker 启动(执行 migration
5. API Server 启动
**关闭顺序**:
1. 停止接收新 HTTP 请求(健康检查返回非 200
2. 等待现有请求处理完成(超时 30 秒)
3. 停止 Worker 定时器
4. 关闭数据库连接池
5. 退出进程
### 3.3 配置管理
- 配置文件 `config.yaml` + 环境变量覆盖。
- 敏感字段(密钥、密码)仅通过环境变量传入,不落地配置文件。
- 支持热更新的配置:告警规则、通知渠道。
---
## 4. 灾备设计
### 4.1 数据库灾备
| 策略 | 方案 | RTO | RPO |
|------|------|-----|-----|
| 主库故障 | 自动切换至备库 | < 5 min | < 1 min |
| 逻辑损坏 | 从备库恢复 + 审计日志回放 | < 30 min | < 1 min |
| 全库损坏 | 每日冷备份恢复 | < 2 h | < 24 h |
### 4.2 应用层灾备
| 场景 | 处理 |
|------|------|
| API Server 单机故障 | 负载均衡自动移除,剩余节点继续服务 |
| Worker 单机故障 | 剩余 Worker 继续执行定时任务,某些任务可能延迟 |
| Redis 故障 | 审计日志落地 PostgreSQL告警缓存失效不影响核心功能 |
| Prometheus 故障 | 实时指标采集中断,告警引擎依赖本地缓存继续运行 |
### 4.3 多中心部署
- 当前阶段为单中心部署。
- 备份中心仅用于数据库备份恢复,不提供活跃服务。
- 未来扩展至多中心时,需要解决 PostgreSQL 的分布式写入和 Prometheus 的联邦查询问题。

836
tech/HLD.md Normal file
View File

@@ -0,0 +1,836 @@
# AI-Ops 智能运维系统 — 高层设计文档 (HLD)
> 版本v1.0
> 负责人TechLead
> 目标读者后端开发、SRE、QA
> 状态:初稿
---
## 1. 设计目标与约束
### 1.1 核心目标
| 指标 | 基线值 | 目标值 | 验证方式 |
|------|--------|--------|---------|
| 核心故障 MTTR | >30 min | <10 min | 从告警触发到服务恢复的 P99 时长 |
| P1/P2 自动化处理覆盖率 | 0% | >=60% | 自愈成功事件数 / (P1+P2 总事件数) |
| 告警噪声率 | >20% | <5% | 误告警数 / 总告警数 |
| 配置回滚时间窗口 | 无 | <5 min | 回滚指令发出到验证通过的时长 |
| 审计日志保留期 | 无 | >=90 天 | 存储系统自动清理策略 |
### 1.2 技术约束(强制性)
- **语言**: Go 1.22+
- **HTTP 框架**: 标准库 `net/http` + 自定义中间件(禁止引入 Gin/Echo
- **数据库**: PostgreSQL 15+ ,驱动 `jackc/pgx/v5`
- **缓存**: Redis客户端 `redis/go-redis/v9`
- **配置**: YAML + Viper环境变量覆盖敏感字段
- **日志/审计**: 结构化日志,审计事件模型与 supply-api/ 一致
- **错误码**: `{SOURCE}_{CATEGORY}_{CODE}` 格式,例如 `OPS_ALT_4001`
- **健康检查**: `/actuator/health``/actuator/health/live``/actuator/health/ready`
- **测试**: Go testing + testify覆盖率门槛 domain >= 70%、service/handler >= 80%
- **Store 接口**: 必须包含版本控制(乐观锁)
- **条件能力**: 默认关闭,需要在 `BuildServer` / `BuildRuntime` 中显式挂载才算已交付
### 1.3 运行模式
系统必须同时支持两种运行模式:
| 模式 | 特征 | 部署方式 |
|------|------|---------|
| **独立运行** | 自有 `cmd/ai-ops/main.go`,独立数据库 schema独立 docker-compose | `docker-compose up` 或单独容器 |
| **集成运行** | 作为 Go module 被 `gateway/``supply-api/` 引入,共享数据库连接池和配置,通过内部接口注册 | 编译时作为子模块编译,运行时挂载到立交桥主进程 |
**集成约束**
- 独立运行时,系统提供完整的 HTTP API 和管理后台。
- 集成运行时,系统提供 `IntegrationPlugin` 接口,允许主程序通过配置开关启用/禁用各模块。
- 数据库 schema 必须使用独立的 `ai_ops_` 前缀,避免与主项目表名冲突。
- 配置文件必须支持分离加载:独立运行时读取自己的 `config.yaml`,集成运行时合并到主项目配置。
---
## 2. 系统架构总览
### 2.1 逻辑架构图
```
+---------------------+ +---------------------+ +---------------------+
| 运维控制台 (Web) | | 外部系统调用者 | | 通知渠道 |
| - 监控看板 | | - NewAPI/Sub2API | | - Webhook |
| - 告警管理 |<--->| - 企业微信/飞书 |<--->| - 邮件 |
| - 日志查询 | | - Prometheus | | - 短信 |
+----------+----------+ +----------+----------+ +----------+----------+
| | |
v v v
+---------------------+ +---------------------+ +---------------------+
| HTTP API Layer | | /metrics (Prom) | | Notification |
| (标准库 net/http) | | /api/v1/ai-ops/ | | Dispatcher |
+----------+----------+ +----------+----------+ +----------+----------+
| | |
v v v
+-----------------------------------------------------------------------------+
| AI-Ops Core Domain Layer |
| +----------------+ +----------------+ +----------------+ +-----------+ |
| | Metric Service | | Alert Service | | Healing Engine | | Capacity | |
| | (指标采集/查询) | | (告警规则/触发) | | (自愈动作执行) | | Service | |
| +----------------+ +----------------+ +----------------+ +-----------+ |
| +----------------+ +----------------+ +----------------+ +-----------+ |
| | Audit Service | | Config Service | | Log Service | | Authz | |
| | (审计/回滚) | | (配置变更) | | (日志查询) | | Service | |
| +----------------+ +----------------+ +----------------+ +-----------+ |
+-----------------------------------------------------------------------------+
|
v
+-----------------------------------------------------------------------------+
| Infrastructure Layer |
| +----------------+ +----------------+ +----------------+ +-----------+ |
| | Metric Store | | PostgreSQL | | Redis | | Time-Series| |
| | (Prom/Victoria)| | (主审计/配置) | | (缓存/状态) | | DB | |
| +----------------+ +----------------+ +----------------+ +-----------+ |
+-----------------------------------------------------------------------------+
|
v
+-----------------------------------------------------------------------------+
| Bridge Integration Layer |
| +----------------+ +----------------+ +----------------+ +-----------+ |
| | Token Gateway | | Channel Manager| | Provider Health| | Runtime | |
| | (请求量/延迟) | | (供应商/路由) | | (健康检查) | | Status | |
| +----------------+ +----------------+ +----------------+ +-----------+ |
+-----------------------------------------------------------------------------+
```
### 2.2 服务边界与职责
| 服务 | 职责 | 对应 PRD 场景 | 对应 AC |
|------|------|--------------|---------|
| **Metric Service** | 采集 gateway/、supply-api/、platform-token-runtime/ 的指标,提供 PromQL 查询、分钟级聚合 | A, H | AC-1, AC-2, AC-11 |
| **Alert Service** | 维护告警规则状态机,执行阈值评估,生成告警事件,负责聚合与抑制 | C, E, G | AC-3, AC-4, AC-5 |
| **Healing Engine** | 执行自愈动作:切换备用路由、限流、重启实例、触发脚本;记录执行结果 | C, D, F | AC-6 |
| **Audit Service** | 捕获所有配置变更,写入不可篡改审计日志,支持按原始操作记录回滚 | B, F, I | AC-7, AC-8 |
| **Config Service** | 管理告警规则、通知渠道、自愈策略的 CRUD支持版本化与验证 | B, I | AC-7, AC-8 |
| **Log Service** | 按时间范围、服务、状态码、用户 ID 等维度筛选日志,支持 CSV 导出 | A, H | AC-10 |
| **Capacity Service** | 汇总过去 7 天 Token/QPS/延迟/利用率趋势,计算负载等级与增长率预测 | - | AC-9 |
| **Authz Service** | 角色鉴权:查看者/运维人员/管理员;控制台访问控制 | - | AC-12 |
| **Notification Dispatcher** | 将告警事件路由到配置的通知渠道,支持主备自动切换 | C, E | AC-4, AC-5 |
---
## 3. 核心模块设计
### 3.1 自动运维流水线 (AutoOps Pipeline)
运维流水线是系统的主干,接收指标数据,经过规则引擎评估,生成告警事件,触发自愈动作,并验证效果。
```
指标数据流
|
v
+-------------------+ +-------------------+ +-------------------+
| Metric Ingestor | --> | Rule Engine | --> | Alert Event |
| (报文解析/格式化) | | (阈值评估/分级) | | Generator |
+-------------------+ +-------------------+ +---------+---------+
|
v
+-------------------+ +-------------------+ +-------------------+
| Validation Loop | <-- | Healing Engine | <-- | Notification |
| (2min 效果评估) | | (自愈动作执行) | | Dispatcher |
+-------------------+ +-------------------+ +-------------------+
```
**流水线状态机**
| 状态 | 转移条件 | 超时 |
|------|---------|------|
| `triggered` | 规则阈值被触发 | - |
| `notified` | 通知已发送 | 30s (P0/P1), 120s (P2) |
| `healing` | 自愈动作执行中 | 60s 内完成 |
| `resolved` | 监控指标回复正常 | - |
| `escalated` | 自愈失败或未配置自愈 | 立即 |
| `acknowledged` | 人工确认 | 2h 未确认则自动升级 |
### 3.2 健康探针 (Health Probe)
参考 LiteLLM 的多层级健康检查设计,对于集成运行模式提供以下端点:
| 端点 | 用途 | 检查内容 | 失败策略 |
|------|------|---------|---------|
| `/actuator/health` | 综合健康 | DB、Redis、时序库连接性 | 返回 503触发内部告警 |
| `/actuator/health/live` | 存活探针 | 进程是否运行 | Kubernetes 重启 Pod |
| `/actuator/health/ready` | 就绪探针 | 所有依赖是否可服务 | 从负载均衡移除 |
| `/actuator/health/backlog` | 队列积压 | 告警事件队列长度 | >100 时触发内部告警 |
| `/actuator/health/datasource` | 数据源状态 | 最近 5min 内是否有新数据点 | 触发 P2 内部告警 |
独立运行时,系统自身提供以上端点。集成运行时,通过 `IntegrationPlugin` 将检查逻辑注入到主程序的健康检查中。
### 3.3 异常自动恢复 (Healing Engine)
自愈引擎的核心是动作执行器。每个动作是一个独立的可执行单元,支持沙盘模式验证。
**自愈动作类型**
| 动作 | 说明 | 执行时间限制 | 回退策略 |
|------|------|-----------|---------|
| `switch_provider` | 将流量从主路由切换到备用供应商 | 30s | 自动恢复原路由,升级人工告警 |
| `throttle` | 对目标服务/供应商启动限流 | 15s | 解除限流,升级人工告警 |
| `restart_service` | 重启异常服务(通过调用管理 API | 45s | 不可回退,升级人工告警 |
| `invoke_script` | 执行用户配置的程序化脚本 | 60s | 脚本自身决定回退逻辑 |
| `isolate_node` | 将异常节点从负载均衡中移除 | 20s | 恢复节点到负载均衡 |
**沙盘模式**
- 所有自愈动作必须在沙盒环境中模拟触发 >=10 次,所有次数的执行结果符合预期,才能关联到生产告警规则。
- 沙盒模式下,动作不会真正修改生产状态,而是记录 "dry-run" 结果。
- 每个动作的沙盒执行结果必须包含:预期变更、实际变更、差异说明、风险标记。
**级联故障防护**(对应 PRD 场景 F-6
- 每次自愈动作执行前,系统记录当前状态快照(包含相关配置版本号)。
- 若自愈动作执行后 2min 内触发新的 P1 以上告警,系统自动检测是否为级联故障。
- 检测到级联故障时,自动回退上一步操作,然后升级为 P0 人工告警。
### 3.4 规模调度与容量视图 (Capacity Board)
容量服务不执行自动扩缩容决策(当前版本 Out of Scope仅提供量化视图与趋势预测。
**容量指标**
| 指标 | 采集频率 | 保留时长 | 负载等级判定 |
|------|---------|---------|-----------|
| Token 消耗量 | 1 min | 7 天(原始) / 30 天(分钟级) / 90 天(小时级) | 超过日上限 80% 为警告100% 为过载 |
| QPS | 1 min | 同上 | 超过设计值 80% 为警告100% 为过载 |
| P99 延迟 | 1 min | 同上 | 超过 5000ms 为警告,超过 10000ms 为过载 |
| 供应商资源利用率 | 5 min | 同上 | 超过 80% 为警告,超过 95% 为过载 |
**增长率预测算法**
- 采用简单线性回归,基于过去 7 天的分钟级数据计算日均增长率。
- 计算公式:`days_to_limit = (limit - current) / daily_growth`,其中 `daily_growth = (latest - earliest) / 7`
- ⚠️ **免责声明**:结果仅供**参考,不作为扩容决策依据**。线性回归无法捕捉季节性波动和突增流量(如大促、热点事件),实际容量规划应以人工判断为主。
- 建议在 UI 界面上也同步显示同样免责声明,控制台显示为 "预计 X 天达到上限(仅供参考,不作为扩容决策依据)"。
### 3.5 知识库管理 (审计与回滚)
审计服务是运维系统的可信基础。所有生产配置变更必须被捕获并不可篡改地存储。
**审计事件模型**(与 supply-api/ 审计规范一致):
```go
type AuditEvent struct {
EventID string `json:"event_id"`
TenantID string `json:"tenant_id"` // 工作区 ID
ObjectType string `json:"object_type"` // 例如 "alert_rule", "route_policy"
ObjectID string `json:"object_id"`
Action string `json:"action"` // "create", "update", "delete", "rollback"
BeforeState map[string]any `json:"before_state"`
AfterState map[string]any `json:"after_state"`
RequestID string `json:"request_id"`
ResultCode string `json:"result_code"` // "OK", "OPS_AUD_4001"
SourceIP string `json:"source_ip"`
ActorID string `json:"actor_id"` // 操作人 ID
CreatedAt time.Time `json:"created_at"`
}
```
**高风险变更检测**(对应 PRD 场景 I
- 对于每次配置变更,系统计算 "影响面分数"。
- 影响面计算方式:变更后将导致被拒绝的请求占比。若估算拒绝率 > 50%,标记为高风险。
- 高风险变更在执行前必须弹出二次确认窗口,管理员角色才能继续。
**回滚机制**
- 回滚操作不是简单的 "恢复原值"而是一个新的审计事件Action="rollback"),生成新的版本。
- **fail-closed 设计**任何配置变更操作必须先完成审计日志写入ai_ops_audits 插入),审计记录写入成功后才能执行业务操作。若审计写入失败,业务操作立即中止并返回错误。回滚时先写入回滚审计记录,再执行回滚操作,确保审计链路始终先于业务执行。
- 回滚前必须检查目标资源是否仍然存在。若不存在,返回错误码 `OPS_AUD_4101`。若目标已被后续修改覆盖,返回 `OPS_AUD_4102`
- 回滚执行前必须显示将被覆盖的子资源列表,并要求管理员二次确认。
- 回滚必须在 60s 内完成并通过验证。
---
## 4. 数据模型设计
### 4.1 核心实体关系图 (ER)
```
+----------------+ +----------------+ +----------------+
| ai_ops_rules |<----->| ai_ops_alerts |<----->| ai_ops_healings|
+----------------+ +----------------+ +----------------+
| | |
v | v
+----------------+ | +----------------+
| ai_ops_channels| | | ai_ops_snapshots|
+----------------+ | +----------------+
| |
v v
+----------------+ +----------------+
| ai_ops_audits | | ai_ops_configs |
+----------------+ +----------------+
|
v
+----------------+
| ai_ops_metrics |
+----------------+
```
> **说明**ER 图中已删除 `ai_ops_events` 和 `ai_ops_notifys` 两张表。
> - `ai_ops_events` 的功能已被 `ai_ops_alerts` 表的状态变化triggered→notified→healing→resolved和 `ai_ops_healings` 表的执行记录覆盖。
> - `ai_ops_notifys` 的功能已被 `ai_ops_channels` 表(渠道配置)以及 `ai_ops_alerts` 表的通知状态字段覆盖。
> - `ai_ops_configs` 和 `ai_ops_snapshots` 保留在 ER 图中,将在 migration 中补齐表结构。
### 4.2 数据表结构
> **安全约束**:所有数据库交互必须使用参数化/预编译查询prepared statements。任何动态构建 SQL 的场景(如日志查询的模糊匹配、自定义规则的条件编译查询)必须通过应用层的 Query Builder 构建,禁止任何字符串拼接 SQL 的方式。Code Review 时必须检查所有数据库操作是否使用参数化查询。
#### 4.2.1 `ai_ops_rules` — 告警规则
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | UUID | PK, 默认 gen_random_uuid() | 规则唯一标识 |
| `name` | VARCHAR(128) | NOT NULL, UNIQUE | 规则名称 |
| `metric_source` | VARCHAR(64) | NOT NULL | 指标来源gateway/supply-api/platform-token-runtime |
| `metric_name` | VARCHAR(128) | NOT NULL | 指标名称qps/latency_p99/error_rate/… |
| `threshold_type` | VARCHAR(16) | NOT NULL, CHECK IN ('>', '<', '=', 'regex') | 阈值类型 |
| `threshold_value` | TEXT | NOT NULL | 阈值(支持正则表达式) |
| `duration_min` | INT | NOT NULL, DEFAULT 1, CHECK >=1 | 持续触发时长(分钟) |
| `level` | VARCHAR(8) | NOT NULL, CHECK IN ('P0','P1','P2','P3') | 告警级别 |
| `channel_ids` | UUID[] | NOT NULL, DEFAULT '{}' | 关联通知渠道 ID 列表 |
| `healing_action` | VARCHAR(32) | DEFAULT NULL | 自愈动作类型(可选) |
| `healing_config` | JSONB | DEFAULT NULL | 自愈动作参数 |
| `is_sandboxed` | BOOLEAN | NOT NULL, DEFAULT FALSE | 是否已通过沙盒验证 |
| `enabled` | BOOLEAN | NOT NULL, DEFAULT TRUE | 是否启用 |
| `created_by` | VARCHAR(64) | NOT NULL | 创建人 |
| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT NOW() | 创建时间 |
| `updated_at` | TIMESTAMPTZ | NOT NULL, DEFAULT NOW() | 更新时间 |
| `version` | INT | NOT NULL, DEFAULT 1 | 乐观锁版本 |
**索引**`CREATE INDEX idx_rules_enabled ON ai_ops_rules(enabled);`
#### 4.2.2 `ai_ops_alerts` — 告警事件
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | UUID | PK | 告警事件 ID |
| `rule_id` | UUID | NOT NULL, FK -> ai_ops_rules | 触发规则 |
| `level` | VARCHAR(8) | NOT NULL | 告警级别(可能升级) |
| `resource_type` | VARCHAR(64) | NOT NULL | 资源类型service/provider/model |
| `resource_id` | VARCHAR(128) | NOT NULL | 资源标识 |
| `current_value` | TEXT | NOT NULL | 触发时的实际值 |
| `threshold_value` | TEXT | NOT NULL | 触发时的阈值 |
| `status` | VARCHAR(16) | NOT NULL, DEFAULT 'triggered' | triggered/notified/healing/resolved/escalated/acknowledged |
| `is_aggregated` | BOOLEAN | NOT NULL, DEFAULT FALSE | 是否为聚合告警 |
| `aggregated_count` | INT | DEFAULT 0 | 聚合的子告警数量 |
| `parent_alert_id` | UUID | NULL, FK -> ai_ops_alerts | 父聚合告警 ID |
| `started_at` | TIMESTAMPTZ | NOT NULL | 开始时间 |
| `resolved_at` | TIMESTAMPTZ | NULL | 解除时间 |
| `acknowledged_by` | VARCHAR(64) | NULL | 确认人 |
| `acknowledged_at` | TIMESTAMPTZ | NULL | 确认时间 |
**索引**
```sql
CREATE INDEX idx_alerts_status ON ai_ops_alerts(status);
CREATE INDEX idx_alerts_started_at ON ai_ops_alerts(started_at DESC);
CREATE INDEX idx_alerts_resource ON ai_ops_alerts(resource_type, resource_id);
```
#### 4.2.3 `ai_ops_healings` — 自愈执行记录
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | UUID | PK | 自愈执行 ID |
| `alert_id` | UUID | NOT NULL, FK -> ai_ops_alerts | 关联告警 |
|| `action_type` | VARCHAR(32) | NOT NULL | switch_route/throttle/restart_instance/invoke_script/isolate_node |
| `config` | JSONB | NOT NULL | 执行时的参数快照 |
| `status` | VARCHAR(16) | NOT NULL, DEFAULT 'pending' | pending/succeeded/failed/rolled_back |
| `dry_run` | BOOLEAN | NOT NULL, DEFAULT FALSE | 是否沙盒执行 |
| `result_detail` | JSONB | NULL | 执行结果详情 |
| `error_code` | VARCHAR(16) | NULL | 失败时的错误码 |
| `started_at` | TIMESTAMPTZ | NOT NULL | 开始时间 |
| `completed_at` | TIMESTAMPTZ | NULL | 完成时间 |
#### 4.2.4 `ai_ops_channels` — 通知渠道
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | UUID | PK | 渠道 ID |
| `name` | VARCHAR(128) | NOT NULL | 渠道名称 |
| `channel_type` | VARCHAR(32) | NOT NULL, CHECK IN ('webhook','email','feishu','wechat','sms') | 渠道类型 |
| `config` | JSONB | NOT NULL | 渠道配置URL/密钥/接收人等) |
| `priority` | INT | NOT NULL, DEFAULT 1 | 优先级(低数 = 高优先) |
| `enabled` | BOOLEAN | NOT NULL, DEFAULT TRUE | 是否启用 |
| `created_at` | TIMESTAMPTZ | NOT NULL | 创建时间 |
#### 4.2.5 `ai_ops_audits` — 审计日志
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | UUID | PK | 审计事件 ID |
| `tenant_id` | VARCHAR(64) | NOT NULL | 工作区 ID |
| `object_type` | VARCHAR(64) | NOT NULL | 目标资源类型 |
| `object_id` | VARCHAR(128) | NOT NULL | 目标资源 ID |
| `action` | VARCHAR(32) | NOT NULL | create/update/delete/rollback |
| `before_state` | JSONB | NULL | 变更前状态 |
| `after_state` | JSONB | NULL | 变更后状态 |
| `request_id` | VARCHAR(64) | NOT NULL | HTTP 请求 ID |
| `result_code` | VARCHAR(16) | NOT NULL | OK 或错误码 |
| `source_ip` | VARCHAR(45) | NOT NULL | 操作人 IP |
| `actor_id` | VARCHAR(64) | NOT NULL | 操作人 ID |
| `risk_level` | VARCHAR(8) | NOT NULL, DEFAULT 'normal' | normal/high/critical |
| `parent_audit_id` | UUID | NULL, FK -> ai_ops_audits | 回滚时关联原始审计 |
| `created_at` | TIMESTAMPTZ | NOT NULL, DEFAULT NOW() | 创建时间 |
**索引**
```sql
CREATE INDEX idx_audits_tenant_created ON ai_ops_audits(tenant_id, created_at DESC);
CREATE INDEX idx_audits_object ON ai_ops_audits(object_type, object_id);
CREATE INDEX idx_audits_actor ON ai_ops_audits(actor_id, created_at DESC);
CREATE INDEX idx_audits_request ON ai_ops_audits(request_id);
```
#### 4.2.6 `ai_ops_metrics` — 时序指标缓存
该表仅在未接入独立时序数据库时作为落地缓存,主时序数据仍然推荐存储在 Prometheus/VictoriaMetrics 中。
| 字段 | 类型 | 约束 | 说明 |
|------|------|------|------|
| `id` | BIGSERIAL | PK | 自增 ID |
| `metric_name` | VARCHAR(128) | NOT NULL | 指标名称 |
| `labels` | JSONB | NOT NULL, DEFAULT '{}' | 标签service/path/supplier 等) |
| `value` | DOUBLE PRECISION | NOT NULL | 指标值 |
| `recorded_at` | TIMESTAMPTZ | NOT NULL | 采集时间 |
**索引**`CREATE INDEX idx_metrics_name_time ON ai_ops_metrics(metric_name, recorded_at DESC);`
**分区策略**:按 `recorded_at` 分区,每日一个分区,自动删除 > 7 天的分区。
### 4.3 实体关系说明
- **Rule -> Alert** (1:N):一条规则在不同时间可触发多个告警事件。
- **Alert -> Healing** (1:1):每个告警事件最多执行一次自愈动作(失败后升级人工处理)。
- **Alert -> Alert** (1:N, 聚合):父告警聚合多个子告警。
- **Audit -> Audit** (1:1, 回滚):回滚审计记录通过 `parent_audit_id` 关联原始记录。
- **Rule -> Channel** (N:M):通过 `channel_ids` 数组实现多对多关系。
---
## 5. 关键流程设计
### 5.1 异常检测 → 诊断 → 恢复 → 验证 → 回复
```
Metric Ingestor Rule Engine Alert Service Healing Engine Validation Loop
| | | | |
| 1. 推送指标数据 | | | |
|---------------------->| | | |
| | 2. 评估阈值规则 | | |
| |---------------------->| | |
| | | 3. 生成告警事件 | |
| | |--------------------->| |
| | | 4. 检查自愈配置 | |
| | |--------------------->| |
| | | | 5. 执行自愈动作 |
| | | |--------------------->|
| | | | 6. 记录执行结果 |
| | |<---------------------| |
| | | 7. 发送通知 | |
| | |------------------------------------------------>|
| | | | | 8. 2min 后验证
| | | |<---------------------|
| | | 9a. 解除告警 | |
| | |<---------------------| |
| | | 9b. 升级人工告警 | |
| | |<---------------------| |
```
**流程说明**
1. **指标采集** (<=15s): Metric Ingestor 每 15s 拉取一次 Prometheus 数据,或通过 Pushgateway 接收推送数据。
2. **规则评估** (<=5s): Rule Engine 对每个启用的规则评估阈值条件。触发条件时,检查是否已在当前持续时间窗口内已存在未关闭的同类告警(抑制重复触发)。
3. **告警生成** (<=1s): 创建 Alert 记录,状态为 `triggered`
4. **自愈检查** (<=1s): 检查规则是否配置了自愈动作,且已通过沙盒验证。
5. **自愈执行** (<=60s): 执行自愈动作,包含最多 1 次重试。
6. **结果记录** (<=1s): 将自愈执行结果写入 Healing 表,更新 Alert 状态为 `healing`
7. **通知发送** (P0/P1 <=30s, P2 <=120s): Notification Dispatcher 路由到配置的通知渠道。
8. **效果验证** (2min 后): Validation Loop 查询监控指标,检查告警条件是否仍然满足。
9. **终态处理**:
- 9a. 若指标恢复正常Alert 状态变为 `resolved`
- 9b. 若指标仍未恢复Alert 状态变为 `escalated`,通知升级为 P0 人工告警。
### 5.2 告警聚合流程
```
Alert Service
|
| 1. 检测到新告警
v
+-----------+ +----------------+ +----------------+
| 同一资源 | --> | 1min 内数量 >20 | --> | 生成集群告警 |
| 在 1min | | 条? | | (is_aggregated) |
| 内的告警 | +----------------+ +--------+-------+
+-----------+ |
| 2. 将子告警关联到父告警
v
+--------+-------+
| 停止单条通知 |
| 发送,只发集群 |
+----------------+
```
**聚合规则**
- 触发条件:同一 `resource_type` + `resource_id` 在 60s 内触发 > 20 条告警。
- 聚合行为:生成一条新的 Alert`is_aggregated=TRUE``aggregated_count=N`,将所有子告警的 `parent_alert_id` 设为该聚合告警 ID。
- 通知行为:只发送一条集群告警通知,包含涉及的规则列表和时间范围。
- 抑制周期:同一规则同一目标在 5min 内只发送 1 次通知(除非级别升级)。
### 5.3 配置回滚流程
```
Admin Console
|
| 1. 选择审计记录,点击回滚
v
Audit Service
|
| 2. 检查目标资源是否存在
v
+-----------+ +----------------+ +----------------+
| 目标存在? | --> | 是 | --> | 显示子资源影响面 |
+-----------+ +----------------+ +--------+-------+
| |
| 否 | 3. 管理员确认
v v
+-----------+ +--------+-------+
| 返回错误 | | 执行回滚 |
| OPS_AUD_ | | (BeforeState |
| 4101 | | -> current) |
+-----------+ +--------+-------+
|
| 4. 生成新审计记录
v
+--------+-------+
| 验证回滚后 |
| 状态,返回结果 |
+----------------+
```
---
## 6. 技术选型与备选方案
### 6.1 时序数据库
| 方案 | 选择 | 理由 | 备选 |
|------|------|------|------|
| Prometheus | 推荐 | 已为 PRD 假设依赖,生态成熟,支持 PromQL与 NewAPI/Sub2API 的 `/metrics` 集成自然 | VictoriaMetrics更高性能更低资源占用 |
| PostgreSQL 时序表 | 落地缓存 | 作为 Prometheus 不可用时的降级方案,保存最近 7 天原始指标 | - |
**决策理由**
- 主指标存储使用 Prometheus提供 `/metrics` 端点供外部 scrape。
- 在 PostgreSQL 中保存分钟级聚合指标(用于控制台快速查询)。
- 若 Prometheus 丢失,系统进入只读降级模式,告警引擎依赖本地缓存持续运行。
### 6.2 告警状态缓存
| 方案 | 选择 | 理由 | 备选 |
|------|------|------|------|
| Redis + 本地内存 (DualCache) | 推荐 | 参考 LiteLLM 的 DualCache 模式Redis 保证多实例共享状态,本地内存降低延迟 | 单纯 Redis |
**设计细节**
- 告警抑制状态存储在 Redis 中TTL 为 5min。
- 告警聚合计数器存储在 Redis 中TTL 为 1min。
- 本地内存作为 L1 缓存,命中失败时才访问 RedisL2
### 6.3 告警批量处理
| 方案 | 选择 | 理由 | 备选 |
|------|------|------|------|
| 内存批量队列 + 定时刷盘 | 推荐 | 参考 LiteLLM CustomBatchLogger每 10s 或队列长度 > 50 时刷盘,避免告警爆炸时的 IO 瓶颈 | 单条同步发送 |
### 6.4 通知渠道
| 渠道 | 优先级 | 备份策略 |
|------|--------|---------|
| Webhook | 1 | 失败时降级到邮件 |
| 邮件 | 2 | 失败时降级到飞书/企业微信 |
| 飞书/企业微信 | 3 | 失败时降级到短信 |
| 短信 | 4 | 失败时通知 TechLead |
---
## 7. 与立交桥主系统的集成点
### 7.1 Token Gateway (gateway/)
**数据提供**
- gateway/ 需要通过 Prometheus 指标暴露以下数据:
- `gateway_requests_total` (标签: path, method, status)
- `gateway_request_duration_seconds` (标签: path, method, quantile)
- `gateway_error_rate_5xx` (标签: path)
- `gateway_degradation_hits_total` (标签: rule_id)
**集成接口**
- gateway/ 提供内部 HTTP 接口供 AI-Ops 调用:
- `GET /internal/gateway/health` — 查询服务健康状态
- `GET /internal/gateway/routes` — 获取当前路由配置,用于影响面分析
- `POST /internal/gateway/routes` — 修改路由策略(如切换供应商、限流配置),自愈动作调用
- `GET /internal/gateway/metrics` — 获取请求量统计
**集成方式**
- 独立运行时:通过配置文件 `gateway.internal_endpoint` 指定地址,使用 API Key 鉴权。
- 集成运行时:通过 `IntegrationPlugin` 直接调用 gateway/ 的内部方法,跳过 HTTP 层。
### 7.2 Channel Manager (supply-api/)
**集成接口**
- supply-api/ 提供以下内部 HTTP 接口供 AI-Ops 调用:
- `GET /internal/supply/accounts/health` — 供应商健康状态
- `GET /internal/supply/audit/schema` — 审计日志格式定义,确保事件格式一致
**审计事件对接**
- AI-Ops 的审计事件格式与 supply-api/ 保持一致。
- 集成运行时,可选择复用 supply-api/ 的 AuditStore 接口,或使用独立的 `ai_ops_audits` 表(推荐独立表,避免 schema 冲突)。
### 7.3 Platform Token Runtime
**集成接口**
- platform-token-runtime/ 提供以下内部 HTTP 接口供 AI-Ops 调用:
- `GET /internal/runtime/token-usage` — 获取 Token 消耗指标
- `GET /internal/runtime/capacity` — 获取容量使用率
---
## 8. 安全设计
### 8.1 角色与权限控制 (RBAC)
| 角色 | 监控查看 | 日志查询 | 告警确认/忽略 | 告警规则管理 | 配置回滚 | 高风险变更 |
|------|---------|---------|-------------|-------------|---------|-----------|
| 查看者 (viewer) | ✅ | ✅ | ❌ | ❌ | ❌ | ❌ |
| 运维人员 (operator) | ✅ | ✅ | ✅ | ✅ | ❌ | ❌ |
| 管理员 (admin) | ✅ | ✅ | ✅ | ✅ | ✅ | ✅ |
**实现方案**
- 独立运行时,系统自带角色表 `ai_ops_roles`
- 集成运行时,通过 `IntegrationPlugin` 接口从主程序获取当前用户角色,或复用主程序的 IAM 系统。
- 每个 HTTP 请求必须经过 Authz Middleware 检查,在响应头中返回 `X-Permitted-Actions` 列表。
### 8.2 审计与日志安全
- 审计日志必须使用只读存储,禁止任何用户/管理员直接修改 `ai_ops_audits` 表。
- 审计日志保留期 >= 90 天,通过 PostgreSQL 分区表 + 自动清理实现。
- 敏感字段脱敏:审计日志中的 `BeforeState` / `AfterState` 包含密钥、密码时,必须通过 Sanitizer 脱敏处理。
- 所有管理端点必须记录访问日志,包含操作人 IP、时间戳、操作类型。
### 8.3 数据隔离
- 所有数据查询必须带有 `tenant_id` / `workspace_id` 过滤条件,防止跨租户数据泄露。
- 数据库层面使用 Row Level Security (RLS) 作为最后一道防线(可选,根据性能决策)。
---
## 9. 性能考量
### 9.1 并发能力
| 指标 | 目标值 | 验证方式 |
|------|--------|---------|
| 告警规则评估吞吐量 | >= 50 条规则 / 15s | 压力测试 |
| 并发告警处理 | >= 100 事件/s | 压力测试 |
| 控制台首页加载 | < 2s | 性能测试 |
| 日志查询首页返回 | < 3s | 性能测试 |
| 审计日志查询 | < 3s | 性能测试 |
### 9.2 扩展性
- **水平扩展**AI-Ops 服务无状态(状态存储在 Redis/PostgreSQL可通过增加 Pod 数量水平扩展。
- **告警引擎分片**:当规则数量 > 200 条时,可将规则按 `metric_source` 分片到不同的评估器实例。
- **时序库扩展**Prometheus 采用 Remote Write 到 VictoriaMetrics 或 Thanos支持长期存储扩展。
### 9.3 存储估算
**指标数据**(以 Prometheus 为主存储):
- 假设 10 个指标,每个指标 10 个标签组合,采集频率 15s。
- 每天数据量: 10 * 10 * (86400/15) * 8 bytes = 4.6 MB/天
- 7 天原始数据: ~32 MB
- 30 天分钟级聚合: ~200 MB
- 90 天小时级聚合: ~150 MB
**审计日志**PostgreSQL
- 假设每天 1000 次配置变更,每条记录平均 2 KB。
- 每天: 2 MB
- 90 天: ~180 MB
**告警事件**PostgreSQL
- 假设每天 500 条告警,每条记录平均 1 KB。
- 每天: 500 KB
- 90 天: ~45 MB
**总存储估算**
- 指标时序库500 MB含小时级聚合
- PostgreSQL (审计+告警+配置): 500 MB
- Redis (状态缓存): 100 MB
总计: ~1.1 GB无压缩实际生产环境建议预留 5 GB 磁盘空间。
---
## 10. 风险评估与缓解策略
| 风险编号 | 风险描述 | 严重级别 | 发生概率 | 缓解策略 |
|---------|---------|---------|---------|---------|
| R-1 | 自愈规则设计不当导致正常流量被截断或重定向 | 高 | 中 | 沙盒模式强制验证;高风险变更二次确认;自愈引擎支持一键关闭 |
| R-2 | 告警规则过于敏感或缺乏抑制,导致噪音爆炸 | 高 | 中 | 告警聚合机制;抑制周期 5min噪声率监控与自动告警间隔 2h 未确认自动升级避免麻木 |
| R-3 | 回滚操作不当导致配置状态更深层次损坏 | 中 | 低 | 回滚前显示子资源影响面;二次确认;回滚后自动验证;高风险变更二次确认 |
| R-4 | 审计日志丢失导致故障定责和合规审查受阻 | 中 | 低 | 主备双写异步文件缓存作为降级90 天保留期;存储监控与预警 |
| R-5 | 时序数据库全面中断 | 高 | 低 | 控制台降级为只读模式告警引擎依赖本地缓存持续运行PostgreSQL 落地缓存作为最后防线 |
| R-6 | 通知渠道全部失效 | 中 | 低 | 主备自动切换机制4 层降级;最终通知 TechLead通知失败记录保留在事件中 |
### 10.1 威胁建模
| 威胁场景 | 攻击/故障路径 | 影响 | 控制措施 | 验证要求 |
|---------|---------------|------|---------|---------|
| 自愈误触发 | 错误规则或坏数据触发切流/限流/重启 | 生产流量中断、雪崩放大 | 沙盒演练、双人确认、高风险动作默认关闭、回滚快照 | 每个高风险动作必须有沙盒验证和回滚演练 |
| 告警洪泛 | 外部噪声或错误规则导致告警风暴 | 值班麻木、真实故障被淹没 | 聚合、抑制、静默窗口、升级策略、噪声率告警 | 压测和回放验证 50 条并发规则下噪声可控 |
| 越权运维操作 | 低权限用户执行回滚/规则修改/高风险变更 | 生产配置被误改 | RBAC、二次确认、审计、资源级鉴权、响应头返回 permitted actions | QA 必测 viewer/operator/admin 差异权限 |
| 审计链路失真 | 审计未先写入或被篡改 | 无法追责、回滚依据失效 | 审计先写后执行业务;审计存储防篡改;失败阻断高风险操作 | 审计写失败时高风险变更必须拒绝 |
|| 外部适配层被滥用 | `/metrics`、Webhook、管理 API 适配暴露过多能力 | 信息泄露、被动放大攻击面 | 最小暴露面、签名校验、限流、只读隔离、错误码映射 | 合同测试覆盖外部接口鉴权与字段边界 |
|| **LLM 模型错误输出导致配置损坏** | AI 生成的自愈配置、回滚策略、影响面分析等包含错误信息,被直接认可后执行 | 配置被误写,影响所有依赖该配置的服务 | **人在环路中心**:任何 LLM 生成的动作或配置必须经过人工审批,不得直接自动执行;对生成内容进行语法/语义校验;限制 LLM 的功能范围(只读/分析/推荐,不写/不执行) | QA 必测 LLM 生成配置的审批流程和拒绝逻辑 |
|| **LLM 提示注入挑战** | 攻击者通过日志字段、Webhook 输入、审计查询参数等渠道注入恶意提示,诱导 LLM 生成危险配置或泄露敏感信息 | 身份认证绕过、审计信息泄露 | 对所有 LLM 输入进行输入验证和过滤;严格区分"系统提示”与"用户输入”LLM 调用使用独立的系统角色,不能获取用户的任何权限;输出经过模板化处理 | QA 必测 LLM 输入渠道的注入防御 |
### 10.2 设计阶段门控结论
**结论REQUEST_CHANGES已转化为以下行动项**
**已完成的修复:**
- [x] 错误码统一PRD / HLD / INTERFACE 回滚错误码统一为 `OPS_AUD_4101` / `OPS_AUD_4102`
- [x] 低级笔误修复:测试策略中的"游戏化事务" → "编程式事务"HLD 中的"预畈" → "预留"
- [x] 数据库 migration SQL补齐 `tech/migrations/000001_init_schema.up.sql` / `.down.sql`,覆盖核心 6 张表 + 审计防篡改触发器 + 分区策略
- [x] 功能清单裁剪:删除 66 条 PM 越界按钮级任务,添加 PM/Engineer 范围边界说明
**进入开发前必须补齐:**
- [ ] 威胁建模验证要求转化为可执行测试:
- 每个威胁场景在 TEST_DESIGN 中必须有对应的 CI 阻断测试用例
- 毒性:自愈误触发 → TC-6.5 沙盒模式验证、TC-6.7 级联故障回退
- 毒性:告警洪泛 → TC-5.1 聚合测试、TC-5.3 抑制周期测试
- 毒性:越权运维 → TC-12.1~12.3 角色权限矩阵
- 毒性:审计鏈路失真 → TC-7.2 审计不可篡改、TC-7.1 审计写入时效
- 毒性:外部适配层被滥用 → TOPS-ADP-01~03 适配层验证
- [ ] `BuildServer` / `BuildRuntime` 显式挂载约束必须落实为 QA 的阻断检查项:
- 每个模块在 `BuildServer` 中必须有对应的 `Register()` 调用,否则 CI 失败
- 每个条件能力在 `BuildRuntime` 中必须有对应的 `Enable()` 调用,否则 CI 失败
- [ ] 独立运行 / 集成运行 / IntegrationPlugin / OpenAPI / 适配层要求必须进入测试阻断矩阵:
- TOPS-RUN-01~04 必须通过 CI
- TOPS-PLG-01~03 必须通过 CI
- TOPS-OAS-01~03 必须通过 CI
- TOPS-ADP-01~03 必须通过 CI
- [ ] 高风险变更必须 fail-closed
- 影响面 > 50% 的变更在审计写入失败时必须拒绝执行,有单独的 CI 测试用例验证
**阻断条件(任一触发则不得进入开发):**
- 自愈动作没有沙盒、快照与回滚闭环。
- 审计日志不能保证先写审计再执行业务。
- 无法证明集成模式中路由、worker、健康检查全部真实挂载。
---
## 11. 可重用的设计模式
| 设计模式 | 来源 | 应用场景 |
|---------|------|---------|
| **CustomBatchLogger** | LiteLLM | 告警事件批量处理,避免高并发下的 IO 瓶颈 |
| **DualCache** | LiteLLM | 告警状态缓存(内存 + Redis确保告警可靠性 |
| **DigestEntry** | LiteLLM | 告警聚合,避免滥发 |
| **AlertType + AlertTypeConfig** | LiteLLM | 可扩展的告警类型系统,支持按类型配置不同策略 |
| **OutageModel + ProviderRegionOutageModel** | LiteLLM | 故障状态机,支持模型级和区域级故障检测 |
| **Cooldown 机制** | LiteLLM | 故障部署自动移除,作为自愈动作的一种 |
| **FreeRide SupplierChain** | FreeRide (OpenClaw) | 供应商多级 Fallback 链 + 冷却期,防止震荡 |
| **SupplierProbe + ELOHistory** | FreeRide (OpenClaw) | 供应商探针定时任务 + 质量趋势记录 |
| **Repository + Service + Handler** | Bridge 主项目 | 分层架构领域层定义接口应用层实现业务逻辑HTTP 层处理协议转换 |
| **Optimistic Locking** | supply-api/ | 配置变更时防止并发覆盖Store 接口必须包含 expectedVersion |
| **Circuit Breaker** | 行业实践 | 自愈动作执行失败时,避免连续重试导致级联故障 |
| **Snapshot + Rollback** | 行业实践 | 自愈动作执行前记录状态快照,支持自动回退 |
---
## X 技术选型(前端)
### 前端技术栈
- **框架**React 18+(或与 gateway 现有前端保持一致)
- **组件库**Tailwind CSS + Headless UI或现有 UI 框架)
- **图表**ECharts 5.x已在功能清单中使用
- **构建工具**Vite
- **状态管理**React Query用于 API 数据获取和缓存)
### 前端工作范围
- 监控首页6 个指标卡片 + 实时刷新)
- 指标下钻页ECharts 趋势图 + 维度筛选)
- 日志查询页(表格 + 分页 + 导出)
- 告警规则管理页CRUD 表单)
- 告警事件列表页(状态 Tab + 集群聚合)
- 配置审计与回滚页
- 容量主板(多图表 + 预测卡片)
### 约束
- 前端不做后端逻辑,所有数据通过 `/api/v1/ai-ops/` REST 接口获取
- 前端与后端通过 JWT Token 认证Token 由后端签发
---
## 12. 技术栈与集成约束
### 12.1 统一技术栈
本项目必须与立交桥主项目保持一致:
- **语言**: Go 1.22+
- **HTTP框架**: 标准库 `net/http` + 自定义中间件(禁止引入 Gin/Echo 等第三方框架,保持与 gateway/ 和 supply-api/ 的一致性)
- **数据库**: PostgreSQL 15+ ,驱动 `jackc/pgx/v5`
- **缓存**: Redis客户端 `redis/go-redis/v9`
- **配置**: YAML + Viper环境变量覆盖敏感字段
- **日志/审计**: 结构化日志,审计事件模型与 supply-api/ 一致
- **错误码**: `{SOURCE}_{CATEGORY}_{CODE}` 格式,例如 `OPS_ALT_4001`
- **健康检查**: `/actuator/health``/actuator/health/live``/actuator/health/ready`
- **测试**: Go testing + testify覆盖率门槛 domain ≥ 70%、service/handler ≥ 80%
### 12.2 独立运行与集成运行
本系统必须同时支持两种运行模式:
| 模式 | 特征 | 部署方式 | 适用场景 |
|------|------|---------|---------|
| **独立运行** | 自有 `cmd/ai-ops/main.go`,独立数据库 schema独立 docker-compose | `docker-compose up` 或单独容器 | 外部用户只需要运维能力,不想接入立交桥全套 |
| **集成运行** | 作为 Go module 被 `gateway/``supply-api/` 引入,共享数据库连接池和配置,通过内部接口注册 | 编译时作为子模块编译,运行时挂载到立交桥主进程 | 立交桥用户希望获得一体化运维能力 |
**集成约束**:
- 独立运行时,系统必须提供完整的 HTTP API 和管理后台。
- 集成运行时,系统必须提供 `IntegrationPlugin` 接口,允许主程序通过配置开关启用/禁用各模块。
- 数据库 schema 必须使用独立的 `ai_ops_` 前缀,避免与主项目表名冲突。
- 配置文件必须支持分离加载:独立运行时读取自己的 `config.yaml`,集成运行时合并到主项目配置。
### 12.3 NewAPI / Sub2API 适配支持
本系统的核心能力必须能够对接 NewAPI 和 Sub2API 系统:
- **监控数据推送**: 提供 Prometheus 格式的 `/metrics` 接口NewAPI/Sub2API 可通过 Prometheus scrape 获取运维数据。
- **告警回调**: 支持 Webhook 告警通知NewAPI/Sub2API 可配置接收本系统的告警事件。
- **自愈脚本扩展**: 自愈动作中的“触发程序化脚本”支持调用 NewAPI/Sub2API 的管理 API如切换供应商、限流配置、重启实例
- **独立部署时**: 通过配置文件指定 NewAPI/Sub2API 的管理端点地址和鉴权信息,本系统通过适配层与之交互。
- **集成部署时**: 若立交桥 gateway/ 已接入 NewAPI/Sub2API本系统通过 gateway/ 的内部路由接口操作上游状态。
### 12.4 对外接口契约
- 必须提供 OpenAPI 3.0 接口文档,确保 NewAPI/Sub2API 开发者可以独立接入。
- 接口路径前缀默认为 `/api/v1/ai-ops/`,集成运行时可通过配置改为 `/internal/ai-ops/`
---
## 13. 变更日志
| 版本 | 日期 | 修改人 | 内容 |
|------|------|--------|------|
| v1.0 | 2026-04-27 | TechLead | 初稿:完成系统架构、模块设计、数据模型、流程设计、技术选型、集成点、安全、性能、风险、设计模式 |
---
## 附录 Y参考文档与外部依赖
| 参考项目 | 版本/日期 | URL | 用途 |
|---------|---------|-----|------|
| LiteLLM | v1.40.0 (2026-03) | https://docs.litellm.ai/ | 模型接口标准化、健康检查设计 |
| Sub2API | main分支 (2026-04) | https://github.com/WeI-Shaw/sub2api | 公告系统、用户体系参考 |
| Intercom | - | https://www.intercom.com/ | 客服体验对标 |
| Prometheus | 3.x (2026-Q1) | https://prometheus.io/ | 时序数据存储 |
| VictoriaMetrics | 1.100.x (2026-Q1) | https://victoriametrics.com/ | 时序数据备选存储 |
| Playwright | 1.50.x (2026-Q1) | https://playwright.dev/ | 浏览器自动化 |
| Qdrant | 1.12.x (2026-Q1) | https://qdrant.tech/ | 向量数据库备选 |
| PGVector | 0.8.x (2026-Q1) | https://github.com/pgvector/pgvector | PostgreSQL向量扩展 |
以上版本号为评审时2026-04-28的最新稳定版随着项目开发应定期更新。

387
tech/INTERFACE.md Normal file
View File

@@ -0,0 +1,387 @@
# AI-Ops 核心接口设计
> 版本v1.0 | 状态:初稿
---
## 1. 内部模块间接口
### 1.1 MetricService
```go
type MetricService interface {
// 采集指标
Collect(ctx context.Context, source string, metrics []MetricPoint) error
// 查询时序数据
Query(ctx context.Context, req MetricQueryRequest) (*MetricQueryResult, error)
// 获取最新值
GetLatest(ctx context.Context, source, metricName string) (*MetricPoint, error)
// 存储保留期检查
PurgeExpired(ctx context.Context, before time.Time) (int64, error)
}
type MetricPoint struct {
Source string
Name string
Value float64
Tags map[string]string
Timestamp time.Time
}
type MetricQueryRequest struct {
Source string
Name string
StartTime time.Time
EndTime time.Time
Interval time.Duration // 聚合间隔
Tags map[string]string
}
type MetricQueryResult struct {
Points []MetricPoint
}
```
### 1.2 AlertService
```go
type AlertService interface {
// 规则 CRUD
CreateRule(ctx context.Context, rule AlertRule) (*AlertRule, error)
UpdateRule(ctx context.Context, rule AlertRule) (*AlertRule, error)
DeleteRule(ctx context.Context, ruleID string) error
GetRule(ctx context.Context, ruleID string) (*AlertRule, error)
ListRules(ctx context.Context, filter RuleFilter) ([]AlertRule, error)
// 告警事件管理
ListAlerts(ctx context.Context, filter AlertFilter) ([]AlertEvent, error)
Acknowledge(ctx context.Context, alertID, actorID string) error
Ignore(ctx context.Context, alertID, actorID string) error
Escalate(ctx context.Context, alertID, reason string) error
// 实时评估
Evaluate(ctx context.Context, ruleID string) (*AlertEvent, error)
}
type AlertRule struct {
ID string
Name string
MetricSource string
MetricName string
ThresholdType string // > < = regex
ThresholdValue string
DurationMin int
Level string // P0 P1 P2 P3
ChannelIDs []string
HealingAction *string
HealingConfig map[string]any
IsSandboxed bool
Enabled bool
Version int
}
type AlertEvent struct {
ID string
RuleID string
Level string
ResourceType string
ResourceID string
CurrentValue string
ThresholdValue string
Status string // triggered notified healing resolved escalated acknowledged
IsAggregated bool
AggregatedCount int
CreatedAt time.Time
UpdatedAt time.Time
}
```
### 1.3 HealingService
```go
type HealingService interface {
// 执行自愈动作
Execute(ctx context.Context, action HealingAction, target ResourceTarget) (*HealingResult, error)
// 获取可用动作列表
ListActions(ctx context.Context) []HealingActionMeta
// 回滚自愈动作
Rollback(ctx context.Context, executionID string) error
// 查询执行历史
ListExecutions(ctx context.Context, filter ExecutionFilter) ([]HealingExecution, error)
}
type HealingAction struct {
Type string // restart_instance switch_route throttle isolate_node invoke_script
Config map[string]any
}
type ResourceTarget struct {
Type string // service provider model
ID string
}
type HealingResult struct {
ExecutionID string
Success bool
BeforeState map[string]any
AfterState map[string]any
Error *string
ExecutedAt time.Time
}
```
### 1.4 AuditService
```go
type AuditService interface {
// 记录审计事件
Record(ctx context.Context, event AuditEvent) error
// 查询审计日志
Query(ctx context.Context, filter AuditFilter) ([]AuditEvent, error)
// 回滚操作
Rollback(ctx context.Context, eventID string, actorID string) (*AuditEvent, error)
// 影响面计算
CalculateImpact(ctx context.Context, objectType, objectID string, proposedState map[string]any) (*ImpactReport, error)
}
type AuditEvent struct {
EventID string
TenantID string
ObjectType string
ObjectID string
Action string // create update delete rollback
BeforeState map[string]any
AfterState map[string]any
RequestID string
ResultCode string
SourceIP string
ActorID string
CreatedAt time.Time
}
type ImpactReport struct {
RiskLevel string // low medium high
EstimatedRejectRate float64 // 预估拒绝率
AffectedResources []string
RequiresConfirm bool
}
```
### 1.5 CapacityService
```go
type CapacityService interface {
// 获取容量视图
GetDashboard(ctx context.Context, scope CapacityScope) (*CapacityDashboard, error)
// 增长率预测
PredictGrowth(ctx context.Context, metric string, horizon time.Duration) (*GrowthPrediction, error)
// 设置容量阈值
SetThreshold(ctx context.Context, metric string, threshold float64) error
}
type CapacityDashboard struct {
Metrics []CapacityMetric
Predictions []GrowthPrediction
LastUpdated time.Time
}
type CapacityMetric struct {
Name string
Current float64
Limit float64
Unit string
Utilization float64
}
type GrowthPrediction struct {
Metric string
DailyGrowth float64
DaysToLimit *int // nil 表示不会达到上限
}
```
### 1.6 IntegrationPlugin
`IntegrationPlugin` 是 AI-Ops 与立交桥主项目gateway/supply-api集成运行时的核心接口。主项目通过实现该接口将 AI-Ops 的能力挂载到自身进程中。
```go
// IntegrationPlugin 定义了 AI-Ops 模块在集成运行时必须实现的接口契约
// 注意:模块必须通过显式 import + init 注册到全局注册表,
// 且主程序必须通过配置显式 Enable 才能激活模块。
type IntegrationPlugin interface {
// Name 返回模块唯一标识,用于配置关联和日志区分
// 示例: "alert", "healing", "audit", "capacity"
Name() string
// Init 在模块被启用时执行一次初始化
// 负责: 连接数据库、初始化缓存、启动后台 worker 等
// 若初始化失败,整个模块不得启动,主程序应记录错误并继续启动其他模块
Init(ctx context.Context, cfg Config) error
// RegisterRoutes 将模块的 HTTP 接口注册到主程序的 ServeMux
// 路径必须以 /internal/ai-ops/{module}/ 为前缀
// 示例: /internal/ai-ops/alert/rules, /internal/ai-ops/healing/actions
RegisterRoutes(mux *http.ServeMux) error
// HealthChecks 返回模块的健康检查函数列表
// 主程序将聚合所有模块的健康检查到 /actuator/health 和 /actuator/health/ready
HealthChecks() []HealthCheckFunc
// Shutdown 在主程序退出时按 LIFO 顺序调用
// 负责: 关闭数据库连接、停止 worker、释放资源
// 超时上限 30 秒,超时后强制终止
Shutdown(ctx context.Context) error
}
// HealthCheckFunc 是健康检查函数签名
type HealthCheckFunc func(ctx context.Context) (name string, status string, detail string)
// PluginRegistry 是全局模块注册表(线程安全)
var registry = make(map[string]IntegrationPlugin)
var registryMu sync.RWMutex
// Register 在 init() 中调用,将模块注册到全局注册表
func Register(p IntegrationPlugin) {
registryMu.Lock()
defer registryMu.Unlock()
if _, exists := registry[p.Name()]; exists {
panic("duplicate plugin registration: " + p.Name())
}
registry[p.Name()] = p
}
// GetRegisteredPlugins 返回已注册的所有模块拷贝
func GetRegisteredPlugins() []IntegrationPlugin {
registryMu.RLock()
defer registryMu.RUnlock()
result := make([]IntegrationPlugin, 0, len(registry))
for _, p := range registry {
result = append(result, p)
}
return result
}
```
**注册与使用示例**
```go
package alert
import (
"context"
"net/http"
aiops "github.com/company/ai-ops"
)
func init() {
// 显式注册到全局注册表
aiops.Register(&AlertPlugin{})
}
type AlertPlugin struct{ /* ... */ }
func (p *AlertPlugin) Name() string { return "alert" }
func (p *AlertPlugin) Init(ctx context.Context, cfg aiops.Config) error { /* ... */ }
func (p *AlertPlugin) RegisterRoutes(mux *http.ServeMux) error { /* ... */ }
func (p *AlertPlugin) HealthChecks() []aiops.HealthCheckFunc { /* ... */ }
func (p *AlertPlugin) Shutdown(ctx context.Context) error { /* ... */ }
```
**关键约束**
1. **显式 Enable**:主程序配置文件中必须显式开启模块,默认关闭。示例:`ai_ops.alert.enabled: true`
2. **路由前缀统一**:所有注册的路由必须以 `/internal/ai-ops/` 为前缀,避免与主系统路径冲突。
3. **数据库前缀统一**:插件创建的表必须使用 `ai_ops_` 前缀,避免 schema 冲突。
4. **健康检查注入**:插件实现的 HealthChecks 必须被主程序聚合到 /actuator/health 和 /actuator/health/ready 。
5. **顺序关闭**主程序关闭时必须按后进先出LIFO顺序调用各插件的 Shutdown 。
---
## 2. 外部系统集成接口
### 2.1 与 Bridge Gateway 集成
| 方法 | 路径 | 请求 | 响应 | 说明 |
|------|------|------|------|------|
| 查询服务状态 | `GET /internal/gateway/health` | - | `{"status":"up","services":{}}` | 诊断时查询各服务健康状态 |
| 获取路由策略 | `GET /internal/gateway/routes` | - | `{"routes":[]}` | 读取当前路由配置,用于影响面分析 |
| 修改路由策略 | `POST /internal/gateway/routes` | `{"action":"switch_route","target":"","config":{}}` | `{"success":true}` | 自愈动作调用,需审计 |
|| 获取请求量统计 | `GET /internal/gateway/metrics` | `?metric=qps&duration=5m` | `{"value":1234.5}` | 采集指标数据 |
> **安全约束**`/internal/gateway/metrics` 端点仅限内网 IP 访问(如 10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16或需要携带有效的服务间 API Key。公网直接访问应返回 403 Forbidden。
### 2.2 与 supply-api 集成
| 方法 | 路径 | 请求 | 响应 | 说明 |
|------|------|------|------|------|
| 查询供应商状态 | `GET /internal/supply/accounts/health` | - | `{"accounts":[]}` | 诊断供应商健康状态 |
| 获取审计日志格式 | `GET /internal/supply/audit/schema` | - | `{"schema":{}}` | 确保审计事件格式一致 |
### 2.3 与 platform-token-runtime 集成
| 方法 | 路径 | 请求 | 响应 | 说明 |
|------|------|------|------|------|
| 获取 Token 消耗 | `GET /internal/runtime/token-usage` | `?window=1h` | `{"total":12345,"by_model":{}}` | 采集 Token 消耗指标 |
| 获取容量使用率 | `GET /internal/runtime/capacity` | - | `{"utilization":0.75}` | 采集容量指标 |
---
## 3. API 接口规范
### 3.1 REST API 基础
- **基础路径**: `/api/v1/ai-ops/`
- **内部路径** (集成模式): `/internal/ai-ops/`
- **内容类型**: `application/json`
- **错误响应格式**:
```json
{
"error_code": "OPS_{CATEGORY}_{CODE}",
"message": "人类可读的错误信息",
"detail": {} // 可选,包含额外的调试信息
}
```
### 3.2 错误码
| 错误码 | HTTP 状态 | 说明 |
|---------|-----------|------|
| `OPS_GEN_4001` | 400 | 请求参数错误 |
| `OPS_GEN_4002` | 401 | 未授权 |
| `OPS_GEN_4003` | 403 | 权限不足 |
| `OPS_GEN_4004` | 404 | 资源不存在 |
| `OPS_GEN_4005` | 409 | 资源冲突(如名称已存在) |
| `OPS_GEN_4006` | 413 | 请求体过大(如日志查询时间范围过大) |
| `OPS_GEN_5001` | 500 | 内部服务错误 |
| `OPS_MET_4001` | 400 | 指标名称无效 |
| `OPS_MET_4002` | 400 | 时间范围不合法 |
| `OPS_ALT_4001` | 400 | 规则名称已存在 |
| `OPS_ALT_4002` | 400 | 规则参数验证失败 |
| `OPS_ALT_4003` | 409 | 规则被其他用户修改(版本冲突) |
| `OPS_HEAL_4001` | 400 | 自愈动作参数无效 |
| `OPS_HEAL_4002` | 409 | 自愈动作正在执行中 |
| `OPS_HEAL_4003` | 400 | 回滚目标执行不存在 |
| `OPS_AUD_4001` | 403 | 无权进行审计操作 |
| `OPS_AUD_4101` | 400 | 回滚目标资源不存在 |
| `OPS_AUD_4102` | 409 | 回滚目标已被后续修改覆盖 |
| `OPS_CAP_4001` | 400 | 容量指标不存在 |
### 3.3 分页
- `列表接口` 支持分页参数:`?page=1&page_size=20`
- 默认 `page_size=20`,最大 `page_size=100`
- 响应体包含:`{"items":[],"total":123,"page":1,"page_size":20}`
### 3.4 WebSocket 接口
**路径**: `/ws/v1/ai-ops/alerts`
**鉴权机制**:
- 连接建立时必须在查询参数中携带有效 JWT Token`?token=<jwt>`。
- 服务端在升级 WebSocket 连接前必须验证 token 有效性、过期时间和角色权限。
- token 无效或已过期时,立即返回 401 Unauthorized 并关闭连接。
- 订阅范围根据用户角色过滤,查看者只能接收 P1 及以下级别告警,管理员可接收所有级别。
**功能**:
- 客户端订阅后,实时推送新告警事件。
- 支持按级别过滤:`?levels=P0,P1`。
- 心跳间隔 30 秒。

129
tech/QA_REVIEW_REPORT.md Normal file
View File

@@ -0,0 +1,129 @@
# QA 审核报告AI-Ops 测试设计文档
> 审核日期2026-05-11
> 审核人QA Agent
> 审核对象TEST_DESIGN.md / CASES.md / STRATEGY.md
> 对照基准PRD.md (AC-01 ~ AC-12, F-01 ~ F-08)
---
## 总体评级C
**评级依据**测试策略框架和分层模型设计较为完整Mock 策略、环境矩阵、灰度 Phase 规划具备可执行基础。但存在 3 项 P0 严重缺陷AC 负向用例大面积缺失、异常流程 F-05~F-08 在 CASES.md 中完全遗漏、CI 集成零配置。上述问题将导致测试覆盖存在盲区,且无法形成自动化门禁闭环。
---
## 优点
1. **测试分层模型清晰**TEST_DESIGN.md 1.1 明确划分 Unit → Integration → E2E 三层STRATEGY.md 补充 Chaos Test结构合理。
2. **Mock 策略全面**:覆盖 Prometheus、 supply-api、token-runtime、通知渠道、PostgreSQL、Redis 等全部核心外部依赖工具选型合理sqlmock / miniredis / gock / httptest
3. **环境矩阵设计完整**Local Dev / CI / Sandbox / Staging / Production 五层环境各有明确的用途、数据特征和外部依赖策略。
4. **灰度 Phase 规划可落地**Phase 1~4 的验证内容与回归集范围明确,与 PRD 发布策略对应。
5. **发布门禁检查表8.1)覆盖关键风险点**:独立/集成双模式验证、沙盒验证、回滚演练、权限矩阵、端到端链路验证等 8 项全部列出。
6. **回归集分级合理**区分快速回归集9 条5-10 分钟与完整回归集43 条30-60 分钟),适合不同触发条件。
---
## 发现问题(按严重度分类)
### P0 — 阻塞级(必须修复,否则无法进入开发/提测)
| 编号 | 问题描述 | 影响 | 依据 |
|------|---------|------|------|
| P0-01 | **AC 负向测试用例大面积缺失**。12 个 AC 中至少 8 个AC-01/02/04/05/06/09/10/11在 CASES.md 与 TEST_DESIGN.md 中均无任何负向/异常输入用例。仅 AC-03、AC-08 有明确的 Negative 用例AC-12 有权限越界类负向用例。 | 无法验证系统在非法输入、边界越界、权限不足、数据异常等场景下的行为,存在生产缺陷逃逸风险。 | 审核标准 #1 |
| P0-02 | **CASES.md 遗漏异常流程 F-05~F-08**。PRD 明确定义 F-01~F-08 共 8 条异常流程CASES.md 仅覆盖 TC-E1~E4对应 F-01~F-04F-05审计满盘、F-06级联故障、F-07数据库全面中断、F-08看板计算超时完全缺失。 | 核心容灾与降级场景无测试用例兜底,与 PRD 6. 节要求不符。 | 审核标准 #2 |
| P0-03 | **CI 集成零配置**。STRATEGY.md 6. 仅文字描述"PR 提交时自动触发",未提供任何 CI 配置文件(如 .github/workflows/ci.yml、Pipeline 阶段定义、失败通知模板、覆盖率采集与阻断逻辑。 | 无法形成自动化质量门禁,所有覆盖率/通过率要求沦为纸面标准。 | 审核标准 #6 |
| P0-04 | **性能压测方法过于简略,无执行载体**。TEST_DESIGN.md 9.1 虽列出 k6 并发用户数,但未提供 k6 脚本、压测环境规格CPU/内存/DB 实例、数据量基准、P99 计算方式、持续时间。"单次告警触发计时"未说明计时起点/终点和采样次数。 | 性能基准无法复现和验证,灰度门禁中"性能基准测试通过"无法判定。 | 审核标准 #8 |
### P1 — 高优先级(强烈建议修复,否则提测后返工风险高)
| 编号 | 问题描述 | 影响 | 依据 |
|------|---------|------|------|
| P1-01 | **覆盖率门槛缺少验证机制**。文档多次声明 domain ≥70%、service/handler ≥80%,但未说明:使用 `go test -coverprofile` 还是第三方工具、CI 中如何解析并阻断未达标 PR、覆盖率报告存储位置、增量覆盖率是否校验。 | 覆盖率目标无法自动 enforce开发者可能随时跌破门槛。 | 审核标准 #4 |
| P1-02 | **混沌测试Chaos Test无具体用例设计**。STRATEGY.md 提到 chaos-mesh / 自定义脚本和三类故障(单机故障、网络分区、主从切换),但 TEST_DESIGN.md 与 CASES.md 中均未设计任何 Chaos 用例(无 Given-When-Then、无验证点、无预期行为。 | 混沌测试 layer 有名无实,无法验证系统韧性。 | 审核标准 #3 |
| P1-03 | **测试数据管理策略缺关键细节**。STRATEGY.md 提到 `test/fixtures/` 和"自洁"但未给出fixtures 目录结构规范、大数据量(如 10000 条审计日志)的生成脚本、敏感数据脱敏方法、不同测试并行时的数据隔离策略。 | 大数据量性能用例和 E2E 用例可能因数据准备不足而无法稳定执行。 | 审核标准 #7 |
| P1-04 | **灰度门禁缺少自动化判定脚本**。TEST_DESIGN.md 5.2 列出 6 项检查项,但均为人工勾选(`- [ ]`),未说明每项如何自动采集结果(如覆盖率报告解析、沙盒验证次数统计、安全扫描工具输出格式)。 | Phase 升级依赖人工审核,效率低且易遗漏。 | 审核标准 #5 |
| P1-05 | **安全扫描工具与阈值未指定**。灰度门禁和发布门禁均提到"安全扫描通过(无高危漏洞)"但未指定扫描工具Trivy / Snyk / Gosec、漏洞等级定义、扫描时机CI / 镜像构建 / 发布前)。 | 安全门禁无法执行。 | 审核标准 #5 |
| P1-06 | **E2E 测试缺少详细场景设计**。STRATEGY.md 提到"自定义 Go E2E 框架"和"前端流程测试",但 TEST_DESIGN.md / CASES.md 中无任何 E2E 级别的 Given-When-Then 用例(如完整链路:模拟指标异常 → 告警触发 → 通知发送 → 自愈执行 → 事件记录)。 | E2E 覆盖率无法评估。 | 审核标准 #3 |
### P2 — 一般优化(建议修复,提升可维护性)
| 编号 | 问题描述 | 影响 |
|------|---------|------|
| P2-01 | **用例编号风格不统一**。TEST_DESIGN.md 使用 `TC-01-01`CASES.md 使用 `TC-1.1`,同一项目内两种命名规范,易导致用例追溯混乱。 |
| P2-02 | **CASES.md TC-E2 与 PRD 描述不一致**。CASES.md 写"模拟 Webhook 8xx"PRD F-2 写"Webhook 8xx/5xx",遗漏 5xx 场景。 |
| P2-03 | **AC-06 自愈缺少负向/非法配置用例**。如:配置不存在的自愈动作类型、自愈脚本权限不足、沙盒模式未通过却尝试生产执行等。 |
| P2-04 | **AC-10 日志查询缺少负向用例**。如:超大时间范围查询、非法正则过滤、无权限访问其他服务日志等。 |
| P2-05 | **测试通过标准TEST_DESIGN.md 1.2)中"告警噪声率 ≤1%"和"自愈误触发 0 次"缺少测量方法**。未说明沙盒测试的样本量、统计周期、噪声率计算公式。 |
---
## 改进建议
### 立即行动(进入开发前必须完成)
1. **补齐 AC 负向用例**
- AC-01增加"未登录访问首页返回 401"、"非法时间范围参数返回 400"。
- AC-02增加"下钻不存在的 service 返回空结果/404"、"超大时间范围返回 413/截断"。
- AC-04增加"通知渠道全部失效时记录失败并触发内部告警"、"非法事件 ID 查询返回 404"。
- AC-05增加"聚合阈值设置为 0 或负数时的校验拒绝"。
- AC-06增加"沙盒未通过时禁止关联生产规则"、"自愈动作类型非法返回 400"。
- AC-09增加"容量主板数据源丢失时展示降级提示"。
- AC-10增加"导出超过 10000 条时返回 413 或分批"。
- AC-11增加"查询已清理数据返回空并提示保留策略"。
2. **在 CASES.md 中补全 F-05~F-08**
- TC-E5模拟审计磁盘满验证丢弃非关键字段/异步上报且业务不阻断。
- TC-E6模拟自愈切换导致新故障验证自动回退 + P0 升级。
- TC-E7模拟时序库全面中断验证控制台只读 + 告警引擎缓存运行。
- TC-E8模拟看板查询超时验证显示上次成功结果 + 时间戳标注。
3. **提供 CI 配置文件**
- 创建 `.github/workflows/ci.yml`(或对应平台配置),至少包含:
- Go 版本声明1.22+
- `go test -race -coverprofile=coverage.out ./...`
- 覆盖率解析步骤(如使用 `gocov` 或自定义脚本检查 domain ≥70%、service ≥80%
- 未达标时 PR 阻断exit 1
- 测试失败通知 TechLead / QA 的机制(如 Slack / 邮件 Webhook
- 每日定时 E2E / 每周 Chaos 的 workflow 文件
4. **输出可执行的性能压测资产**
- 提供 `test/perf/` 目录,包含:
- `dashboard_k6.js`50 并发首页加载压测脚本
- `drilldown_k6.js`20 并发下钻压测脚本
- `alert_latency_test.go`:告警触发到通知的计时单测(含重试统计)
- `PERF_ENV.md`压测环境规格、数据量基准、判定标准P99 计算方式、持续 5min
### 短期优化(提测前完成)
5. **建立覆盖率验证机制**
- 在 CI 中引入 `go tool cover -func=coverage.out` 解析按模块domain / service / handler分别校验阈值。
- 引入增量覆盖率检查(如 codecov / coveralls要求新增代码覆盖率 ≥80%。
6. **补充混沌测试用例**
- 在 TEST_DESIGN.md 中新增"混沌测试"章节,至少设计 3 条可执行用例:
- Chaos-01随机杀死一个服务 Pod验证告警引擎本地缓存持续运行且控制台进入只读。
- Chaos-02模拟 Redis 网络分区 30s验证告警抑制状态不丢失、恢复后不重复通知。
- Chaos-03模拟 PostgreSQL 主从切换,验证审计写入短暂失败后异步补写。
7. **完善测试数据管理规范**
- 创建 `test/fixtures/` 目录结构文档,规定 SQL / JSON / Go seed 三种数据注入方式。
- 为大数据量性能测试提供数据生成脚本(如 `generate_audit_logs.go` 生成 10000 条审计记录)。
- 明确并行测试隔离方案testcontainers 独立数据库 / 事务回滚 / 唯一 schema
8. **统一用例编号规范**
- 建议统一为 `TC-{AC}-{序号}`(如 `TC-01-01`),并同步修改 CASES.md。
---
## 审核结论
**当前状态REQUEST_CHANGES**
本文档在测试策略框架层面具备较好的完整性分层模型、Mock 策略、环境矩阵和发布门禁检查表已达到可评审水平。但由于 P0-01 ~ P0-04 四项阻塞级缺陷负向用例大面积缺失、异常流程遗漏、CI 零配置、性能压测无载体),**当前测试设计不足以支撑进入开发或提测阶段**。
建议研发团队优先补齐上述"立即行动"项,完成后提交 QA 复评。
---
> 报告生成路径:`/home/long/project/ai-ops/tech/QA_REVIEW_REPORT.md`

View File

@@ -0,0 +1,111 @@
## Security 审核报告
项目AI-Ops 智能运维系统
审核日期2026-05-11
审核范围HLD.md第 8 节、第 10.1 节、INTERFACE.md、PRD.md、000001_init_schema.up.sql、TEST_DESIGN.md
审核人Security Role
---
### 总体评级B
安全设计具备基本框架RBAC、审计日志、威胁建模等核心模块已有原则性设计但存在多项与 fail-closed 策略冲突的设计缺陷、权限边界模糊、以及缺乏可落地的实现细则。在进入开发前必须修复 P0/P1 项,否则生产环境存在越权操作、审计失效和自愈引擎被滥用的风险。
---
### 优点
1. 威胁建模已覆盖运维核心场景自愈误触发、告警洪泛、越权操作、审计失真、外部适配层滥用并映射到具体控制措施与验证要求HLD 10.1)。
2. 数据库层通过 BEFORE UPDATE/DELETE 触发器实现审计表 append-only配合 CHECK 约束限制 action/risk_level 枚举值基础防篡改机制存在migration SQL
3. RBAC 三角色权限矩阵在控制台层面有明确区分viewer/operator/admin并在响应头设计 `X-Permitted-Actions` 返回HLD 8.1)。
4. 自愈引擎引入沙盘模式dry-run和级联故障自动回退设计降低了自动化动作对生产环境的直接冲击HLD 3.3)。
5. 数据隔离在架构层面要求 tenant_id 过滤,并保留 Row Level SecurityRLS作为最后一道防线HLD 8.3)。
6. 测试设计将安全项纳入 CI 门禁权限越界、审计篡改、SQL 注入均有测试用例TEST_DESIGN.md 第 10 节)。
---
### 发现问题(按严重度 P0/P1/P2 分类)
#### P0 — 阻塞性风险(进入开发前必须修复)
| 编号 | 问题 | 证据 | 风险 |
|------|------|------|------|
| P0-001 | **审计写入失败时未阻断业务,与 fail-closed 策略直接冲突** | PRD F-5 明确写道:"审计日志存储满盘/写入失败 - 丢弃非关键字段或改为异步上报,不阻断业务操作"。HLD 10.2 和 TEST_DESIGN 8.1 虽声明"高风险操作审计失败即拒绝",但 PRD 的故障路径与之矛盾。 | 审计链路在降级场景下失效,无法保证"先写审计再执行业务",导致合规断裂和事后无法追责。 |
| P0-002 | **自愈引擎 invoke_script 缺少执行环境沙盘隔离** | HLD 3.3 定义 invoke_script 动作可"执行用户配置的程序化脚本",但文档中仅存在 dry-run 沙盘验证动作逻辑无任何关于脚本运行时隔离容器化、seccomp、资源限制、网络策略、文件系统隔离的设计。 | 攻击者或误配置可导致任意代码执行RCE直接控制生产环境或窃取密钥。 |
| P0-003 | **高风险变更二次确认可被 API 直接绕过** | HLD 3.5 和 10.1 将二次确认描述为"弹出二次确认窗口"UI 层面),但未在 INTERFACE.md 或 HLD 中设计 API 层的防绕过机制(如二次确认令牌、幂等键、管理员数字签名)。 | 攻击者通过直接调用 REST API 即可绕过前端确认,执行影响面 >50% 的高风险变更。 |
#### P1 — 高风险(必须在上线前修复)
| 编号 | 问题 | 证据 | 风险 |
|------|------|------|------|
| P1-001 | **审计防篡改机制无法抵御特权用户攻击** | migration SQL 中的触发器可被超级用户postgres或具有 TRIGGER/ALTER 权限的用户禁用或删除;缺少对 DDL 操作DROP TRIGGER、ALTER TABLE的审计无哈希链或数字签名。 | 拥有数据库高权限的内部人员或入侵者可静默抹除审计痕迹。 |
| P1-002 | **外部管理接口攻击面过大API Key 管理缺失** | HLD 7.1 指出 AI-Ops 通过 POST /internal/gateway/switch-route、throttle、restart 等接口直接控制 gateway。独立运行时使用"API Key 鉴权",但未描述 Key 的存储、轮换、最小权限、生命周期管理。 | 若 AI-Ops 服务被攻破,攻击者可一键切流、限流或重启实例,造成生产事故。 |
| P1-003 | **RBAC 缺少自愈动作与资源级权限控制** | HLD 8.1 RBAC 矩阵未包含"执行自愈动作"权限INTERFACE.md 3.2 的 POST /api/v1/ai-ops/healing/execute 未标注角色要求PRD AC-12 未限制 operator 是否可触发人工自愈。同时缺少同角色用户只能操作自己创建的资源的水平越权防护。 | operator 可能执行超出职责范围的自愈动作;用户 A 可修改/回滚用户 B 创建的规则。 |
| P1-004 | **敏感数据在配置表和审计日志中无加密存储设计** | ai_ops_channels.config 存储 Webhook URL 和密钥ai_ops_rules.healing_config 可能包含管理 API 凭据HLD 8.2 仅声明 Sanitizer 脱敏,无字段级加密或密钥托管设计。 | 数据库备份泄露、SQL 注入成功或内部人员越权查询即可直接获取明文密钥。 |
| P1-005 | **SQL 注入与 PromQL 注入缺少架构级强制约束** | TEST_DESIGN.md 有 SQL 注入测试项,但 HLD/INTERFACE 中未强制要求所有 SQL 必须使用参数化查询。threshold_value 支持 regex 类型,若该值被拼接进 PromQL 或 SQL存在注入风险。 | 攻击者通过构造恶意阈值规则,可能读取未授权数据或篡改时序查询。 |
#### P2 — 中等风险(建议修复)
| 编号 | 问题 | 证据 | 风险 |
|------|------|------|------|
| P2-001 | **威胁建模缺少 OWASP Top 10 系统性映射和 LLM/Gateway 特有风险** | HLD 10.1 的 5 个威胁场景覆盖运维故障较多,但未明确映射 A02、A05、A06、A07、A10。对于 LLM 网关场景,缺少对 Prompt Injection、Model DoS、SSRF 的专项分析。 | 安全测试覆盖不全,可能导致未知攻击面遗漏。 |
| P2-002 | **影响面计算单一,无法覆盖多种高风险场景** | HLD 3.5 仅通过"拒绝率 > 50%"判定高风险。未考虑告警阈值过度敏感导致的告警风暴、通知渠道误删导致的告警黑洞等。 | 真正的风险变更可能被误判为低风险,绕过二次确认。 |
| P2-003 | **/metrics 和 WebSocket 接口的鉴权与限流设计缺失** | /metrics 对外暴露WebSocket /ws/v1/ai-ops/alerts 未描述 JWT 验证、连接数限制、订阅权限校验。 | 潜在信息泄露和 DoS 攻击面。 |
| P2-004 | **错误码重复定义且 HTTP 状态码语义不一致** | INTERFACE.md 3.3 中 OPS_AUD_4101 出现两次OPS_AUD_4001 定义为"无权进行审计操作"却对应 403。 | 客户端错误处理混乱,增加集成方开发成本。 |
| P2-005 | **审计日志外键允许隐式修改审计记录** | migration SQL 中 parent_audit_id 使用 ON DELETE SET NULL。虽触发器阻止 DELETE on ai_ops_audits但如果 TRUNCATE 或超级用户绕过,子记录的 parent_audit_id 会被设为 NULL。 | 审计关联完整性受损,影响回滚追溯。 |
| P2-006 | **回滚操作自身缺少版本并发控制** | HLD 3.5 提到回滚前检查目标资源是否被后续修改覆盖(返回 4102但未明确回滚执行期间是否加乐观锁或分布式锁。 | 并发回滚与修改可能导致配置状态进一步损坏。 |
---
### 改进建议
1. **统一 fail-closed 策略,消除文档冲突**
- 修改 PRD F-5将"审计写入失败不阻断业务"改为"审计写入失败时,高风险操作必须拒绝执行;低风险操作可降级至本地队列缓存,但必须在 5 分钟内补写成功,否则触发 P1 内部告警"。
- 在 HLD 5.3 配置回滚流程和告警规则变更流程中,明确画出"先写审计表INSERT ai_ops_audits -> 获得 audit_id -> 执行业务 SQL -> 更新审计结果"的时序图。
2. **为 invoke_script 增加运行时沙盘**
- 采用 gVisor、Firecracker 或至少 Docker + seccomp + 只读根文件系统运行用户脚本。
- 限制:禁止访问环境变量 secrets、禁止出站网络除白名单外、CPU/内存硬限制、执行超时强制 kill。
- 脚本内容在保存前需经过静态安全扫描(如禁止 os.exec、net.Dial 等敏感调用)。
3. **在 API 层实现不可绕过的二次确认机制**
- 对影响面 > 50% 的变更,后端生成一次性 confirmation_token绑定用户、资源、变更哈希、TTL=5min前端弹窗只是展示层。
- 执行高风险 API 时必须在请求头中携带有效的 confirmation_token否则返回需要二次确认。
- 该机制同时适用于回滚操作。
4. **加固审计防篡改能力**
- 引入审计日志哈希链:每条新记录包含 previous_hash = SHA256(上一条记录的 id + created_at + 内容),应用层计算并存储。
- 对 ai_ops_audits 启用 pgaudit 扩展,记录所有 DDL 和超级用户操作。
- 定期(每日)将审计日志摘要写入不可篡改的外部存储(如 WORM 存储或独立只读实例)。
- 将 parent_audit_id 的 ON DELETE SET NULL 改为 ON DELETE RESTRICT。
5. **细化 RBAC 并增加资源级鉴权**
- 扩展 RBAC 矩阵:增加 healing:execute、channel:manage、capacity:threshold_write 等细粒度权限。
- 增加资源所有者概念:用户只能修改/删除自己创建的 rules/channelsadmin 可绕过此限制。
- 在独立运行模式下为 ai_ops_roles 增加权限位字段bitmask避免硬编码角色逻辑。
6. **强制参数化查询与注入防护**
- 在 HLD 技术约束中增加条款:所有 SQL 操作必须使用 pgx 参数化查询,禁止字符串拼接 SQL。所有 PromQL 操作必须经过白名单校验。
- threshold_type = 'regex' 的场景regex 值只应用于应用层阈值评估,不应作为 SQL LIKE 或 PromQL 的查询条件。
7. **加密存储敏感配置**
- ai_ops_channels.config 和 ai_ops_rules.healing_config 中的敏感字段在写入前使用 AES-256-GCM 加密,密钥由外部 KMS/Vault 托管。
- 审计日志的 before_state / after_state 在序列化前由 Sanitizer 递归扫描并替换敏感值为 "***REDACTED***",确保 JSONB 中洼套的密钥均被脱敏。
8. **缩小外部接口攻击面**
- 为 /internal/gateway/* 接口引入短期有效的 mTLS 或至少 HMAC-SHA256 签名验证API Key 存储在内存加密空间(非环境变量明文)。
- WebSocket 接口实现 JWT Token 验证和每 IP 最大连接数限制。
- /metrics 端点增加 IP 白名单或基础鉴权,避免暴露过多内部元数据。
---
### 门禁检查清单(进入开发前必须通过)
- [ ] PRD F-5 修正审计写入失败时高风险操作必须拒绝fail-closed
- [ ] HLD 补充二次确认 API 防绕过机制设计。
- [ ] HLD 补充 invoke_script 运行时沙盘隔离方案。
- [ ] RBAC 矩阵增加自愈执行、通知渠道、容量阈值等细粒度权限。
- [ ] 审计触发器增加 pgaudit DDL 监控 + 哈希链设计。
- [ ] 数据库层强制参数化查询约束落地到 HLD 技术约束中。
- [ ] 敏感配置字段加密存储方案确认。
- [ ] 错误码重复定义问题修复并与前端对齐。

378
tech/TEST_DESIGN.md Normal file
View File

@@ -0,0 +1,378 @@
# AI-Ops 测试设计方案
> 版本v1.0
> 日期2026-04-27
> 状态:初稿
> 覆盖AC-01 ~ AC-12、异常流程 F-01 ~ F-08、边缘流程 G ~ I
---
## 1. 测试策略
### 1.1 测试分层模型
```
┌─────────────────────────────────────────────────┐
│ E2E Tests (黑盒) │
│ 场景:用户操作链路 + 系统集成验证 │
│ 工具Go test + k6 / 自制 E2E runner │
│ 覆盖率目标:每个主流程 ≥ 1 条 │
└─────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ Integration Tests (灰盒) │
│ 场景Service 间协作、数据库读写、外部 API Mock │
│ 工具Go test + testify + sqlmock + httptest │
│ 覆盖率门槛service ≥ 80%, handler ≥ 80% │
└─────────────────────────────────────────────────┘
┌─────────────────────────────────────────────────┐
│ Unit Tests (白盒) │
│ 场景:单个函数/方法逻辑、边界条件、错误分支 │
│ 工具Go test + testify + gomock │
│ 覆盖率门槛domain ≥ 70% │
└─────────────────────────────────────────────────┘
```
### 1.2 测试通过标准
| 维度 | 标准 |
|------|------|
| 覆盖率 | domain ≥ 70%, service/handler ≥ 80% |
| 主流程 | AC-01 ~ AC-12 全部有至少 1 条通过测试 |
| 异常流程 | F-01 ~ F-08 全部有至少 1 条验证测试 |
| 边缘流程 | G、H、I 全部有至少 1 条验证测试 |
| 告警噪声率 | 沙盒测试中误报率 ≤ 1%,超过则 CI 失败 |
| 自愈误触发 | 沙盒测试中 0 次误触发,否则 CI 失败 |
### 1.3 测试环境矩阵
| 环境 | 用途 | 数据特征 | 外部依赖 |
|------|------|---------|---------|
| **Local Dev** | 开发者快速验证 | Mock 数据 | Mock 所有外部服务 |
| **CI** | PR Merge 门禁 | Mock 数据 | Mock 所有外部服务 |
| **Sandbox** | 沙盒验证(自愈规则) | 生产数据脱敏副本 | Mock + 部分真实依赖 |
| **Staging** | 上线前全流程验证 | 生产数据脱敏副本 | 全真实依赖 |
| **Production** | 灰度上线 | 真实数据 | 全真实依赖 |
---
## 2. Mock 策略
### 2.1 外部依赖 Mock
| 依赖 | Mock 方案 | 工具 |
|------|---------|------|
| **Prometheus / 时序数据库** | 嵌入式 mock server返回预置指标数据 | httptest + 自定义 mock |
| **gateway/internal/metrics** | Mock HTTP handler返回 JSON 指标 | gock / httptest |
| **supply-api/ 供应商健康接口** | Mock 返回 200/401/429/500 | gock |
| **platform-token-runtime/ 运行时状态接口** | Mock 返回正常/异常状态 | gock |
| **通知渠道Webhook/邮件/飞书)** | Mock server 接收并验证请求格式 | httptest |
| **PostgreSQL** | sqlmock 拦截 SQL验证查询正确性 | github.com/DATA-DOG/go-sqlmock |
| **Redis** | miniredis 内存模拟 | github.com/alicebob/miniredis |
### 2.2 Mock 分层
```
Production 依赖:
gateway metrics API ──→ supply-api 供应商接口 ──→ token-runtime 状态接口
│ │ │
▼ ▼ ▼
Mock (CI/Local): Mock (CI/Local): Mock (CI/Local):
MetricsMockServer → SupplierMockServer → RuntimeMockServer
```
---
## 3. 测试用例矩阵(按 AC 编号)
### AC-01 实时监控看板
| 用例 ID | 描述 | 类型 | 覆盖条件 |
|---------|------|------|---------|
| TC-01-01 | 首页加载时间 <2s | Performance | Given 用户登录 When 访问首页 Then 响应时间 ≤2s |
| TC-01-02 | 首页显示 6 个指标 | Happy Path | Given 系统运行 When 首页加载 Then 显示 QPS/延迟/P99/错误率/供应商数/告警数 |
| TC-01-03 | 指标卡片 15s 内刷新 | Functional | Given 指标更新 When 数据推送 Then 15s 内页面刷新 |
| TC-01-04 | 无数据时看板展示"无数据" | Edge | Given 指标源断开 When 首页加载 Then 不显示过期数据 |
| TC-01-NEG-01 | 未登录访问首页返回 401 | Negative | Given 未登录 When 访问首页 Then 返回 401 |
| TC-01-NEG-02 | 非法时间范围参数返回 400 | Negative | Given 非法时间范围参数 When 请求指标 Then 返回 400 |
### AC-02 指标下钻
| 用例 ID | 描述 | 类型 | 覆盖条件 |
|---------|------|------|---------|
| TC-02-01 | 下钻显示 1 小时趋势图 | Happy Path | Given 点击指标卡片 When 下钻 Then 显示 60min 趋势 |
| TC-02-02 | 按 service/path/supplier 维度分割 | Functional | Given 趋势图 When 按 supplier 下钻 Then 正确分割 |
| TC-02-03 | 下钻查询 <3s | Performance | Given 大数据量 When 执行下钻 Then 响应 <3s |
| TC-02-04 | 无数据范围返回空图表 | Edge | Given 无数据 When 下钻 Then 显示空图表而非报错 |
| TC-02-NEG-01 | 下钻不存在的 service 返回空结果/404 | Negative | Given 不存在的 service When 下钻 Then 返回空结果或 404 |
| TC-02-NEG-02 | 超大时间范围返回 413/截断 | Negative | Given 超大时间范围 When 下钻 Then 返回 413 或自动截断 |
### AC-03 告警规则配置
| 用例 ID | 描述 | 类型 | 覆盖条件 |
|---------|------|------|---------|
| TC-03-01 | 创建告警规则 | Happy Path | Given 登录管理员 When 创建规则 Then 规则保存成功 |
| TC-03-02 | 规则字段完整性校验 | Negative | Given 缺少必填字段 When 创建规则 Then 返回 400 |
| TC-03-03 | 规则变更 30s 内生效 | Functional | Given 规则已创建 When 修改阈值 Then 30s 后新规则生效 |
| TC-03-04 | 支持 50 条规则并发运行 | Load | Given 50 条规则 When 同时触发 Then 全部正确评估 |
| TC-03-05 | 规则编辑/禁用/删除 | Functional | Given 规则存在 When 编辑/禁用/删除 Then 状态正确变更 |
### AC-04 告警通知触达
| 用例 ID | 描述 | 类型 | 覆盖条件 |
|---------|------|------|---------|
| TC-04-01 | P0/P1 告警 30s 内通知 | Performance | Given P1 告警触发 When 通知发送 Then ≤30s 到达 |
| TC-04-02 | P2 告警 120s 内通知 | Performance | Given P2 告警触发 When 通知发送 Then ≤120s 到达 |
| TC-04-03 | 至少 2 种通知渠道 | Functional | Given 告警触发 When 发送 Then 飞书和邮件均收到 |
| TC-04-04 | 通知内容完整性 | Functional | Given 告警发送 Then 包含级别/规则名/时间/当前值/阈值/事件ID/链接 |
| TC-04-05 | Webhook 通知失败后自动切换 | Resilience | Given Webhook 发送失败 When 告警触发 Then 自动切换至邮件 |
| TC-04-NEG-01 | 通知渠道全部失效时记录失败并触发内部告警 | Negative | Given 所有通知渠道失效 When 告警触发 Then 记录失败并触发内部 P2 告警 |
| TC-04-NEG-02 | 非法事件 ID 查询返回 404 | Negative | Given 非法事件 ID When 查询事件 Then 返回 404 |
### AC-05 告警聚合与抑制
| 用例 ID | 描述 | 类型 | 覆盖条件 |
|---------|------|------|---------|
| TC-05-01 | 1 分钟内 >20 条告警触发聚合 | Functional | Given 同一资源 1min 内触发 25 条 When 聚合 Then 生成 1 条集群告警 |
| TC-05-02 | 集群告警包含累计数量和规则列表 | Functional | Given 集群告警生成 Then 内容包含数量≥20 和规则列表 |
| TC-05-03 | 5 分钟抑制期内同一规则不重复通知 | Functional | Given 告警已发送 When 5min 内再次触发 Then 不重复通知 |
| TC-05-04 | 级别升级时抑制解除 | Functional | Given P2 告警抑制中 When 升级为 P1 Then 立即通知 |
| TC-05-NEG-01 | 聚合阈值设置为 0 或负数时的校验拒绝 | Negative | Given 阈值为 0 或负数 When 创建/编辑规则 Then 返回 400 并拒绝 |
### AC-06 自动自愈
| 用例 ID | 描述 | 类型 | 覆盖条件 |
|---------|------|------|---------|
| TC-06-01 | 自愈动作 60s 内完成 | Performance | Given 自愈规则触发 When 执行切换路由 Then ≤60s 完成含重试 |
| TC-06-02 | 自愈成功记录事件 | Happy Path | Given 自愈执行成功 When 完成 Then 事件记录 success |
| TC-06-03 | 自愈失败升级 P0 人工告警 | Functional | Given 自愈重试均失败 When 停止 Then 升级 P0 通知 |
| TC-06-04 | 无自愈规则时仅通知 | Functional | Given 告警无自愈配置 When 触发 Then 仅发送通知 |
| TC-06-05 | 沙盒模式:自愈不生效 | Resilience | Given 沙盒模式 When 自愈触发 Then 仅记录,不实际执行 |
| TC-06-06 | 自愈后 2min 评估是否解除 | Functional | Given 自愈执行 When 2min 后 Then 评估条件是否满足 |
| TC-06-07 | 自愈级联失败回退 | Functional | Given 自愈切换导致新故障 When 检测到 Then 回退并升级 |
| TC-06-NEG-01 | 沙盒未通过时禁止关联生产规则 | Negative | Given 沙盒测试未通过 When 关联生产告警规则 Then 返回 400 并拒绝 |
| TC-06-NEG-02 | 自愈动作类型非法返回 400 | Negative | Given 非法自愈动作类型 When 配置规则 Then 返回 400 |
### AC-07 配置审计日志
| 用例 ID | 描述 | 类型 | 覆盖条件 |
|---------|------|------|---------|
| TC-07-01 | 配置变更 1s 内生成审计记录 | Performance | Given 执行配置变更 When 完成 Then ≤1s 审计记录存在 |
| TC-07-02 | 审计字段完整性 | Functional | Given 审计记录 When 查询 Then 包含全部 10 个字段 |
| TC-07-03 | 审计日志不可篡改 | Security | Given 审计记录 When 尝试修改 Then 数据库层拒绝或被检测 |
| TC-07-04 | 审计日志 90 天保留 | Functional | Given 审计数据 91 天 When 查询 Then 91 天前记录不存在(新数据已清理) |
| TC-07-05 | 审计查询 <3s | Performance | Given 10000 条审计记录 When 按条件查询 Then <3s |
### AC-08 配置回滚
| 用例 ID | 描述 | 类型 | 覆盖条件 |
|---------|------|------|---------|
| TC-08-01 | 正常回滚 <60s | Performance | Given 审计记录存在 When 执行回滚 Then ≤60s 完成 |
| TC-08-02 | 回滚前显示子资源影响列表 | Functional | Given 回滚操作 When 执行前 Then 显示将被覆盖的子资源 |
| TC-08-03 | 回滚生成新审计记录 | Functional | Given 回滚执行 When 完成 Then 新审计记录关联原始 ID |
| TC-08-04 | 目标不存在时返回 OPS_AUD_4101 | Negative | Given 目标已被删除 When 执行回滚 Then 返回错误码且不执行 |
| TC-08-05 | 回滚失败不静默 | Resilience | Given 回滚执行失败 When 完成 Then 返回错误码并通知 |
### AC-09 容量主板
| 用例 ID | 描述 | 类型 | 覆盖条件 |
|---------|------|------|---------|
| TC-09-01 | 显示 7 天趋势数据 | Functional | Given 容量主板 When 加载 Then 显示 7 天 Token/QPS/延迟趋势 |
| TC-09-02 | 负载等级标注(正常/警告/过载) | Functional | Given 负载数据 When 展示 Then 正确标注等级 |
| TC-09-03 | 预测触达上限时间 | Functional | Given 增长率数据 When 计算 Then 显示预测时间(仅供参考) |
| TC-09-NEG-01 | 容量主板数据源丢失时展示降级提示 | Negative | Given 时序库断开 When 访问容量主板 Then 显示降级提示而非错误 |
### AC-10 日志/指标查询
| 用例 ID | 描述 | 类型 | 覆盖条件 |
|---------|------|------|---------|
| TC-10-01 | 按多维度筛选日志 | Functional | Given 查询条件 When 执行 Then 正确过滤 |
| TC-10-02 | 日志查询 <3s | Performance | Given 10000 条日志 When 查询 Then <3s |
| TC-10-03 | CSV 导出 10000 条 | Load | Given 查询结果 When 导出 Then 正确生成 CSV |
| TC-10-04 | 分页查询第 2 页 | Functional | Given 分页请求 When 获取第 2 页 Then 返回正确偏移 |
| TC-10-NEG-01 | 导出超过 10000 条时返回 413 或分批 | Negative | Given 查询结果 >10000 条 When 导出 CSV Then 返回 413 或自动分批导出 |
### AC-11 监控数据保存
| 用例 ID | 描述 | 类型 | 覆盖条件 |
|---------|------|------|---------|
| TC-11-01 | 原始数据保留 ≥7 天 | Functional | Given 8 天前数据 When 查询 Then 7 天内数据存在 |
| TC-11-02 | 分钟级聚合保留 ≥30 天 | Functional | Given 31 天前数据 When 查询 Then 31 天前不存在 |
| TC-11-03 | 小时级聚合保留 ≥90 天 | Functional | Given 91 天前数据 When 查询 Then 不存在 |
| TC-11-NEG-01 | 查询已清理数据返回空并提示保留策略 | Negative | Given 查询已清理时段 When 查询原始数据 Then 返回空并提示保留策略 |
### AC-12 角色与权限
| 用例 ID | 描述 | 类型 | 覆盖条件 |
|---------|------|------|---------|
| TC-12-01 | 查看者只能读不可写 | Security | Given 查看者 When 尝试写操作 Then 返回 403 |
| TC-12-02 | 运维人员不可执行回滚 | Security | Given 运维人员 When 执行回滚 Then 返回 403 |
| TC-12-03 | 管理员可执行所有操作 | Functional | Given 管理员 When 执行任意操作 Then 成功 |
---
## 4. 异常流程测试F-01 ~ F-08
| 用例 ID | 异常场景 | 验证点 | 预期行为 |
|---------|---------|-------|---------|
| TF-01 | 自愈动作重试均失败 | P0 人工告警触发 | 10s 内重试 1 次,失败后立即升级 P0 电话/短信 |
| TF-02 | 通知渠道失效Webhook 5xx | 备用渠道切换 | 记录失败,使用邮件→飞书→短信 三次切换 |
| TF-03 | 回滚目标已不存在 | OPS_AUD_4101 | 返回错误码,运营手动修复 |
| TF-04 | 指标采集器 5min 无数据 | 数据源丢失标识 | 控制台显示丢失标识,触发 P2 内部告警 |
| TF-05 | 审计日志存储满盘 | 降级不阻断业务 | 丢弃非关键字段或异步上报,业务操作继续 |
| TF-06 | 自愈形成级联故障 | 回退并升级 | 自动恢复上一步,升级人工告警,立即电话通知 |
| TF-07 | 监控数据库全面中断 | 只读/降级模式 | 控制台只读,告警引擎本地缓存继续运行 |
| TF-08 | 实时看板指标计算超时 | 显示上次结果 | 显示上次成功结果并标注时间戳 |
---
## 5. 灰度发布验证计划
### 5.1 各 Phase 验证内容
| Phase | 验证内容 | 通过标准 | 回归集 |
|-------|---------|---------|--------|
| **Phase 1** | 监控看板 + 日志查询 | AC-01, AC-02, AC-10, AC-11 全部通过 | 无历史功能 |
| **Phase 2** | 告警规则 + 通知渠道 | AC-03, AC-04, AC-05 全部通过 | Phase 1 全量 |
| **Phase 3** | 自愈引擎 + 审计回滚 | AC-06, AC-07, AC-08 全部通过 + 沙盒 10 次无误触发 | Phase 1+2 全量 |
| **Phase 4** | 容量主板 | AC-09 全部通过 | Phase 1+2+3 全量 |
### 5.2 灰度门禁检查项
每次 Phase 升级前必须全部通过:
- [ ] 所有 AC 测试用例 100% 通过
- [ ] 单元测试覆盖率达标domain ≥70%, service ≥80%
- [ ] 自愈沙盒验证 ≥10 次无误触发
- [ ] 回滚演练(至少 3 个资源类型)成功
- [ ] 性能基准测试通过(响应时间符合 AC 要求)
- [ ] 安全扫描通过(无高危漏洞)
---
## 6. 回归测试集
### 6.1 快速回归集(每次 PR
```
TC-01-01, TC-01-02, TC-03-01, TC-03-03, TC-04-01, TC-07-01, TC-07-02, TC-12-01, TC-12-03
共 9 条,约 5-10 分钟
```
### 6.2 完整回归集(每次 Phase 升级)
```
TC-01-01 ~ TC-01-04, TC-01-NEG-01, TC-01-NEG-02
TC-02-01 ~ TC-02-04, TC-02-NEG-01, TC-02-NEG-02
TC-03-01 ~ TC-03-05
TC-04-01 ~ TC-04-05, TC-04-NEG-01, TC-04-NEG-02
TC-05-01 ~ TC-05-04, TC-05-NEG-01
TC-06-01 ~ TC-06-07, TC-06-NEG-01, TC-06-NEG-02
TC-07-01 ~ TC-07-05
TC-08-01 ~ TC-08-05
TC-09-01 ~ TC-09-03, TC-09-NEG-01
TC-10-01 ~ TC-10-04, TC-10-NEG-01
TC-11-01 ~ TC-11-03, TC-11-NEG-01
TC-12-01 ~ TC-12-03
TF-01 ~ TF-08
共 53 条,约 30-60 分钟
```
---
## 7. 技术栈与集成约束验证
### 7.1 统一技术栈与双运行模式验证
| 用例 ID | 描述 | 类型 | 验证条件 |
|---------|------|------|---------|
| TOPS-RUN-01 | 独立运行模式启动 | Happy Path | Given 独立 `config.yaml` 与独立数据库/Redis/时序库 When 启动 `cmd/ai-ops/main.go` Then `/actuator/health/ready` 返回 200`/api/v1/ai-ops/*` 可访问 |
| TOPS-RUN-02 | 集成运行模式挂载 | Integration | Given gateway 或 supply-api 主进程加载 `IntegrationPlugin` When 启动 Then `/internal/ai-ops/*` 路由、后台 worker、健康检查挂载成功 |
| TOPS-RUN-03 | 配置分离加载 | Functional | Given 独立模式与集成模式分别启动 When 读取配置 Then 独立模式仅使用自身配置,集成模式正确合并主项目配置 |
| TOPS-RUN-04 | 数据库前缀隔离 | Structural | Given 执行迁移 When 检查 schema Then 仅创建 `ai_ops_` 前缀表 |
### 7.2 独立运行与集成运行验证
### 7.3 IntegrationPlugin 与模块挂载验证
| 用例 ID | 描述 | 类型 | 验证条件 |
|---------|------|------|---------|
| TOPS-PLG-01 | IntegrationPlugin 注册路由与健康检查 | Integration | Given 集成模式 When 插件注册 Then 监控、告警、日志、审计、健康检查路由挂载成功 |
| TOPS-PLG-02 | 模块开关生效 | Functional | Given `enabled_modules` 关闭某模块 When 启动 Then 对应路由/后台任务不注册,其他模块不受影响 |
| TOPS-PLG-03 | 集成模式共享资源 | Integration | Given 主进程注入共享 DB/Redis/logger/metrics client When 插件启动 Then 使用共享资源且不重复初始化冲突依赖 |
### 7.3 OpenAPI 契约验证
| 用例 ID | 描述 | 类型 | 验证条件 |
|---------|------|------|---------|
| TOPS-OAS-01 | OpenAPI 文档可访问 | Functional | Given 服务启动 When 请求 `/openapi.json``/docs` Then 返回 200 且包含监控、告警、自愈、审计、日志查询接口 |
| TOPS-OAS-02 | 路由与 OpenAPI 一致 | Contract | Given 导出的 OpenAPI 文档 When 对照 HTTP 路由 Then 请求/响应/错误码与实现一致,无缺失公开接口 |
| TOPS-OAS-03 | 集成前缀可配置 | Contract | Given 集成模式配置内部前缀 When 导出文档 Then 文档反映 `/internal/ai-ops/` 前缀或明确区分外部/内部暴露面 |
### 7.4 NewAPI / Sub2API 适配层验证
| 用例 ID | 描述 | 类型 | 验证条件 |
|---------|------|------|---------|
| TOPS-ADP-01 | `/metrics` 采集适配 | Contract | Given NewAPI/Sub2API 通过 Prometheus scrape 拉取指标 When 调用 `/metrics` Then 指标命名、label、采样频率满足契约 |
| TOPS-ADP-02 | 告警回调适配 | Integration | Given 外部系统配置 Webhook 回调 When 告警触发 Then 回调内容完整、签名正确、失败可重试 |
| TOPS-ADP-03 | 自愈脚本调用外部管理 API | Integration | Given 自愈动作触发程序化脚本 When 通过适配层调用 NewAPI/Sub2API Then 鉴权、错误码映射、回退逻辑符合设计 |
---
## 8. 发布门禁与阶段结论
### 8.1 发布门禁检查表
以下门禁项全部通过前,不得进入生产交付:
- [ ] 独立运行与集成运行模式均完成启动验证路由、worker、健康检查真实挂载
- [ ] `BuildServer` / `BuildRuntime` 中条件能力已显式接入,而非仅存在定义
- [ ] OpenAPI、`/metrics`、Webhook、管理 API 的鉴权与字段边界合同测试通过
- [ ] 自愈动作均完成沙盒验证、快照记录与回滚演练
- [ ] 审计日志保证先写审计再执行业务,高风险操作审计失败即拒绝
- [ ] viewer / operator / admin 三类角色权限矩阵验证通过
- [ ] 告警洪泛、自愈误触发、时序库中断、通知渠道失效四类高风险回归全部通过
- [ ] 至少一条真实故障检测 → 告警 → 通知/回滚链路完成端到端验证
### 8.2 阶段门控结论
**当前结论REQUEST_CHANGES已转化为具体行动项见 HLD 10.2 节)**
**进入开发/实现前必须补齐:**
- [ ] 将 HLD 中的威胁建模点全部下沉为可执行测试与阻断项(每个威胁场景必须有对应 CI 阻断测试用例)。
- [ ] 为"定义 → 装配 → 调用 → 入口"四层链路补充 QA 检查要求,重点覆盖自愈、告警、审计、权限。
- [ ] 分别给出独立模式与集成模式的最小验证命令、预期输出与失败判定。
- [ ] 高风险变更必须 fail-closed影响面 > 50% 的变更在审计写入失败时必须拒绝执行。
**阻断条件(任一触发则不得进入开发):**
- 高风险动作没有沙盒/回滚闭环。
- 审计不能证明先写后执行业务。
- 关键能力只存在接口声明,未真实接入运行主链路。
- HLD 门控 8.1 中任意一项未通过。
---
## 9. 性能测试
### 9.1 性能基准
| 指标 | 目标值 | 压测方法 |
|------|-------|---------|
| 首页加载 | <2s (P99) | k6 并发 50 用户 |
| 告警触发到通知 | P0/P1 <30s, P2 <120s | 单次告警触发计时 |
| 下钻查询 | <3s (P99) | k6 并发 20 用户 |
| 审计查询 | <3s (P99) | 10000 条数据下查询 |
| 配置回滚 | <60s (P99) | 单次回滚计时 |
| 支持并发告警规则 | ≥50 条同时评估 | 并发注入 50 条告警数据 |
---
## 10. 安全测试
| 测试项 | 方法 | 验证点 |
|-------|------|-------|
| 权限越界 | 使用低权限 Token 尝试高权限操作 | 返回 403 |
| 审计日志篡改 | 尝试 UPDATE/DELETE 审计表 | 操作被拒绝或被检测 |
| SQL 注入 | 输入 `' OR 1=1 --` 等 | 参数化查询无注入 |
| 告警信息泄露 | 跨用户查询告警 | 无数据泄露 |
| 高风险变更未二次确认 | 提交影响 90% 流量的变更 | 变更被标记待确认 |

View File

@@ -0,0 +1,111 @@
## TechLead 审核报告 — AI-Ops 智能运维系统
审核日期2026-05-11
审核范围HLD.md、INTERFACE.md、DEPLOYMENT.md、000001_init_schema.up.sql
审核人TechLead
---
### 总体评级B
架构方向正确核心设计审计防篡改、沙盒自愈、DualCache、独立/集成双模式有成熟模式支撑。但三份文档之间存在多处接口命名和路径不一致ER 图与 migration 存在表缺失IntegrationPlugin 未定义接口,这些问题必须在进入开发前修复。
---
### 优点
1. 技术选型有明确决策理由和备选方案Prometheus vs VictoriaMetrics、DualCache、CustomBatchLogger降低未来换型风险。
2. 核心业务指标均有量化目标和验证方式MTTR<10min、噪声率<5%、覆盖率>=60%),便于 QA 建立阻断测试。
3. 审计设计采用 append-only + 数据库触发器防篡改,符合合规和故障定责要求。
4. 安全设计覆盖 RBAC、敏感字段脱敏、Row Level Security 可选方案,数据隔离意识到位。
5. 风险分析包含威胁建模和六条具体风险项,并给出了缓解策略。
6. 支持独立运行与集成运行两种模式,且 schema 强制使用 `ai_ops_` 前缀,避免与主项目冲突。
7. 借鉴 LiteLLM 的 CustomBatchLogger、DualCache、DigestEntry 等模式,降低实现不确定性。
---
### 发现问题(按严重度分类)
#### P0 — 阻断开发
| 编号 | 问题描述 | 影响 | 位置 |
|------|---------|------|------|
| P0-1 | HLD 与 INTERFACE 外部集成接口定义严重不一致。gateway/HLD 写 `POST /internal/gateway/throttle``/switch-route``/restart`INTERFACE 写 `POST /internal/gateway/routes`。supply-api/HLD 写 `/internal/suppliers/health``/audit/events``/usage/token-stats`INTERFACE 写 `/internal/supply/accounts/health``/internal/supply/audit/schema`。token-runtime/HLD 写 `/internal/tokens/status`INTERFACE 写 `/internal/runtime/token-usage`。 | 开发团队无法确定真实调用契约,集成测试无法编写,联调必失败。 | HLD §7 / INTERFACE §2 |
| P0-2 | HLD ER 图§4.1)中出现 `ai_ops_events``ai_ops_notifys``ai_ops_configs``ai_ops_snapshots` 四张表,但 HLD §4.2 表结构、INTERFACE、migration SQL 中均完全缺失。 | 数据模型不完整,核心流程(通知、快照、配置版本)无法落地。 | HLD §4.1 vs §4.2 / migration |
| P0-3 | 自愈动作类型命名不一致。HLD §3.3 定义 `switch_route``restart_instance``isolate_node`INTERFACE §1.3 HealingAction.Type 注释写 `restart_service switch_provider throttle isolate_node`。 | 同一概念多个命名导致存储序列化、API 校验、前端枚举全部混乱。 | HLD §3.3 / INTERFACE §1.3 |
| P0-4 | 集成运行模式的核心契约 `IntegrationPlugin` 未在任何文档中定义 Go interface。HLD 仅文字描述“通过 IntegrationPlugin 将检查逻辑注入到主程序的健康检查中”,但没有接口方法、生命周期、注册方式。 | 集成模式无法编码实现,也无法做 CI 阻断检查HLD §10.2 要求 BuildServer/BuildRuntime 显式挂载约束落实为 CI 检查,但无接口无法执行)。 | HLD §1.3 / §3.2 / §7 / §10.2 |
#### P1 — 必须修复
| 编号 | 问题描述 | 影响 | 位置 |
|------|---------|------|------|
| P1-5 | DEPLOYMENT §1.1 写“AI-Ops API Server x 2 (主备)”,但 §4.2 写“负载均衡自动移除,剩余节点继续服务”。主备模式下备机不处理请求,与负载均衡多活逻辑矛盾。 | 部署架构描述混乱SRE 无法按文档实施。 | DEPLOYMENT §1.1 / §4.2 |
| P1-6 | DEPLOYMENT §3.2 启动顺序让 Worker 执行 migration。若 Worker 为多副本,同时启动会导致并发 migration 冲突(锁竞争或重复执行)。 | 可能导致数据库状态损坏或启动失败。 | DEPLOYMENT §3.2 |
| P1-7 | HLD §8.1 提到“系统自带角色表 `ai_ops_roles`”,但 HLD §4.2 和 migration 中均无该表定义。 | RBAC 无法落地。 | HLD §8.1 vs migration |
| P1-8 | HLD §3.3 级联故障防护要求“记录当前状态快照(包含相关配置版本号)”,但无 `ai_ops_snapshots` 表结构。P0-2 已提,此处强调其业务必要性。 | 自愈回退和级联故障检测缺少数据支撑。 | HLD §3.3 |
| P1-9 | 告警聚合流程HLD §5.2)定义了聚合触发条件(>20条/60s但未定义聚合告警如何解除、子告警状态如何同步到父告警、聚合告警 resolved 后子告警是否自动 resolved。 | 告警状态机不完整,可能导致聚合告警永久挂起。 | HLD §5.2 |
| P1-10 | 性能目标“>= 50 条规则 / 15s”对于实时告警场景仅约 3.3 条规则/秒,未说明规则评估是否支持水平分片并行。若规则数增长到 200 条,单实例评估可能超时。 | 扩展性设计停留在文字,未给出分片策略和负载均衡方案。 | HLD §9.1 / §9.2 |
#### P2 — 建议优化
| 编号 | 问题描述 | 影响 | 位置 |
|------|---------|------|------|
| P2-11 | INTERFACE §3.3 错误码列表中 `OPS_AUD_4001`403 无权)与 `OPS_AUD_4101`400 回滚目标不存在)排版紧邻,且 `OPS_AUD_4101` 重复出现两次,易混淆。 | 错误码使用方容易误用。 | INTERFACE §3.3 |
| P2-12 | migration 中 `ai_ops_metrics_p` 仅创建 DEFAULT 分区,未建立按天 RANGE 分区,也未实现“自动删除 > 7 天的分区”。pg_partman 仅为注释。 | 时序缓存表会随着数据增长性能急剧下降,且无法自动清理。 | migration §6 |
| P2-13 | WebSocket 接口INTERFACE §3.4)缺少鉴权机制说明。告警数据为敏感生产信息,公开 WebSocket 无鉴权存在数据泄露风险。 | 安全合规风险。 | INTERFACE §3.4 |
| P2-14 | Graceful ShutdownDEPLOYMENT §3.2)未说明 WebSocket 长连接的关闭策略。若仅关闭 HTTP serverWebSocket 客户端可能异常断连。 | 用户体验和监控准确性下降。 | DEPLOYMENT §3.2 |
| P2-15 | HLD §9.3 存储估算假设 Prometheus 每个样本 8 bytes实际 Prometheus TSDB 包含时间戳、变长标签、chunk 元数据等,真实存储远高于此。按此估算生产磁盘规划可能不足。 | 生产环境磁盘空间不足风险。 | HLD §9.3 |
---
### 改进建议
1. **统一三文档外部集成契约**:以 INTERFACE.md 为基准,组织一次 HLD + INTERFACE + DEPLOYMENT 的接口对齐评审,确定 gateway/supply-api/token-runtime 的正式路径、请求/响应字段、鉴权方式,形成一份 `INTEGRATION_CONTRACT.md` 作为唯一可信源。
2. **补齐或裁剪 ER 图**
-`ai_ops_events``ai_ops_notifys``ai_ops_configs``ai_ops_snapshots` 确实需要,在 HLD §4.2 和 migration 中补充表结构、字段、索引、外键。
- 若不需要,从 ER 图中删除,并说明替代方案(例如 `ai_ops_events` 是否被 `ai_ops_alerts` + `ai_ops_healings` 覆盖,`ai_ops_notifys` 是否被通知渠道 + alert status 覆盖)。
3. **定义 IntegrationPlugin 接口**:在 INTERFACE.md 中增加 `IntegrationPlugin` Go interface至少包含
```go
type IntegrationPlugin interface {
Name() string
Init(ctx context.Context, cfg Config) error
RegisterRoutes(mux *http.ServeMux) error
HealthChecks() []HealthCheckFunc
Shutdown(ctx context.Context) error
}
```
并说明注册方式import + 显式 Enable
4. **修正 API Server 部署描述**:将 DEPLOYMENT §1.1 的“主备”改为“多实例 Active-Active + 负载均衡”,与 §4.2 的故障处理逻辑一致。
5. **分离 migration 执行**:将数据库 migration 从 Worker 启动逻辑中移出,改为:
- 独立运行:使用 `cmd/migrate` 或 Docker init container 执行。
- 集成运行:由主程序在启动前统一执行,或通过 Kubernetes Job 执行。
6. **补充缺失表结构**:至少补充 `ai_ops_roles`RBAC 需要)和 `ai_ops_snapshots`(自愈回退需要)。
7. **建立 metrics 分区管理策略**:选择以下之一并在 migration 中体现:
- 引入 `pg_partman` 扩展并编写初始化脚本;
- 或在应用层编写定时任务每日创建新分区、删除旧分区。
8. **WebSocket 增加鉴权与优雅关闭**
- 连接建立时校验 JWT Token
- Shutdown 阶段先发送 close frame等待客户端 ack 或超时5s后再关闭 TCP 连接。
9. **完善告警聚合状态机**:补充聚合告警的 resolved/escalated 规则,以及子告警状态与父告警的同步策略(例如父告警 resolved 时是否批量 resolved 子告警)。
10. **重新校准时序存储容量估算**:参考 Prometheus 官方容量规划公式(`bytes_per_sample ≈ 1-2 bytes 压缩后,但写放大和索引占主要空间`),给出更保守的磁盘规划建议。
---
### 审核结论
**当前状态REQUEST_CHANGES**
本设计在架构层面具备可行性,核心决策有理据。但文档间的接口不一致和模型缺失是足以导致开发返工的系统性问题。建议在进入编码前:
1. 召开接口对齐会1-2 小时),统一 HLD / INTERFACE / DEPLOYMENT 中的所有外部路径和命名;
2. 由架构负责人补充 IntegrationPlugin 接口定义和缺失的表结构;
3. 将上述修复重新提交 TechLead 审核,通过后方可进入开发。

View File

@@ -0,0 +1,6 @@
DROP TABLE IF EXISTS ai_ops_metrics CASCADE;
DROP TABLE IF EXISTS ai_ops_healings CASCADE;
DROP TABLE IF EXISTS ai_ops_alerts CASCADE;
DROP TABLE IF EXISTS ai_ops_channels CASCADE;
DROP TABLE IF EXISTS ai_ops_rules CASCADE;
DROP TABLE IF EXISTS ai_ops_audits CASCADE;

View File

@@ -0,0 +1,180 @@
-- AI-Ops 初始化 schema
-- 表前缀 ai_ops_避免与桥项目表名冲突
-- 1. 告警规则
CREATE TABLE IF NOT EXISTS ai_ops_rules (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(128) NOT NULL,
metric_source VARCHAR(64) NOT NULL,
metric_name VARCHAR(128) NOT NULL,
threshold_type VARCHAR(16) NOT NULL CHECK (threshold_type IN ('>', '<', '=', 'regex')),
threshold_value TEXT NOT NULL,
duration_min INT NOT NULL DEFAULT 1 CHECK (duration_min >= 1),
level VARCHAR(8) NOT NULL CHECK (level IN ('P0', 'P1', 'P2', 'P3')),
channel_ids UUID[] NOT NULL DEFAULT '{}',
healing_action VARCHAR(32) DEFAULT NULL,
healing_config JSONB DEFAULT NULL,
is_sandboxed BOOLEAN NOT NULL DEFAULT FALSE,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
created_by VARCHAR(64) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
version INT NOT NULL DEFAULT 1,
CONSTRAINT uq_rules_name UNIQUE (name)
);
CREATE INDEX IF NOT EXISTS idx_rules_enabled ON ai_ops_rules(enabled);
-- 2. 告警事件
CREATE TABLE IF NOT EXISTS ai_ops_alerts (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
rule_id UUID NOT NULL REFERENCES ai_ops_rules(id) ON DELETE CASCADE,
level VARCHAR(8) NOT NULL,
resource_type VARCHAR(64) NOT NULL,
resource_id VARCHAR(128) NOT NULL,
current_value TEXT NOT NULL,
threshold_value TEXT NOT NULL,
status VARCHAR(16) NOT NULL DEFAULT 'triggered'
CHECK (status IN ('triggered', 'notified', 'healing', 'resolved', 'escalated', 'acknowledged')),
is_aggregated BOOLEAN NOT NULL DEFAULT FALSE,
aggregated_count INT DEFAULT 0,
parent_alert_id UUID NULL REFERENCES ai_ops_alerts(id) ON DELETE SET NULL,
started_at TIMESTAMPTZ NOT NULL,
resolved_at TIMESTAMPTZ NULL,
acknowledged_by VARCHAR(64) NULL,
acknowledged_at TIMESTAMPTZ NULL
);
CREATE INDEX IF NOT EXISTS idx_alerts_status ON ai_ops_alerts(status);
CREATE INDEX IF NOT EXISTS idx_alerts_started_at ON ai_ops_alerts(started_at DESC);
CREATE INDEX IF NOT EXISTS idx_alerts_resource ON ai_ops_alerts(resource_type, resource_id);
-- 3. 自愈执行记录
CREATE TABLE IF NOT EXISTS ai_ops_healings (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
alert_id UUID NOT NULL REFERENCES ai_ops_alerts(id) ON DELETE CASCADE,
action_type VARCHAR(32) NOT NULL
CHECK (action_type IN ('switch_route', 'throttle', 'restart_instance', 'invoke_script', 'isolate_node')),
config JSONB NOT NULL,
status VARCHAR(16) NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'succeeded', 'failed', 'rolled_back')),
dry_run BOOLEAN NOT NULL DEFAULT FALSE,
result_detail JSONB NULL,
error_code VARCHAR(16) NULL,
started_at TIMESTAMPTZ NOT NULL,
completed_at TIMESTAMPTZ NULL
);
CREATE INDEX IF NOT EXISTS idx_healings_alert ON ai_ops_healings(alert_id);
-- 4. 通知渠道
CREATE TABLE IF NOT EXISTS ai_ops_channels (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
name VARCHAR(128) NOT NULL,
channel_type VARCHAR(32) NOT NULL
CHECK (channel_type IN ('webhook', 'email', 'feishu', 'wechat', 'sms')),
config JSONB NOT NULL,
priority INT NOT NULL DEFAULT 1,
enabled BOOLEAN NOT NULL DEFAULT TRUE,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
-- 5. 审计日志append-only禁止更新和删除
CREATE TABLE IF NOT EXISTS ai_ops_audits (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
tenant_id VARCHAR(64) NOT NULL,
object_type VARCHAR(64) NOT NULL,
object_id VARCHAR(128) NOT NULL,
action VARCHAR(32) NOT NULL
CHECK (action IN ('create', 'update', 'delete', 'rollback')),
before_state JSONB NULL,
after_state JSONB NULL,
request_id VARCHAR(64) NOT NULL,
result_code VARCHAR(16) NOT NULL,
source_ip VARCHAR(45) NOT NULL,
actor_id VARCHAR(64) NOT NULL,
risk_level VARCHAR(8) NOT NULL DEFAULT 'normal'
CHECK (risk_level IN ('normal', 'high', 'critical')),
parent_audit_id UUID NULL REFERENCES ai_ops_audits(id) ON DELETE SET NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_audits_tenant_created ON ai_ops_audits(tenant_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_audits_object ON ai_ops_audits(object_type, object_id);
CREATE INDEX IF NOT EXISTS idx_audits_actor ON ai_ops_audits(actor_id, created_at DESC);
CREATE INDEX IF NOT EXISTS idx_audits_request ON ai_ops_audits(request_id);
-- 审计日志防篡改触发器(仅允许插入,禁止更新和删除)
CREATE OR REPLACE FUNCTION ai_ops_audit_readonly()
RETURNS TRIGGER AS $$
BEGIN
RAISE EXCEPTION 'ai_ops_audits is append-only. Updates and deletes are not allowed.';
END;
$$ LANGUAGE plpgsql;
DROP TRIGGER IF EXISTS trg_ai_ops_audits_no_update ON ai_ops_audits;
CREATE TRIGGER trg_ai_ops_audits_no_update
BEFORE UPDATE ON ai_ops_audits
FOR EACH ROW
EXECUTE FUNCTION ai_ops_audit_readonly();
DROP TRIGGER IF EXISTS trg_ai_ops_audits_no_delete ON ai_ops_audits;
CREATE TRIGGER trg_ai_ops_audits_no_delete
BEFORE DELETE ON ai_ops_audits
FOR EACH ROW
EXECUTE FUNCTION ai_ops_audit_readonly();
-- 6. 时序指标缓存(降级方案,主存储推荐 Prometheus / VictoriaMetrics
CREATE TABLE IF NOT EXISTS ai_ops_metrics (
id BIGSERIAL PRIMARY KEY,
metric_name VARCHAR(128) NOT NULL,
labels JSONB NOT NULL DEFAULT '{}',
value DOUBLE PRECISION NOT NULL,
recorded_at TIMESTAMPTZ NOT NULL
);
CREATE INDEX IF NOT EXISTS idx_metrics_name_time ON ai_ops_metrics(metric_name, recorded_at DESC);
-- 分区表(按天分区,自动清理 > 7 天的分区)
CREATE TABLE IF NOT EXISTS ai_ops_metrics_p (
id BIGSERIAL NOT NULL,
metric_name VARCHAR(128) NOT NULL,
labels JSONB NOT NULL DEFAULT '{}',
value DOUBLE PRECISION NOT NULL,
recorded_at TIMESTAMPTZ NOT NULL,
PRIMARY KEY (id, recorded_at)
) PARTITION BY RANGE (recorded_at);
-- 创建当前日分区
CREATE TABLE IF NOT EXISTS ai_ops_metrics_p_default PARTITION OF ai_ops_metrics_p
DEFAULT;
-- 启用 pg_partman 扩展后可自动管理分区(建议生产环境使用)
-- SELECT partman.create_parent('public.ai_ops_metrics_p', 'recorded_at', 'native', 'daily');
-- 7. 配置版本管理(支持审计回滚)
CREATE TABLE IF NOT EXISTS ai_ops_configs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
object_type VARCHAR(64) NOT NULL,
object_id VARCHAR(128) NOT NULL,
config_data JSONB NOT NULL,
version INT NOT NULL DEFAULT 1,
created_by VARCHAR(64) NOT NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
CONSTRAINT uq_configs_object_version UNIQUE (object_type, object_id, version)
);
CREATE INDEX IF NOT EXISTS idx_configs_object ON ai_ops_configs(object_type, object_id, created_at DESC);
-- 8. 状态快照(自愈回滚用)
CREATE TABLE IF NOT EXISTS ai_ops_snapshots (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
healing_id UUID NOT NULL REFERENCES ai_ops_healings(id) ON DELETE CASCADE,
snapshot_type VARCHAR(32) NOT NULL
CHECK (snapshot_type IN ('route', 'rate_limit', 'instance', 'script', 'node')),
before_state JSONB NOT NULL,
after_state JSONB NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_snapshots_healing ON ai_ops_snapshots(healing_id);

View File

@@ -0,0 +1,17 @@
-- 通知日志表
CREATE TABLE IF NOT EXISTS ai_ops_notification_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
event_id UUID NOT NULL REFERENCES ai_ops_alerts(id) ON DELETE CASCADE,
channel_id UUID NOT NULL REFERENCES ai_ops_channels(id) ON DELETE CASCADE,
channel_type VARCHAR(32) NOT NULL,
status VARCHAR(16) NOT NULL DEFAULT 'pending'
CHECK (status IN ('pending', 'sent', 'failed', 'retrying')),
retry_count INT NOT NULL DEFAULT 0,
error_message TEXT NULL,
sent_at TIMESTAMPTZ NULL,
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_notification_logs_event ON ai_ops_notification_logs(event_id);
CREATE INDEX IF NOT EXISTS idx_notification_logs_status ON ai_ops_notification_logs(status);
CREATE INDEX IF NOT EXISTS idx_notification_logs_created ON ai_ops_notification_logs(created_at DESC);

View File

@@ -0,0 +1,22 @@
-- Phase 1: 补充请求日志表,支持日志查询功能
CREATE TABLE IF NOT EXISTS ai_ops_request_logs (
id UUID PRIMARY KEY DEFAULT gen_random_uuid(),
timestamp TIMESTAMPTZ NOT NULL DEFAULT NOW(),
service VARCHAR(64) NOT NULL,
path VARCHAR(256) NOT NULL,
method VARCHAR(8) NOT NULL,
status_code INT NOT NULL,
latency_ms DECIMAL(10,3) NOT NULL,
user_id VARCHAR(64),
supplier_id VARCHAR(64),
error_code VARCHAR(64),
created_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
);
CREATE INDEX IF NOT EXISTS idx_request_logs_timestamp ON ai_ops_request_logs (timestamp DESC);
CREATE INDEX IF NOT EXISTS idx_request_logs_service ON ai_ops_request_logs (service);
CREATE INDEX IF NOT EXISTS idx_request_logs_path ON ai_ops_request_logs (path);
CREATE INDEX IF NOT EXISTS idx_request_logs_status_code ON ai_ops_request_logs (status_code);
CREATE INDEX IF NOT EXISTS idx_request_logs_user_id ON ai_ops_request_logs (user_id);
CREATE INDEX IF NOT EXISTS idx_request_logs_supplier_id ON ai_ops_request_logs (supplier_id);
CREATE INDEX IF NOT EXISTS idx_request_logs_time_service ON ai_ops_request_logs (timestamp DESC, service);