必须使用requirements.in配合pip-tools锁定版本,因其分离人工声明与机器生成:requirements.in写顶层宽松约束,pip-compile据此生成带精确版本和哈希的requirements.txt,确保环境一致、可复现且防篡改。

因为不锁定版本,生产环境随时可能崩溃——不是“会不会”,而是“什么时候”。
pip install 时没写 == 就等于埋雷
如果你在 requirements.txt 里写的是 requests>=2.28.0 或干脆只写 requests,那每次部署都可能拉到不同版本。2026年6月 requests 2.32.0 刚发布,它把 Session.close() 改成异步了,而你的旧代码还在同步调用——服务一启动就 RuntimeError: Event loop is closed。
- pip 默认行为是“找最新兼容版”,不是“找最稳版”
- PyPI 上包的版本号不保证向后兼容,哪怕只是 patch 版本(如 2.31.1 → 2.31.2)也可能修复一个 bug,却意外暴露你代码里的隐式假设
- CI/CD 流水线里没锁版本 = 每次构建都是抽奖
Moondream2 这类模型对依赖极其敏感
Local Moondream2 的加载逻辑会穿透到 transformers 的 PretrainedConfig.from_pretrained、torch.nn.Module.load_state_dict,甚至 PIL.Image.open 的解码器分支。这些底层行为在 minor 版本更新中就可能变化:
-
transformers==4.45.2能正确加载 moondream2-v1-0 的 config.json;transformers==4.46.0把trust_remote_code默认值从False改成True,导致模型加载时多执行一段未经验证的远程代码,直接报SecurityError -
torch==2.4.0的load_state_dict对 state dict key 缺失容忍度高;torch==2.4.1加了 strict 检查,同一份权重文件就卡住不动 - 连
tokenizers的encode_batch返回格式,在 0.19.1 和 0.19.2 之间都有微小差异,影响 prompt 构建逻辑
requirements.in + pip-compile 是唯一能兼顾人可读和机器可靠的方案
直接手写带版本号的 requirements.txt 看似简单,实则不可维护:你改一个 django 版本,就得手动去查它依赖的 asgiref、sqlparse、pytz 全部兼容版本——这根本不是人该干的事。
-
requirements.in只写意图:moondream2~=1.0、torch>=2.4.0,让pip-compile去算最优解 -
pip-compile生成的requirements.txt不仅带精确版本,还附带--hash校验值,防止下载被篡改的包 - CI 中必须加
--upgrade参数跑pip-compile,否则缓存可能复用旧解析结果,导致不同机器生成不同requirements.txt
真正容易被忽略的不是“要不要锁”,而是“锁在哪一层”:Python minor 版本(3.11.8 vs 3.11.9)、pip-tools 版本(7.3.0 vs 7.4.0)、甚至 pip 本身(24.0 vs 24.1)都会影响依赖解析结果。所以锁定依赖,本质是锁定整个工具链快照,而不是单个包版本。
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!











