api-server/docs/ai-runtime-architecture.md
wangdl 804c414901
All checks were successful
Deploy API Server / build-and-deploy (push) Successful in 42s
feat: AI Runtime 总体架构文档 (API-AI-000)
定义 API / Rust Heavy Runtime / document runtime / iOS / Admin 职责边界、
Docker 内部网络部署、Job 异步任务流、用户 Key 与平台 Key 管理、失败重试与
熔断、结果落库边界、RAG 共存策略与后续扩展预留。

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-06-11 20:33:22 +08:00

9.7 KiB
Raw Blame History

AI Runtime 总体架构

1. 概述

M-API-AI-RUNTIME 里程碑新增 Rust Heavy Runtime 作为内部重任务执行器,完成 DeepSeek 调用、学习状态分析、题目/卡片候选生成。主 API 保持业务权威层地位不变。

架构图

iOS / Admin / Web
       ↓
  主 APINestJS
       ↓
  AiRuntimeJob / LearningAnalysisSnapshot
       ↓
  Rust Heavy Runtime内部 HTTP
       ↓
  DeepSeek API
       ↓
  Rust Heavy Runtime 输出结构化结果
       ↓
  主 API 二次校验 / 落库
       ↓
  iOS 展示 / Admin 诊断

2. 职责边界

2.1 API本仓库

负责 不负责
用户权限与会员额度 直接调用 DeepSeek
学习数据读取与聚合 Prompt 渲染
用户 DeepSeek key 加密存储 模型输出校验
AI Job 创建与调度 任务消费
Snapshot 构建 结构化 JSON 解析
Runtime 内部接口提供 题目/卡片生成
Runtime 结果校验与落库
iOS / Admin 对外 API
平台预算与熔断

2.2 Rust Heavy Runtime

负责 不负责
Job Worker 消费 用户登录与会员
DeepSeek 调用 直接写业务主表
Prompt 渲染 对公网暴露接口
结构化 JSON 校验 处理 readingTargetType
题目/卡片候选生成 用户数据查询
调用日志回传

2.3 Rust Document Runtime

负责 不负责
文档解析与阅读状态 readingTargetType
阅读事件 V2 生成 userId
EventBuffer 上传 API

2.4 iOS

负责 不负责
阅读页 UI 直接调 DeepSeek
heartbeat tick 控制 直接调 Rust Heavy Runtime
补充 readingTargetType
本地上传队列 + ack

2.5 Admin

负责 不负责
管理页面 直接调 Rust Runtime
成本统计与诊断

3. Docker 部署

┌─────────────────────── Docker internal network ───────────────────────┐
│                                                                        │
│  ┌─────────┐   ┌──────────────────┐   ┌──────────────────────┐       │
│  │  MySQL   │   │  api (NestJS)    │   │  heavy-runtime (Rust) │       │
│  │  :3306   │   │  :3000           │   │  :8080                │       │
│  │          │   │  → 公网暴露       │   │  → 不暴露公网          │       │
│  └─────────┘   └────────┬─────────┘   └──────────┬───────────┘       │
│                         │                        │                    │
│                         ├── 调 POST /internal/runtime/* ──→          │
│                         │                        │                    │
│                         │←── Runtime 调 internal API ──┤             │
│                                                                        │
└──────────────────────────────────────────────────────────────────────┘

docker-compose 要点

services:
  api:
    environment:
      RUNTIME_INTERNAL_BASE_URL: http://heavy-runtime:8080
      RUNTIME_SERVICE_TOKEN: ${RUNTIME_SERVICE_TOKEN}
    depends_on:
      - heavy-runtime
    networks:
      - zhixi-internal

  heavy-runtime:
    environment:
      API_INTERNAL_BASE_URL: http://api:3000
      RUNTIME_SERVICE_TOKEN: ${RUNTIME_SERVICE_TOKEN}
      DEEPSEEK_API_KEY: ${DEEPSEEK_API_KEY}
    expose:
      - "8080"
    networks:
      - zhixi-internal

networks:
  zhixi-internal:
    driver: bridge

关键约束:

  • heavy-runtime 不映射公网端口
  • 服务间通过 Docker 内部 DNS 发现(http://heavy-runtime:8080
  • service token 通过环境变量注入

4. 通信方式

4.1 主任务流Job 异步

API 创建 AiRuntimeJob(status=pending)
  → Runtime poll /internal/runtime/jobs/poll
  → Runtime lock job
  → Runtime 获取 Snapshot + credential
  → Runtime 执行 DeepSeek 调用
  → Runtime 提交 result 到 /internal/runtime/jobs/{jobId}/result
  → API 校验并落库

4.2 内部接口

接口 调用方 说明
POST /internal/runtime/jobs/poll Runtime 拉取 pending job
POST /internal/runtime/jobs/{jobId}/lock Runtime 锁定 job
POST /internal/runtime/jobs/{jobId}/heartbeat Runtime 心跳续约
GET /internal/runtime/jobs/{jobId}/snapshot Runtime 获取快照
POST /internal/runtime/model-credentials/resolve Runtime 获取模型 key
POST /internal/runtime/jobs/{jobId}/result Runtime 提交成功结果
POST /internal/runtime/jobs/{jobId}/fail Runtime 提交失败
POST /internal/runtime/invocation-logs Runtime 提交调用日志
GET /internal/runtime/health API Runtime 健康检查

4.3 鉴权

  • 复用已有 InternalAuthGuard,使用 x-internal-api-key header
  • 新增 X-Runtime-Instance-Id header 用于追踪
  • 普通用户 JWT 不可访问 internal 接口
  • service token 不可访问普通用户 API

5. AI Job 生命周期

5.1 状态机

pending ──→ locked ──→ running ──→ succeeded
  │          │           │
  │          │           └──→ failed (retryable) ──→ pending
  │          │           └──→ failed (non-retryable)
  │          │           └──→ expired
  │          │
  │          └──→ expired (lockUntil 超时)
  │
  └──→ cancelled

5.2 Job 类型

类型 说明 输出
learning_state_analysis 学习状态分析 AiLearningAnalysis
weak_point_analysis 薄弱点分析 WeakPointCandidate[]
next_action_planning 下一步建议 NextActionRecommendation[]
quiz_generation 题目生成 QuizQuestion[]
flashcard_generation 卡片生成 Flashcard[]

5.3 锁定与超时

lockUntil = now + 60s (推荐初始值)
heartbeat 延长 lockUntil
lockUntil 超时后其他 Runtime 可接管
maxRetryCount = 3默认

6. 用户 Key 与平台 Key

6.1 两种模式

模式 Key 来源 消费方
platform_key 环境变量 DEEPSEEK_API_KEY 或 API 配置 平台预算
user_deepseek_key 用户在 iOS 填写API 加密存储 用户自己

6.2 Key 流转

用户填 key → API 加密落库(UserModelCredential)
           → Runtime resolve → API 解密返回明文 → 仅内存使用 → 不写日志
           → ModelInvocationLog 只记录 credentialId不记录 key

6.3 安全规则

  • encryptedApiKeyAES-256-GCM 加密,密钥来自环境变量
  • 明文 key 不落库、不进日志、不返回前端、Admin 不可查看
  • maskedKeysk-****xxxx

7. 失败与重试

7.1 retryable 错误

MODEL_TIMEOUT, MODEL_RATE_LIMIT, NETWORK_ERROR, TEMPORARY_PROVIDER_ERROR
→ retryable=true, job 回到 pending, retryCount+1

7.2 non-retryable 错误

INVALID_SNAPSHOT, INVALID_SCHEMA, INVALID_CREDENTIAL
→ retryable=false, job 直接 failed

7.3 熔断

连续失败 N 次 platform_key job → 平台熔断 open → 拒绝新的 platform_key job → half_open 后试探

7.4 取消

  • pending job用户/Admin 可直接取消
  • running job标记 cancelRequestedRuntime 下次 heartbeat 获知

8. 结果落库边界

Runtime 提交 → API 校验 → 落业务表

Runtime submit result
  → API RuntimeOutputBusinessValidator 二次校验
  → 源数据归属校验 (sourceBlockIds, knowledgePointId)
  → 去重 (exact hash)
  → 写入对应业务表 (AiLearningAnalysis / QuizQuestion / Flashcard / ...
  → 更新 job 状态 succeeded

Runtime 不直接写AiLearningAnalysis, QuizQuestion, Flashcard, WeakPointCandidate, NextActionRecommendation, QuestionGenerationPlan, FlashcardGenerationPlan。这些只由 API 写。

9. 与现有 M1 RAG/Chat 的共存

  1. 本批不迁移现有 M1 RAG。
  2. 现有 Chat / RAG 问答链路AiGatewayService → DeepSeek继续运行。
  3. 新 AI Runtime 只做:学习状态分析、题目/卡片候选生成。
  4. 两者不共享 Job 队列。
  5. 若 Chat 结果和 AI Analysis 结果同时存在,前端应区分展示:
    • 对话回答:来自 Chat/RAG时效性高
    • 学习分析建议:来自 AI Runtime基于 Snapshot 聚合
  6. 后续 RAG 迁移需要独立里程碑。

10. 后续扩展预留

方向 本批 后续
RAG 迁移 独立里程碑
批量知识库分析 (只做 user/material 级) parentJob + childJob
多模型供应商 (只做 DeepSeek) ModelProvider trait
A/B 测试 promptVersion 字段已预留
Prompt 热更新 (静态模板) PromptRegistry
用户自定义 baseUrl 需安全审计

11. 验收清单

  • 文档明确 API 是业务权威层
  • 文档明确 Runtime 是内部重任务执行器
  • 文档明确 Runtime 不对公网暴露
  • 文档明确 Docker 内部网络部署方式
  • 文档明确本批不迁移 RAG
  • 文档明确 AI Job 异步流程
  • 文档明确 Runtime 结果最终由 API 校验和落库
  • 文档明确后续 iOS / Admin 只访问 API不访问 Runtime
  • 文档明确后续 RAG 迁移只是预留
  • 文档能指导 API-AI-001~072 的实现