首页
/ GraphRAG monorepo 依赖更新实战指南:从 uv 工作区重新锁定到 pandas 3.0 迁移问题修复

GraphRAG monorepo 依赖更新实战指南:从 uv 工作区重新锁定到 pandas 3.0 迁移问题修复

2026-09-05 20:08:51作者:舒璇辛Bertina

本文基于 GraphRAG 仓库中官方维护的依赖更新技能文档 SKILL.md,完整拆解这个 uv workspace monorepo 的依赖升级标准流程:哪些版本说明符可以改、哪些版本行绝不可手改、如何正确执行 uv lock/uv sync 重新锁定,以及升级 pandas/numpy 大版本后如何用仓库验证过的迁移模式修复测试与类型检查失败。读完后你可以独立完成一次「依赖清扫(dependency sweep)」,并让 uv run poe checkuv run poe test_unit 双双转绿。

一、先认清仓库结构:这是一个 uv workspace monorepo

依赖更新的所有操作都建立在对仓库布局的准确理解之上。根据根目录 pyproject.toml,GraphRAG 的依赖分布在三个层次:

  1. pyproject.toml 的 dev 依赖组[dependency-groups] 下的 dev 组集中了开发工具链,包括 coverage~=7.6deptry~=0.21mkdocs-material~=9.5pandas-stubs~=3.0poethepoet~=0.31pyright~=1.1pytest~=9.1ruff~=0.8semversioner~=3.0 等(见 pyproject.toml#L26-L48)。
  2. 各成员包的运行时依赖:每个 packages/*/pyproject.toml[project] dependencies 中。例如 packages/graphrag/pyproject.toml 声明了 pandas~=3.0numpy~=2.1pydantic~=2.10networkx~=3.4spacy~=3.8 等。
  3. 工作区成员之间的互相引用:通过 [tool.uv.sources] 中的 { workspace = true } 声明(pyproject.toml#L60-L67 列出了 graphrag-chunkinggraphrag-commongraphrag-inputgraphrag-storagegraphrag-cachegraphrag-vectorsgraphrag-llm 七个成员),并以 graphrag-*==X.Y.Z 的精确版本行互相锁定。例如 packages/graphrag-llm/pyproject.toml#L38-L39 中的 graphrag-cache==3.1.1graphrag-common==3.1.1

工作区成员范围由 [tool.uv.workspace] members = ["packages/*"] 定义(pyproject.toml#L57-L58)。此外还有一个关键点:包解析不走公共 PyPI,而是走 Microsoft 内部 feed 代理:

[[tool.uv.index]]
url="https://packagefeedproxy.microsoft.io/pypi/simple"
default=true

pyproject.toml#L53-L55)任务编排则统一由 poethepoet 承担,[tool.poe.tasks] 定义了 checkfixformattest_unittest_verbstest_integration 等命令(pyproject.toml#L70-L148)。

二、两条不可协商的硬性规则

官方技能文档把两条规则列为 non-negotiable,违反它们会直接导致解析或同步失败:

规则 1:只能使用 Microsoft feed 代理索引

所有 resolve 和 sync 必须走 [[tool.uv.index]] 配置的 https://packagefeedproxy.microsoft.io/pypi/simple严禁针对公共 PyPI 解析、严禁添加 --index/--default-index/--index-url 覆盖参数、严禁把 UV_INDEX_URLPIP_INDEX_URL 设为 pypi.org,也不允许禁用或重排已配置的索引。

规则 2:目标版本必须发布满 7 天以上

该代理不提供服务最近一周内发布的版本——同步到一个「太新」的版本必然失败。因此:

  • 若要精确钉住某个版本,先核实其发布日期,选取「超过 7 天的最新 release」;
  • 否则就让版本说明符保持浮动(如 ~=X.Y),交给 uv lock 自行选择——代理上本来就只看得见合格版本。

这个规则解释了后文一个高频故障模式:如果 uv sync 找不到你刚钉住的版本,几乎可以断定该版本在代理上的「年龄」不足一周,此时应退一档到超过一周的最新 release,而不是怀疑锁文件损坏。

三、三类「发布流程持有」的版本行:禁止手改

这是本仓库依赖更新中最容易踩错的地方。以下三类内容不属于依赖更新者的编辑范围,因为它们由发布(release)流程统一管理:

  1. 跨包精确钉住:任何包中的 graphrag-cache==...graphrag-llm==... 等行。它们由脚本 scripts/update_workspace_dependency_versions.py 自动重写。从源码看,该脚本调用 uv run semversioner current-version 取当前版本,再遍历 packages/*,用正则 {包名}\s*==\s*\d+\.\d+\.\d+ 把所有跨包钉住统一替换为当前版本(scripts/update_workspace_dependency_versions.py#L26-L54)。手工编辑这些行只会造成版本漂移(drift)。
  2. [project] version 字段:由 semversioner 管理。packages/graphrag/pyproject.toml#L3-L4 中甚至有显式注释:# Maintainers: do not change the version here manually
  3. graspologic-native>=1.2,<1.3 保留钉住packages/graphrag/pyproject.toml#L46-L49 中的注释说明了原因——1.3.x 会改变 Leiden 聚类输出(社区数量/层级),从而破坏固定的回归测试与黄金社区数据。只有在有意的黄金数据刷新时才可升级,并且必须明确声明这一动作。

发布流程如何驱动上述自动化的完整链条,可以在根 pyproject.tomlrelease 任务序列中看到:先 semversioner release 与生成 changelog,再逐个执行 _semversioner_update_*_toml_version(用 update-toml 把各包 project.version 写为 semversioner current-version 的值),最后运行 _semversioner_update_workspace_dependency_versions(即上面的脚本)和 _syncpyproject.toml#L116-L132)。理解这条链后就能明白:依赖更新者只需要动「第三方库的说明符」,其余交给发布流水线。

四、完整更新流程:八步走

以下是技能文档规定的标准流程,每一步都给出了可直接执行的命令。

1. 先建立基线(Baseline first)

在改动任何版本之前,确认工作树干净且检查/测试本来就通过,这样后续失败才能归因于本次升级。推荐在独立分支(如 dep-sweep)上操作:

uv run poe check
uv run poe test_unit

2. 确定升级范围并编辑说明符

范围可以是用户点名的目标包集合,也可以是一次完整清扫。编辑对象是相关 packages/*/pyproject.toml[project] dependencies 中的 ~=/>=/< 说明符,以及根 dev 组。上节列出的「发布持有」行保持不动。编辑完成后务必复核:版本编辑会触碰多个 pyproject.toml,确认自己没有在改相邻说明符时误伤 graphrag-*== 钉住或 version 字段。

3. 解析与锁定(全部走已配置的 feed 代理,不传任何索引覆盖)

# 完整「取到允许的最新版本」清扫
uv lock --upgrade

# 编辑说明符后的定向升级
uv lock

# 安装所有工作区成员(注意是 --all-packages,不是裸 uv sync)
uv sync --all-packages

失败处理原则:

  • 若解析失败,阅读冲突信息,放宽或调整有问题的说明符后重新锁定,不要删除 uv.lock 来强制通过
  • 若 sync 找不到刚钉住的版本,按规则 2 退到超过一周的最新 release。

4. 静态检查

uv run poe check     # = ruff format --check + ruff check + pyright
uv run poe fix       # 应用安全的 ruff 自动修复
uv run poe format    # ruff format 格式化

从根 pyproject.toml#L142-L144 可以看到 check 任务的确切序列为 ['check_format', '_ruff_check', '_pyright']。剩余的 lint/类型错误需手工修复——参见下一节的迁移模式。

5. 测试

uv run poe test_unit          # 快速反馈循环(pytest ./tests/unit)
uv run poe test_verbs        # 变更范围广或触及 indexing 时运行(pytest ./tests/verbs)
uv run poe test_integration  # 同上(pytest ./tests/integration)

注意不要uv run poe test——它会跑全部用例并附 coverage 报告(_test_all + coverage_reportpyproject.toml#L146-L148),速度很慢。每一个新增失败都要调查清楚。

6. 修复破坏

对因库 API 变化导致的测试/类型失败,加载参考文档 .agents/skills/update-deps/references/migration-gotchas.md,套用其中经过本仓库验证的修复模式。原则:修复保持最小、与同包内的兄弟代码风格一致;有真实修复可用时,优先真实修复而不是 # noqa

7. 记录变更

uv run semversioner add-change -t patch -d "<简短描述>"

只有用户意图确实需要时才用 minor/major

8. 最终验证

重新运行 uv run poe checkuv run poe test_unit,两者都必须转绿;在下结论前先看下一节的「已知 flake」说明,避免把偶发失败误判为回归。

五、升级后破坏修复:仓库验证过的迁移模式

当升级(尤其是 pandas / numpy 大版本)引发测试或 pyright 失败时,migration-gotchas.md 收录了「本仓库实际命中并修复过」的模式,以下逐一展开其原理。

pandas 3.0:np.array_split(df, n) 不再返回 DataFrame

np.array_split 内部调用 np.swapaxes,该函数在 pandas 2.1 弃用、3.0 移除,过去它会委托给 DataFrame.swapaxes 并保留列名返回 DataFrame;现在则退化为返回纯 numpy 数组。用 pd.DataFrame(fold) 重建后列名变成整数 RangeIndex,后续 df["some_column"] 直接抛 KeyError(traceback 终点在 pandas/core/indexes/range.py ... get_loc)。

修复模式是对位置索引做切分,再用 iloc 选行,从而保留列、dtype 乃至各 fold 的规模:

# Broken under pandas 3.0
return [pd.DataFrame(fold) for fold in np.array_split(reports, n)]

# Fixed — preserves columns, dtypes, and even fold sizes
return [
    reports.iloc[indices]
    for indices in np.array_split(np.arange(len(reports)), n)
]

pandas 3.0:copy= 关键字被移除

pandas 3.0 默认启用 Copy-on-Write(CoW)并删除了 copy= 参数,df.merge(other, copy=False)pd.concat([...], copy=False) 等调用会抛 TypeError。修复方式直接删除 copy= 参数——CoW 本身已避免不必要的拷贝。

pandas 3.0:CoW 下的链式赋值

在 CoW 下,对切片做原地修改(df[mask]["col"] = x)不再写回,可能告警或报错。修复:通过 .loc 赋值(df.loc[mask, "col"] = x),并把 inplace=True 式操作的结果重新赋回变量,而不是依赖对视图的原地修改。

numpy 2.x 常见破坏点

  • 移除的别名(np.float_np.int0np.bool8np.object0 等)——改用内置类型或显式带大小 dtype(np.float64np.bool_);
  • 对 DataFrame 使用 np.array_split 不再保留 frame(即上文的 pandas 条目);
  • 部分函数移出顶层命名空间,需从文档指定的子模块导入。

ruff:本仓库启用 preview 模式

pyproject.toml#L151-L161[tool.ruff] 设了 target-version = "py310",且 formatlint 均开启 preview = true。这意味着某些 preview-only 规则在本仓库会被触发(在其他仓库未必),典型两条:

  • RUF069(浮点相等比较)x == 0.0 / != 0.0 会被标记。语义允许时改用非相等保护(如非正除零保护写 x <= 0.0),容差判断用 math.isclose(...)
  • ASYNC119(异步生成器中持有上下文管理器 yield):不要在 with/async with 块内直接 yield,应先在块内物化数据、块关闭后再 yield:
with Path.open(path, "r", encoding=enc) as f:
    rows = list(csv.DictReader(f))
for row in rows:
    yield transform(row)

pyright:类型桩随大版本走

dev 组钉了 pandas-stubs~=3.0pyproject.toml#L37)。升级 pandas 时必须同步升级匹配的 stubs,让 pyright 反映新 API;依赖变更后 pyright 可能暴露来自新 stub 的 optional/overload 错误,应在调用点修复而不是抑制(除非能证明 stub 本身错了)。

通用排查方法

参考文档给出的三步法:1) 把 traceback/诊断读到叶子帧——出问题的库调用和被改动的符号通常就在最里面;2) 看同包内兄弟模块如何处理同一模式,保持写法一致;3) 每次修复后重跑 uv run poe checkuv run poe test_unit 确认。

六、仓库级 Gotchas 与完成前自检清单

容易混淆的仓库级细节

  • test_unit 而非 testpoe test 全量跑 coverage,慢;快速反馈循环用 test_unitpytest ./tests/unit)。
  • Ruff 运行于 preview 模式preview = truetarget-version = "py310"),preview-only 规则(如 RUF069、ASYNC119)在本仓库会触发。
  • 已知存量 flaketests/unit/indexing/test_profiling.py::TestWorkflowProfiler::test_handles_exception_in_context 对时序敏感、可能偶发失败——它不是依赖回归。从源码看(tests/unit/indexing/test_profiling.py#L70-L84),该用例在 profiler 上下文中抛异常后断言 metrics.overall > 0 等指标确实被采集,属于典型的耗时敏感断言,判读失败结论前应先排除这一干扰。
  • uv sync --all-packages:安装全部工作区成员必须带 --all-packages,裸 uv sync 会漏装成员包。
  • pandas 处于 3.0 线、numpy 处于 2.x:它们的大版本 API 变化是本仓库升级后破坏的常规来源。
  • 版本编辑涉及多个 pyproject.toml,务必确认没有误改 graphrag-*== 钉住或 version 字段。

完成前自检清单(Completion checklist)

一次依赖更新只有全部满足以下条件才算完成:

检查项 要求
索引合规 所有 resolve/sync 均使用 packagefeedproxy.microsoft.io 索引;未引入公共 PyPI 或任何索引覆盖
版本年龄 没有任何依赖被升级到最近 7 天内发布的版本
编辑范围 只有预期的说明符被改动;未触碰 graphrag-*== 钉住或 version 字段
锁文件 uv.lockuv lock/uv lock --upgrade 重新生成,未被手工编辑或删除
静态检查 uv run poe check 通过(ruff format、ruff lint、pyright)
单元测试 uv run poe test_unit 通过(仅可忽略已知的 profiling flake)
更广套件 若变更范围广,已运行 test_verbs/test_integration
变更日志 已通过 semversioner 添加 changelog 条目
保留钉住 高风险/被有意压住的钉住(如 graspologic-native)保持原状,除非明确升级

七、小结

GraphRAG 的依赖更新流程本质上是一次「受约束的自动化协作」:更新者负责第三方库说明符的编辑与失败修复,[tool.uv.sources] 工作区解析、scripts/update_workspace_dependency_versions.py 的跨包钉住重写、semversioner 的版本管理则分别接管了自己领域内的版本行。把两条硬规则(只用 feed 代理、版本年龄 ≥ 7 天)与「三不碰」原则(跨包钉住、version 字段、graspologic-native 压住行)作为前置约束,再配合 migration-gotchas.md 中针对 pandas 3.0 / numpy 2.x / ruff preview 的验证过修复模式,即可把一次大版本依赖清扫的失败面收敛到可预测、可归因、可复验的范围。

登录后查看全文
热门项目推荐
相关项目推荐

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
528
588
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
906
1.83 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
docsdocs
暂无描述
Markdown
891
5.79 K
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.53 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.34 K
1.45 K
cann-learning-hubcann-learning-hub
CANN 学习中心仓,支持在线互动运行、边学边练,提供教程、示例与优化方案,一站式助力昇腾开发者快速上手。
Jupyter Notebook
988
506
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384