Langflow 在 macOS Intel (x86_64) + Python 3.13 上 PyTorch Wheel 缺口的根因调查与 PEP 508 平台排除实践
本文基于 Langflow 仓库内的调查文档 TORCH_MACOS_AMD64_PYTHON313_INVESTIGATION.md 展开,完整还原一个典型的跨平台依赖故障:PyTorch 在 2.2.2 之后停止发布 macOS x86_64(Intel)二进制 wheel,而 Python 3.13 在其后才发布,导致“macOS Intel + Python 3.13”这个组合永久性地没有官方 PyTorch 二进制可用,进而在 Langflow 的 test-installation-experimental CI 任务上产生持续性安装失败。读完本文,你将掌握如何用 PEP 508 环境标记(environment markers)在 pyproject.toml 中按平台精确排除依赖、如何理解 uv lockfile 中按平台分裂的 wheel 解析结果,以及如何在 CI 矩阵中用 continue-on-error 与“稳定/实验分层”策略处理平台 EOL(End-of-Life)问题。
一、问题结论先行:这是一个上游永久性缺口,不是 Langflow 的 Bug
调查文档的 TL;DR 给出了明确结论:
- PyTorch 在 2.2.2 版本之后正式放弃了 macOS x86_64(Intel)的 wheel 构建(废弃里程碑为 PyTorch 2.3,2024 年 3 月);
- Python 3.13 于 2024 年 10 月发布,晚于上述截止点,因此“macOS x86_64 + Python 3.13”这一组合不存在任何官方 PyTorch wheel;
- 这是一个上游(upstream)的、永久性的支持缺口,不是 Langflow 自身的缺陷;
- 受影响的 CI 任务是运行在
macos-latest-large(AMD64)上的test-installation-experimental,配合continue-on-error: true标记,该失败不阻塞发布,但属于持续性、可预期的失败。
PyTorch macOS x86_64 废弃时间线
| 事件 | 时间 | 说明 |
|---|---|---|
| PyTorch 社区发起废弃 macOS x86_64 构建的 RFC(issue #114602) | 2023 年 11 月 | 上游决策起点 |
| PyTorch 2.2.2 发布(最后一批 x86_64 macOS wheel) | 2024 年 3 月 | 该版本仅含 cp310、cp311、cp312 三种 ABI 的 macOS x86_64 wheel |
| PyTorch 2.3.0 发布(不再包含任何 macOS x86_64 wheel) | 2024 年 4 月 | x86_64 废弃的正式里程碑 |
| Python 3.13 发布 | 2024 年 10 月 | 时间点晚于 PyTorch 放弃 macOS x86_64,缺口自此形成 |
关键事实是:PyTorch 2.2.2 虽然有 macOS x86_64 的 wheel,但只覆盖 Python 3.10/3.11/3.12,没有 3.13;而 PyTorch 2.3 及以后对 macOS x86_64 平台完全不再发布 wheel。两个事实叠加,封死了“macOS Intel + Python 3.13”的所有官方二进制路径。
二、根因分析:uv 解析器如何“选中”一个无 wheel 的版本
1. uv lockfile 中 torch 的平台分裂
在 macOS x86_64 + Python 3.13 环境下进行依赖解析时,uv lockfile 中的 torch 条目按平台分裂为如下结构(调查文档中的快照):
torch 2.2.2 → Python < 3.13, macOS x86_64 (有 wheel: cp310, cp311, cp312)
torch 2.2.2+cpu → Python >= 3.13, macOS x86_64 (未列出任何 WHEEL!)
torch 2.10.0 → macOS arm64 (所有 Python 版本)
torch 2.10.0+cpu → Linux/Windows (所有 Python 版本)
解析器在“macOS x86_64 + Python 3.13”组合下会选中 torch 2.2.2+cpu,但该版本在目标平台上没有任何可用 wheel。安装随即失败——不是依赖冲突,而是“没有兼容二进制可下载”。这类故障的特征是:依赖树本身能解析通过,失败发生在安装(download/unpack)阶段。
2. torch 是如何被 Langflow 拉进依赖树的
主 langflow 包依赖 langflow-base[complete],其中多个 extras 会传递性地引入 torch。调查文档梳理的依赖链如下:
| Extra | 依赖链 | 在 macOS x86_64 上是否已排除 |
|---|---|---|
altk |
agent-lifecycle-toolkit → torch(直接依赖) |
否 |
altk |
agent-lifecycle-toolkit → sentence-transformers → torch |
否 |
altk |
agent-lifecycle-toolkit → trl → accelerate → torch |
否 |
docling |
docling → docling-ibm-models → torch |
部分(docling 二进制被排除,但 docling-core 未排除) |
easyocr |
easyocr → torch |
是(在 macOS x86_64 上完全排除) |
langchain-huggingface |
langchain-huggingface → sentence-transformers → torch |
否 |
其中 ALTK(Agent Lifecycle Toolkit)extra 是迫使 torch 在 macOS x86_64 上安装的主要未设防路径——该问题最初正是在 ALTK 链路上被观察到的,但真正的根因是 PyTorch 的平台支持策略。
3. 代码库中已有的同类缓解措施
Langflow 早已对部分 torch 依赖包使用 PEP 508 平台标记做了 macOS x86_64 排除。调查文档引用的当时配置如下:
# src/backend/base/pyproject.toml
docling = [
"docling-core>=2.36.1,<3.0.0",
"docling>=2.36.1,<3.0.0; sys_platform != 'darwin' or platform_machine != 'x86_64'",
]
easyocr = ["easyocr>=1.7.2,<2.0.0; sys_platform != 'darwin' or platform_machine != 'x86_64'"]
标记 sys_platform != 'darwin' or platform_machine != 'x86_64' 的语义是:只要不是“darwin 且 x86_64”就安装,即精确命中 Intel Mac 并跳过,对 Apple Silicon(arm64)和所有 Linux/Windows 环境保持完整功能。问题在于 altk 和 langchain-huggingface 当时没有同类排除标记。
4. CI 侧的配套配置
实验性安装测试位于 .github/workflows/cross-platform-test.yml 的 test-installation-experimental 任务中(见 任务定义):
- 在包括 macOS AMD64 在内的所有平台上测试较新的 Python 版本;
- 任务级声明
continue-on-error: true,失败不会阻塞发布流水线; - 下游的 test-summary 聚合任务把实验性平台的失败视为“可接受结果”。
当前仓库中该聚合逻辑仍保留:summary 任务对实验性结果有专门的容忍分支(“实验性平台可以失败”),稳定平台则必须全部成功(见 汇总判定)。
三、四个整改选项及其权衡
调查文档给出了四个选项,这里完整保留其配置示例与利弊分析。
选项 A:在 macOS x86_64 上排除所有 torch 依赖 extras(文档推荐)
仿照 easyocr 的既有做法,给所有传递依赖 torch 的 extras 添加平台标记:
# 在 src/backend/base/pyproject.toml 中
altk = ["agent-lifecycle-toolkit~=0.4.4; sys_platform != 'darwin' or platform_machine != 'x86_64'"]
langchain-huggingface = ["langchain-huggingface==0.3.1; sys_platform != 'darwin' or platform_machine != 'x86_64'"]
- 优点:CI 在所有实验性平台上通过;macOS x86_64 + Python 3.13 用户仍可正常使用 Langflow(只是没有 ALTK/HuggingFace 功能);与既有 docling/easyocr 模式一致。
- 缺点:降低了 macOS x86_64 的功能可用性;且影响该平台上的所有 Python 版本,而非仅 3.13。
选项 B:Python 版本 + 平台的复合标记
更“外科手术”的方案——只在真正坏掉的那个组合上排除:
altk = ["agent-lifecycle-toolkit~=0.4.4; (sys_platform != 'darwin' or platform_machine != 'x86_64' or python_version < '3.13')"]
- 优点:macOS x86_64 + Python 3.10–3.12 上的功能完整保留,仅排除坏掉的那个组合。
- 缺点:标记更复杂;PEP 508 对复合 OR 条件的求值在不同工具链中可能带来兼容性问题。
选项 C:从实验性 CI 矩阵中移除 macOS AMD64(最简)
鉴于 macOS x86_64 是正在退场的平台(Apple 自 2022 年起不再销售 Intel Mac),可直接从 CI 矩阵移除:
# 从实验性矩阵中移除该条目:
# - os: macos
# arch: amd64
# runner: macos-latest-large
# python-version: "3.13"
- 优点:改动最小(一行);节省 CI 成本(
macos-latest-largerunner 昂贵);与平台 EOL 的现实一致。 - 缺点:失去对 macOS x86_64 回归的可见性;仍有部分用户停留在 Intel Mac。
选项 D:维持现状(Status Quo)
实验性任务本就带 continue-on-error: true,test-summary 也将其报告为可接受;该失败是一个已知且已记录的限制。
- 优点:无需任何代码改动;保持 CI 可见性。
- 缺点:持续红色的 CI 任务造成告警疲劳(alert fatigue);可能掩盖实验性矩阵中其他真实失败。
文档给出的最终推荐:选项 A + 选项 C 组合
- 给
altk与langchain-huggingface添加 macOS x86_64 平台排除标记(选项 A),杜绝 Intel Mac 终端用户的安装失败; - 可选地从 Python 3.13 实验性矩阵中移除 macOS AMD64(选项 C),降低 CI 成本与噪声。
组合方案同时兼顾终端用户体验与 CI 健康度。在 macOS Intel 上损失部分功能被认为是可接受的,因为:Apple 已于 2022 年 6 月停止生产 Intel Mac;PyTorch 已于 2024 年 3 月放弃 Intel Mac 支持;HuggingFace/ML 生态正在快速向 macOS ARM-only 迁移。
四、仓库现状佐证:推荐方案已落地
调查文档提出的是方案;当前仓库源码与 CI 配置则展示了该方案落地后的状态。对照源码可以看到:
1. pyproject.toml 中的平台排除标记已就位
在 src/backend/base/pyproject.toml 中:
-
altk extra(第 366 行) 已带标记,且注释直接说明了原因——“Excluded on macOS x86_64: PyTorch dropped Intel Mac wheel builds after v2.2.2”:
altk = ["agent-lifecycle-toolkit>=0.10.1,<1.0; sys_platform != 'darwin' or platform_machine != 'x86_64'"] -
langchain-huggingface extra(第 373 行) 同样带标记,注释写明“transitive torch dependency (via sentence-transformers) has no Intel Mac wheels”。
-
docling 与 easyocr(第 385–399 行) 保持了同类排除模式,其中 docling 的排除施加在
docling-slim二进制侧,docling-core保留。
这与文档“选项 A”的建议完全一致,版本约束虽随时间演进(如 agent-lifecycle-toolkit>=0.10.1,<1.0,注释说明是为 PyTorch 2.6.0 兼容性升级),但平台标记策略未变。
2. CI 矩阵:macOS Intel 被系统性收缩
当前 cross-platform-test.yml 的矩阵体现了“选项 C”精神并已进一步演化:
- 稳定矩阵中 macOS AMD64 仅保留 Python 3.12 一档,且运行在昂贵的
macos-latest-large上(矩阵条目); - Python 3.13 已从实验性转正为稳定(blocking),但注释明确指出 macOS Intel 被刻意排除,Intel 平台对新 Python 版本的覆盖转移到实验层(矩阵注释);
- 实验性矩阵当前面向 Python 3.14,macOS Intel 被整体省略,注释 解释得非常透彻:langflow 在 Python 3.14 上要求
onnxruntime>=1.26,而 onnxruntime 自 1.24 起不再发布 macOS x86_64 wheel,因此“macOS Intel + Python 3.14”同样是永久不可满足的组合——保留它只会让昂贵的macos-latest-largerunner 烧在一个“注定失败且无信号”的用例上。
这个注释与本文调查文档形成呼应:同一平台在 PyTorch 与 onnxruntime 两条依赖链上先后触及“Intel Mac wheel 断供”问题,最终都选择了从矩阵中移除而非长期挂红。
3. 当前 lockfile 中 torch 的平台解析
调查文档附录中的 torch 版本表是 2026 年 4 月调查时的快照(2.2.2 / 2.10.0)。当前仓库的 uv.lock 中,torch 已统一解析到更高版本,且依旧按平台分裂为两组来源(均为 https://download.pytorch.org/whl/cpu 索引):
- 标准版
torch 2.13.0,标记为 macOS arm64 或 Python 3.14+ 的 darwin 环境(见 uv.lock 第 129–130 行); torch 2.13.0+cpu覆盖非 darwin 或非 arm64 的组合。
从源码结构看,macOS Intel(darwin + x86_64)在新旧两代 lockfile 中都不会被分配到“有 wheel 保证”的条目——平台标记机制持续保证该组合不会走到 torch 的直接依赖路径上,这正是 pyproject 层排除标记在锁定文件中的投影效果。
五、附录:受影响的 Lockfile 条目(调查时点快照)
调查文档附录记录了当时 uv 按平台解析出的 torch / torchvision 版本矩阵,完整保留如下。
torch 按平台解析的版本
| 版本 | 平台 | Python | 有 wheel? |
|---|---|---|---|
2.2.2 |
macOS x86_64 | < 3.13 | 是(cp310、cp311、cp312) |
2.2.2+cpu |
macOS x86_64 | >= 3.13 | 否 |
2.10.0 |
macOS arm64 | 全部 | 是(cp310–cp313) |
2.10.0+cpu |
Linux/Windows | 全部 | 是(cp310–cp313) |
torchvision 按平台解析的版本
| 版本 | 平台 | Python | 有 wheel? |
|---|---|---|---|
0.17.2 |
macOS x86_64 | < 3.13 | 是(cp310、cp311、cp312) |
0.17.2+cpu |
macOS x86_64 | >= 3.13 | 否 |
0.25.0 |
macOS arm64 | 全部 | 是 |
0.25.0+cpu |
Linux/Windows | 全部 | 是 |
六、可复用的方法论总结
这篇调查文档及其在仓库中的落地,沉淀出一套处理“上游二进制支持断供”问题的通用方法,值得在类似项目中复用:
- 先定性再动手:用 lockfile 反查“解析选中了哪个版本、该版本在目标平台是否有 wheel”,把“依赖冲突”与“二进制缺失”区分开。本案例中 uv 解析本身成功,失败在安装阶段,根因在上游平台支持矩阵而非本项目依赖声明的错误。
- 用 PEP 508 环境标记做平台级熔断:
sys_platform != 'darwin' or platform_machine != 'x86_64'是精确命中单一架构组合的标准写法;对“仅某个 Python 版本 + 某个平台”的坏组合,可叠加python_version构成复合标记(选项 B),但需评估跨工具的标记求值兼容性。 - CI 分层隔离 EOL 风险:稳定矩阵(blocking)只覆盖有长期支持承诺的“平台 × Python”组合;实验性矩阵用
continue-on-error: true观察生态演进,并由 summary 任务显式区分“稳定失败=阻断 / 实验失败=可接受”的判定语义(见 汇总任务)。 - 在配置文件中留注释讲清“为什么排除”:Langflow 的 pyproject.toml 在每条排除标记前都注明上游版本断供的事实(如 “PyTorch dropped Intel Mac wheel builds after v2.2.2”),使后来者无需重走一遍根因调查。
适用前提与限制:本文结论均基于当前仓库的源码、lockfile 与 CI 配置;PyTorch 上游若改变平台支持策略,或 macOS x86_64 用户群发生变化,选项 A/C 的取舍需要重新评估。对于运行 Langflow 的用户,实操建议是:Intel Mac 用户优先使用 Python 3.12 或以下版本以获得最完整的依赖面,Apple Silicon 用户则不受此问题影响。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0622
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00