Langflow Nightly 发布机制详解:协调式 .devN 版本链、发布顺序与安装验证指南
本文围绕 Langflow 仓库中的 nightly(夜间版)发布规范文档 src/bundles/NIGHTLY.md 展开,系统讲解 Langflow 及其配套包(langflow-base、lfx、langflow-sdk、lfx-* 扩展)的协调式 .devN 版本号计算方式、依赖发布顺序、nightly 安装方法、dry run 演练机制与发布前验证清单,并结合仓库内的版本计算脚本与 CI 工作流源码,说明每一环节的实际实现与可验证依据。读完本文,你可以完整理解 Langflow nightly 的版本设计原则,并能独立安装、演练和审计一个 nightly 发布。
一、什么是“规范名 nightly”:不发布平行的 *-nightly 包
Langflow 的 nightly 发布遵循一条与常规项目不同的设计决策:nightly 使用规范包名(canonical package names)配合协调一致的 .devN 版本号发布,而不是另起炉灶发布 langflow-nightly、langflow-base-nightly 这类平行的 Python 发行版。
这一原则直接体现在版本计算脚本 scripts/ci/pypi_nightly_tag.py 的模块注释中:nightly 以规范 .devN 预发布版本(例如 langflow==X.Y.Z.devN)的形式发布,dev 计数器是相对规范包 langflow / langflow-base 在 PyPI 上的历史计算的(其中 .devN 预发布版本才计数,稳定正式版永不参与计数)。这样做的好处是:
- 下游用户无需改变依赖声明中的包名,只需允许预发布版本解析,即可拿到最新 nightly;
- 规范 PyPI 项目名上的版本历史保持单一、连续,避免
-nightly影子项目造成的版本碎片化; - 版本号与稳定版共享同一条
X.Y.Z基线,语义上与 RELEASE.md 中“Langflow 与 LFX 共享 major.minor 版本线”的兼容契约保持一致。
脚本中定义的两个 PyPI 查询端点即对应这两个规范项目:
# 针对规范项目计数(而不是 `*-nightly`),因为 nightly
# 就是规范 .devN 预发布版本
PYPI_LANGFLOW_URL = "https://pypi.org/pypi/langflow/json"
PYPI_LANGFLOW_BASE_URL = "https://pypi.org/pypi/langflow-base/json"
二、版本链:一条精确到 .devN 的依赖锁
文档 src/bundles/NIGHTLY.md 定义了 nightly 的核心版本链:workflow 从 langflow、langflow-base、lfx、langflow-sdk 四个包的规范发布历史中推导出一个协调的 Langflow 开发版本,且这条依赖链在 nightly 场景下是精确(exact)的:
langflow==X.Y.Z.devN
-> langflow-base==X.Y.Z.devN
-> lfx==X.Y.Z.devN
其中:
- SDK(
langflow-sdk)使用同一协调版本,保证lfx对 SDK 的依赖可被本地 wheel 解析; - 独立的扩展发行版(
lfx-*bundles)保持规范包名和带边界的 LFX 兼容范围(bounded LFX compatibility ranges)。这一点可以从仓库根 pyproject.toml 看到当前主干的稳定依赖写法,如lfx-ibm>=0.1.5,<1.0.0、lfx-docling>=0.1.0,<1.0.0、lfx-datastax>=0.1.3,<1.0.0等——扩展包各自独立演进,不跟随 nightly 的.devN版本号; - 受影响的扩展 wheel 先于
langflow-base构建并发布,确保 base 发布时其依赖的扩展版本已在 PyPI 上可解析。
2.1 共享 dev 号的计算规则
dev 号 N 的计算逻辑在 scripts/ci/pypi_nightly_tag.py 中,核心规则可以概括为:
- 以根
pyproject.toml的base_version为基准(例如1.10.0)。脚本从根目录pyproject.toml读取版本号并取其base_version,脚本注释特别强调:full 与 base 的 nightly 刻意都从根 pyproject 取基线版本,如果 base 改读src/backend/base/pyproject.toml,两个包的 dev 计数器可能分叉,导致某个精确==pin 指向一个从未发布的版本; - 只统计同系列、带 dev 号的版本:遍历两个规范项目(
langflow与langflow-base)的 PyPI 发布历史,仅当version.base_version与基准版本一致且version.dev is not None时才计入。稳定正式版(如1.10.0)与旧系列(如1.9.x的 dev)都不参与计数; - 取两包最大值加一:
next_dev = max(dev_numbers) + 1,首个 nightly 则从dev0开始。这保证结果严格领先于两个包中最新的同系列 dev 版本,避免重复发布; - fail closed(失败即中止):PyPI 查询中,404 表示该项目尚无发布(例如历史首个 nightly),贡献空列表;但任何其他失败——网络错误、5xx/403 等非 404 HTTP 状态、200 但响应缺少
releases字段的畸形响应——都会抛出异常中止 nightly 任务。源码注释解释了原因:如果高版本号一侧的包查询临时失败,max(dev) + 1会被压低,从而重新生成一个已经发布过的版本号;在修改 tag 之前中止,正是为了防止这种回退。
测试文件 scripts/ci/test_pypi_nightly_tag.py 对上述规则做了全量覆盖(所有 PyPI 流量均被 mock,无网络访问),典型断言包括:
- 两包历史错位时(
langflow最新dev54、langflow-base最新dev48),main、base、both三种 build type 均返回同一标签v1.10.0.dev55,即max(54, 48) + 1; - 基准版本从
1.10.0升到1.10.1时,旧系列的 dev 不泄漏进新系列,结果重置为v1.10.1.dev0; - 仅有正式版发布时计数器从
dev0起步;正式版发布不推进 dev 计数器; - 畸形响应、500/503 错误、网络异常均抛出异常(对应文档中“构建前确认版本”的防线之一);
- 无法解析的版本字符串(如
not-a-version)被静默跳过。
2.2 “both” 模式:一次快照,杜绝跨调用漂移
脚本的 main 入口接受 base、main、both 三种 build type,其中 both 模式会把同一标签打印两次。这是 nightly workflow nightly_build.yml 中 create-nightly-tag 任务的实际用法:
TAGS_OUTPUT="$(uv run ./scripts/ci/pypi_nightly_tag.py both)"
RELEASE_TAG="$(printf '%s\n' "$TAGS_OUTPUT" | sed -n '1p')"
BASE_TAG="$(printf '%s\n' "$TAGS_OUTPUT" | sed -n '2p')"
# 若两个标签不一致则直接失败
“main”与“base”构建类型返回完全相同的版本是设计使然(lockstep versioning);both 模式让 workflow 从**一次调用(一个 PyPI 快照)**中同时读取 release 与 base 两个标签,从根上避免两次独立查询之间 PyPI 状态变化导致的标签漂移。
2.3 协调版本号如何写入各包
nightly 任务计算出四个标签后,通过 scripts/ci/update_pyproject_combined.py 把协调版本链写入各 pyproject.toml:
- 更新
src/backend/base/pyproject.toml的langflow-base版本号为base_version; - 在
langflow-base中写入对lfx的精确 dev pin(update_lfx_dep_in_base); - 更新根
pyproject.toml的langflow版本号为main_version,并把其对langflow-base的 uv workspace 依赖重新 pin 到协调的 base 版本。
随后 workflow 执行 uv lock(根目录与 src/lfx 各自锁定)、git commit 并打上 vX.Y.Z.devN 标注(annotated tag)推送到远端。需要留意 nightly_build.yml 中提交前的一条注释:nightly 保持规范包名,且稳定的 lfx-* bundles 不被修改,因此没有任何 bundle 的 pyproject 参与这个 nightly 提交——这正是第一节约束在版本管理上的落地。当前主干版本为 1.12.0(见 pyproject.toml、src/backend/base/pyproject.toml、src/lfx/pyproject.toml),因此当前版本线下的 nightly 形如 v1.12.0.devN。
三、发布顺序:按依赖拓扑从底向上
文档给出的发布顺序是:
langflow-sdklfx- 受影响的
lfx-*扩展发行版 langflow-baselangflow
并有一条硬性不变量:langflow-base 与 langflow 的版本号必须一致,不支持“仅 base”或“仅 full”的 nightly 版本。
这条顺序在 nightly 发布工作流 release_nightly.yml 的 job 依赖图中被逐字实现。各 publish 任务的 needs 链为:
| 发布任务 | 前置任务(needs) | 说明 |
|---|---|---|
publish-nightly-sdk |
build-nightly-lfx、test-cross-platform |
最先发布 SDK |
publish-nightly-lfx |
上一项 + publish-nightly-sdk |
LFX 依赖 SDK 的精确 dev 版本 |
publish-nightly-bundles |
上一项 + build-nightly-main、test-cross-platform |
扩展先于 base,满足“扩展 wheel 先于 langflow-base 发布” |
publish-nightly-base |
上一项 + 两个 build 任务 + 跨平台测试 | base 在扩展之后 |
check-nightly-main-pypi-dependencies |
上一项 + bundle 发布 | 等待 PyPI 传播(见下) |
publish-nightly-main |
上一项 + base 发布 | 最后发布 langflow |
几个值得展开的实现细节:
(1)bundle 发布的幂等与限流处理。 publish-nightly-bundles 任务先运行一段内嵌 Python 生成“发布计划”:逐个读取 bundle wheel 的 METADATA,向 PyPI 查询该版本是否已发布,已存在则跳过(“重新运行 nightly 但 bundle 版本未变应当是 no-op”),最终按根 pyproject.toml 中依赖声明的顺序排序输出。逐个 uv publish 时,每个 wheel 之间固定 sleep 60 秒;遇到 HTTP 429(PyPI 限流)会退避重试,最多 5 次;遇到 already exists 类错误则视为跳过而非失败。
(2)发布 full 前的 PyPI 传播等待。 check-nightly-main-pypi-dependencies 任务解析根 pyproject.toml 中 langflow-base 与所有 lfx-* 的直接依赖,然后在 20 分钟超时内、以 15 秒间隔轮询 PyPI(最多 60 次),确认每个要求都至少有一个已发布的版本能满足 spec,并且请求头携带 Cache-Control: no-cache 与缓存破坏参数。只有全部就绪,publish-nightly-main 才会执行——这保证了 langflow==X.Y.Z.devN 发布到 PyPI 后,用户 uv pip install --pre langflow 能立即解析出完整可安装的依赖链。
(3)跨平台安装测试先于一切发布。 三个 build 任务(LFX / base / main)各自构建 wheel 并通过 actions/upload-artifact 产出 dist-nightly-sdk、dist-nightly-lfx、dist-nightly-base、dist-nightly-main、dist-nightly-bundles 工件;test-cross-platform 任务随后调用 .github/workflows/cross-platform-test.yml 子工作流(pre_release: true)在多平台上安装并校验这些本地 wheel。所有 publish 任务都把它列在 needs 中——没有通过跨平台安装测试,一个 wheel 都不会发布。
3.1 构建阶段的关键校验
构建任务本身内嵌了文档“验证”一节要求的大部分检查:
- LFX 构建(
build-nightly-lfx):先用 grep 断言src/sdk/pyproject.toml的包名必须是langflow-sdk、版本必须等于传入的nightly_tag_sdk;再用uv tree --package lfx断言 LFX 包名与nightly_tag_lfx一致(源码注释解释了为何要--package定根:直接grep lfx会先命中lfx-ibm这类 bundle)。然后uv build --wheel构建 SDK 与 LFX 两个 wheel,并在干净 venv 中同时安装两个 wheel、运行lfx --help验证 CLI; - Base 构建(
build-nightly-base):从工件--force-reinstall --no-deps装回刚构建的 LFX wheel(注释说明:workspace 解析装的是源码,这里要测试的正是即将发布到 PyPI 的 wheel),校验langflow-base包名/版本后执行make build base=true args="--no-sources --wheel";随后安装${WHEEL_FILE}[complete]启动python -m langflow run --host localhost --port 7860 --backend-only,轮询http://localhost:7860/api/v1/auto_login直到服务就绪(120 秒超时),再确认进程能被正常终止; - Main 构建(
build-nightly-main):同样强制重装 LFX 与 base 两个构建产物 wheel,用uv tree校验langflow的版本等于nightly_tag_release,执行make build main=true,安装 main wheel 后以/health_check端点做同样的启动/关闭冒烟;最后遍历src/bundles/*/pyproject.toml为每个 bundle 构建 wheel 到bundles-dist/,供跨平台测试与发布使用。
构建全程使用 Python 3.13(工作流 env: PYTHON_VERSION: "3.13"),而 nightly 流水线上游的后端单元测试矩阵覆盖 3.10–3.14。
四、Nightly 流水线的触发与门禁
nightly 的入口是 nightly_build.yml,它由每日 00:00 UTC 的 cron 定时触发(注释注明对应美西下午 4/5 点)或手动 workflow_dispatch(可选 runs_on、skip_frontend_tests、skip_backend_tests、push_to_registry 等输入)驱动。其 create-nightly-tag 任务仅在主仓库生效,流程为:
- 解析最新的
release-*分支(git ls-remote按版本号排序取最高者)作为 nightly 基线; - 调用
pypi_nightly_tag.py both生成共享的 full/base 标签,并分别生成 LFX、SDK 标签; - 删除远端已存在的同名标签后,用
update_sdk_version.py、update_lfx_version.py、update_pyproject_combined.py写版本,uv lock两次(根目录与src/lfx),提交并推送 annotated tag; - 前端测试(Linux 阻塞、Windows 非阻塞)、后端单元测试(3.10–3.14)、压力测试通过后,
release-nightly-build调用 release_nightly.yml 完成构建与发布; - 随后执行数据库迁移验证(
db-migration-validation,使用规范仓库langflowai/langflow下的 nightly.devX镜像);任何阻塞任务失败或被取消都会向 Slack 发送包含失败 job 名与运行日志链接的通知。
五、安装 Nightly:预发布解析 + 规范包名
文档给出的安装方式是使用预发布解析(prerelease resolution)配合规范包名:
uv pip install --pre langflow
如果只需要不带 provider 扩展的可运行应用:
uv pip install --pre langflow-base
两个包都提供 langflow 命令——这与 release 工作流中的冒烟测试相互印证:build-nightly-base 任务正是安装 base wheel 后运行 python -m langflow run ... 验证 CLI 可用的。
理解这两条命令的前提:
- 不加
--pre时,pip/uv 默认不选择.devN预发布版本,因此该参数是拿到 nightly 的必要条件; langflow-base依赖lfx~=X.Y.0(当前主干为lfx~=1.12.0,见 src/backend/base/pyproject.toml),其 provider 相关能力以 extras(如beautifulsoup、sandbox、toolguard等映射到lfx[...])或独立lfx-*扩展的形式提供;langflow则把langflow-base与一组精选lfx-*扩展声明为直接依赖(见 pyproject.toml 中langflow-base~=1.12.0及lfx-*依赖清单)。nightly 场景下这些 pin 会被update_pyproject_combined.py精确重写为当次的 dev 版本,因此--pre安装 full 包时能整链解析到同一 nightly 版本线。
六、Dry Run:完整演练但不发布
规范文档保留了一个 dry_run 入口:发布工作流 .github/workflows/release.yml 的 release_tag 输入描述明确写道,该参数可以是发布 tag,也可以在 dry_run 为 true 时使用不可变的 commit SHA 或 pull request ref;dry_run 输入本身控制着全部“写外部世界”的动作。
dry run 的语义是:构建并验证每一个选中的 wheel 与镜像,但禁用以下操作——
- PyPI 发布(各 publish step 均以
if: ${{ !inputs.dry_run }}门控); - 容器镜像 registry 推送(
push_to_registry: ${{ !inputs.dry_run }}传递给 docker 构建子工作流); - tag 创建;
- GitHub Release 写入。
这使得 nightly 流程的任何改动都可以先在 PR 或特定 commit 上完整走一遍构建与校验路径,而不产生任何版本副作用。
七、发布前验证清单
文档“Verification”一节的六项检查是启用正式发布前的验收标准,结合仓库证据逐条说明:
- 构建前确认 root 与 base 版本一致——由
pypi_nightly_tag.py both的单快照机制与create-nightly-tag中的“两标签不一致即失败”断言共同保证; - 检查 wheel 元数据中的精确 nightly pin——沿 SDK/LFX/base/full 依赖链核验。
publish-nightly-bundles的发布计划脚本本身就是“读取 wheel 内*.dist-info/METADATA中 Name/Version”的实现范例; - 把本地 wheel 一起安装并运行
pip check——跨平台测试子工作流接收全部五个 dist 工件(含pre_release: true)做本地安装解析,等价于在发布前暴露依赖冲突; - 确认 base 不包含任何 provider 的
lfx-*、PyTorch、TorchVision 发行版——从源码结构看,provider 扩展被声明在 full 包 pyproject.toml 的依赖列表中,而 src/backend/base/pyproject.toml 只声明lfx~=1.12.0及将部分 extras 转发到lfx[...]的兼容层,与“base 精简、扩展独立”的架构一致; - 确认 full 包能发现(discover)其精选扩展——full 的直接依赖清单(
lfx-ibm、lfx-docling、lfx-datastax、lfx-toolguard等)即“精选扩展”的权威列表,且check-nightly-main-pypi-dependencies会在发布前逐一确认它们在 PyPI 上可解析; - 启用发布前运行 scripts/ci/test_pypi_nightly_tag.py 与发布工作流契约测试——前者验证 lockstep 版本计算的全部边界行为,后者(如 scripts/ci/test_release_workflow.py)守护工作流合同,两者均在仓库的 CI 脚本测试中可运行。
八、关键文件索引
| 主题 | 路径 |
|---|---|
| nightly 规范文档(本文依据) | src/bundles/NIGHTLY.md |
| 稳定发布流程与版本管理 | RELEASE.md |
| 共享 dev 号计算 | scripts/ci/pypi_nightly_tag.py |
| dev 号计算单元测试 | scripts/ci/test_pypi_nightly_tag.py |
| 协调版本写入 pyproject | scripts/ci/update_pyproject_combined.py |
| nightly 触发与打标(含定时任务) | .github/workflows/nightly_build.yml |
| nightly 构建与 PyPI 发布 | .github/workflows/release_nightly.yml |
| 正式发布工作流(dry run 入口) | .github/workflows/release.yml |
| 跨平台安装测试 | .github/workflows/cross-platform-test.yml |
| nightly Docker 镜像构建 | .github/workflows/docker-nightly-build.yml |
适用前提小结:以上机制基于当前仓库主干(版本线 1.12.0,构建环境 Python 3.13)的实际内容;安装 nightly 需要工具链支持预发布解析(如 uv pip install --pre),且 nightly 作为预发布版本,其稳定性预期低于按 RELEASE.md 中 4–6 周节奏发布的稳定版。
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 StartedRust0627
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