
1. 为什么我要自己做一个本地 AI 学习软件1.1 从“云端对话”到“桌面工具”的转变动机最开始接触大模型那会儿我和大多数人一样打开浏览器就能用觉得挺方便。但用得越久心里越不踏实。倒不是说功能不好而是有几个很现实的问题一直绕不过去第一每次对话都要联网网络一波动或者服务端一维护手头的事情就得停第二我经常拿它来整理一些工作笔记、项目草稿虽然平台都说数据安全但东西毕竟不在自己硬盘上总有一种“寄人篱下”的感觉第三很多平台对上下文长度、调用频率都有限制想批量处理一些本地文档用起来束手束脚。后来我开始琢磨能不能把模型直接搬到自己的电脑上跑。正好那段时间开源模型生态越来越成熟像 Llama 系列、Qwen 系列、DeepSeek 系列都有可以本地部署的版本配合 Ollama 这类运行时工具在 Windows 11 或者 Linux 上跑起来并不算难。于是我就动手做了一个本地 AI 学习软件定位很明确完全离线运行、免费开源、面向个人学习场景。它不是一个要跟商业产品拼功能的“全能助手”而是一个能安安静静待在你电脑里、随时打开就能用的学习工具。这个软件解决的核心问题就三个一是数据不出本机所有对话记录、上传的文档、生成的笔记都只存在本地二是不依赖网络装好模型之后断网也能正常问答三是可自由修改代码全部开源你想改界面、加功能、换模型都没人拦着。适合谁来用我觉得有三类人比较合适正在学 AI 应用开发的学生、想拿本地模型做知识管理的职场人、以及喜欢折腾开源项目的技术爱好者。哪怕你之前没接触过命令行跟着步骤走也能跑起来。1.2 本地运行到底意味着什么很多人听到“本地运行”第一反应是“是不是很吃配置”。这话对了一半。本地运行确实需要一定的硬件基础但并没有想象中那么夸张。以我自己的测试环境为例一台三年前买的笔记本16GB 内存、RTX 3060 显卡6GB 显存跑一个 7B 参数、4-bit 量化的模型对话响应速度完全可用日常问答、总结文档、写代码片段都没问题。如果只有 CPU用 8GB 内存跑 3B 左右的量化模型也能凑合只是速度慢一些。这里的关键在于量化。原始模型动辄几十 GB普通电脑根本装不下。量化就是把模型参数从高精度浮点数压缩成低精度整数比如从 FP16 压到 INT4体积能缩小到原来的四分之一甚至更少而效果损失在大多数学习场景下几乎感知不到。Ollama 默认拉取的模型很多都是量化版本这也是为什么它能在消费级硬件上跑起来的原因。另一个容易被忽略的点是推理框架的选择。同样的模型用不同的运行时跑速度和内存占用差别很大。我试过直接用手写 Python 脚本加载模型也试过用 llama.cpp、Ollama、LM Studio 这些工具最后选 Ollama 作为默认后端原因是它把模型下载、量化版本管理、API 服务这几件事都封装好了一条命令就能跑对新手最友好。而且它自带一个兼容 OpenAI 接口的本地服务意味着我后面想换前端或者接其他工具成本很低。2. 整体架构与技术选型拆解2.1 三层结构界面、服务、模型这个软件的架构不复杂我把它拆成三层来看。最上面是用户界面层负责聊天窗口、历史记录、文档上传、设置面板这些交互中间是服务层负责把用户输入组装成模型能理解的提示词调用本地模型接口再把返回结果流式吐给界面最下面是模型层由 Ollama 管理具体的模型文件对外暴露一个 HTTP 接口。这么分层的好处是每一层都可以独立替换。比如你嫌默认界面不好看可以只改前端后端逻辑一行不动你想换一个更强的模型只需要在 Ollama 里 pull 一个新模型然后在设置里改一下模型名就行。我自己在开发过程中就经常这么干前端调样式的时候用一个小模型快速验证功能稳定了再换大模型测效果。界面层我选的是Electron Vue 3。选 Electron 的理由很直接我熟悉 Web 技术栈用 HTML/CSS/JS 写界面效率最高而且 Electron 能直接打包成 Windows、macOS、Linux 三个平台的桌面应用一套代码到处跑。Vue 3 的组合式 API 写起来清爽状态管理用 Pinia组件库用的 Naive UI整体开发体验很顺。如果你更习惯 React换成 React 也完全没问题服务层通过 HTTP 通信跟前端框架解耦。服务层我用Node.js写了一个轻量级的中间层跑在 Electron 的主进程里。它主要做四件事管理对话上下文、拼接系统提示词、调用 Ollama 的/api/chat接口、处理流式返回。这里没有用 Python是因为 Electron 本身就带 Node 环境少引入一个运行时能降低打包复杂度。当然如果你要做更复杂的 RAG检索增强生成或者文档解析用 Python 写一个独立服务也合理通过本地端口通信即可。2.2 为什么选 Ollama 而不是自己造轮子市面上本地推理方案不少llama.cpp、text-generation-webui、LM Studio、vLLM 各有各的适用场景。我最终选 Ollama主要基于三个考量。第一是安装和模型管理足够简单。Windows 11 上直接下载安装包双击装完打开终端敲ollama run qwen2.5:7b它自动下载模型并进入对话。对比自己编译 llama.cpp、手动转换模型格式、配置各种参数这个体验对新手友好太多。而且它内置了模型库常用的开源模型基本都能一条命令拉到。第二是API 设计干净。Ollama 的接口风格跟 OpenAI 很像/api/chat接收 messages 数组返回流式 JSON。这意味着我前端写的调用逻辑以后想切换到其他兼容 OpenAI 接口的服务改动量极小。我在代码里把 base URL 做成了可配置项默认指向http://localhost:11434你想换成别的本地服务改个地址就行。第三是社区活跃、更新快。开源项目最怕的就是没人维护。Ollama 的迭代节奏很快新模型支持、性能优化、平台兼容性修复都跟得上。我遇到过几次 Windows 下的显存调度问题升级版本之后就解决了。这种“背后有人持续修”的感觉比自己维护一套推理脚本踏实得多。当然它也不是没缺点。比如对多模态模型的支持相对晚一些某些冷门模型的量化版本不全自定义参数不如直接调 llama.cpp 灵活。但对于“本地 AI 学习软件”这个定位来说它的优点远大于缺点。2.3 开源协议与项目结构项目采用MIT 协议开源。选 MIT 而不是 GPL是因为我希望别人能自由地把代码拿去改、拿去用甚至集成到自己的商业项目里没有太多约束。开源项目的价值在于被使用和被改进协议越宽松参与的人可能越多。项目目录结构大致如下local-ai-study/ ├── electron/ # 主进程代码 │ ├── main.js # 入口创建窗口 │ ├── ollama.js # 封装 Ollama API 调用 │ └── store.js # 本地数据存储对话记录、设置 ├── src/ # 渲染进程前端 │ ├── views/ # 页面组件 │ ├── components/ # 通用组件 │ ├── stores/ # Pinia 状态管理 │ └── utils/ # 工具函数 ├── public/ # 静态资源 ├── package.json └── README.md对话记录和设置用lowdb存在本地 JSON 文件里路径在用户目录下的.local-ai-study文件夹。选 lowdb 而不是 SQLite是因为数据量不大JSON 读写足够而且方便用户直接查看和备份。如果你要做大量对话的全文检索换成 SQLite 更合适这个后面在扩展部分会提。3. 核心功能实现与关键细节3.1 流式对话是怎么做出来的流式输出是提升体验的关键。如果等模型把整段话生成完再一次性显示用户盯着空白屏幕等好几秒会以为程序卡死了。流式就是模型每生成一个 token就立刻推送到界面上看起来像在“打字”。实现上分两段。后端 Node 这边调用 Ollama 的/api/chat时设置stream: true然后用fetch的response.body拿到一个可读流逐块解析 JSON。每个数据块长这样{model:qwen2.5:7b,message:{role:assistant,content:你},done:false}我把content字段提取出来通过 Electron 的 IPC 通道发给渲染进程。前端收到之后追加到当前消息的文本末尾Vue 的响应式系统会自动更新界面。这里有个细节要注意IPC 消息频率很高如果每个 token 都触发一次 Vue 更新性能会有压力。我的做法是在前端做一个小的缓冲每 30 毫秒合并一次更新肉眼看起来依然是连续的但渲染压力小很多。另一个坑是流的中断处理。用户可能在模型生成到一半时点“停止”这时候要能主动断开 fetch 连接并且把已经生成的部分保留下来。我在代码里用AbortController实现调用abort()之后catch 到中断异常把当前已累积的文本作为完整消息存入历史。如果不做这个处理用户点了停止界面可能卡在半截或者报一个看不懂的错误。3.2 对话上下文管理记住多少才合适大模型本身没有记忆它每次只能看到你这次发给它的内容。所谓“多轮对话”其实是每次请求都把之前的对话历史一起发过去。这就带来一个问题上下文越长占用的显存越多速度越慢而且超过模型的最大上下文长度就会报错。我的策略是滑动窗口 系统提示词固定。系统提示词比如“你是一个耐心的学习助手”永远放在最前面不参与裁剪。后面的历史消息按轮次保留默认保留最近 10 轮用户可以在设置里调整。当历史超出窗口时从最老的一轮开始丢弃。这个方案简单直接对学习场景够用。更高级的做法是摘要压缩当历史太长时先让模型把前面的对话总结成一段简短摘要用摘要替代原始历史。这样能保留更长的“记忆”但实现复杂而且摘要本身也要消耗一次推理。我在项目里留了接口但没有默认开启因为对大多数学习问答来说10 轮上下文已经能覆盖一个完整话题了。这里有个实操心得系统提示词的质量直接决定回答风格。我默认写的是“你是一个严谨、耐心的学习助手回答尽量分点、给例子不确定的内容要说明”实测下来比不写系统提示词的回答结构清晰很多。你可以根据自己的需求改比如学编程就强调“给出可运行的代码示例”学语言就强调“中英对照、解释语法点”。3.3 本地文档问答的简化实现学习场景里经常需要针对某份 PDF 或笔记提问。完整的 RAG 方案涉及文档切分、向量化、向量数据库检索工程量不小。我做了一个简化版用户上传纯文本或 Markdown 文件程序把文件内容读进来截取前 N 个字符默认 3000 字可调直接拼到系统提示词里作为“参考资料”发给模型。这个做法很“土”但胜在简单可靠不需要额外装向量数据库也不需要 embedding 模型。缺点是只能处理短文档长文档会超出上下文。对于学习笔记、课程大纲、单篇论文这类场景3000 字往往够用。如果你要处理整本书那就得上真正的 RAG这个我在扩展部分再说。文件读取用 Node 的fs模块PDF 的话需要额外引入pdf-parse这类库。我在项目里只默认支持.txt和.mdPDF 支持作为可选依赖因为不同 PDF 的编码和排版差异很大解析出来经常有乱码需要用户自己判断。这也是一个避坑点不要盲目相信 PDF 解析结果尤其是扫描版 PDF解析出来可能是空的得先确认文件是文字版还是图片版。3.4 设置面板里那些真正有用的选项设置面板我没有堆一堆花哨的东西只留了几个真正影响使用的选项设置项默认值说明模型名称qwen2.5:7b对应 Ollama 里的模型 tag服务地址http://localhost:11434Ollama 默认端口上下文轮数10保留最近多少轮对话温度0.7越高回答越随机越低越确定系统提示词内置默认可自定义流式输出开启关闭则等完整结果温度这个参数值得说一下。它控制模型输出的随机性范围一般 0 到 1有些模型支持到 2。学习场景我建议0.3 到 0.7太低比如 0.1回答会很死板每次都差不多太高比如 1.0 以上容易跑偏、胡言乱语。写代码、做数学题可以调到 0.2 左右求稳头脑风暴、写创意文案可以调到 0.8 左右求发散。还有一个隐藏设置是请求超时时间。本地模型首次加载比较慢尤其是大模型可能要几十秒。如果超时设太短第一次请求就会失败。我默认设成 120 秒并且在界面上加了“模型加载中”的提示避免用户以为程序没反应。4. 从零跑起来的完整实操流程4.1 环境准备装什么、怎么装先把基础环境搭好。你需要三样东西Ollama、Node.js、Git可选用来克隆代码。Ollama 去官网下载 Windows 安装包双击安装装完在终端敲ollama --version能输出版本号就说明成功了。Node.js 建议装 LTS 版本18 或 20装完敲node -v和npm -v验证。Git 如果不想装直接下载项目 ZIP 包解压也行。注意Windows 下 Ollama 默认安装到用户目录模型文件也放在用户目录下的.ollama文件夹。这个文件夹会越来越大一个 7B 量化模型大概 4 到 5 GB装几个模型就十几 GB。建议提前确认 C 盘空间或者通过环境变量OLLAMA_MODELS把模型目录改到其他盘。4.2 拉取模型选哪个、多大合适装好 Ollama 之后打开终端拉模型。新手我推荐从Qwen2.5 7B或者Llama 3.1 8B的量化版开始中文场景 Qwen 表现更好一些。命令是ollama pull qwen2.5:7b这个 tag 默认拉的是 4-bit 量化版本体积约 4.7 GB。如果你的显存只有 4GB 或者纯 CPU可以选更小的ollama pull qwen2.5:3b3B 版本体积约 2 GB速度更快但回答质量会下降适合配置有限的机器先跑通流程。等确认整个软件能用了再换大模型。拉完之后用ollama list查看已安装的模型用ollama run qwen2.5:7b可以直接在终端里测试对话。这一步很重要先确认模型本身能跑再排查软件问题能省很多时间。如果终端里都跑不起来那问题出在 Ollama 或硬件上跟我的软件无关。4.3 启动软件开发模式和打包模式克隆代码之后进入项目目录先装依赖npm install然后启动开发模式npm run dev这个命令会同时启动 Vite 开发服务器和 Electron 窗口。第一次启动会慢一些因为要编译前端资源。窗口出来后如果设置里的服务地址是默认的http://localhost:11434并且 Ollama 正在运行就可以直接对话了。想打包成可执行文件用npm run build打包产物在dist目录下Windows 下是一个.exe安装包或者免安装的文件夹。打包配置在electron-builder的配置段里你可以改应用图标、名称、版本号。这里有个坑打包后的应用访问localhost一般没问题但如果你的 Ollama 装在另一台机器上需要确保防火墙允许对应端口并且把服务地址改成那台机器的 IP。4.4 首次使用的参数调优建议软件跑起来之后别急着问复杂问题先做几个小测试确认链路通畅。我一般会按这个顺序测问一句“你好”看是否有流式回复。有回复说明前后端和模型都通了。问“11 等于几”看回答是否正常。这种简单问题能排除模型加载异常。上传一个短文本文件问“这个文件讲了什么”测试文档问答功能。连续问五轮相关问题测试上下文是否保留。如果第 1 步就没回复先检查 Ollama 是否在运行终端敲ollama list看有没有报错再检查设置里的地址和模型名是否跟ollama list里的一致。模型名写错是最常见的低级错误比如把qwen2.5:7b写成qwen2.5Ollama 找不到对应 tag 就会报错。5. 踩过的坑与常见问题排查5.1 模型加载慢、首次响应超时这是新手遇到最多的现象点发送之后界面转圈十几秒甚至更久然后报超时。原因通常是模型第一次加载需要把权重从硬盘读进内存/显存7B 模型大概要 10 到 30 秒取决于硬盘速度。机械硬盘比固态硬盘慢很多。解决办法有两个。一是把超时时间调长我在设置里默认给了 120 秒。二是提前预热软件启动时后台发一个极短的请求比如就发一个空格让 Ollama 把模型加载好等用户真正提问时就已经在内存里了。这个预热逻辑我在代码里做了开关默认开启对体验提升很明显。实操心得如果你经常切换模型每次切换后的第一次请求都会慢。建议固定用一两个模型不要频繁换。另外Ollama 默认会在模型闲置一段时间后卸载释放显存。如果你的显存够用可以设置OLLAMA_KEEP_ALIVE环境变量让它常驻比如设成-1表示永不卸载。5.2 显存不足与模型选择报错信息里出现out of memory或者CUDA error基本就是显存不够。这时候有几个选择换更小的模型7B 换 3B、换量化程度更高的版本比如 q4 换 q3、或者强制用 CPU 跑。强制 CPU 的方法是在 Ollama 启动时设置环境变量CUDA_VISIBLE_DEVICES-1或者在模型参数里指定num_gpu 0。CPU 跑会慢很多但至少能跑起来。我实测 3B 模型在纯 CPU 上i7 处理器大概每秒 5 到 10 个 token日常问答能接受长文生成就有点熬人。还有一个隐蔽的坑显存被其他程序占用。浏览器开太多标签页、游戏没关干净都会占显存。遇到莫名其妙的显存不足先关掉其他吃显存的程序再试。5.3 中文乱码与编码问题Windows 下终端默认编码可能是 GBK而模型输出和文件读取都是 UTF-8处理不当就会出现乱码。我在代码里统一做了编码转换读取文件时显式指定utf-8输出到界面时也确保是 UTF-8。如果你自己改代码记得在fs.readFile里加上utf8参数否则读出来是 Buffer直接拼到提示词里会出问题。另一个乱码场景是对话记录存储。lowdb 写 JSON 文件时默认是 UTF-8但如果你的系统区域设置有问题可能写出乱码。建议在写文件时显式指定编码并且用支持 UTF-8 的编辑器查看 JSON 文件确认。5.4 常见问题速查表现象可能原因排查方向点发送无反应Ollama 未启动终端执行ollama list报模型不存在模型名写错对照ollama list输出首次响应超时模型加载慢调大超时、开启预热显存不足报错模型太大换小模型或强制 CPU中文乱码编码不一致检查文件读写编码流式中断后卡住未处理 abort检查中断异常捕获上下文丢失轮数设置太小调大上下文轮数回答质量差模型太小或温度不对换大模型、调温度5.5 几个容易被忽略的细节对话记录的备份。数据存在本地 JSON 文件里好处是透明坏处是容易误删。我建议定期把.local-ai-study文件夹复制一份到别的盘。软件里也做了导出功能可以把单条对话导出成 Markdown方便整理成笔记。模型更新。开源模型迭代很快隔几个月就有更好的版本。Ollama 里用ollama pull重新拉同名 tag 会更新到最新版。但要注意更新后回答风格可能变化如果你对某个版本的回答很满意可以给它打个不同的 tag 保留比如ollama cp qwen2.5:7b qwen2.5:7b-backup。端口冲突。Ollama 默认用 11434 端口如果这个端口被别的程序占了Ollama 会启动失败或者换端口。遇到连接不上先确认端口。Windows 下可以用netstat -ano | findstr 11434查看端口占用情况。6. 后续可以怎么扩展6.1 接入真正的 RAG 做长文档问答前面说的简化版文档问答只能处理短文本。要处理整本书或者大量资料需要上 RAG。基本流程是把文档切成小块比如每 500 字一块用 embedding 模型把每块转成向量存进向量数据库用户提问时把问题也转成向量在数据库里找最相似的几块拼到提示词里发给模型。本地做 RAGembedding 模型可以用 Ollama 里的nomic-embed-text向量数据库可以用 Chroma 或者 LanceDB都是轻量级的能嵌进应用里。这个工程量比现在的版本大不少但如果你有大量资料要查询值得投入。我在项目 issue 里看到有人已经做了这个扩展可以参考。6.2 多模型切换与对比现在软件一次只能用一个模型。一个有意思的扩展是同时接多个模型让它们回答同一个问题并排对比。这对学习特别有用你能直观看到不同模型在同一问题上的表现差异。实现上就是把请求发给多个模型前端分栏显示。Ollama 支持同时加载多个模型显存够的话或者串行调用也行。6.3 提示词模板库学习场景里很多提问是有固定套路的比如“解释这个概念”“帮我总结这段”“出几道练习题”。可以做一个提示词模板库用户点一下就把预设的提示词填进输入框省去每次手打的麻烦。模板可以存在本地也支持导入导出方便分享。6.4 语音输入与朗读本地语音识别和语音合成现在也有开源方案比如 Whisper 做识别、Edge TTS 做合成。接进来之后就能用说话的方式提问让软件把回答读出来。对学语言或者不方便打字的时候挺实用。不过语音模型也吃资源建议做成可选功能按需加载。我在实际使用中最大的体会是本地 AI 软件的价值不在于功能多强大而在于它完全属于你。你可以断网用、可以随便改、可以存任何东西不用担心。这种掌控感是云端服务给不了的。如果你也想动手做一个建议先从跑通最小可用版本开始别一上来就追求功能齐全。先把“能对话”这一件事做扎实后面加什么都是水到渠成。