Files
ai-gateway-go/README.md
T
superidou 5759c1862e AI Gateway Go 0.10.0 源码快照 + 旗舰版需求规划报告
M0-M7 已完成:核心网关(身份/RBAC/TOTP/OIDC/SAML/Provider/配额/路由/内容策略/审计/定价)+ 资源市场(MCP/Skills/数字员工)。
含 22 个 PostgreSQL 迁移、管理端/门户端前端源码、OpenAPI 契约、部署 compose。

Co-Authored-By: Claude <noreply@anthropic.com>
2026-08-12 11:45:54 +08:00

113 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# AI Gateway Go
AI Gateway 的全量 Go 重构工程。M0–M6 工程实现已完成,当前可运行基线包含 PostgreSQL、双 Redis、独立迁移器、Art Design Pro 管理端/门户端、OpenAI 兼容网关和可发布的 AI 资产编排运行时。
## 当前能力
- `GET /healthz`:进程存活检查。
- `GET /readyz`PostgreSQL、critical Redis 和 cache Redis 状态;前两者失败会返回 `503`
- `GET /metrics`:不依赖外部组件的基础 Prometheus 文本指标。
- `POST /v1/chat/completions``POST /v1/responses``POST /v1/embeddings``POST /v1/messages`:透明代理,支持 SSE。
- `GET /v1/models`:透明代理。
- 独立 `gateway-migrator`API 启动时不会修改数据库结构。
- PostgreSQL 权威管理员/门户身份、PBKDF2 旧密码兼容和 Redis 可撤销会话。
- 管理端与门户端 RFC 6238 TOTP 两步验证、5 分钟挑战令牌、时间步防重放和一次性备用码。
- Provider 管理 API;凭据使用 AES-256-GCM 加密,变更与 outbox 同事务提交。
- PostgreSQL Provider 原子运行时快照、默认/显式路由、能力校验和共享 HTTP 连接池;刷新失败保留上一有效版本。
- Provider 连接测试和模型目录同步;上游缺失模型保留历史记录并自动停用,同步事件与目录更新同事务提交。
- 管理员/门户账号管理、内置角色与可扩展 `resource:action` 权限字符串;账号和权限变更即时生效。
- 层级部门管理和门户账号部门绑定;循环层级、停用父部门和停用在用部门均由服务端约束。
- OIDC Authorization Code + PKCE 登录、RS256 ID Token 校验、外部账号映射与自动开户。
- SAML 2.0 SP 发起登录、SP metadata、签名断言验证、RelayState/Request ID 绑定、断言防重放与自动开户。
- 旧系统 38 个持久化实体的数据字典,以及幂等的旧 ID → UUIDv5 兼容映射基础设施。
- PostgreSQL API Key(明文仅显示一次、scope、过期时间、Redis 共享缓存、即时撤销)及 Art 管理页面。
- 按 API Key 配置的每分钟请求上限、UTC 自然月请求配额和 Token 配额;critical Redis Lua 原子执行,Token 采用请求前预留、JSON/SSE usage 回写校准,返回 429、`Retry-After` 和配额响应头。
- Provider 级响应头超时、幂等安全重试与熔断;POST 只有在客户端提供 `Idempotency-Key` 且请求体可重放时才会重试。
- PostgreSQL 模型别名和条件路由,按 endpoint、API Key、tenant 过滤,并在最高优先级组内做确定性加权 Provider 选择;规则通过不可变快照运行并由 Redis 通知多实例刷新。
- 有界异步调用审计和按日 usage 聚合:批量写 PostgreSQL,记录状态、延迟及输入/输出 Token;管理端提供权限隔离的筛选查询,审计存储异常不会阻塞模型调用。
- 独立事务 Outbox Worker:多实例 `SKIP LOCKED` 抢占、Redis Stream 原子去重投递、指数退避与死信;管理端可审阅并人工重试,消费者可用同事务幂等入口。
- PostgreSQL 审计月分区维护:自动预创建、default 分区在线迁移、过期整分区快速丢弃、边界精确清理和更长期的 usage 保留策略。
- 可扩展内容策略:Go RE2 不可变编译快照,按端点、模型/API Key 匹配,支持仅审计、阻断与提示词文本脱敏;默认保护常见 API Key、Token、密码和 secret。
- 带时间版本的模型价格与成本核算:按 Provider/模型选择价格,输入与输出 Token 分别计价,结果进入调用审计和 PostgreSQL 按日聚合。
- Prompt 分类、模板和不可变版本,支持显式变量定义、必填校验、历史版本激活与 API Key 渲染接口。
- PostgreSQL 知识库:2 MiB 有界文本正文、段落感知重叠分块、FTS + 中文二元词片混合检索,以及可替换的 `Retriever` 接口;不依赖对象存储或向量数据库。
- 声明式 HTTP 工具:JSON Schema 基础校验、KEK 加密请求头、注册和拨号双层 SSRF 防护、禁止重定向、1 MiB 响应限制与调用记录。
- AI 应用草稿和不可变发布版本,将模型、Prompt、知识库、工具组合为 `/v1/applications/{code}/chat/completions`;所有模型轮次继续经过鉴权、配额、内容策略、路由、成本和审计。
- 独立通知 Worker 消费可靠 outbox,按精确事件或末尾 `*` 模式投递 HMAC-SHA256 Webhook;内容策略命中由审计批处理异步产生脱敏事件,失败投递可在 Art 管理端重试。
- 门户自助工作台:部门范围资产目录、Prompt 搜索/收藏、个人审计/用量/成本、模型访问申请与管理员审批。
- 门户应用托管会话:服务端加密运行凭证、单会话租约、不可变消息序列和 SHA-256 哈希链,不向浏览器暴露应用 API Key。
- 独立事实核验配置、作用域策略与事件契约,复用 Provider 加密凭据和知识库引用,为同步/异步执行器保留清晰模块边界。
- 旧 Python 源码 201 条路由全部有覆盖、替代或退役决策,未决契约缺口为 0;OpenAPI 0.10.0 覆盖全部 Go 字面量路由。
MinIO/S3 和 ClickHouse 不属于基线部署,也不是启动依赖。审计与统计第一阶段存放在 PostgreSQL;对象存储和分析库仅保留后续 adapter 扩展点。
## 本地启动
1. 复制 `.env.example``.env` 并修改密钥。
2. 启动 PostgreSQL 和两套 Redis`docker compose -f deploy/docker-compose.yml up -d postgres redis-critical redis-cache`
3. 执行迁移:`go run ./cmd/gateway-migrator`
4. 设置 `BOOTSTRAP_ADMIN_PASSWORD` 后执行 `go run ./cmd/gateway-bootstrap` 创建初始管理员。
5. 启动 API`go run ./cmd/gateway-api`
6. 启动可靠事件投递:`go run ./cmd/gateway-outbox-worker`
7. 启动审计分区与保留维护:`go run ./cmd/gateway-maintenance`
8. 启动通知投递:`go run ./cmd/gateway-notification-worker`
完整容器部署可执行 `docker compose -f deploy/docker-compose.yml up -d --build`。Art Design Pro 管理端默认暴露在 `http://127.0.0.1:8081`,门户端在 `http://127.0.0.1:8082`;两者同源代理 `/api/*``/v1/*``/healthz``/readyz` 到 Go APIGo API 仍可从 `8080` 端口直接访问。
生产部署请使用 `deploy/docker-compose.production.yml`
`deploy/production.env.example`,完整步骤见
[`deploy/PRODUCTION.md`](deploy/PRODUCTION.md)。生产编排默认仅绑定回环地址、要求显式提供数据库/Redis/加密密钥,并关闭迁移期 bootstrap API key。
如果主机未安装 Go,可以在 Compose 依赖启动和迁移完成后执行:
```bash
docker compose -f deploy/docker-compose.yml run --rm \
-e BOOTSTRAP_ADMIN_PASSWORD='替换为强口令' \
--entrypoint gateway-bootstrap gateway-api
```
未设置 `HTTP_ADDR` 时只监听 `127.0.0.1:8080`;容器配置会显式监听 `:8080`
生产环境必须设置 `APP_ENV=production`,并使用带 TLS 的数据库和 Redis 地址。启用环境变量上游回退时必须设置 `UPSTREAM_API_KEY`。数据库 API Key 已可用于网关请求;bootstrap key 默认关闭,仅用于迁移兼容,需要时显式设置 `GATEWAY_BOOTSTRAP_API_KEY_ENABLED=true` 并配置强随机值,迁移结束后立即关闭,此时无需再配置 bootstrap key。`gateway_bootstrap_api_key_uses_total` 指标可用于确认旧客户端是否已经清零。bootstrap key 会绕过按 key 的限流与配额,切勿长期开启。
内置管理员角色为 `superadmin``operator``auditor`。超级管理员拥有通配权限;运维管理员默认管理 Provider 和 API Key;审计员只有读取权限。账号还可获得独立的 `resource:action` 权限,服务端每次请求都会从 PostgreSQL 复核账号状态和权限,因此停用或权限回收即时生效。
内容策略和模型价格以 PostgreSQL 为权威源,管理端保存后本实例立即刷新;其他实例分别按 `CONTENT_POLICY_REFRESH_INTERVAL``PRICING_REFRESH_INTERVAL`(默认 30 秒)加载不可变快照。正则采用 Go RE2,不支持回溯、环视等可能导致灾难性耗时的表达式。价格金额以微货币单位整数保存,避免浮点累计误差;例如 USD 2.50/百万 Token 存为 `2500000`
部门采用稳定 UUID 与邻接表层级。部门仍包含启用门户用户或启用子部门时不能停用;移动部门时会在事务内检测自身引用和任意深度循环。门户账号只能绑定启用部门,解绑不会删除任何历史身份数据。
OIDC 登录使用 Redis 保存 5 分钟一次性 `state``nonce` 和 PKCE verifier;回调校验发现文档、JWKS/RS256 签名、issuer、audience/azp、iat/nbf/exp 与 nonce。门户会话令牌不进入回调 URL,只使用 60 秒一次性交换码。OIDC Client Secret 使用 `identity-provider-credentials` 独立 AEAD 用途加密。
SAML 当前只开放 SP-initiated Redirect 登录和 POST ACS,显式拒绝 IdP-initiated 与 Artifact 绑定。IdP metadata 通过 SSRF 安全客户端获取并短时缓存,启用前校验 Entity ID、Redirect SSO 端点、签名证书和过期时间。ACS 依次验证 XML 签名、issuer、audience、destination、recipient、InResponseTo 和时间窗,只接受 SHA-256 及以上的签名/摘要算法,并使用 Redis 防止 RelayState 和 Assertion ID 重放。
登录防爆破采用两层叠加:账号锁定(`LOGIN_MAX_FAILURES` 次失败后锁定 `LOGIN_LOCK_DURATION`,针对单账号)与按 IP 的 Redis 滑动窗口限流(`LOGIN_RATE_LIMIT_MAX` 次/`LOGIN_RATE_LIMIT_WINDOW`,超出返回 429,针对跨账号撞库)。限流在 Redis 不可用时 fail-open,账号锁定仍然生效。来源 IP 取自 `X-Forwarded-For``deploy/nginx-web.conf``/api/` 路径用 `$remote_addr` 覆盖该头,避免客户端伪造头绕过限流;直接访问网关端口绕过 nginx 的请求仍可伪造该头,因此生产建议将管理面代理收敛在受信网络内。
旧 Python 数据结构的完整字段字典见 `docs/legacy-data-dictionary.md`。迁移使用 `gateway.legacy_id_mappings` 保存来源、实体、旧 ID 与新 UUID 的对应关系;新 UUID 由固定 namespace 的 UUIDv5 生成,同一条旧数据可安全重跑而不会生成不同主键。字段字典可用 `scripts/export_legacy_dictionary.py` 从旧工程重新生成。
`CREDENTIAL_MASTER_KEY` 必须是 32 字节密钥的 Base64 编码。Compose 中的默认值只允许本地开发,生产环境必须替换并纳入密钥托管与备份;丢失该密钥会导致 Provider 凭据、TOTP、工具请求头、通知签名密钥和应用运行凭证无法解密。每类密文使用独立用途标签,不能相互替换。
工具端点和通知 Webhook 默认只允许公网 HTTP(S) 地址,并在实际拨号时重新解析与校验地址。确有内网服务时分别显式设置 `ALLOW_PRIVATE_TOOL_URLS=true``ALLOW_PRIVATE_WEBHOOK_URLS=true`;这两个开关与 Provider 私网开关相互独立。
影子流量默认关闭。设置 `SHADOW_BASE_URL`、专用 `SHADOW_API_KEY` 和大于 0 的 `SHADOW_SAMPLE_RATE` 后,只复制确定性采样的非流式 JSON POST;生产客户端凭据不会转发。主响应不等待影子请求,Prometheus 指标只比较 HTTP 状态和 JSON 结构签名,不记录提示词或模型正文。压测使用独立 `gateway-loadtest` 二进制,可用错误率和 p95 阈值直接控制退出码。
旧路由矩阵由 `scripts/compare_route_contracts.py` 从 Python AST 与 Go OpenAPI 生成。旧源码当前实际包含 201 个路由装饰器,并非早期估算的 141 个;矩阵明确区分同契约覆盖、新契约替代、退役和真实缺口。切换步骤见 `docs/cutover-runbook.md`,旧数据暂存与密文边界见 `docs/legacy-import-runbook.md`
KEK 轮换时,将 `CREDENTIAL_KEK_VERSION``CREDENTIAL_MASTER_KEY` 设置为新活动版本与新密钥,并用 `CREDENTIAL_KEK_KEYRING` 加载历史密钥,例如 `{"1":"<old-base64-key>"}`。服务重启并确认可解密后,在供应商页面执行“轮换凭据”;所有旧版本 Provider 凭据和对应 outbox 事件会在一个事务内提交。确认全部 Provider 已切换后才能从 keyring 移除旧密钥。TOTP 同样通过 keyring 保持历史版本可解密,新配置会使用活动版本。
Provider 以 PostgreSQL 为权威源,在进程内构建不可变快照。管理 API 修改后会刷新本实例并通过 critical Redis Pub/Sub 通知其他实例立即刷新;默认每 5 秒轮询仍作为通知丢失或 Redis 短暂异常时的兜底。请求可通过 `X-Gateway-Provider` 指定 Provider;未指定时使用 `config.default=true` 的启用项,否则使用按 code 排序的第一项。`UPSTREAM_FALLBACK_ENABLED=false` 可关闭环境变量上游回退。
供应商连接测试和模型同步访问 OpenAI-compatible `/v1/models`。控制面请求限制为 10 秒、4 MiB 响应,拒绝重定向,并在禁用私网 Provider 时对实际拨号地址再次执行 SSRF 校验。模型同步不会物理删除旧模型,本次未出现的模型会标记为停用,为后续别名和路由规则保留引用稳定性。
## 目录
- `api/openapi`:对外契约。
- `cmd`:可部署二进制。
- `internal/platform`:配置、数据库、缓存、HTTP 运行时。
- `internal/provider`:上游 Provider 扩展接口及实现。
- `internal/gateway`:协议入口和代理编排。
- `internal/workbench`:Prompt、知识、工具、应用编排和通知。
- `internal/portal`:门户目录、申请、个人统计、加密应用凭证与托管会话。
- `internal/factcheck`:事实核验设置、策略和事件契约。
- `migrations`:仅由 migrator 执行的 PostgreSQL 迁移。
- `web`Art Design Pro 管理端和门户端。