GraphRAG monorepo 依赖更新实战指南:从 uv 工作区重新锁定到 pandas 3.0 迁移问题修复
【免费下载链接】graphragA modular graph-based Retrieval-Augmented Generation (RAG) system项目地址: https://gitcode.com/GitHub_Trending/gr/graphrag
本文基于 GraphRAG 仓库中官方维护的依赖更新技能文档 SKILL.md,完整拆解这个 uv workspace monorepo 的依赖升级标准流程:哪些版本说明符可以改、哪些版本行绝不可手改、如何正确执行uv lock/uv sync重新锁定,以及升级 pandas/numpy 大版本后如何用仓库验证过的迁移模式修复测试与类型检查失败。读完后你可以独立完成一次「依赖清扫(dependency sweep)」,并让uv run poe check与uv run poe test_unit双双转绿。
一、先认清仓库结构:这是一个 uv workspace monorepo
依赖更新的所有操作都建立在对仓库布局的准确理解之上。根据根目录 pyproject.toml,GraphRAG 的依赖分布在三个层次:
- 根
pyproject.toml的 dev 依赖组:[dependency-groups]下的dev组集中了开发工具链,包括coverage~=7.6、deptry~=0.21、mkdocs-material~=9.5、pandas-stubs~=3.0、poethepoet~=0.31、pyright~=1.1、pytest~=9.1、ruff~=0.8、semversioner~=3.0等(见 pyproject.toml#L26-L48)。 - 各成员包的运行时依赖:每个
packages/*/pyproject.toml的[project] dependencies中。例如 packages/graphrag/pyproject.toml 声明了pandas~=3.0、numpy~=2.1、pydantic~=2.10、networkx~=3.4、spacy~=3.8等。 - 工作区成员之间的互相引用:通过
[tool.uv.sources]中的{ workspace = true }声明(pyproject.toml#L60-L67 列出了graphrag-chunking、graphrag-common、graphrag-input、graphrag-storage、graphrag-cache、graphrag-vectors、graphrag-llm七个成员),并以graphrag-*==X.Y.Z的精确版本行互相锁定。例如 packages/graphrag-llm/pyproject.toml#L38-L39 中的graphrag-cache==3.1.1、graphrag-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]定义了check、fix、format、test_unit、test_verbs、test_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_URL或PIP_INDEX_URL设为 pypi.org,也不允许禁用或重排已配置的索引。
规则 2:目标版本必须发布满 7 天以上
该代理不提供服务最近一周内发布的版本——同步到一个「太新」的版本必然失败。因此:
- 若要精确钉住某个版本,先核实其发布日期,选取「超过 7 天的最新 release」;
- 否则就让版本说明符保持浮动(如
~=X.Y),交给uv lock自行选择——代理上本来就只看得见合格版本。
这个规则解释了后文一个高频故障模式:如果uv sync找不到你刚钉住的版本,几乎可以断定该版本在代理上的「年龄」不足一周,此时应退一档到超过一周的最新 release,而不是怀疑锁文件损坏。
三、三类「发布流程持有」的版本行:禁止手改
这是本仓库依赖更新中最容易踩错的地方。以下三类内容不属于依赖更新者的编辑范围,因为它们由发布(release)流程统一管理:
- 跨包精确钉住:任何包中的
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)。 [project] version字段:由 semversioner 管理。packages/graphrag/pyproject.toml#L3-L4 中甚至有显式注释:# Maintainers: do not change the version here manually。graspologic-native>=1.2,<1.3保留钉住:packages/graphrag/pyproject.toml#L46-L49 中的注释说明了原因——1.3.x 会改变 Leiden 聚类输出(社区数量/层级),从而破坏固定的回归测试与黄金社区数据。只有在有意的黄金数据刷新时才可升级,并且必须明确声明这一动作。
发布流程如何驱动上述自动化的完整链条,可以在根pyproject.toml的release任务序列中看到:先semversioner release与生成 changelog,再逐个执行_semversioner_update_*_toml_version(用update-toml把各包project.version写为semversioner current-version的值),最后运行_semversioner_update_workspace_dependency_versions(即上面的脚本)和_sync(pyproject.toml#L116-L132)。理解这条链后就能明白:依赖更新者只需要动「第三方库的说明符」,其余交给发布流水线。
四、完整更新流程:八步走
以下是技能文档规定的标准流程,每一步都给出了可直接执行的命令。
1. 先建立基线(Baseline first)
在改动任何版本之前,确认工作树干净且检查/测试本来就通过,这样后续失败才能归因于本次升级。推荐在独立分支(如dep-sweep)上操作:
uv run poe check uv run poe test_unit2. 确定升级范围并编辑说明符
范围可以是用户点名的目标包集合,也可以是一次完整清扫。编辑对象是相关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_report,pyproject.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 check与uv 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.int0、np.bool8、np.object0等)——改用内置类型或显式带大小 dtype(np.float64、np.bool_); - 对 DataFrame 使用
np.array_split不再保留 frame(即上文的 pandas 条目); - 部分函数移出顶层命名空间,需从文档指定的子模块导入。
ruff:本仓库启用 preview 模式
根 pyproject.toml#L151-L161 中[tool.ruff]设了target-version = "py310",且format与lint均开启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.0(pyproject.toml#L37)。升级 pandas 时必须同步升级匹配的 stubs,让pyright反映新 API;依赖变更后 pyright 可能暴露来自新 stub 的 optional/overload 错误,应在调用点修复而不是抑制(除非能证明 stub 本身错了)。
通用排查方法
参考文档给出的三步法:1) 把 traceback/诊断读到叶子帧——出问题的库调用和被改动的符号通常就在最里面;2) 看同包内兄弟模块如何处理同一模式,保持写法一致;3) 每次修复后重跑uv run poe check与uv run poe test_unit确认。
六、仓库级 Gotchas 与完成前自检清单
容易混淆的仓库级细节
test_unit而非test:poe test全量跑 coverage,慢;快速反馈循环用test_unit(pytest ./tests/unit)。- Ruff 运行于 preview 模式(
preview = true、target-version = "py310"),preview-only 规则(如 RUF069、ASYNC119)在本仓库会触发。 - 已知存量 flake:
tests/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.lock由uv 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 的验证过修复模式,即可把一次大版本依赖清扫的失败面收敛到可预测、可归因、可复验的范围。
【免费下载链接】graphragA modular graph-based Retrieval-Augmented Generation (RAG) system项目地址: https://gitcode.com/GitHub_Trending/gr/graphrag
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考