Skip to content

架构概览

整体拓扑

┌─────────────────────────────────────────────────────────────────┐
│                    learning-backend (单二进制)                   │
│                                                                  │
│   ┌──────────────┐    ┌──────────────────┐   ┌──────────────┐  │
│   │ axum Router  │───▶│   AppState       │──▶│   Store      │  │
│   │  /api/*      │    │  - amas: Arc<…>  │   │ (SQLite WAL) │  │
│   │  /admin/*    │    │  - store: Arc<…> │   │  r2d2 pool   │  │
│   │  /health     │    │  - updater       │   └──────────────┘  │
│   └──────┬───────┘    │  - rate_limit    │                     │
│          │            └────────┬─────────┘   ┌──────────────┐  │
│          ▼                     │             │ AMASEngine   │  │
│   静态文件 (static/)              ├────────────▶│ +16 子配置   │  │
│   ↑ 前端构建产物                 │             │ +热加载       │  │
│                                │             └──────┬───────┘  │
│   ┌───────────────────────┐    ▼                    │          │
│   │  Workers(leader 实例) │────tokio::spawn         │          │
│   │  - config_watcher     │◀────────── notify ──────┘          │
│   │  - llm_advisor        │                                    │
│   │  - update_checker     │                                    │
│   │  - 其余聚合/清理 job   │                                    │
│   └───────────────────────┘                                    │
└─────────────────────────────────────────────────────────────────┘

后端骨架(src/

模块职责
main.rs启动入口:加载 env / AMASConfig → 建 Store → 建 AMASEngine → AppState → 起 Router + Workers
config.rs环境变量解析为强类型 Config(含 UpdateCheckConfigLlmConfigAmasConfigOverrides 等)
state.rsAppState:注入所有共享依赖给 handler
routes/HTTP 路由(按 mod.rs 挂载):核心学习链路 auth / users / words / word_states / wordbooks / wordbook_center / learning / study_config / records / word_favorites / word_notes / user_profile;内容与运营 content / notifications / resource_packs(资源包热更);可观测 feedback / probe_results / telemetry / analytics / metrics / status / realtime(SSE);v1(兼容别名)/ healthadmin/*(含 probe / probe_telemetry / feedback / monitoring / rbac / 资源包管理 等)
services/业务编排:updater(自更新)、llm_providerbroadcastmetrics_reporter
store/SQLite 持久层:schema.rs(DDL)/migrate.rs(版本化迁移)/operations/*(按表分文件)
amas/AMAS 核心:见下方"AMAS 模块"
workers/后台任务(共 27 个 worker):见下方"Workers"
blocking.rsrun_blocking():把 SQLite/算法等阻塞计算丢到 spawn_blocking
response.rs统一 AppError + ok() JSON 响应包装

中间件栈(按外层→内层)

CORS → Compression(gzip/br)→ Trace → CatchPanic → 安全响应头(CSP / HSTS / X-Frame-Options / nosniff / Referrer-Policy)→ Router。

AMAS 模块(src/amas/

amas/
├── config.rs           # AMASConfig:16 个子配置块(feature_flags / ensemble / modeling / …)
├── engine.rs           # AMASEngine:process_event / get_config / reload_config / is_healthy
├── types.rs            # RawEvent / ProcessResult / StrategyParams / UserState 等
├── decision/           # 决策算法层
│   ├── heuristic.rs    # 经验规则
│   ├── ige.rs          # 智能梯度(Intelligent Gradient Estimator)
│   ├── swd.rs          # 间隔加权(Spaced Weighted Decay)
│   └── ensemble.rs     # 信任分加权融合 + fallback
├── memory/             # 记忆模型层
│   ├── mdm.rs          # 多模型记忆曲线 (Multi-Decay Model)
│   ├── mastery.rs      # 单词掌握度状态
│   ├── iad.rs          # 干扰感知衰减 (Interference-Aware Decay)
│   ├── mtp.rs          # 间隔预测
│   ├── ssp.rs          # 间隔策略预计算表
│   ├── evm.rs          # 期望值模型
│   └── benchmark_adapter.rs # MDM 基准回放适配(t/r history → retention 区间)
├── word_selector.rs    # 选词评分:综合算法输出对候选词排序
├── elo.rs              # ELO 评分 + ZPD 优先级
├── metrics.rs          # 内存级指标注册表
├── metrics_persistence.rs # 指标快照落库 / 重启恢复
├── monitoring.rs       # 事件采样落库
├── constants.rs        # 引擎级常量(锁清理阈值 / 信号阈值 等)
└── tuning_whitelist.rs # 可调参数白名单 + 安全区间

事件流:POST /api/amas/process-eventAMASEngine::process_event() → 内部按 user 加锁 → 特征向量 → 候选策略生成(heuristic + IGE + SWD)→ 信任分加权融合 → 约束兜底 → 持久化 + 监控采样。

Admin GUI(admin-ui/,后端内嵌)

本节描述的是后端的内嵌运维 GUI,不是独立前端项目。源码在 admin-ui/,构建产物落仓库根 static/,由后端 tower-http::fs::ServeDir 作为 fallback 服务出去 —— 生产环境用户永远不会单独访问 admin-ui 这个 npm 项目,它没有独立部署形态。

选型版本
框架SolidJS 1.9
路由@solidjs/router
数据层SolidJS 原生 createResource(不再依赖 @tanstack/solid-query
样式Tailwind CSS v4(@tailwindcss/vite 插件)
构建Vite 7
图表ECharts 6
疲劳检测@mediapipe/tasks-vision + 本仓 crates/visual-fatigue-wasm(wasm-pack 产物)
测试Vitest(单测)+ Playwright(E2E,覆盖登录 / 学习流 / 词书 / 设备 / 通知 / 资源包等 11 个 spec)

构建产物落 static/,被后端的 tower-http::fs::ServeDir fallback 服务出去——生产环境单二进制即包含完整 admin GUI

Workers(src/workers/

WorkerManager 统一调度(基于 tokio-cron-scheduler),仅 WORKER_LEADER=true 的实例运行:

类别Worker
AMASconfig_watcher(热加载,main.rs 持久跑)、llm_advisor(DeepSeek 调参建议)、algorithm_optimization(指标聚合)、canary_monitor(per-patch 金丝雀自动回滚监测)
聚合统计daily_aggregationweekly_reportmetrics_flushhealth_analysis
缓存维护cache_cleanupconfusion_pair_cachesession_cleanuppassword_reset_cleanup
学习数据forgetting_alertdelayed_reward
内容/投递scheduled_broadcast(定时广播)、outbox_processor(出站消息可靠投递)
探针/监控monitoring_retention(事件表 retention + 月度 VACUUM)、telemetry_cleanup(遥测数据清理)、error_rate_watchdog(5xx 滚动告警)、scheduler_health_watchdog(worker 漏跑检测)、probe_cleanupprobe_confirm_sweeper
运维heartbeat_watchdog(持久跑,不归 Manager)、update_checker(GitHub Releases 轮询 + SSE)、log_exportdb_backup(每日备份独立循环)、backup_offsite(备份异地上传)

数据存储

SQLite + WAL 单库设计:

  • 连接池:r2d2 + r2d2_sqlitePRAGMA journal_mode=WAL + synchronous=NORMAL + foreign_keys=ON
  • 迁移:store/migrate.rsschema_version 表做增量迁移(DDL 在 schema.rs),首次启动跑全量 DDL,老库走增量
  • 备份:自更新前 PRAGMA wal_checkpoint(TRUNCATE)VACUUM INTO 生成单文件快照

历史上有 sled 实现,已通过一次性二进制 migrate-sled-to-sqlite 迁出,sled 依赖被 sled-migration feature 隔离,默认不编译。

术语 reconciliation:数据库内部沿用 client_* 命名(client_devices 表、client_id 字段、adminApi.{getClients,banClient,unbanClient} 等),UI 层统一改为 device/设备 表达(DevicesPage / "设备管理" 菜单 / <h1>设备</h1>)。DB 层因迁移成本(schema_version 兼容、回滚保护)暂保留旧命名;新增字段一律用 device_*。这套不对称是有意为之,不属于命名 bug。

自更新链路

  1. update_checker worker 每小时拉 GitHub Releases,结果走 Updater 的 ETag 缓存
  2. 管理员后台 /admin/updates 看到新版本提醒(SSE 推送)
  3. 触发 POST /admin/updates/install → 下载 tarball(≤ 200 MiB)→ 校验 → SQLite 备份 → 原子替换二进制 → exec 重启
  4. 失败兜底:semver 比对禁止 downgrade(除非 UPDATE_ALLOW_DOWNGRADE=true),fs2 文件锁防并发

自更新换的是整个后端二进制;资源包热更换的是客户端不发版的内容/配置,两条链路互不相关,见下。

资源包热更链路

面向 Web / iOS / Android 三端的不发版内容热更:服务端把签名后的 payload.json 托管在 static/packs/<pack>/<ver>/,客户端按需拉取、验签、消费。

  1. admin 在「资源包」页上传 payload.json(≤ 4 MiB 不透明 JSON)→ 服务端算 SHA-256 + Ed25519 签名落盘(routes/resource_packs.rs
  2. admin 切某通道(stable / beta / internal)「激活」→ 服务端广播 SSE resource_pack_available(同 pack×通道 5 分钟去重)
  3. 客户端 GET /api/resource-packs/<packId>/manifest?appVersion=&locale=&channel= 拿到 downloadURL + sha256 + 签名 → 下载 → SHA-256 校验 + Ed25519 验签(三端硬编码生产公钥为信任锚)+ minAppVersion 门控
  4. 注册的 consumer 消费 payload → 渲染 → POST /api/telemetry/resource-pack-install 回传 installed / verify_failed / rollback

投递链路对任意 packId 通用,内容/配置类用途收敛到两个通用容器content-slots(公告 / 内容卡 / 激励语 / 空状态等结构化内容位)与 app-config(kill-switch / 数值配置类远程开关)。这是数据热更不是界面热更——只能给客户端预埋了消费代码的位置喂新数据。完整契约、安全约束与三端消费现状见 资源包热更

下一步

WordForge — 智能英语学习平台