课本上的图是静的,考试要的是走一遍 —— 把原理跑给你看。
线上:https://xiamimate.com/cslab/ · 平台首页:https://xiamimate.com
数据结构 / 组成原理 / 操作系统 / 计算机网络,外加大模型推理引擎与具身智能两条职业线。 每个实验都是真仿真:可探索的状态空间,能单步走、能改参数、能看它演失败, 而不是一个返回标准答案的函数。
当前:244 个仿真内核(src/kernels/)。
npm install
npm run dev
npm test # 跑全部测试只有计算机领域的正确性能被程序自动判(跑参考实现比对轨迹),所以只有这个领域 敢让 AI 参与生成新实验。验证器降低的是出错率和出内容的成本 —— 它是一件有用的工具, 不是护城河:仿真谁都能写,验证器谁都能写,别拿它当壁垒。
AGPL-3.0 —— 拿去改可以;如果你用它对外提供服务,源码也要公开。
以下是开发笔记,原样保留。
计算机专业课交互仿真实验室 —— 引擎与内核。
对标粒子先生的物理实验室,做计算机专业课(数据结构 / 组成原理 / 操作系统 / 计算机网络)的交互仿真。 不叫"考研 408":考研三年跌 130 万,但那四门课全国计算机在校生都要上。
这里没有护城河。 仿真谁都能写,验证器谁都能写 —— 别拿它当壁垒。
验证器是一件有用的工具,不是护城河:只有计算机领域的正确性能被程序自动判 (跑参考实现比对轨迹),所以只有这个领域敢让 AI 生成新实验。它降低的是出错率和 出内容的成本,不构成任何人进不来的理由。
npm install
npm test # 跑全部测试
npm run typecheck # tsc --noEmit
npm run web # 起视图层(30 个实验都能跑)·「独立形态」
npm run web:single # 打成一个自包含 HTML
npm run demo:cache # 单看 Cache 参考实现的轨迹
npm run demo:sched
npm run demo:tcp本仓同一份代码有两种跑法,区别只由挂载路径决定(见 web/src/platform.ts):
| 独立形态 | 并入形态 | |
|---|---|---|
| 起法 | npm run web |
npm run web:lab + npm run gateway |
| base | / |
/cslab/ |
| 平台页眉页脚 | 无 | 有(加载主站 /chrome 制品) |
| 学习进度 | 只存本机 | 登录后与账号双向合并 |
| 外观 | 跟随系统 | 跟平台的「随系统 / 白天 / 黑夜」 |
| 冒烟 | npm run smoke -- http://127.0.0.1:5178/ |
npm run smoke:platform |
并入形态的本机入口是 http://127.0.0.1:3000/cslab,与虾米看股、虾米看AI 一致 ——
主站的 next.config.ts 把 /cslab/* 转给本仓的 dev server。
不要直接开 :5178:那儿拿不到 /chrome 也拿不到 /v1,
两个「看起来都对」的地址只有一个是并入后的样子。
# 终端 1(本仓) VITE_BASE=/cslab/ 的 dev server(:5178)
npm run web:lab
# 终端 2(tools-frontend)主站 :3000,rewrites 负责分流
npm run dev
# 终端 3(tools-backend)账号与进度接口 :8200
bash scripts/dev.sh
# 然后开 http://127.0.0.1:3000/cslabnpm run web:lab,不能用 npm run web。 后者挂在根上,
HTML 里写的是 src="/src/main.tsx",经 :3000 转过去落到主站身上 ——
页面回 200,内容却是空的。冒烟脚本的前置检查专门查这一条。
:3000 走的是 Next dev 的 rewrites,方便,但不是线上的形状。
网关把线上那套单域名分流搬到本机,规则与 deploy/caddy-snippet.conf 一一对应
(改一边要改另一边),能验到「不存在的资源回不回 404」这类只有静态托管才成立的事:
npm run web:build:lab
node scripts/local-gateway.mjs --lab=static --main=static
node scripts/platform-smoke.mjs http://127.0.0.1:8090真源是平台的 localStorage["xm-theme"](主站 lib/theme.ts),
主站、虾米看股、虾米看AI 都照它走,本仓也一样。本仓不自己做开关 ——
设置在账户中心那一处,多一个入口就等于多一份要同步的状态。
深浅两套色号写在 web/src/styles.css 的令牌块里,深色那份全部收在 --dk-*。
浅色的强调色是另一套色号,不是同一个色号调亮度:琥珀 #F0B429 压在白纸上
只有 1.86:1,它本来就是为暗底选的。
npm run contrast # 两套外观 × 30 个实验,逐个元素量**合成之后**的对比度门槛是:浅色 0 处不达标;深色只要求「欠账不比改浅色之前多」——
深色那批 912px 的小字一直是 2.54.2:1,是既有欠账,要不要一起修是另一件事。
并入的整体做法见 虾米看股并入虾米伙伴, 本仓的差异见 logs/2026-08-18-platform-integration.md。
右下角一张悬浮讲解卡(形态参照 Transformer Explainer): 可以 ‹ › 翻页、折叠、隐藏。讲到哪儿就把页面上那块用虚线描一圈;反过来, 点页面上几乎任何一块,卡片都直接翻过去 —— 舞台、位域、轴、日志、读数、真题、 边界、目录、页签、每一颗预置按钮、每一个参数旋钮。Cache 那一屏是 27 张卡。
内容一部分手写(回答什么问题 / 屏幕上每块是什么 / 先拧什么看什么 / 名词),
一部分派生:预置卡直接用预置的 note(那句话本来就是被测试逐条验过的行为主张 ——
按钮上写什么、讲解里说什么、测试验什么,是同一句话),参数卡用选项自动生成,
页面各区域写一次、并进每个实验。数据在 web/src/guide.ts。
锚点一处定义两个方向用:卡 → 元素(高亮)、元素 → 卡(点击跳转), 所以不会出现"点得到但讲不了"或者反过来。
本仓(引擎层)没有接运行时 AI 智能体,这是刻意的 —— 一个大模型在验过的答案旁边给出可能错的解释,是最坏的位置;而且讲解框是每个新手 都会点的东西,接按次计费的模型等于给最不产生收入的动作装计价器。 AI 的位置在作者侧(起草词条),产出是审过的静态文本。理由详见 logs/2026-08-18-guide-layer.md。
一行能说完的东西不占一张卡:读数与参数标签带虚下划线,悬停给一句话
(TIPS,只写名字自己说不清的那些)。这一层照的是参照站的分工 ——
它有 Tooltip(悬停一行)和 TextbookTooltip(点开翻到那一页)两层。
判据挂在最容易漂的地方:锚点选择器必须落得下 —— 舞台改个 class,翻到那一页时
屏幕上就没反应了,没有报错、靠看是看不出来的。冒烟把 30 个实验的每一页都翻一遍,
逐页问"页面上有没有高亮";该不该高亮由组件自己在 data-anchored 上声明
("没锚点"和"锚点落空"看起来一样,但一个是设计、一个是 bug)。
导览里点名的旋钮与预置同样逐个核对。
现在不上。 清单写在 deploy/README.md:后端建表+重启 →
前端带 VITE_BASE 构建发布 → 贴 Caddy 片段 → 线上自查 → 运营台勾开入口。
最后那一步是唯一的一道门:本仓页面是公开的,没有服务端鉴权。
src/
├── core/
│ ├── document.ts 文档层:SimDocument / Entity / Stream / AxisSpec
│ ├── kernel.ts 内核契约 + 执行器 run() / resume()
│ └── verify.ts 验证器:四种比较器
├── kernels/ 领域内核(实现 Kernel<S>)
│ ├── cache.ts Cache 命中率 · step 轴
│ ├── scheduler.ts 进程调度甘特图 · time 轴
│ ├── tcp.ts TCP 拥塞窗口 · time 轴
│ ├── page.ts 页面置换 · step 轴(FIFO/LRU/OPT/CLOCK)
│ ├── disk.ts 磁盘调度 · step 轴(FCFS/SSTF/SCAN/C-SCAN/LOOK)
│ ├── sweep.ts 参数扫描(高阶) · parameter 轴 → 曲线
│ └── compare.ts 并排对比(高阶) · 沿用内层轴 → N 条轨迹对齐
└── reference/ 独立参考实现 —— 验证基准,不是内核
web/ 视图层(Vite + React)
├── src/shell/ 共享框架:轴 · 日志 · 参数 · 读数 · 边界
├── src/stages/ 每个内核一个舞台
└── src/registry.ts 实验注册表 —— 加实验只改这里
tests/ 每个测试都自带"必须能红"的自检
docs/
├── blueprint.md 总蓝图(产品闭环 + 架构 + 标准)
├── standards.md 验收标准 / 内容标准 / 依赖准入
├── decisions/ ADR 决策记录
└── research/ 调研原始材料
logs/ 每次验证的结果与发现
文档 Document ──compile()──▶ 仿真模型 SimModel ──run()──▶ 轨迹 Trace ──▶ 渲染 / 验证
▲ ▲
造物型从这里进 408 从这里进
六条路共用这一条流水线。详见 docs/blueprint.md。
| 阶段 | 内容 | 状态 |
|---|---|---|
| 0 | DSL 收敛验证(三个实验挤一个 schema) | ✅ 通过 |
| 0b | parameter 轴 · 高阶内核 | ✅ 通过 |
| 0c | 验收标准 5 / 6 | ✅ 通过 |
| 0d | 内容环实测:AI 填 DSL | ✅ 精确题 60/60(20题×3次)、陷阱题 6/6 |
| 1 | 宿主框架 + 视图层 | ✅ 标准 3 已验 |
| 1b | 扩实验:页面置换 · 磁盘调度 | ✅ 5 个实验 |
| 1c | 接真题:判题 + 跳到那一步看为什么 | ✅ 答案从轨迹派生 |
| 1d | 扩实验:排序 · Dijkstra · 银行家 · 滑动窗口 ARQ | ✅ 9 个实验 |
| 1e | 输入全开放:驱动序列 + 实体表可编辑 | ✅ 参数换不了题面数据,这两个才行 |
| 1f | 408 全景表实现完毕 | ✅ 30 个实验 · 30 道题 139 问 · 四科全覆盖 |
| 0e | L2 组合级:AI 自选原语 | ✅ 36/36(12题×3次),选原语与填参数均 100% |
| 3 | L3 新原语(风险最高,可能做不成) | 未开始 |
| 2 | 前端版式:Cache 那套(因果链+表+搬运)铺满 30 个 | ✅ 3 个实验级开关(whyInRail 30 · tickChip 7 · sequence.chips 9) |
| 2 | 本步推演(step,右栏「本步为什么」) |
✅ 30/30 · 冒烟拿真轨迹 458 步逐个走过 |
| 2 | 引导式实验笔记(brief:输入→规则→结果 + 本次发现) |
✅ 30/30 · 14 份新 verdict 全现算(拿真轨迹逐个核过) |
| 2 | 一句话结论式副标题(tasks.md P1-2) |
⏭️ 已超越 · 副标题现为问句;结论改为在实验记录/笔记里现算,比静态标语更符合"答案从轨迹派生" |
详细的落地进度与下一步在 docs/tasks.md 的「进度快照」一节(2026-08-21 校准)。
AI 填 DSL 实测要点(详见 logs/2026-08-17-ai-bench.md):
- MiniMax 的 Anthropic 兼容端点不支持
output_config.format,强制工具调用tool_choice才是可用路径(脚本内置逐级降级探测,换模型自动重测) - 强制
tool_choice仍有 ~3% 偶发不出tool_use块 →fillWithRetry()重试 - 端点不强制 schema 的
required→ 落地校验必须自己做(validateDocument关卡 0) - 但缺"有语义的值"和缺"空集合"要分开处理 →
normalizeDocument()把省略的数组补成[] - 端点同样不强制
enum→ 凡是能从别处拿到权威值的字段就别让模型填(kind直接用工具名覆盖)
npm run ai:bench # L1:填参数,跑一遍
npm run ai:bench -- 3 # 每题 3 次
npm run ai:l2 # L2:6 个工具混着给,模型自选原语
npm run ai:l2 -- 3- 状态必须自足 —— 只能读
prev,不许读闭包里的可变状态。JSON 往返后还能续跑。 - 参考实现独立 ——
src/reference/与src/kernels/不共享代码,否则是自己验自己。 - 不会红的检查等于没有检查 —— 每条标准都要有一个故意做错的版本能把它弄红。
- 答案从轨迹派生 —— 题库里绝不手写答案;人会写错,而且配置一改答案就得跟着改。
- 出处不编 —— 记不准的年份题号一律不写,按题型标注,等有可核对的来源再补。