🧠 第二章 模型部署:在本地使用DeepSeek
📄 一句话概括

八个模块里缺两个——requests 和 flask 都没有。 但真正值得看的不是缺几个,是这台机器的底子:Python 3.13.14、8 核、15.9 GB 内存、 系统盘剩 285 GB。装依赖失败,九成是环境问题,不是包问题。

📝 本节和前面几节的关系

上一节算的是硬件,这一节算软件。为什么本地部署要先管 Python? 因为 Ollama 本体不用 Python,但围着它转的工具几乎全是 Python。

一、为什么本地部署要先管 Python

Ollama 本体是 Go 写的,装完就能用,不需要 Python。 但真正干活的东西都在外围:调 API 的脚本、批量处理的工具、做微调的训练代码、 把结果整理成表的小程序——全是 Python。 所以「装 Python 依赖」这件事,本质是为后面所有 Demo 铺路。 这一节装不好,后面每一步都会以「No module named …」的形式失败。 而失败的原因,绝大多数不在包里,在环境里。三种典型: 版本不对:包不支持当前的 Python 版本(新的 Python 出来时,很多库要等几个月才跟上)。 装错了地方:pip 装到 A 解释器,脚本用 B 解释器跑。网络不通:连不上 PyPI,卡在下载。

二、自检比安装重要

在敲 pip install 之前,先把五项量出来:Python 版本、解释器路径、操作系统、CPU 核数、内存和磁盘。 解释器路径这一项最容易被跳过,也最容易出事。一台机器上常常躺着三四个 Python:系统的、 Anaconda 的、某个软件自带的。 pip install 装进了第一个,脚本却用第二个跑,报的错永远是 ModuleNotFoundError。 依赖探测要用 import 试,不要用 pip list 看。 因为 pip list 只告诉你「装了」,不告诉你「能不能导入」——架构不匹配、动态库缺失、包损坏, 在 pip list 里都是「已安装」。 这就是 Demo 那段脚本的核心: 逐个数 __import__,成功就报版本,失败就报异常类型。 一行都不用猜。

三、八个模块各自是干什么的

Demo 里探测的八个,正好覆盖了这本书会用到的四类活儿:

模块 用途 缺了会怎样
numpy 数值计算底座 几乎所有 AI 库都装不上
matplotlib 画图与曲线 训练过程看不见
PIL 图像读写 绘画模型那章做不了
onnxruntime 跑导出的模型 端侧推理跑不起来
requests 调 HTTP 接口 得退回 urllib 手写
flask 起本地服务 做不了简易 API 服务
yaml 读配置文件 配置只能写死在代码里
tqdm 进度条 长任务不知道跑到哪
这台机器缺的是 requests 和 flask。
后果很具体:后面所有「调 API」的 Demo 都得用标准库的 urllib 手写,
「起服务」的 Demo 得用 http.server。能用,但代码会长不少。
这就是自检的价值:它提前告诉你「接下来要在哪儿绕路」。

四、装什么、怎么装、装到哪

三条规矩,按重要性排: 一个项目一个虚拟环境。 python -m venv .venv 建一个,激活之后 pip install, 装的东西全在这个目录里。删掉目录就等于卸载干净——这是它最大的好处。 装到当前解释器。 用 python -m pip install 而不是直接 pip install, 这样「装」和「跑」一定是同一个解释器。这一条能消掉一大半玄学问题。 装完再跑一遍自检。 看「缺」变成「已安装」,才算装完。没跑自检就说「装好了」,等于没装。 国内网络连 PyPI 慢的话,换个源是常规操作,一行参数的事,不算偏门技巧。

五、动手 Demo:自检这台机器:Python 3.13.14、8 核、15.9 GB,八个模块缺两个

写一个能反复用的环境自检脚本:先报五项硬指标(Python 版本、解释器、平台、CPU 核数、内存与磁盘), 再逐个 import 八个常用模块,成功报版本、失败报异常类型。

class MS(ctypes.Structure):        # 用系统接口取真实内存
    _fields_ = [(u'dwLength', ctypes.c_ulong),
                (u'ullTotalPhys', ctypes.c_ulonglong),
                (u'ullAvailPhys', ctypes.c_ulonglong)]

for name in (u'numpy', u'matplotlib', u'PIL', u'onnxruntime',
             u'requests', u'flask', u'yaml', u'tqdm'):
    try:
        mod = __import__(name)
        rows.append([name, u'已安装', getattr(mod, u'__version__', u'-')])
    except Exception as e:
        rows.append([name, u'缺', type(e).__name__])

实跑输出:

--------------------------------------------------------------------
安装 Python 依赖:先自检环境,再谈装什么
--------------------------------------------------------------------
  Python                   3.13.14
  解释器                   python.exe
  平台                     Windows 10
  CPU 逻辑核               8
  内存                     共 15.9 GB,可用 6.6 GB
  系统盘                   共 410 GB,剩余 285 GB

  依赖自检:能不能 import,比版本号更重要。
  模块          状态     版本/原因
  -----------------------------------------
  numpy         已安装   2.5.2
  matplotlib    已安装   3.11.1
  PIL           已安装   12.3.0
  onnxruntime   已安装   1.29.0
  requests      缺       ModuleNotFoundError
  flask         缺       ModuleNotFoundError
  yaml          已安装   6.0.3
  tqdm          已安装   4.70.0
  8 个里缺 2 个。**缺的那几个就是 pip 要装的东西,不是凭感觉装的。**

  这段脚本可以直接留在项目里当 setup_check.py:
  换一台机器、换一个虚拟环境,先跑它,再决定装什么。
  **「装依赖失败」的绝大多数原因,是环境本身有问题,不是包有问题。**

先看第一段。 Python 3.13.14、解释器 python.exe、Windows 10、8 个逻辑核、 内存共 15.9 GB 可用 6.5 GB、系统盘剩 285 GB。 这五项里,可用内存那一项最值得盯:共 15.9 GB 但只剩 6.5 GB,说明机器上跑着不少东西。 想跑 7B 模型(8.9 GB),得先关一批程序。 系统盘剩 285 GB,按上一节的表,能塞下 70B(42.4 GB)——但塞得下不等于跑得动, 70B 在这台机器上出字 0.6 tok/s。 第二段是依赖自检:八个里六个有、两个缺。缺的是 requests 和 flask,都报 ModuleNotFoundError。 注意这两行报的是异常类型,不是「未安装」三个字。 区别很重要:ModuleNotFoundError 是「没装」,如果是 ImportError 或 OSError, 那就是「装了但加载不了」——修法完全不同。 这段脚本可以直接留在项目里当 setup_check.py。换机器、换虚拟环境、换同事的电脑,先跑它。 三十秒省掉半小时。

30 秒实验

  1. 把探测列表加上 torch、transformers、jieba、pandas 再跑一遍。 你会看到这台机器缺得更多——这正是「先自检」的意义:知道要装多少,才不慌。
  2. 故意 __import__('this_module_does_not_exist'),看它抛什么异常。 再故意导入一个装了但缺动态库的包,对比两者的异常类型差异。
  3. 把脚本改成缺包时 sys.exit(1), 它就能接进自动化流程——装依赖这件事,也可以变成一个可判定的检查项。

常见误区

  1. 「pip install 成功就是装好了」。可能装到了另一个解释器。 用 python -m pip 装、装完再 import 一次,才算闭环。
  2. 「版本越新越好」。新 Python 出来时,很多库要等几个月才发轮子。 3.13 上装不上某个包,不是你操作错了,是它还没跟上。
  3. 「虚拟环境是多此一举」。 等到两个项目要不同版本的同一个库,就知道后悔了——那时候只能重装整个系统 Python。
自测三问(点开对答案) 1. 为什么用 import 探测依赖,而不是 pip list? —— pip list 只说明「装了」,import 才证明「能加载」。 架构不匹配、缺动态库、包损坏,在 pip list 里都显示已安装。 2. 解释器路径为什么重要? —— 一台机器常有好几个 Python。 pip 装到 A、脚本用 B 跑,就会报 ModuleNotFoundError,而包明明装着。 用 `python -m pip` 能避免。 3. 系统盘只剩 5 GB,能下载 7B 模型吗? —— 不能。7B 的 q4 是 4.6 GB,下载时是「先写临时文件再合并」,峰值占用接近两倍约 9.2 GB。 **按体积乘 2 来判断,不是按体积。**

环境备好了,接着装真正干活的那个程序。下一节讲 Ollama 怎么装,以及装完之后怎么判断它真的在跑。

相关笔记