
本地跑大模型这件事我从去年折腾到现在前后换过三台机器、重装过不下十次环境踩的坑足够写一本小册子。最开始的想法特别朴素我只是想要一个能离线用、数据不出本机、还能按自己需求改的 AI 学习工具。市面上的在线服务要么按量计费要么把对话记录留在别人服务器上要么功能被砍得只剩一个聊天框。于是我干脆自己动手用开源模型加本地推理引擎搭了一套完整的学习软件从模型加载、对话管理到知识库检索全部跑在本地代码也全部开源出去了。这篇文章不讲空泛的概念只讲我实际做出来的东西它由哪些模块组成、每个模块为什么这么选、本地推理的性能怎么调、知识库检索怎么落地、以及我在真实使用中遇到的那些文档里不会写的坑。无论你是刚接触本地大模型的新手还是已经跑过几轮推理想进一步做应用的老手都能从下面这些内容里找到能直接抄作业的部分。核心关键词就三个AI、开源、本地运行全文围绕它们展开。1. 为什么我坚持把 AI 学习软件做成本地运行1.1 在线服务的三个硬伤逼我转向本地先说清楚动机不然很多人会觉得本地跑模型是脱裤子放屁。我最初也是在线服务的重度用户直到遇到三件让我彻底改变想法的事。第一件是数据归属。我用 AI 辅助整理一些内部技术笔记和项目复盘这些东西虽然不算机密但也不适合长期躺在别人的服务器上。在线服务的隐私条款写得再漂亮数据终究是离开了我的硬盘。第二件是可用性。有段时间我需要在没有外网的环境里查资料、做总结在线服务直接歇菜而我手头明明有一块能跑推理的显卡。第三件是可控性。我想调整系统提示词、想换一个更适合中文的模型、想接入自己的文档库在线服务要么不支持要么得加钱上企业版。这三件事叠加起来结论就很明确了我需要一个数据不出本机、断网可用、能随意改造的 AI 工具。本地运行不是目的而是满足这三个需求的唯一路径。1.2 本地运行到底解决了什么问题很多人对本地运行有个误解以为只是为了省钱。省钱只是顺带的真正的价值在于三点。其一是数据主权。所有对话、上传的文档、生成的向量索引全部存在本机磁盘上。我可以随时删除、随时备份、随时迁移不需要向任何第三方申请导出。对于需要处理敏感资料的人来说这一条就值回票价。其二是离线可用。模型权重下载到本地之后推理过程完全不依赖网络。我在高铁上、在会议室断网的环境里都用过体验和联网时没有区别。这一点对经常出差或者工作环境网络受限的人特别友好。其三是可改造性。开源意味着我能看到每一行推理逻辑能替换模型、能改提示词模板、能加自定义工具调用。我后来给这套软件加了一个专利文档辅助检索的模块在线服务根本不可能让我这么干。1.3 这套软件的定位学习工具而非聊天玩具需要明确一点我做的是一个学习软件不是又一个聊天框。两者的区别在于聊天框只负责把问题丢给模型、把回答显示出来学习软件要解决的是如何让模型基于我的资料回答问题以及如何让我的使用过程可积累、可检索、可复用。所以这套软件的核心能力包括本地模型推理、多轮对话管理、本地知识库检索增强、对话记录持久化、以及一个能让我快速切换模型和参数的配置层。下面几节会逐个拆开讲。2. 技术选型推理引擎、模型与前端怎么搭2.1 推理引擎为什么选 Ollama 而不是自己写本地推理的引擎选择其实不多主流的就那么几个llama.cpp 直接调用、Ollama、以及一些 Python 侧的封装库。我最终选 Ollama 作为默认引擎理由很实际。llama.cpp 是最底层的性能最好、控制最细但它的接口偏底层模型格式转换、量化参数、上下文长度这些都要自己处理对新手不友好。而 Ollama 在 llama.cpp 之上做了一层封装把模型下载、加载、量化、服务化都包好了一条命令就能拉起一个本地推理服务暴露的是标准的 HTTP 接口。这意味着我的前端代码不需要关心底层是 llama.cpp 还是别的什么只要按接口调用就行。提示Ollama 默认监听本机的 11434 端口只对本机开放不需要额外配置防火墙规则。如果你的机器上有多个用户注意这个端口默认没有鉴权别随意改成对外监听。当然 Ollama 也有代价它的抽象层会带来一点点性能损耗而且模型格式受限于它支持的 GGUF。但对我这种以应用为主、不追求极限性能的场景来说这点损耗完全可以接受。如果你追求极致吞吐可以后期把引擎换成直接调 llama.cpp 的 server接口层不用动。2.2 模型选择中文能力、显存占用与量化等级的平衡模型选择是本地运行里最纠结的一环。我的筛选标准有三条中文能力要过关、显存占用要能塞进我的显卡、量化之后质量不能崩得太厉害。先说量化。GGUF 格式的模型有 Q4、Q5、Q8 等不同量化等级数字越大精度越高、体积越大。Q4_K_M 是社区里公认的甜点4bit 量化后 7B 模型大概占 4 到 5GB 显存13B 模型大概 8GB 左右。我实测下来Q4_K_M 在日常问答和文档总结场景里和 Q8 的差距肉眼几乎看不出来但显存占用少了一半。下面是我实际用过的几个模型对比供参考模型规模量化等级显存占用中文表现适用场景7BQ4_K_M约 4.5GB良好日常问答、短文档总结7BQ8_0约 8GB优秀对精度要求高的推理13BQ4_K_M约 8GB优秀长文档理解、复杂问答13BQ5_K_M约 10GB优秀平衡精度与占用我的建议是显存 8GB 以下选 7B 的 Q4_K_M8GB 到 12GB 选 13B 的 Q4_K_M12GB 以上可以考虑 13B 的 Q5 或者更大的模型。别一上来就追求最大最强的模型跑不动等于零。2.3 前端形态为什么我放弃了纯网页方案前端我一开始做的是纯网页浏览器打开就能用。但用了一段时间发现两个问题一是浏览器标签页一多就容易误关对话记录丢失二是网页方案很难做系统级的快捷键唤起和文件拖拽。后来我改成了本地 Web 服务加桌面壳的方案。核心逻辑还是一个本地 HTTP 服务前端用轻量的框架渲染外面套一层桌面容器。这样既保留了网页开发的灵活性又有了桌面应用的稳定性和系统集成能力。文件拖拽、全局快捷键、托盘常驻这些都能做。如果你不想折腾桌面壳纯网页方案也完全够用只要把对话记录存在本地数据库而不是浏览器 localStorage 里就行。localStorage 会被清理这是很多人踩过的坑。3. 本地知识库检索增强的落地细节3.1 为什么光有模型不够必须加检索大模型有个致命问题它的知识截止到训练数据的时间点而且它不知道你的私有文档里写了什么。你直接问它我上周那份项目复盘里提到的性能瓶颈是什么它只会一本正经地胡说八道。解决办法就是检索增强生成也就是常说的 RAG。思路很直白把你的文档切块、转成向量、存进本地向量库用户提问时先把问题也转成向量在向量库里找出最相关的几个文档块连同问题一起塞给模型让模型基于这些材料回答。这样一来模型回答的内容就有了依据而且这个依据完全来自你本地的文档不涉及任何外部传输。3.2 文档切块策略切多大、怎么切切块是 RAG 里最容易被忽视但影响最大的环节。切太大检索出来的块里噪音多模型容易被无关内容带偏切太小一个完整的语义被切断检索出来答非所问。我试过几种策略最后稳定在按语义段落切、目标块大小 500 到 800 字、块之间保留 100 字左右重叠。按段落切是因为中文文档的段落本身就是语义单元比按固定字数硬切要合理得多。保留重叠是为了防止一个关键信息正好卡在两块的边界上被切断。具体实现上我先把文档按换行拆成段落然后贪心地往当前块里塞段落塞到接近目标大小就封口同时把最后一段的一部分作为下一块的开头。代码逻辑大概是这样def split_into_chunks(text, target_size600, overlap100): paragraphs [p.strip() for p in text.split(\n) if p.strip()] chunks [] current for para in paragraphs: if len(current) len(para) target_size: current para \n else: if current: chunks.append(current.strip()) # 保留重叠部分 tail current[-overlap:] if len(current) overlap else current current tail para \n if current.strip(): chunks.append(current.strip()) return chunks注意overlap 不要设得太大否则向量库里会有大量重复内容检索时容易返回一堆相似的块反而稀释了有效信息。100 字左右是个比较稳的值。3.3 向量化与本地向量库的选择向量化就是把文本转成一串数字向量语义相近的文本向量距离也相近。这一步需要一个嵌入模型。我选的是本地能跑的中文嵌入模型体积小、速度快几百字的块毫秒级就能出向量。向量库我用的是轻量级的本地方案数据直接存成文件不需要额外起数据库服务。对于个人使用场景几万条向量的规模这种方案完全够用而且备份就是复制文件特别省心。如果你要处理几十万条以上的向量再考虑上专业的向量数据库。检索的时候有个细节我默认返回 top 5 个最相关的块但会做一个相似度阈值过滤低于阈值的块直接丢掉。这样当用户问的问题和知识库完全无关时不会硬塞一堆不相关的材料给模型避免模型被误导。4. 对话管理与本地持久化的实现4.1 对话记录为什么必须落盘前面提过 localStorage 会被清理的坑这里展开说。浏览器存储有几个问题容量有限、清理策略不透明、换浏览器就没了。我有个朋友用网页版工具整理了两个月的学习笔记结果一次浏览器更新全没了欲哭无泪。所以对话记录必须落到本地文件或者本地数据库。我用的是轻量的本地数据库每条对话存成一条记录包含时间戳、模型名、完整的消息列表、以及引用的知识库块。这样既能按时间检索也能按关键词搜索历史对话。4.2 多轮对话的上下文管理多轮对话不是把历史消息一股脑全塞给模型。模型的上下文窗口是有限的塞太多会超出限制而且历史越长推理越慢、显存占用越高。我的策略是滑动窗口加摘要。最近几轮对话完整保留更早的对话压缩成一段摘要。具体来说保留最近 6 轮完整消息再往前的对话用模型自己总结成一段话放在最前面。这样既保留了长期上下文又控制了 token 数量。这里有个实操心得摘要的生成不要每轮都做那样太浪费算力。我的做法是当历史消息超过 10 轮时才触发一次摘要把最老的几轮压缩掉。实测下来这个频率比较合理。4.3 对话导出与迁移既然是学习工具对话记录的导出就很重要。我做了两种导出格式Markdown 和 JSON。Markdown 方便人阅读和整理成笔记JSON 方便程序处理和迁移到其他工具。导出的时候我会把引用的知识库来源也带上这样回头看的时候能知道当时模型是基于哪份文档回答的。这个细节很多人不做但实际用起来特别有用尤其是做技术调研的时候。5. 性能调优让本地推理跑得更快更稳5.1 显存不够时的分层加载策略显存不够是最常见的问题。模型加载不进去要么报错要么被迫用 CPU 推理速度慢到无法忍受。Ollama 支持把一部分层放在 GPU、一部分放在 CPU通过参数控制 GPU 加载的层数。层数越多越快但显存占用也越高。我的经验是先把 GPU 层数设成一个保守值跑起来看显存占用再逐步往上加加到接近显存上限但还留一点余量为止。提示留余量很重要。显存跑满会导致系统卡顿甚至推理进程被杀。一般留 500MB 到 1GB 的余量比较稳妥。5.2 上下文长度对性能的影响上下文长度是个隐形杀手。很多人把上下文设成 8192 甚至更大觉得越大越好结果发现推理慢得离谱。原因是注意力机制的计算量随上下文长度增长得很快上下文翻倍计算量可能翻好几倍。我的建议是按需设置。日常问答 2048 到 4096 足够长文档总结再临时调到 8192。而且要注意上下文长度是预分配的即使你实际只用了 500 个 token设成 8192 也会占用对应的显存。所以别没事就拉满。5.3 并发请求与队列控制本地推理通常是单请求串行的同时来两个请求会互相抢资源结果两个都变慢。我的做法是在服务层加一个简单的队列请求进来先排队一个一个处理。虽然牺牲了一点并发性但保证了每个请求的响应速度稳定。如果你确实需要并发可以考虑起多个推理实例每个实例绑定不同的端口前端做负载分发。但这会成倍占用显存一般个人使用没必要。6. 实际使用中踩过的坑与排查过程6.1 模型加载失败从报错到定位的完整链路有一次我换了个新模型加载直接失败报错信息很模糊只说加载出错。我的排查链路是这样的第一步确认模型文件完整性。下载中断会导致文件损坏用校验工具对一下哈希值。第二步确认量化格式是否被当前引擎版本支持。有些新量化格式需要更新引擎版本。第三步看显存是否真的够。有时候报错不是显存不足但实际是显存碎片导致的分配失败重启一下推理服务就好了。第四步看模型文件路径有没有中文或空格某些底层库对路径字符很敏感。最后定位到是量化格式太新引擎版本没跟上。更新引擎后问题解决。这个链路我后来整理成了排查清单遇到加载问题就按顺序过一遍基本能覆盖九成情况。6.2 中文乱码与编码问题中文乱码在本地处理文档时特别常见。表现是检索出来的内容是一堆问号或者方块。根因通常是文件编码不是 UTF-8而读取时按 UTF-8 解析了。解决办法是在读取文件时先探测编码或者统一转成 UTF-8 再处理。我在文档导入环节加了一个编码检测步骤遇到非 UTF-8 的文件先转换再入库。这个坑看起来小但不处理的话整个知识库都是废的。6.3 检索结果不相关的调优过程有段时间我发现检索出来的块经常和问题不相关。排查下来有三个原因一是切块太大块里混了太多无关内容二是嵌入模型对中文的语义理解不够好三是相似度阈值设得太低把不相关的块也放进来了。对应的调整是把块大小从 1000 字降到 600 字换了一个中文表现更好的嵌入模型把相似度阈值从 0.3 提到 0.5。三步做完检索准确率明显提升。这个过程说明 RAG 的效果不是一蹴而就的需要根据实际数据反复调。7. 开源之后的一些体会代码开源出去之后陆续有人提 issue、提 PR也有人在评论区分享自己的用法。有几件事让我印象挺深。一个是有人把模型换成了更小的版本跑在了一台老笔记本上虽然慢但能用他说这比没有强。这让我意识到本地运行的价值不只是性能还有可及性。另一个是有人给知识库模块加了 PDF 解析直接把我没做的功能补上了。开源的好处就在这里你做一个骨架别人帮你长出血肉。如果你也想做类似的东西我的建议是先把最小可用版本跑通别一上来就追求功能齐全。我第一版只有模型加载和对话两个功能能跑起来之后才逐步加的知识库、导出、多模型切换。先让它能用再让它好用这个顺序别搞反。最后分享一个我一直在用的小技巧把常用的系统提示词存成模板文件切换场景的时候直接加载对应模板比每次手敲提示词效率高得多。我目前存了技术问答、文档总结、代码解释三个模板日常够用了。