实测 MisakaNet 的资源账单:0.79 秒、54 MB 与一个 2.3 MB 的语料库
技术栈极简不等于开销为零。这篇不谈设计理念,只记账:克隆一次占多少磁盘、查一次花多少时间和内存、语料涨上去会先撞哪面墙。数字来自同一台机器的实际运行——Apple Silicon 的 macOS、Python 3.13.12、浅克隆的仓库,被测对象是仓库自带的 search_knowledge.py 与 PyPI 上的 misakanet-core。
测量口径
复现任何一组数字前要说清三件事。浅克隆与完整克隆不同:--depth 1 不含历史。首跑与二跑不同:仓库有文件级缓存,第一次查询要付解析成本。额度用尽后命令会早退:我最初测到的"0.13 秒"其实是没执行检索。
磁盘:53 MB 里只有 2.3 MB 是知识
浅克隆后整个目录 53 MB,.git 独占 16 MB,工作区约 38 MB。按目录拆开,重量分布有些出乎意料:
| 目录 | 体积 | 说明 |
|---|---|---|
| docs/ | 15 MB | 文档站素材 |
| promotional/ | 9.1 MB | 宣传物料 |
| lessons/ | 2.3 MB | 真正被检索的语料 |
| data/ | 1.6 MB | 结构化数据 |
| tests/、scripts/ | 各 1.4 MB | 测试与脚本 |
| workers/、tasks/ | 0.9 / 0.5 MB | 辅助组件 |
lessons/ 下共 454 个 Markdown,合计 2396 KB,单条平均 5.28 KB——知识本身只占磁盘账单的约 6%。要担心磁盘就该盯 clone 总量而非语料增长。
一次检索:冷跑 0.94 秒,热跑 0.79 秒
清掉缓存后的首跑,工具自报 检索 407 篇文档耗时 0.94s,第二跑为 0.79 秒,多次重复稳定在这一带。进程总墙钟略高,在 0.93 至 0.99 秒之间。
固定成本可以拆出来:解释器空跑约 0.03 秒,import misakanet_core 约 0.042 秒,合计约 0.07 秒,占一次查询不到一成——主要耗时在遍历语料,不在启动。峰值常驻内存约 54 MB,单机并发几十次查询不构成内存问题。
两组对照可以给出参照系。用纯 Python 把 lessons/ 下所有文件读一遍、只统计字符数,耗时 0.915 秒,总字符量 1 374 302;用 ripgrep 做同关键词匹配只用 0.004 秒,命中 2 个文件。
第一组最有说明力:"只读文件"几乎和"读文件并排序"一样慢,0.79 秒里 BM25 打分占比极小,开销集中在 Python 逐文件 stat 与读取解释。第二组揭示另一面——原生扫描快两个数量级,却给不了相关性排序,换来"找得到",丢掉"哪条最相关"。
缓存用的是标准库 sqlite3,省掉的不是检索
缓存位于 REPO/.cache/search_cache.db,体积 110 592 字节(约 108 KB),开启 WAL,核心是一张 file_cache 表,按「路径 + mtime + size」判断文件是否需要重新解析。介质用的 sqlite3 本身就是标准库,"零依赖"并未被它破坏。
收益比想象中小:冷 0.94 秒对热 0.79 秒,只省下约 16%。缓存省掉 Markdown 解析,省不掉每个文件的 stat,也省不掉对全部文档打分——复杂度仍是每次查询 O(文档数)。性能余量来自语料还小,而非架构上有什么巧妙设计。
零依赖是真的,Python 是硬前置
在干净虚拟环境里装完 misakanet-core 后 pip list,列表里只有它自己(实测 2.7.0)。包内容是一个 202 行的单文件模块,只导入 math、re、json、typing、collections、dataclasses,全来自标准库——这个承诺真实兑现了。
但零依赖不等于零前置。在全新 clone 上直接照"零依赖路径"跑检索,会得到:
ModuleNotFoundError: No module named 'misakanet_core' # 前置:装好 misakanet-core
脚本开头有显式的生态断言,要求 misakanet_core 可导入才继续。准确说法是:它不依赖第三方生态,但依赖可用的 Python 环境与这一个 core 包。
没有守护进程,启动费按次支付
它无常驻进程,每次查询重启一次解释器,约 0.07 秒。单次可忽略,量级上却决定适用边界:按次调用几乎无感;若需求是每秒几十次在线检索,这笔固定税就会显形,常驻方案在该维度更划算,代价是常驻内存与更大的运维面。反过来,它不占端口、不装系统服务、无常驻内存,这三点换回的收益远大于那 0.07 秒。
第 6 次搜索为什么直接返回
实测中值得单独说的一件事:连续查询几次后命令不再输出结果,而是提示搜索额度已用尽(5/5),并说明贡献一条 lesson 可恢复。
实现里 FREE_SEARCH_QUOTA 常量的值是 5,计数落在仓库内的本地 JSON 文件,走贡献流程后重置。它不是网络限流,而是本地的一层"查询与回流绑定"机制。
对做基准的人,这会直接污染读数:不重置状态文件,量到的是早退时间。做本地工具实测前先复位状态,是通用纪律。
454、407、393:三个数不能混用
同一份仓库,我在三处看到三个文档数:lessons/ 下 454 个 Markdown;检索器载入并打分 407 篇;页面标的是 393 条 canonical(去重后)。算磁盘看 454,算检索成本看 407,对外引用用 393。差的 61 篇来自口径差异——检索器排除模板、归档与索引类文件,canonical 口径还按标题去重,镜像与翻译副本会合并并优先保留原版。"文件数"与"知识条数"本来就不同义,混用会得出错误结论。
语料涨到 2 万条会先撞哪面墙
按实测单条 5.28 KB 推算,2 万条纯文本约 103 MB,缓存库按当前比例也就几 MB 级——磁盘和内存都还不算问题。
墙在时间上。耗时随文档数近似线性增长,0.79 秒的构成又以逐文件读取为主,语料放大五十倍对应几十秒量级。必须说明这是线性外推,我没有 2 万条语料可测,实际曲线可能偏离。方向是清楚的:瓶颈会从解析迁移到"每次都要重扫一遍"这个模式本身。
实测小结
- 磁盘:浅克隆 53 MB,语料仅 2.3 MB,
docs与promotional占 24 MB; - 单次检索:0.79 至 0.94 秒,峰值常驻约 54 MB,无端口、无守护进程;
- 固定开销:约 0.07 秒启动与导入,按次调用可忽略;
- 缓存收益:约 16%,省解析不省扫描;
- 成本大头:Python 逐文件读取,不是 BM25 计算,也不是 CPU。
它的问题不在资源,而在召回质量与线性扫描这两条设计后果。按次查询、离线可用、多环境一致做得很便宜;高频并发、超大语料、语义检索它给不了。
想横向比较其它同类插件的资源与接入方式,可以从这份清单入手 https://dpharness.com/top