pip 升级成功,LangChain 却还在旧版?1.5.0 升级排障:Python、依赖与镜像一次讲清

你执行了升级,命令没有报错,LangChain 却仍停在 1.4.x。
你改成指定 langchain==1.5.0,又收到:

ERROR: No matching distribution found for langchain==1.5.0

第一反应是换一个国内源,第二反应是清缓存。
但这一次,真正的线索可能就在前面那句 Requires-Python 里。

LangChain 1.5.0 已于 2026 年 11 月 11 日发布,最低 Python 版本提高到 3.11,依赖的 langchain-core 下限提高到 1.8.0。
这两项变化见 LangChain 官方发布说明。

本文用真实 pip 实验复现“找不到新版”和“成功选到旧版”,再给出从定位到迁移、验证、回滚的完整操作路径。
你不用 API Key,也不用付费模型。

图 1:同一个版本目标,在不同 Python 约束下会产生不同结果;安装成功只是验证的第一层。

核验日期:2026-11-12。
下载实验在 Linux、Python 3.12.3、pip 24.0 上执行,通过 --python-version 指定目标解释器版本。
这不是在真实 Python 3.10 / 3.11 进程中运行 LangChain;实际安装与离线运行验证使用 Python 3.12.3。

一、先分清三种现象,别让一条报错带偏方向

现象 优先核对 为什么
升级命令成功,版本仍是 1.4.x 当前 Python、版本范围、锁文件 新版可能不属于当前环境的兼容候选
指定 1.5.0,提示没有匹配版本 前面的 Requires-Python 提示、目标源是否提供该版本 同一句末尾错误可能有不同原因
装好了,但项目启动失败 实际解释器、provider 包、旧 API 与项目约束 下载和安装并没有执行你的业务路径

pip 需要同时满足版本要求、Python 要求和相关依赖约束。
“最新可安装版本”并不总是“这个项目发布的最新版本”。

本次核对的 PyPI 1.5.0 元数据声明 Python 范围为 <4.0.0,>=3.11.0。
1.4.10 的元数据则仍允许 Python 3.10;core 1.8.0 同样要求 Python 3.11 起步。
因此,不要把“LangChain 已经发了新版”理解成“任何解释器都能装新版”。

二、第一步:确认运行代码的 Python,和安装包的是同一个

在你真正启动项目的终端里执行:

python -c "import sys; print(sys.executable); print(sys.version)"
python -m pip --version
python -m pip show langchain langchain-core langgraph

看两个位置:sys.executable 指向哪里,pip --version 的路径属于哪个环境。
这里统一使用 python -m pip,让安装命令明确绑定到这一条 Python 解释器。

如果你在 Notebook 中遇到“终端已经升级、单元格还是旧版”,先在单元格执行:

import sys
from importlib.metadata import version

print(sys.executable)
print(sys.version)
for name in ("langchain", "langchain-core", "langgraph"):
    print(name, version(name))

包未安装时,version() 会抛出 PackageNotFoundError;这也是“当前内核不是预期环境”的线索。
应让 Notebook 内核指向新环境,并在安装后重启内核,避免已加载模块仍驻留内存。
仅修改终端的 PATH,不能证明已启动的内核也换了解释器。

容器和服务同理:应在实际运行的容器或服务环境内检查,不能用宿主机的 Python 版本代替。
本次只做本地环境实验,没有更改论坛服务器或生产依赖。

图 2:建议按解释器、Python 兼容范围、包源候选、整组依赖的顺序缩小问题。

三、真实复现:不安装旧 Python,也能看到候选怎样被筛掉

pip download 官方文档支持为目标解释器下载分发包。
我们利用这个能力检查候选筛选,不修改当前环境中的 LangChain。

下面命令只下载顶层 wheel,不下载依赖。
--isolated 用来忽略环境变量与用户配置,减少这轮实验受到额外配置的影响;显式指定官方源便于复现本次证据,网络受限时应使用可访问且可信的源。

实验 A:目标 Python 3.10,强制要求 1.5.0

python -m pip --isolated download --index-url https://pypi.org/simple --no-deps --only-binary=:all: --python-version 3.10 --dest wheels310-pinned "langchain==1.5.0"

本地实际退出码为 1。
日志节选如下,省略了冗长的历史版本列表:

ERROR: Ignored the following versions that require a different python version: 1.5.0 Requires-Python <4.0.0,>=3.11.0
ERROR: No matching distribution found for langchain==1.5.0

关键证据是第一行:候选存在,但被 Python 版本约束排除了。
此时仅仅更换镜像,并不会改变 1.5.0 的 Python 要求。
如果你的实际日志没有这条提示,仍需继续核对索引可达性、版本是否存在,以及其他兼容条件,不能直接套用本例根因。

实验 B:仍是 Python 3.10,但允许 1.4 到 1.5 系列

python -m pip --isolated download --index-url https://pypi.org/simple --no-deps --only-binary=:all: --python-version 3.10 --dest wheels310-range "langchain>=1.4,<1.6"

本次快照实际退出码为 0,下载文件是:

langchain-1.4.10-py3-none-any.whl

这正是“命令成功,却没拿到期待的新版”的机制:要求允许旧版本,而旧版本仍满足当前 Python 约束。
本例没有真实执行 Python 3.10 环境下的 pip install -U,也没有声称所有项目都会选择 1.4.10。
未来的 1.4.x 补丁、你自己的约束和其他依赖,都可能改变具体选择。

实验 C:把目标提高到 Python 3.11

python -m pip --isolated download --index-url https://pypi.org/simple --no-deps --only-binary=:all: --python-version 3.11 --dest wheels311-pinned "langchain==1.5.0"

本地实际退出码为 0,下载文件为:

langchain-1.5.0-py3-none-any.whl

注意这里的证明边界:--no-deps 让实验聚焦顶层包,不能证明全部依赖在 Python 3.11 和你的操作系统上可安装。
完整的跨平台下载还涉及平台、ABI、实现及依赖分发包;本文没有把这三条命令当作部署打包方案。

四、真正迁移:建立新环境,不在旧环境里反复拆装

建议先保留旧环境、锁文件和原始启动方式,再用明确的 Python 路径建立新环境。
以下是 Linux / macOS 操作示例,前提是已经安装 Python 3.12:

python3.12 -m venv .venv-lc15
.venv-lc15/bin/python -m pip install "langchain==1.5.0"
.venv-lc15/bin/python -m pip check

Windows 可以使用:

py -3.12 -m venv .venv-lc15
.venv-lc15\Scripts\python.exe -m pip install "langchain==1.5.0"
.venv-lc15\Scripts\python.exe -m pip check

Windows 命令为路径适配说明,本次未在 Windows 执行。
缺少对应解释器时,先完成解释器安装;不要把 pip install python 当作升级 Python 运行时的办法。

我们在全新 Python 3.12.3 虚拟环境中实际安装了 1.5.0,并执行 pip check,结果为:

No broken requirements found.

这个结果表示已安装分发包之间的声明依赖未发现冲突,不表示旧 API、模型权限、网络调用或业务语义全部兼容。
本次环境只包含基础 LangChain 安装及其解析依赖,没有你的项目依赖,也没有额外安装模型 provider。

项目还固定 core 1.7.x,怎么办?

1.5.0 要求 langchain-core>=1.8.0,<2.0.0。
如果你又在 constraints 或锁文件中固定 core 1.7.x,这两个条件没有交集。
此时应检查整组依赖的可用兼容版本,不能靠反复单独升级顶层包解决。

先在新环境恢复原项目的依赖约束,并检查 provider 包、LangGraph、持久化组件和测试工具。
逐项确认冲突来源,再有意识地更新版本组合。
不要删掉所有版本约束后,将一次碰巧成功的解析视为迁移完成。

本例下载实验使用 --no-deps 是为了隔离观察变量;迁移项目时不要照搬它来跳过依赖冲突。
同样,不建议用 --ignore-requires-python 把不支持的解释器硬塞进运行环境。
包能被强行放进去,与项目能正确运行,是两回事。

五、别止步于 import:跑一个真正的离线 Agent 冒烟

下面代码会执行真实 create_agent 流程,但用官方核心包中的假聊天模型返回固定消息。
它还直接调用一个本地工具,检查工具输入校验与执行路径。

保存为 smoke.py,在新虚拟环境执行:

.venv-lc15/bin/python smoke.py
"""Offline smoke test: real LangChain agent with a fake model, no network."""
import json
import sys
from importlib.metadata import version
from langchain.agents import create_agent
from langchain_core.language_models.fake_chat_models import FakeMessagesListChatModel
from langchain_core.messages import AIMessage
from langchain_core.tools import tool

@tool
def add(a: int, b: int) -> int:
    """Add two integers locally."""
    return a + b

model = FakeMessagesListChatModel(responses=[AIMessage(content='offline-ok')])
agent = create_agent(model=model, tools=[])
result = agent.invoke({'messages': [{'role': 'user', 'content': 'health check'}]})
assert result['messages'][-1].content == 'offline-ok'
assert add.invoke({'a': 2, 'b': 3}) == 5
print(json.dumps({
    'python': sys.version.split()[0],
    'langchain': version('langchain'),
    'langchain-core': version('langchain-core'),
    'langgraph': version('langgraph'),
    'agent_reply': result['messages'][-1].content,
    'tool_direct_result': add.invoke({'a': 2, 'b': 3}),
    'live_model_called': False,
}, ensure_ascii=False, indent=2))

本地实际输出:

{
  "python": "3.12.3",
  "langchain": "1.5.0",
  "langchain-core": "1.8.0",
  "langgraph": "1.2.20",
  "agent_reply": "offline-ok",
  "tool_direct_result": 5,
  "live_model_called": false
}

这里最容易误读的是工具那一行。
Agent 的 tools=[],所以 tool_direct_result=5 来自代码对 add.invoke() 的直接调用,不是模型自行选择工具。
agent_reply=offline-ok 说明真实 Agent 编排路径在这个最小场景中跑通,模型输出则是我们预先指定的。

这组检查不覆盖真实模型 SDK、流式输出、模型选择工具、认证、检索和数据库持久化。
你仍需在项目里增加最小业务回归,而不是把假模型冒烟当成上线评测。

图 3:三次目标版本下载实验与一次真实隔离安装验证,各自证明不同的事情。

六、还有三类高频坑,升级前顺手排掉

1. 镜像确实不同步,但别靠猜

先看同一版本的官方发布记录与 PyPI 元数据,确认该版本真的存在,再检查当前源是否可访问、是否提供对应候选。
如果相同解释器在官方源能找到,在镜像找不到,才有理由继续调查镜像同步、索引配置和网络链路。

不要在公开求助中粘贴带用户名、令牌或内部地址的完整索引配置。
通常提供去敏后的错误片段、Python 版本、包版本要求和源类型,就能开始定位。

2. lock 文件固定了旧版,升级命令与项目工具不在一套流程

如果项目由 uv、Poetry 或其他锁文件管理,先确认实际部署使用的锁文件和 Python 约束。
在旁边运行一次 pip,不能自动更新项目的锁定结果;手工编辑版本号也不等于重新完成依赖解析。

本文没有逐个验证这些工具的升级子命令,因此不提供猜测式通用命令。
迁移原则是:用项目原本采用的工具更新、重建环境,并保留可回退的锁文件版本。

3. 旧代码接口报错,和 Python 兼容性是两层问题

如果你从更早的 LangChain 0.x 跨到 1.5,可能同时遇到 API 迁移。
“换成 Python 3.12”只解决运行时要求,不会自动把旧导入路径和业务代码改成新接口。

应把安装失败、import 失败、模型调用失败、业务行为退化分开记录。
每一步保留实际报错和最小复现,避免一个错误还没定位就同时改包版本、模型、检索器和提示词。

七、从“装上了”走到“可以切换”,需要四层证据

层次 本文是否验证 你接入项目后还要补什么
顶层包与目标 Python 的候选匹配 已验证三组下载结果 目标操作系统、完整依赖的安装
新环境声明依赖一致 已执行 pip check 原项目全套依赖与 provider
最小 Agent 与本地工具路径 已用假模型和直接工具调用验证 真模型、工具选择、流式和错误处理
旧业务能力保留 本文未验证 固定样本、逐条对比、生产前回归

如果要回滚,优先切回保留的旧环境或旧镜像、旧锁文件与原启动方式。
不要在已经反复升级的新环境里盲目降级几个顶层包,再假设它等于迁移前状态。
涉及数据库或持久化格式变化时,还应有单独的备份和回滚设计;本次未测试这类迁移。

固定样本的回归方法可参考昨日发布的Agent 逐条评测与退化排障;如果项目带中断恢复和写操作,还可以接着检查重复执行与业务幂等。

一手来源与复现边界

本文所有依赖解析与安装结果均为 2026-11-12 的本地快照;不是所有机器、源和项目的兼容性承诺。
三张图为原创工程图解,未用模拟日志冒充真实错误,未调用付费模型或修改生产环境。

遇到升级问题时,可以贴出脱敏后的 Python 版本、实际解释器路径、目标包版本与最早出现的错误片段。
先判断“新版没有成为候选”,还是“已经装上但业务不兼容”,往往比继续换源更快找到下一步。