我是 Jungle,一个大三在读、边考研边做独立开发的计算机学生。这篇文章记录了我最最近一周,把一个 AI 知识管理工具的知识处理链路从"调 API"彻底重构成"浏览器内置模型"的全过程。
先给结论:现在打开知叶,不需要填任何 API Key,浏览器会自己下载一个 ~70MB 的模型,在本地做知识点的分类、章节匹配和总结生成。整个过程数据不出你的电脑。
👉 体验地址:KnowLeaf – 知叶(手机/PWA 效果最佳,电脑也能用)
如果你也在做 AI 工具,或者对浏览器端推理感兴趣,这篇文章应该能帮你少踩一些坑。
一、知叶是什么
知叶(KnowLeaf) 是一个 PWA 知识管理工具,定位是三件事:
碎片知识整理:拍照/输入一段文字 → 自动提取知识点 → 分到 7 个类型(概念/定义/定理/公式/示例/习题/笔记)
艾宾浩斯复习:根据遗忘曲线自动推送需要复习的内容
思维导图可视化:用树形结构把零散知识点串起来
最早版本的知识提取靠调外部 API(DeepSeek、GLM-4 之类),用户得自己去注册 Key。这个门槛对普通用户来说太高了。
所以上周做了一个决定:把 AI 管线全部搬进浏览器。
二、本次更新:你能用到什么
如果你是知叶用户,这次更新带来了两个变化:
2.1 不用填 API Key 了——内置模型开箱即用
以前打开知叶想分析一段知识点,得先去注册 AI 平台的 Key,填到设置面板里,大部分人卡在这一步就走了。
现在打开直接用。浏览器会自动下载一个约 70MB 的本地模型,分类、章节匹配、总结生成全在本地完成,你的学习数据不会离开你的设备。没网也能用(模型缓存到浏览器后离线跑)。
一个细节:如果你之前配过外部 API Key(DeepSeek 之类),不影响,会自动进入"本地分类 + API 增强"模式——总结内容会更丰富一些,但没有 API Key 也完全够用。
2.2 分类越用越准——它会记住你的纠正
这是这次更新最核心的功能:反馈学习。
每次分析完一个知识点,知叶会弹出一个确认窗口,你对分类不满意可以当场改:
你输入:"泰勒公式的推导过程"
AI 分类:高等数学 → 级数 → 定理
你觉得不对,改成:高等数学 → 级数 → 公式
点保存 →
✅ 记录:"泰勒"→ 级数,权重 +1.5
✅ 下次输入"泰勒展开",直接命中"级数"章节
✅ 同一个错误不会犯第三次
这套系统有两条学习路径:
| 本地即时学习 | 你自己 | 纠正后立刻生效 |
| 社区共享学习(新增) | 所有用户 | 打开网页自动拉取 |
你不填任何东西就能给别人贡献纠正数据,也能白嫖别人的纠正——就像维基百科,只不过条目是"泰勒→高数"这种关键词映射。
隐私方面:只传前 300 字文本和分类结果,没有用户标识,不传你的完整知识库。
如果你想看自己的纠正数据:F12 → Application → Local Storage → knowleaf_feedback(反馈记录)和 knowleaf_keyword_weights(关键词权重)。
三、为什么选了浏览器本地模型
路线选择是这样的:
免费 API(智谱 GLM-4-Flash)→ 输出乱码,指令跟随太差
↓
换 DeepSeek(免费但需要 Key)→ 普通用户不会注册
↓
Cloudflare Workers 代理(我持 Key,用户免填)→ 免费的 Key 实际上都要充值/绑卡
↓
浏览器内置模型 ← 到这里
其实有一步让我彻底死心:用 GLM-4-Flash 测试"TCP 三次握手",它输出了"三角函数/牛顿定律"。不是幻觉,是模型压根没有指令跟随能力——200 字 system prompt + 7 字段 JSON 输出这个任务,对轻量模型来说太重了。
后来也想过去微调一个分类模型部署到服务器上,但一个学生项目没必要搞这么重。而且知识管理工具的数据隐私本来就敏感——用户拍的笔记、学习资料,全走服务器说不过去。
浏览器端推理刚好满足:免费、隐私、离线可用。
模型选了 SmolLM2-135M,~70MB,一次下载缓存到 IndexedDB,之后完全离线。
不过实际落地后发现,纯靠小模型做分类准确率不够。最终方案是 规则引擎 + 模型 + TF-IDF 匹配的混合管线,这个后面细说。
四、技术演进:从 P0 到 P20
整个重构分了 20 个阶段,每个阶段出一个 Claude Code 提示词(我没直接写代码,让 Claude Code 执行)。按功能线整理如下:
4.1 数据模型 v2.1(P0)
把原来的 3 层结构(学科→章节→叶子节点)改成 4 层固定结构:
学科 (L1) → 章节 (L2) → 7 板块容器 (L3) → 知识点条目 (L4)
一个学科对应一个思维导图,L3 的 7 个板块是概念/定义/定理/公式/示例/习题/笔记。新加章节时自动建 7 个子板块。
这次迁移动的是全部 9 个 JS 文件,约 6000 行代码,Claude Code 一次跑完。
4.2 本地模型落地(P11-P16)
这是最核心的部分。最终架构是 三级管线,每级有兜底:
输入(文字/图片)
│
▼
第一级:规则引擎(纯正则)
├─ 检测公式:$$…$$ / $…$ / f(x)=… → 标记"公式"
├─ 检测代码:```代码块``` → 标记"示例"
├─ 检测列表:- 开头/数字编号 → 标记"笔记"
└─ 全部不匹配 → 进入第二级
│
▼
第二级:Transformers.js 模型分类(7 选 1)
└─ 模型加载失败或置信度 < 0.5 → 进入第三级
│
▼
第三级:TF-IDF + 关键词权重匹配
├─ 对已有知识库做余弦相似度匹配
├─ 查用户纠正历史的关键词权重映射("泰勒"→"级数" +0.1)
└─ 任一章匹配分 < 0.3 → 提示新建章节
│
▼
确认弹窗 → 用户确认/调整 → 单条目入库
图片输入额外加了一层 Tesseract.js OCR(chi_sim 中文语言包 ~10MB,首次下载)转文字后再走上面的管线。
关键设计决策:不管输入多长,"一段文字 = 一个条目"。旧版 API prompt 里有"【粒度细化】如果包含多条并列规则必须拆分"的指令,导致一段"极限性质"被拆成 7 个独立条目。新版系统 prompt 彻底删掉了拆分逻辑,始终单条目输出。
4.3 反馈学习闭环(P14-P15)
分类不是一次性的,每次用户纠正都会写入反馈库。闭环设计:
用户确认弹窗
├─ 没改 → 记录"正确"(正向样本)
└─ 改了 → 记录 { AI 预测, 用户选择, wasCorrect: false }
│
▼
getCorrectionStats() 汇总:
"概念→定理" 发生了 3 次,"操作系统→高等数学" 发生了 5 次
│
▼
下次分类时 applyCategoryFeedback() 查表:
同一错误 ≥ 2 次 + 占比 ≥ 30% → 降低原分类置信度
+ 弹窗显示 💡 "过去你常将此内容从 概念 调整为 定理"
但这里有一个重要的设计原则:建议但不替用户做决定。 反馈系统只会降低置信度和显示提示,永远不会自动改分类结果。
4.4 关键词权重即时学习(P18)
TF-IDF 有个硬伤——不看语义。"泰勒公式"和"操作系统/MMU"在 TF-IDF 向量空间里可能因为统计噪音被误匹配。
我的解法是在 TF-IDF 之前加一层关键词权重映射:
用户把"泰勒公式"从"操作系统"纠正到"高等数学/级数"
↓
learnFromCorrection() 提取关键词:"泰勒""公式"
↓
权重映射更新:
"泰勒" → { subject: "高等数学", chapter: "级数", weight: 1.5, count: 1 }
↓
下次输入"泰勒展开" → TF-IDF 匹配前先查表 → "级数"章节 +0.075 加分
↓
再纠正一次 → weight 升到 2.0 → +0.1 加分
↓
三次纠正后 → "级数"稳居第一
"公式""定理"这类通用词不会被加入权重库,因为它们的 IDF 值太低——在所有章节都出现过,没有区分度。只有真正有区分度的词才会建立映射。
效果:同一个错误不会犯第三次。
4.5 API 大模型统一管线(P17)
内置模型跑通后,外部大模型还能用,但行为必须统一。
旧版 API 路径的问题是:system prompt 让 LLM 自由发挥,一段内容被拆成几十个条目,没有分类流程,直接灌入知识库。
新管线:
输入 → 始终先跑本地管线(分类+章节+总结)
│
├─ 无 API Key → 确认弹窗 → 入库
│
└─ 有 API Key → enhanceWithApi() 增强
API 输出结构化内容:
├─ keyPoints: 2-5 个关键要点
├─ detail: 详细解释 100-300 字
├─ relatedConcepts: 关联概念标签
└─ difficulty: 难度评级
确认弹窗展示展开内容 → 入库
管线控制权永远在本地,API 只做增强。挂了就降级到纯本地,不影响使用。
4.6 跨用户知识共享(P20)
反馈数据存在 localStorage 里,换浏览器就没了。多人用同一个工具的时候,一个人纠正过的分类其他人不能受益。
最初用 Cloudflare Worker 做中间层,但 .workers.dev 域名大陆不通。
最终方案:浏览器直连 GitHub API。 一个共享 token 写死在代码里(只有 public_repo 权限),所有人打开网页后纠正过的分类自动 commit 到仓库的 data/community-feedback.json。其他人打开网页时从 raw.githubusercontent.com 直接拉取,合并到本地分类器。
隐私考虑:只传前 300 字文本 + 分类结果,完全匿名,没有用户标识。
五、踩过的坑
记录几个印象深刻的 bug,所有做 AI 产品的人都会遇到类似的:
Bug 1:data.js 多了一个 } 导致整个 JS 文件解析失败
Claude Code 执行 P15 时在 getLearnFeedbackByType 函数最后多写了一个花括号。整个 data.js 挂了,findSubjects 等等 20 多个函数全部未定义。症状是"设置页面一切到本地模型就白屏"。
排查方法:node -c data.js 直接报 Unexpected token '}'。删掉就修好了。
教训:AI 改代码后,跑一下语法检查是必须的。
Bug 2:_feedbackAdjusted 访问 undefined 崩溃
applyCategoryFeedback 只在触发纠正建议时才给对象加 _feedbackAdjusted 字段。没触发时返回原对象,没有这个字段。但 runLocalAnalysis 的返回语句直接访问 category._feedbackAdjusted,没做防御判断。
修复:4 处访问全部加 category && / chapterResult && 防御。
教训:AI 写的可选字段,必须考虑"没被赋值"的情况。
Bug 3:GLM-4-Flash 输出完全不相关的内容
输入"TCP 三次握手",输出"三角函数/牛顿定律"。模型有输出,格式也对,但内容完全跑偏。
不是 bug,是能力不够。小模型做分类可以,做结构化 JSON 提取不行。
Bug 4:.workers.dev 域名在大陆不通
Cloudflare Worker 部署成功,海外能访问,大陆 timeout。DNS 解析正常但 HTTP 不通,换 IPv4 也一样。
最终放弃 Worker,改用浏览器直连 GitHub API 的方案。
六、一些我觉得值得说的设计决策
"一段文字 = 一个条目"
这个决策争议最大——为什么不让我一段话里提取多个知识点?
我的理由是:如果系统帮你拆,拆出来的东西你得一个个去审核改错;如果系统不拆,你手动输入多段文字也就多点几次。前者让用户"改错",后者让用户"创建"——改错比创建累得多。
而且单条目管线对模型来说是确定性任务(输入→输出),不是开放式任务(输入→拆成 N 个不确定的输出)。确定性任务的出错率低一个数量级。
本地优先,API 为辅
目前 80% 的输入不需要 API 就能处理完。规则引擎覆盖了公式/代码/列表这些高频场景,模型分类做剩下 20%,API 只在你手动配了 Key 的时候做润色。
建议但不替用户决定
反馈学习系统会显示"你过去常把这个从 X 调整到 Y",但不会自动改。用户始终是最终决策者。自动改错了比不改更让用户生气。
七、当前状态和下一步
已上线:
-
✅ 浏览器本地模型分类(Transformers.js + SmolLM2-135M)
-
✅ 图片 OCR(Tesseract.js)
-
✅ 反馈学习闭环(纠正一次 = 学一次)
-
✅ 跨用户知识共享(GitHub 直连)
-
✅ API 大模型统一管线(本地分类优先)
-
✅ 4 层数据模型(学科→章节→7 板块→条目)
下一步:
-
部署到 GitHub Pages(本地 20 个文件待 push)
-
关键词权重库的人工种子数据(预置一些常见学科的关键词映射)
-
微调专属 7 分类模型(用收集到的反馈数据 fine-tune DistilBERT)
最后
知叶 GitHub | 还在开发中,欢迎 Star 和提 Issue。
如果你也在做浏览器端的 AI 推理,或者有知识管理工具的需求,可以在评论区交流。踩过的坑分享出来,大家都能少走弯路。




