From 5c7b8d18550f2a8702f0992c1859cf5e345ae406 Mon Sep 17 00:00:00 2001 From: wangdl Date: Thu, 18 Jun 2026 13:49:45 +0800 Subject: [PATCH] docs: add API reference with error codes, rate limiting, changelog (API-AI-076) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Complete error code enumeration: Internal API + User API + Runtime errors - Rate limiting: user quota, platform circuit breaker, global throttle - Changelog: v1.0.0 initial → v1.1.0 current with all changes - Integration examples: heartbeat cancel detection, job creation idempotency Co-Authored-By: Claude Opus 4.7 --- docs/ai-runtime-api-reference.md | 191 +++++++++++++++++++++++++++++++ 1 file changed, 191 insertions(+) create mode 100644 docs/ai-runtime-api-reference.md diff --git a/docs/ai-runtime-api-reference.md b/docs/ai-runtime-api-reference.md new file mode 100644 index 0000000..1746b64 --- /dev/null +++ b/docs/ai-runtime-api-reference.md @@ -0,0 +1,191 @@ +# AI Runtime 接入文档 + +面向 Runtime 开发者和 iOS/Admin 前端开发者的 API 参考。 + +--- + +## 1. 错误码枚举 + +### 1.1 Internal API 错误码(Runtime ↔ API) + +| 错误码 | HTTP | 说明 | retryable | +|--------|------|------|:---------:| +| `JOB_NOT_FOUND` | 404 | Job 不存在 | false | +| `JOB_NOT_ACTIVE` | 409 | Job 状态不是 locked/running | false | +| `JOB_ALREADY_LOCKED` | 409 | 已被其他 Runtime 锁定 | true | +| `SNAPSHOT_NOT_FOUND` | 404 | 快照不存在(已废弃:自动重建) | false | +| `CREDENTIAL_NOT_FOUND` | 404 | 凭证不存在或已删除 | false | +| `CREDENTIAL_REQUIRED` | 400 | user_deepseek_key 模式缺少 credentialId | false | +| `RESULT_ALREADY_EXISTS` | 409 | 重复提交(幂等 key 冲突) | false | +| `RESULT_SCHEMA_UNSUPPORTED` | 422 | schema 版本不支持 | false | +| `INTERNAL_ERROR` | 500 | 服务器内部错误 | true | + +### 1.2 User API 错误码(iOS / Admin → API) + +| 错误码 | HTTP | 说明 | +|--------|------|------| +| `AI_ANALYSIS_DISABLED` | 400 | 用户未开启 AI 分析 | +| `INVALID_JOB_TYPE` | 400 | jobType 不在支持列表中 | +| `INVALID_TARGET_TYPE` | 400 | quiz/flashcard 必须 targetType=knowledge_base | +| `CREDENTIAL_REQUIRED` | 400 | user_deepseek_key 模式需要绑定凭证 | +| `CREDENTIAL_NOT_FOUND` | 404 | 凭证不存在或无权访问 | +| `DAILY_JOB_LIMIT_EXCEEDED` | 400 | 超过每日 AI Job 数量上限 | +| `DAILY_TOKEN_BUDGET_EXCEEDED` | 400 | 超过每日 Token 预算上限 | +| `PLATFORM_CIRCUIT_OPEN` | 503 | 平台熔断器开启,拒绝新请求 | +| `PLATFORM_CIRCUIT_HALF_OPEN` | 503 | 熔断器半开,仅允许少量请求 | +| `PLATFORM_TOKEN_BUDGET_EXCEEDED` | 400 | 平台日 Token 预算耗尽 | +| `PLATFORM_COST_BUDGET_EXCEEDED` | 400 | 平台日成本预算耗尽 | + +### 1.3 Runtime 上报的错误码 + +Runtime 通过 `POST /internal/runtime/jobs/{jobId}/fail` 上报的错误码: + +| 错误码 | 说明 | retryable | +|--------|------|:---------:| +| `JOB_CANCELLED` | 用户取消 Job | false | +| `JOB_TIMEOUT` | Job 执行超时(默认 120s) | false | +| `MODEL_TIMEOUT` | DeepSeek API 超时/503/502/500 | true | +| `MODEL_RATE_LIMIT` | DeepSeek 429 限流 | true | +| `MODEL_NETWORK_ERROR` | 网络连接失败 | true | +| `SNAPSHOT_FETCH_FAILED` | 快照拉取失败 | true | +| `INVALID_SNAPSHOT` | 快照版本不兼容 | false | +| `CREDENTIAL_RESOLVE_FAILED` | 凭证解析失败 | false | +| `UNSUPPORTED_JOB_TYPE` | jobType 不支持 | false | +| `MODEL_RESPONSE_INVALID` | 模型返回无效 JSON | false | +| `MODEL_JSON_PARSE_FAILED` | 模型输出 JSON 解析失败 | false | + +--- + +## 2. 限流说明 + +### 2.1 用户级限流 + +通过 `UserAiSettings` 控制,默认值: + +| 参数 | 默认值 | 说明 | +|------|--------|------| +| `maxDailyAiJobs` | 20 | 每日 AI Job 创建上限 | +| `maxDailyTokenBudget` | 100,000 | 每日 Token 消耗上限 | + +超出限制返回 `DAILY_JOB_LIMIT_EXCEEDED` 或 `DAILY_TOKEN_BUDGET_EXCEEDED`。 + +限流粒度:`(userId, localDate, apiKeyMode)`,platform_key 和 user_deepseek_key 独立计数。 + +### 2.2 平台级熔断 + +平台密钥(platform_key)模式启用的保护机制: + +``` +├── 日 Token 预算:10,000,000 tokens +├── 日成本预算:$500 (50000 cents) +├── 熔断阈值:连续 10 次失败 → open +├── 半开限制:最多 2 个活跃 platform_key Job +└── 恢复:单次成功 → closed(重置失败计数) +``` + +熔断状态流转: +``` +closed ──[10次连续失败]──> open ──[手动半开]──> half_open ──[成功]──> closed + │ │ + └───[超限]───<───────────────[超限]───┘ +``` + +### 2.3 API 全局限流 + +通过 NestJS ThrottlerModule 控制,默认限制: + +| 端点 | 限制 | 窗口 | +|------|------|------| +| `/ai/*` 用户端点 | 60 次/分钟 | 60s | +| `/internal/runtime/*` | 300 次/分钟 | 60s | + +超限返回 HTTP 429。 + +--- + +## 3. 变更日志 + +### v1.1.0(2026-06) + +**新增**: +- Heartbeat 响应新增 `cancelRequested` 字段(HTTP 200 替代 204) +- `getSnapshot` 自动重建过期/缺失快照(不再返回 SNAPSHOT_EXPIRED) +- `submitFailure` 支持 `JOB_CANCELLED` 错误码 +- 用户 API:`POST /ai/jobs` 创建分析 Job(11 步流程含幂等、配额、熔断) +- 用户 API:`GET/POST/PUT/DELETE /ai/model-credentials` 凭证管理 +- 用户 API:`GET /ai/analyses`, `/ai/recommendations`, `/ai/weak-points` 分析结果查询 +- 用户 API:`GET /ai/quizzes`, `/ai/flashcards` 已发布内容查询 +- 平台预算熔断:`PlatformBudgetService` 日 Token/成本限制 + 熔断器 +- 结果落库:`persistResult` 支持 5 种 jobType(learning_state_analysis / weak_point_analysis / next_action_planning / quiz_generation / flashcard_generation) +- 候选转换:`convertQuizCandidates` / `convertFlashcardCandidates` 去重 + 正式记录创建 +- Job 完成通知:`notifyJobComplete` 推送通知给用户 + +**修复**: +- `getProfile` 的 `?? {}` 修复(之前 Promise 永远 truthy) +- `HeartbeatResponse.cancel_requested: bool` 客户端适配 +- N+1 去重查询 → 批量预取(Quiz/Flashcard convertCandidates) +- `persistResult` / `notifyJobComplete` fire-and-forget 增加日志 + 计数器 +- `job-reaper` take:500 上限 → 游标批处理循环 +- `checkAndReserve` → `checkQuota` 重命名(澄清只读语义) +- `testCredential` 使用 ConfigService 获取 DeepSeek baseUrl +- Quota 测试拆分 `mockSettingsFindUnique` / `mockUsageFindUnique` + +### v1.0.0(2026-05) + +**初始版本**: +- Internal API:Poll / Lock / Heartbeat / GetSnapshot / ResolveCredential / SubmitResult / SubmitFailure / SubmitInvocationLogs +- User API:Profile / Settings / Learning Profile CRUD +- 鉴权:InternalAuthGuard(x-internal-api-key)+ JWT(用户端点) +- 加密:CredentialEncryptionService(AES-256-GCM) +- 配额:UserAiQuotaService(checkQuota + incrementJobCount + recordTokenUsage) + +--- + +## 4. 接入示例 + +### 4.1 Runtime 心跳 + 取消检测(v1.1) + +``` +POST /internal/runtime/jobs/{jobId}/heartbeat +Authorization: Bearer +x-runtime-instance-id: runtime-001 +``` + +响应 200: +```json +{ + "jobId": "job-abc123", + "lockUntil": 1700000000123, + "cancelRequested": false +} +``` + +`cancelRequested=true` 时,Runtime 应在下一个 I/O 检查点中止执行并提交 `JOB_CANCELLED` fail。 + +### 4.2 前端创建分析 Job + +``` +POST /ai/jobs +Authorization: Bearer + +{ + "jobType": "quiz_generation", + "targetType": "knowledge_base", + "targetId": "kb-001", + "apiKeyMode": "platform_key", + "idempotencyKey": "client-uuid-xxx", + "questionCount": 10 +} +``` + +幂等:相同 `idempotencyKey` 重复请求返回已有 Job ID(不重复创建)。 + +--- + +## 5. 相关资源 + +- [Internal API 通信协议](./ai-runtime-internal-api-protocol.md) +- [AI Runtime 架构](./ai-runtime-architecture.md) +- [Job 状态机](./ai-job-state-machine.md) +- [数据权限与隐私](./ai-data-permission-privacy.md) +- [用户 AI API 文档](./ai-runtime-user-api.md)