CheetahSpec 这个名字里,“Cheetah”已经说明了它的核心目标——把密码求解的速度拉到接近原生程序的水平。实现路径也很直接:用 WGSL 在浏览器的 WebGPU 计算管线上写 GPU 内核,省掉后端服务,让浏览器直接成为高性能计算终端。说白了,这是一个跑在浏览器里的 cryptosolver,只是计算主力从 CPU 换成了 GPU,而且不需要本机安装 CUDA 工具链。
这类项目最值得关注的点有三个:第一,部署门槛低,浏览器打开就能用;第二,通过 WGSL 计算着色器做并行哈希和穷举,和传统 JavaScript 单线程循环完全不是一个量级;第三,它天然适合需要短平快验证密码学算法的场景,比如 CTF、授权范围内的密码恢复、算法教学实验。本文会围绕 CheetahSpec 拆解它的技术思路、运行环境、启动方式、功能验证路径、批量任务设计和性能观察方法,并给出 WebGPU 项目常见的坑位和排查思路。
如果你关心 WebGPU 计算管线怎么落地,或者想找一个浏览器端并行计算的正向参考项目,这篇文章可以直接收藏。如果你的目标只是“双击跑通一个加密工具”,那请先读完第 2 节,我把使用边界和合规问题放在前面讲清楚。
1. 核心能力速览
从项目标题可以确定几个关键信息:CheetahSpec 是浏览器端项目,计算内核使用 WGSL 编写,目标是达到 native execution speed,主要用途是 cryptosolver。下面的表格把它的能力边界和运行要求整理出来,方便快速判断是否值得在自己机器上试。
| 能力项 | 说明 |
|---|---|
| 项目类型 | 浏览器端密码学求解器(cryptosolver) |
| 计算后端 | WebGPU / WGSL 计算着色器 |
| 运行环境 | 支持 WebGPU 的现代浏览器,无需后端服务 |
| 核心能力 | 哈希计算、字典求解、暴力穷举、掩码求解等,具体以项目支持范围为准 |
| 性能目标 | 通过 GPU 并行计算接近原生执行速度 |
| 启动方式 | 浏览器直接访问 / 本地静态服务器托管 |
| 接口方式 | 页面内 JavaScript API / Web Worker 消息协议 |
| 批量任务 | 支持多哈希、多候选集批量处理,建议按实际项目验证 |
| 显卡要求 | 支持 WebGPU 的 GPU,核显可运行但性能有限 |
| 适合场景 | CTF、密码学实验、授权范围内的密码恢复、WebGPU 性能研究 |
需要说明的是,本文不会编造 CheetahSpec 的具体版本号和实测显存占用。项目源码级的细节、依赖命令和真实 API 路径,要以仓库 README 和实际运行输出为准。下面给的命令和代码,一部分是通用 WebGPU 技术栈的标准写法,一部分是理解计算管线的最小示例,可以当作部署和验证时的模板。
2. 适用场景与使用边界
CheetahSpec 适合谁?第一类是 CTF 选手。比赛中经常遇到 hash 解谜类型的题目,时间窗口短,希望用一个不用装环境的工具快速跑一个小范围的字典或暴力枚举,浏览器里直接开一个页面就能干活。第二类是密码学初学者。想理解 GPU 并行如何加速哈希计算,但不想配置 CUDA、Vulkan 或者 OpenCL 环境,WebGPU 的浏览器方案足够用来做对照实验。第三类是 WebGPU 应用开发者。想找一个计算密集型场景来做性能测试,cryptosolver 是非常典型的并行计算负载,可以观察 workgroup 大小、buffer 分块和并发 Worker 对吞吐量的影响。
能解决什么问题?最直接的是“在浏览器里跑 GPU 计算”,把密码求解从单线程的 JavaScript 循环中解放出来。它还能验证一个非常重要的结论:浏览器已经具备接近原生程序的 GPU 计算能力,只要算法和内存布局设计得当,不一定非要把计算任务搬到服务器端。
不适合什么场景?如果目标是高吞吐、长时间、大规模的生产级密码恢复,比如恢复企业设备固件或磁盘加密,浏览器方案目前不是最优选择。浏览器进程的稳定性、显存限制、功耗控制和长时间运行后的资源回收,都很难和原生工具竞争。CheetahSpec 更适合做研究、实验、比赛和验证,而不是生产环境的主力工具。
合规边界必须单独说:cryptosolver 是一把通用工具。用它测试自己拥有的数据、自己找回自己的账号密码、CTF 比赛提供的靶场,都没有问题;但未经授权对他人系统、他人账号、他人加密文件进行破解,属于非法行为。涉及数据库、后台、账号、加密文件的场景,必须先确认你具备测试或恢复的合法权限。文章后面所有测试步骤,默认都使用本地构造的哈希样本和公开测试数据。
3. 环境准备与前置条件
CheetahSpec 作为浏览器项目,环境准备比原生工具简单很多,但 WebGPU 的兼容性仍然是第一个检查点。
3.1 操作系统与浏览器
Windows 10/11、macOS、Linux 桌面系统都可以,只要浏览器支持 WebGPU。推荐使用最新版 Chrome 或 Edge,两个浏览器从 113 版本开始默认启用 WebGPU。Firefox 需要手动到about:config中打开dom.webgpu.enabled,但稳定性不如 Chromium 系。Safari 从 17 版本起逐步支持 WebGPU,但功能覆盖和数据布局差异较大,不建议作为主要调试环境。
3.2 GPU 与驱动
WebGPU 通过浏览器访问显卡,不需要安装 CUDA、Vulkan SDK 或 OpenCL 开发包,但需要 GPU 驱动足够新。Windows 上建议在“设置 -> 系统 -> 屏幕 -> 显示卡”中,把浏览器设置为“高性能”模式,避免笔记本默认把浏览器调度到核显上。AMD、NVIDIA 和 Apple Silicon 芯片都能跑,差异体现在吞吐量和工作负载上限上。
3.3 检查 WebGPU 是否可用
在浏览器控制台执行下面这段代码:
if (navigator.gpu) { const adapter = await navigator.gpu.requestAdapter(); console.log("WebGPU adapter:", adapter ? adapter.info : "no adapter"); } else { console.error("当前浏览器不支持 WebGPU"); }如果输出了 adapter 信息,说明环境基本可用。如果返回undefined,优先检查浏览器版本,再看看是否启用了硬件加速。Chromium 系浏览器在“设置 -> 系统”里有一个“使用图形加速功能(如可用)”开关,关闭状态会导致 WebGPU 不可用。
3.4 本地静态服务器
即使项目能直接双击 HTML 打开,也建议用本地静态服务器访问。原因有两个:第一,WebGPU 对不安全上下文有限制,file://协议下部分能力可能异常;第二,后续切换工作流、加载字典文件、调试 Worker 时,HTTP 协议更方便。最简单的方式是 Python 或 Node。
# Python 3 cd cheetahspec-project-directory python -m http.server 8080# Node.js 方式,任选一种 npx serve .启动后访问http://127.0.0.1:8080。如果项目提供了package.json,则按仓库说明用npm install安装依赖,再用npm run dev或npm run build启动开发模式。具体脚本名以实际项目为准,这里只给通用流程。
3.5 磁盘与数据准备
字典文件是 cryptosolver 常用的输入。建议准备一个小字典做功能验证,比如几百到几千行的txt文件,后续再换大字典测性能。同时准备一组“已知明文 -> 哈希值”的测试对,用来校验求解结果是否正确。比如:
hello,2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 admin,8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 123456,8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92这些是 SHA-256 哈希示例,用来验证工具是否真的被正确执行,而不是随便跑了个空转。实际使用时可以选择目标哈希算法对应的测试向量。
4. 安装部署与启动方式
因为 CheetahSpec 是浏览器项目,启动路径大概率是下面三种之一。具体以仓库文档为准,但思路是通用的。
4.1 方式一:直接访问托管页面
如果项目有在线 Demo 页面,直接用 Chrome 或 Edge 打开即可。这是最轻量的方式,不需要克隆代码、不需要安装依赖。适合先验证功能再决定要不要本地部署。
4.2 方式二:本地静态服务器
这种方式适合自己改代码、调参数、加字典。先下载或克隆项目源码,然后进入项目目录,启动静态服务器。
git clone <repository-url> cd cheetahspec python -m http.server 8080这里需要把<repository-url>替换成项目实际地址。如果你的项目已经构建出dist或build目录,静态服务器也要指向对应目录。
# 如果项目有构建产物目录 cd cheetahspec/dist python -m http.server 80804.3 方式三:前端构建流程
如果项目包含package.json、vite.config.js或webpack.config.js,说明它可能有构建步骤。通用流程如下:
npm install npm run devnpm run dev启动的是开发服务器,通常会自动打开浏览器并支持热更新。生产构建一般用:
npm run build构建产物会在dist/目录下。注意,npm install如果遇到网络问题,可以把 npm registry 切到国内镜像,例如:
npm config set registry https://registry.npmmirror.com4.4 启动后的基本检查
启动后打开浏览器,按F12打开 DevTools,在 Console 里看有没有 WebGPU 初始化日志。如果页面会显示设备信息和任务输入表单,说明启动成功。如果页面一直在等待、没有反应,优先检查 WebGPU 环境和浏览器控制台报错。这类项目最常见的问题不是代码逻辑错,而是浏览器没有正确把 GPU 设备暴露给页面。
5. 功能测试与效果验证
无论项目本身提供了什么 UI,测试思路都可以拆成四步:先验证 GPU 环境,再验证基础哈希计算,再验证单次求解,最后验证批量求解。下面每小节都给出测试目的、输入、步骤、预期结果和失败时的排查方向。
5.1 验证 WebGPU 设备初始化
测试目的:确认页面能正常拿到 GPU adapter 和 device。
操作步骤:
- 打开页面,进入 DevTools Console。
- 执行
navigator.gpu.requestAdapter()。 - 观察返回值。
预期结果:输出 adapter 信息,不抛异常。如果页面项目内部封装了初始化,通常页面加载后会出现一个状态提示,例如“WebGPU ready”。
常见失败:requestAdapter返回null,说明浏览器没有识别到可用的 GPU 设备。先看操作系统层面浏览器是否被调度到核显,再看浏览器设置中硬件加速是否开启。
5.2 基础哈希计算测试
测试目的:确认 WGSL 计算内核能被正确编译和执行,而不是只靠 JavaScript 端计算。
输入:一个明文,例如hello,在页面输入框中输入,选择 SHA-256 算法,点击计算。
操作步骤:
- 输入明文。
- 选择哈希算法类型。
- 点击执行或计算按钮。
- 等待输出。
预期结果:页面输出2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824,与已知 SHA-256 哈希一致。
判断标准:如果输出与已知哈希一致,说明数据在 CPU 与 GPU 之间的传递、WGSL 内核计算、buffer 回读三条链路都通了,这是整个项目最关键的验证点。如果结果不一致,优先检查字节序问题,常见于把 UTF-8 字符串按Uint32Array直接写进 buffer 时使用了错误的分组方式。
5.3 单哈希求解测试
测试目的:验证求解器能否在给定哈希值的情况下,从候选数据中找回明文。
输入:哈希值5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8,这是password的 SHA-256 哈希。选择字典模式,字典中至少包含password。
操作步骤:
- 粘贴目标哈希。
- 选择字典求解模式。
- 加载包含
password的字典文件。 - 点击开始求解。
预期结果:求解器在字典中命中password,并显示明文。
如果项目支持暴力破解模式,可以设置长度为 8、字符集为小写字母,预期也会命中。暴力模式更依赖 GPU 并行度,可以观察每秒尝试次数。
判断标准:求解结果与预期明文一致,且耗时远小于在 JS 里单线程跑同样字典的耗时,说明 GPU 并行路径真正生效。
5.4 批量哈希求解测试
测试目的:验证项目是否能一次处理多个哈希值。
输入:三个 SHA-256 哈希组成的文件或列表。
2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824 8c6976e5b5410415bde908bd4dee15dfb167a9c873fc4bb8a81f6f2ab448a918 8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92操作步骤:
- 切换到批量求解模式。
- 上传或粘贴包含多个哈希的文件。
- 加载字典。
- 点击运行。
预期结果:三个哈希分别命中hello、admin、123456。如果项目按行输出结果,应该看到一一对应关系。
判断标准:批量任务结束时,页面应显示“完成”状态,并对每个哈希给出明文或“未命中”。如果部分哈希未命中,先确认字典内容是否正确,再确认算法是否选对。
5.5 参数与性能对比测试
测试目的:评估不同参数对求解速度的影响。
操作步骤:
- 固定同一个哈希,使用相同字典。
- 在设置中切换 workgroup 大小(128 / 256 / 512)。
- 分别记录耗时。
预期结果:不同 workgroup 大小下吞吐量有差异,但不一定 workgroup 越大越快,具体受显卡架构影响。这个测试能帮你理解 WebGPU 调度的基本规律。
判断标准:观察是否存在明显性能拐点,并记录当前机器的合理参数。这一步建议做,因为正式跑大任务之前,先确定参数区间可以省很多时间。
6. 接口 API 与批量任务
CheetahSpec 这类浏览器项目通常不会直接暴露 HTTP 接口,它的“API”更可能是页面内的 JavaScript 类、函数,或者 Web Worker 之间的消息协议。理解这一点对二次开发很重要。
6.1 页面内的 JS 调用模板
下面的代码是一个理解浏览器端 solver 调用方式的通用模板,不是 CheetahSpec 的实际源码。实际项目名称和参数请以仓库文档为准。
const solver = new CheetahSpec.Solver({ algorithm: "sha256", charset: "abcdefghijklmnopqrstuvwxyz0123456789", minLength: 4, maxLength: 6, workgroupSize: 256 }); solver.onProgress = (stats) => { console.log(`tried=${stats.tried}, rate=${stats.rate}/s, elapsed=${stats.elapsed}s`); }; const matched = await solver.run({ hash: "5e884898da28047151d0e56f8dc6292773603d0d6aabbdd62a11ef721d1542d8", mode: "dictionary", dict: ["password", "123456", "admin"] }); console.log("matched:", matched);这个模板表达的是一个典型调用流程:创建 solver 实例 -> 注册进度回调 -> 提交任务 -> 获取结果。如果项目本身提供了 npm 包或浏览器全局变量,使用方式会很接近。
6.2 Web Worker 消息协议设计
如果项目把计算放在 Worker 里,主线程和 Worker 之间会走一个消息协议,类似这样:
// 主线程 const worker = new Worker("./solver-worker.js"); worker.postMessage({ type: "solve", algorithm: "sha256", hash: "2cf24dba5fb0a30e26e83b2ac5b9e29e1b161e5c1fa7425e73043362938b9824", mode: "dictionary", dictPath: "./dicts/common.txt" }); worker.onmessage = (e) => { if (e.data.type === "progress") { console.log(e.data.rate, e.data.tried); } if (e.data.type === "done") { console.log("result:", e.data.result); } };这种设计的好处是 UI 不卡顿,GPU 计算过程和浏览器主线程解耦。如果你要二次开发,把页面内调用改造成 Worker 协议,是最可能遇到的改造方向。
6.3 批量任务队列设计
批量求解的核心问题是内存控制和失败重试。一次把几十万条候选数据塞进 GPU 的 storage buffer,很容易超过设备上限,所以批量任务要分块。一个通用的队列结构如下:
class SolverQueue { constructor({ chunkSize = 10000, concurrency = 2 } = {}) { this.chunkSize = chunkSize; this.concurrency = concurrency; this.tasks = []; this.running = 0; } add(task) { this.tasks.push(task); } async run() { while (this.tasks.length > 0 && this.running < this.concurrency) { const task = this.tasks.shift(); this.running += 1; this.execute(task) .catch((err) => console.error("task failed:", err)) .finally(() => { this.running -= 1; this.run(); }); } } async execute(task) { for (let offset = 0; offset < task.candidates.length; offset += this.chunkSize) { const chunk = task.candidates.slice(offset, offset + this.chunkSize); await this.runChunk(task.hash, chunk); } } }这里runChunk需要替换成项目实际的 GPU 调用函数。队列的价值在于:每个 chunk 执行完后释放 buffer,再申请下一个 chunk,避免一次性申请超大显存;同时把并发数限制在安全范围,降低浏览器崩溃概率。
6.4 远程调用改造
如果希望把 CheetahSpec 暴露成 HTTP 接口,供其他工具调用,需要自行包一层服务。思路是:用浏览器内核或 Node.js 的 WebGPU 实现跑计算逻辑,再通过 HTTP/WebSocket 暴露任务提交和结果查询。这个改造会明显增加复杂度,而且性能不一定比原生工具好,建议只在确实需要浏览器计算能力时才做。
7. 资源占用与性能观察
浏览器项目的资源占用,既要看浏览器整体开销,也要看 GPU 进程的占用。和原生工具一样,显存、GPU 利用率、内存占用和吞吐量都可以观察,但观察入口不太一样。
7.1 浏览器侧观察工具
- Chrome 任务管理器:按下
Shift + Esc打开,可以看到 GPU 进程的 GPU 内存占用、CPU 占用和网络占用。运行求解任务时,GPU 进程的内存会明显上涨。 - DevTools Performance:在页面运行任务时录制性能面板,可以观察 GPU 相关任务、JS 主线程任务和 Worker 任务的分布。
- 页面内置进度日志:很多 solver 页面会打印每秒尝试次数,这是最直接的性能指标。
7.2 吞吐量计算方式
吞吐量不依赖 DevTools,通过任务统计即可计算:
吞吐量 = 总尝试候选数 / 总耗时例如一个任务尝试了 10 万个候选,耗时 2 秒,那么吞吐量是 5 万次/秒。某些页面会把“每次尝试”定义为一个哈希计算,也可能定义为一个明文候选,需要区分清楚。
7.3 影响性能的主要因素
- 哈希算法复杂度:不同算法每轮计算的指令数差异很大,SHA-256 和 MD5 的吞吐量不在一个量级。
- workgroup 大小:128、256、512 对不同的显卡架构影响不同,需要实测选优。
- storage buffer 大小:一次写入 GPU 的候选越多,调度效率越高,但受设备上限约束。
- Worker 并发数:多个 Worker 可以并行提交任务,但会放大显存占用。
- 浏览器后台节流:如果标签页没有激活,浏览器可能降低定时器或 GPU 调度频率,导致吞吐量下降。
7.4 降低资源占用的通用方法
如果遇到“页面崩溃”或“GPU 进程内存过高”,按优先级做三件事:
- 降低并发 Worker 数量,例如从 4 降到 2。
- 缩小每次提交的候选块大小,例如从 100000 降到 10000。
- 降低 workgroup 大小,例如从 512 降到 256,观察吞吐量下降是否可接受。
如果目标是长时间跑大任务,建议保持单个标签页、关闭无关动画页面、禁用浏览器后台节流,并且定期查看 GPU 进程状态。常见的大任务失败原因不是算法错误,而是 GPU 进程被系统回收或显存不足。
8. 常见问题与排查方法
浏览器端 cryptosolver 的坑,很多集中在 WebGPU 环境、数据布局和异步流程上。下面这张表覆盖了从启动到批量任务的主要故障点。
| 问题现象 | 可能原因 | 排查方式 | 解决方案 |
|---|---|---|---|
navigator.gpu为 undefined | 浏览器版本过低或未启用 WebGPU | 检查浏览器版本,查看控制台 | 升级到 Chrome/Edge 113+,Firefox 开启dom.webgpu.enabled |
requestAdapter返回 null | 显卡驱动过旧,或浏览器被调度到核显 | 查看系统 GPU 设置,换浏览器尝试 | 更新驱动,在系统中为浏览器指定高性能 GPU |
| 页面白屏且 Console 报错 | WebGPU 设备请求失败 | 查看具体报错信息 | 检查浏览器硬件加速开关,重启浏览器 |
| 哈希计算结果不正确 | WGSL 与 JS 之间的字节序或数据布局不一致 | 用已知明文哈希做校验 | 统一使用Uint32Array布局,注意小端序和字符串填充方式 |
| 任务运行但结果一直为 0 | buffer 未正确映射,或计算未完成就读取结果 | 检查device.queue.onSubmittedWorkDone()调用 | 在计算完成后 await 提交队列,再映射 buffer |
| 高并发运行导致浏览器崩溃 | Worker 并发过多,或显存不足 | 逐步降低并发数,观察 GPU 进程 | 分块提交,限制 Worker 数量 |
| 页面操作卡顿 | 主线程执行了同步等待或大量数据处理 | 打开 Performance 面板查看长任务 | 把数据切块和进度统计放到 Worker |
| 大批量候选集提交失败 | storage buffer 超过设备上限 | 打印device.limits.maxStorageBufferBindingSize | 按上限分块,每次提交合理大小 |
| 本地打开 HTML 无法运行 | file://协议导致 WebGPU 能力受限 | 换http://127.0.0.1访问 | 启动静态服务器 |
| 字典文件加载失败 | 文件路径错误或字符编码问题 | 检查网络面板和文件编码 | 使用 UTF-8 编码,使用相对路径,必要时把字典内容嵌入页面 |
关于字节序问题,值得多说一句。WGSL 和 JavaScript 的 TypedArray 在内存布局上都需要明确字节序,常见的错误是:JS 侧用字符串直接转成ArrayBuffer后,WGSL 里按u32读取,导致字符顺序错乱。调试方式很简单:用一个单字符的明文跑一次哈希,对比正确的哈希值,就能快速定位是分组错误、补位错误还是字节序错误。
9. 最佳实践与使用建议
第一,正确性优先于速度。第一次运行任何求解任务,都应该用一个包含已知结果的样本集验证。可以先跑一个 5 万行的小字典,确认命中结果完全正确,再扩大数据规模。这样能避免在大任务结束后才发现字节序或填充逻辑有问题。
第二,分目录管理数据。建议把字典文件、目标哈希、输出结果分别放到独立目录,并且按任务命名。批量任务会累积大量输出文件,没有目录规划的话,排查效率和二次处理都会受影响。
cheetahspec/ ├── dicts/ │ ├── common.txt │ └── custom-rule.txt ├── targets/ │ ├── single-hash.txt │ └── batch-hash.txt ├── outputs/ │ ├── result-20250101.json │ └── result-20250102.json └── src/第三,批量任务必须加日志和失败重试。每跑完一个 chunk,把进度写进日志文件或控制台;任务失败时,要能定位到具体是哪个 hash 和哪个字典片段,而不是从头再来。如果项目本身没有日志功能,自己包一层也很简单。
第四,正式任务前先跑参数扫描。用同一个 hash、同一个字典,测试不同的 workgroup 大小和并发数,记录哪组参数在当前机器上吞吐量最高。这个步骤十分钟就能完成,但能节省大任务的大量等待时间。
第五,注意浏览器后台节流。长任务运行时,确保浏览器标签页处于激活状态,否则后台节流可能显著降低 GPU 计算速度。如果确实需要挂后台跑,需要在系统或浏览器层面调整电源和性能设置。
第六,所有测试素材要确保授权。字典来自公开数据集没问题,目标哈希只使用自己构造的测试向量,不要导入任何来源不明的用户数据或账号哈希。如果涉及企业环境内的安全测试,先拿到书面授权。
10. 总结与下一步
CheetahSpec 最值得尝试的点,是它把 WebGPU 计算管线带到了一个非常直观的场景里:浏览器打开页面,GPU 开始并行穷举,你能直接看到吞吐量反馈。对于 WebGPU 初学者来说,这是一个比绘制三角形更容易理解“计算着色器如何干活”的入口。
建议第一次上手时,先按第 5 节做一轮最小验证:本地起一个静态服务器,打开页面,用hello的 SHA-256 哈希做字典求解。跑通这步后,再去看项目源码里的 WGSL 内核和 JS 调用逻辑,理解数据是怎么从 CPU 侧进入显存、怎么被 workgroup 并行处理、再从 storage buffer 回读的。最容易踩的坑集中在三处:浏览器 WebGPU 开关没开、字符串到 buffer 的字节序错误、异步计算完成后没有正确等待和映射 buffer。
后续可以继续扩展的方向包括:给项目增加更多哈希算法;把字典攻击扩展成掩码攻击和规则引擎;用多个 Worker 并行分片提升吞吐量;把页面封装成 Electron 桌面应用,摆脱浏览器版本限制;或者接上 WebSocket 服务,把求解能力暴露成局域网内可调用的接口。无论往哪个方向走,先把基础验证路径跑通,再逐步加复杂度,都是最稳的节奏。