Skip to content

feat: add AI Guardian for AI call cost and abuse control#6

Open
LyndonDing wants to merge 1 commit into
floatboatai:mainfrom
LyndonDing:feature/ai-guardian-cost-control
Open

feat: add AI Guardian for AI call cost and abuse control#6
LyndonDing wants to merge 1 commit into
floatboatai:mainfrom
LyndonDing:feature/ai-guardian-cost-control

Conversation

@LyndonDing

Copy link
Copy Markdown

feat: add AI Guardian for AI call cost and abuse control

Branch: feature/ai-guardian-cost-controlmain

Summary

为 Open SaaS Demo AI 应用引入 AI Guardian 模块,在 AI 调用链路中统一实现成本与滥用控制。通过 Redis + Postgres 组合,提供分布式锁、请求幂等、滑动窗口限流、配额预扣/回滚、陈旧预留恢复及全链路审计日志,并配套 Admin 仪表盘与部署前检查脚本。

背景与目标

Demo AI App 的 generateGptResponse 原先缺少系统级防护,存在重复扣费、并发刷量、无限调用等风险。本 PR 在不改变 Wasp 架构的前提下,将 AI 调用收口到 AiGuardian 统一门面,实现可观测、可配置、可测试的防护层。

架构概览

flowchart LR
  Client[DemoAppPage] --> Action[generateGptResponse]
  Action --> Guardian[AiGuardian.enter]
  Guardian --> Lock[DistributedLock]
  Guardian --> Idem[IdempotencyGuard]
  Guardian --> Rate[RateLimiter]
  Guardian --> Quota[QuotaService]
  Action --> OpenAI[OpenAI API]
  Action --> Exit[AiGuardian.exit]
  Exit --> Audit[AiAuditLog]
  Admin[Admin Dashboard] --> Ops[getAiAuditLogs / getAiUsageStats]
  Ops --> Audit
  Lock & Rate --> Redis[(Redis)]
  Quota & Audit --> DB[(Postgres)]
Loading

调用生命周期:

  1. enter() — 分布式锁 → 幂等检查 → 滑动窗口限流 → 配额预扣
  2. 执行 OpenAI 调用
  3. exit() — 写入 token/成本审计、确认或回滚配额、释放锁

主要变更

核心模块 (src/ai-guardian/)

组件 职责
guardian.ts 统一编排门面(enter / exit / forceRelease
distributed-lock.ts Redis 分布式锁,防同用户同 action 并发
idempotency-guard.ts 基于 requestId 的幂等保护
rate-limiter.ts Redis 滑动窗口限流(分钟/小时)
quota-service.ts 日/月配额 + credits 乐观锁预扣
stale-recovery.ts 陈旧预留自动恢复
call-logger.ts 审计日志写入与成本估算
operations.ts Admin 查询:审计日志分页 + 用量统计

数据层

  • User 新增 5 个字段:aiDailyCallCountaiDailyCallDateaiMonthlyCallCountaiMonthlyCallMonthcreditsVersion
  • 新增 AiAuditLog 表,记录 traceId、requestId、status、token 用量、估算成本等

业务集成

  • generateGptResponse 接入 AiGuardian,前端传入 UUID requestId,响应携带 _meta(traceId / usage / quota)
  • 新增 ai-client.ts,分离 OpenAI 调用逻辑
  • DemoAppPage 适配 requestId 生成与 Guardian 错误提示

管理后台

  • 新增 /admin/ai-guardian 仪表盘:审计日志列表 + 用量统计(成功率、限流/超额次数、Token 消耗、日维度 breakdown)
  • Admin Sidebar 添加入口

测试与运维

  • Vitest 单测覆盖 guardian、rate-limiter、quota-service、idempotency-guard 等核心逻辑
  • Wasp mock 层支持脱离 Wasp 编译环境运行测试
  • 部署脚本:run-unit-tests.shpre-deploy-check.shsmoke-test.sh
  • 上线 Checklist:pre-deploy-checklist.md

配置

  • 新增 AI_GUARDIAN_* 环境变量(Redis URL、限流阈值、日/月配额、Token 单价、锁 TTL、时区)
  • 依赖:ioredisvitest

Test plan

  • 运行单元测试:cd template/app && npm run test:unit(或 ./scripts/run-unit-tests.sh
  • 执行数据库迁移:wasp db migrate-dev,确认 AiAuditLog 表及 User 新字段创建成功
  • 配置 .env.server 中的 AI_GUARDIAN_REDIS_URL 和 OpenAI Key,启动 wasp start
  • 正常调用:登录用户生成 AI 日程,确认返回 _meta.traceIdAiAuditLog 写入 SUCCESS 记录
  • 幂等保护:同一 requestId 重复提交,第二次应返回 DUPLICATE 或缓存结果
  • 限流:短时间内连续调用超过 AI_GUARDIAN_RATE_LIMIT_PER_MINUTE,应返回 429
  • 配额耗尽:免费用户超过日限额,应返回 QUOTA_EXCEEDED
  • Admin 仪表盘:以 Admin 身份访问 /admin/ai-guardian,确认审计日志和用量统计正常展示
  • Redis 降级:停止 Redis 后调用,确认降级到 DB 模式仍可正常工作(限流精度降低)
  • 运行 ./scripts/pre-deploy-check.sh 通过全部检查项

部署注意事项

  1. 必须先执行 Prisma migration,再部署应用代码
  2. 生产环境建议配置 Redis(AI_GUARDIAN_REDIS_URL),否则自动降级为 DB 模式
  3. 按预期流量调整限流与配额环境变量,详见 .env.server.example
  4. 配额重置时区可通过 AI_GUARDIAN_QUOTA_TIMEZONE 配置(默认 UTC)

变更规模

  • 49 个文件,+5803 / -114 行
  • 1 个 commitfeat: add AI Guardian for AI call cost and abuse control

Introduce AiGuardian as the unified gatekeeper for OpenAI calls, combining
Redis-backed distributed locking, request idempotency, sliding-window rate
limiting, quota reservation with stale recovery, and Postgres audit logging.

- Add ai-guardian module (guardian, rate-limiter, quota-service, idempotency-guard, etc.)
- Extend Prisma schema with User quota fields and AiAuditLog model
- Integrate demo AI app with requestId idempotency and _meta response contract
- Add admin dashboard for audit logs and usage statistics
- Add Vitest tests, Wasp mocks, and pre-deploy/smoke test scripts
- Configure Redis and AI Guardian env variables

Co-authored-by: Cursor <cursoragent@cursor.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant