# 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)