ADR: DeepMD-kit 依赖管理策略#

  • Status: active

  • Date: 2026-02-04

  • Owners: Maintainers

Context#

DP-EVA 作为上层工作流编排系统,主要通过两种方式与 DeepMD-kit 交互:

  • CLI 调用为主:dp train / dp test / dp eval-desc(通过命令构建与作业调度系统调用,不依赖 DeepMD Python 源码)

  • Python API 调用为辅:仅用于小规模/调试的本地描述符计算(环境缺失时可降级)

当前代码未体现对 DeepMD-kit 源码的二次开发或 Patch 需求。

Decision#

拒绝将 DeepMD-kit 以 Git submodule 方式引入仓库;采用“外部环境依赖 + 版本约束 + 运行时检查”的策略管理 DeepMD-kit。

Consequences#

  • 优点

    • 安装与使用更符合用户预期(Conda/Pip 预编译包)

    • 仓库保持轻量,避免构建 C++/TF/PT 复杂依赖

    • 允许根据 CUDA/硬件选择合适发行包

  • 代价

    • 环境一致性需要通过文档、依赖约束与运行时检查保障

Alternatives Considered#

Git Submodule#

  • 优点:版本锁定、源码级调试便利、Fork 管理清晰

  • 缺点:DeepMD-kit 构建复杂、仓库体积增大、用户体验差、易引发环境冲突

Appendix: Legacy Report (Full Migration)#

以下内容迁移自历史技术决策报告,用于确保旧文档的功能点/示例/注意事项在新位置完整保留(避免信息丢失)。

技术决策报告:DeepMD-kit 依赖管理方案评估#

日期: 2026-02-04
状态: 已评审 (Approved)
决策: 🔴 拒绝采用 Git Submodule,推荐采用 外部环境依赖 + 版本约束 模式。


1. 现状分析:DeepMD-kit 调用场景与耦合度#

通过对 dpeva 代码库的全面审计,我们梳理了项目对 deepmd-kit 的依赖情况:

1.1 调用方式#

项目通过两种方式与 deepmd-kit 交互,呈现 松耦合 特征:

  1. CLI 命令行调用 (主要方式)

    • 模块:/src/dpeva/utils/command.py(DPCommandBuilder)

    • 场景:

      • dp train:模型训练(Trainer)

      • dp freeze:模型导出(Trainer)

      • dp test:模型推理与精度验证(Inference)

      • dp eval-desc:描述符计算(Feature/Collection)

    • 特征:依赖系统 PATH 中的 dp 可执行文件,通过 subprocess 或作业调度系统(Slurm)调用。不依赖 Python 源码。

  2. Python API 调用 (可选方式)

    • 模块:/src/dpeva/feature/generator.py

    • 场景:DescriptorGenerator 的 mode=\"python\"。

    • 代码:

try:
    from deepmd.infer.deep_pot import DeepPot
except ImportError:
    _DEEPMD_AVAILABLE = False
  • 特征:仅用于本地直接计算描述符。若环境未安装 Python 包,代码会自动降级或禁用该功能,不影响核心 CLI 流程。

1.2 定制化需求#

  • 当前代码:未发现对 deepmd-kit 核心算法(如 DescriptSeA, FittingNet)的源码级修改或 Patch。

  • 需求性质:dpeva 定位为 上层工作流编排系统 (Orchestrator),而非 deepmd-kit 的二次开发或插件。


2. 方案评估:Git Submodule vs 现有模式#

2.1 采用 Git Submodule 的权衡#

若将 deepmd-kit 作为 submodule 引入:

  • 优点:

    • 绝对版本锁定:可精确锁定到某次 Commit,确保所有开发者使用完全一致的代码快照。

    • 源码级调试:方便在开发 dpeva 时直接跳转调试 deepmd-kit 内部代码。

    • 私有定制:若未来需修改 deepmd-kit C++ 核心且无法合并回上游,submodule 是管理 Fork 的好方法。

  • 缺点(阻碍性因素):

    • 构建复杂性极高:deepmd-kit 包含大量 C++ 代码,依赖 TensorFlow/PyTorch C++ 库。要求所有 dpeva 用户在安装时本地编译 deepmd-kit 是不现实的(通常通过 Conda/Pip 安装预编译包)。

    • 仓库体积膨胀:deepmd-kit 仓库较大,增加 git clone 时间。

    • 用户体验差:普通用户只想 pip install dpeva,不希望处理子模块同步和编译错误。

    • 环境冲突:Submodule 强制指定版本可能与用户环境中已安装的 deepmd-kit(如系统级 Conda 环境)冲突。

2.2 官方发布版本 (Pip/Conda) 的权衡#

  • 优点:

    • 安装便捷:pip install deepmd-kit 即可获取预编译包。

    • 解耦:dpeva 只关注如何调用,不关注如何构建。

    • 兼容性:允许用户根据硬件(CUDA 版本)自由选择匹配的 DeepMD 版本。


3. 决策结论#

基于上述分析,我们 强烈不建议 使用 Git Submodule。

核心理由:

  1. 构建成本过高:dpeva 是 Python 纯代码项目,引入需编译的 C++ 子模块会破坏项目的轻量级特性。

  2. 定位不符:dpeva 是 deepmd-kit 的使用者,而非扩展者。

  3. 版本稳定性:通过 /pyproject.toml 的版本约束足以满足稳定性需求。


4. 实施方案:替代依赖管理策略#

既然拒绝 Submodule,我们需要更规范地管理外部依赖,防止“环境不一致”导致的问题。

4.1 依赖声明规范化#

建议根据使用程度分级声明(示例):

[project]
name = "dpeva"
dependencies = [
    "dpdata>=0.2.13",
    "numpy",
    "pandas",
    "pydantic>=2.0"
]

[project.optional-dependencies]
local = [
    "deepmd-kit>=2.2.0"
]

4.2 运行时版本检查 (Runtime Version Check)#

在 dpeva 启动时增加版本检查逻辑,确保环境中的 dp 命令版本符合要求。

建议新增模块:/src/dpeva/utils/env_check.py(或等价实现)

import subprocess
from packaging import version

MIN_DEEPMD_VERSION = \"2.0.0\"

def check_deepmd_version():
    try:
        out = subprocess.check_output([\"dp\", \"--version\"], text=True).strip()
    except (FileNotFoundError, subprocess.CalledProcessError):
        raise RuntimeError(\"DeepMD-kit not found. Please install deepmd-kit and ensure 'dp' is in PATH.\")

4.3 CI/CD 策略#

  • 基本策略:在 CI 中对 dpeva 自身的单元测试不强依赖 dp,对依赖 dp 的路径使用跳过或分层 CI(具备 DeepMD 环境的 runner 再跑)。

  • 集成测试:建议在具备 Slurm/DeepMD 的环境跑 tests/integration(与 /docs/guides/testing/* 对齐)。

4.4 文档说明#

  • 安装与环境准备:/docs/guides/installation.md

  • DeepMD 依赖策略(本文档 ADR)


5. 总结#

DeepMD-kit 属于重依赖组件,submodule 引入会显著放大构建与维护成本。对于 DP-EVA 这种上层编排系统,应优先采用外部环境依赖 + 版本约束 + 运行时检查的策略,以获得更好的可用性与可维护性。