Skip to content

插件依赖安装失败时静默忽略,导致运行时 ModuleNotFoundError #53

@TyperBody

Description

@TyperBody

LangBot 插件系统 T2 级事故报告

📋 事故概述

项目 详情
事故等级 T2(严重)
影响范围 所有 LangBot 插件的依赖安装
发现时间 2026-04-17
问题表现 插件依赖安装失败时静默忽略,导致运行时 ModuleNotFoundError

🔍 问题现象

用户报告插件运行时出现依赖缺失错误:

ActionCallError: ActionCallError: ActionCallError: ModuleNotFoundError: No module named 'networkx'

关键矛盾

  • ✅ 插件的 requirements.txt已包含 networkx
  • ✅ LangBot 显示插件依赖安装成功
  • ❌ 实际虚拟环境中 networkx 未被安装

🐛 根本原因分析

Bug 位置

文件: langbot_plugin/runtime/plugin/mgr.py
方法: install_plugin() (第 255-372 行)

问题代码

# mgr.py 第 318-339 行
for i, dep in enumerate(deps):
    # ... 进度汇报 ...
    
    returncode, downloaded_bytes = await pkgmgr_helper.install_single_async(dep)
    total_downloaded += downloaded_bytes

    if returncode != 0:
        logger.error(f"Failed to install dependency: {dep}")
        # ❌ BUG: 仅记录日志,没有抛出异常或中断安装!
        # ❌ BUG: 继续执行,最终报告"安装成功"

问题本质

问题类型 描述
静默失败 依赖安装失败时仅记录错误日志,不抛出异常
虚假成功 无论安装是否成功,都会继续执行并报告"插件安装完成"
错误不传播 前端/用户界面无法感知依赖安装失败
无重试机制 失败后不尝试重新安装

调用链分析

install_plugin()
    ↓
pkgmgr_helper.install_single_async(dep)
    ↓
返回 (returncode, downloaded_bytes)
    ↓
if returncode != 0:
    logger.error(...)  ← 仅日志记录
    # 继续循环,不中断!
    ↓
yield {"current_action": "launching plugin"}  ← 虚假成功

📊 影响评估

直接影响

  1. 用户体验严重受损

    • 用户看到"安装成功"提示
    • 插件实际无法正常工作
    • 错误信息误导性强,难以排查
  2. 信任度下降

    • 插件系统的可靠性受质疑
    • 用户需要手动检查依赖安装状态

受影响的场景

场景 影响程度
从 Marketplace 安装插件 🔴 高
从 GitHub 安装插件 🔴 高
本地上传 .zip 安装 🔴 高
调试模式插件 🟡 中(需手动安装依赖)

🛠️ 临时解决方案(已执行)

# 手动在 LangBot 虚拟环境中安装缺失的依赖
cd /home/typer/Desktop/LangBot && source .venv/bin/activate && pip install networkx

验证结果

Successfully installed networkx-3.6.1

💡 建议修复方案

短期修复(紧急)

修改 mgr.py 中的 install_plugin 方法:

# 修复后的代码
for i, dep in enumerate(deps):
    # ... 进度汇报 ...
    
    returncode, downloaded_bytes = await pkgmgr_helper.install_single_async(dep)
    total_downloaded += downloaded_bytes

    if returncode != 0:
        logger.error(f"Failed to install dependency: {dep}")
        # ✅ 修复:收集失败的依赖
        failed_deps.append(dep)

# ✅ 修复:安装完成后检查失败列表
if failed_deps:
    yield {
        "current_action": "dependency installation failed",
        "error": f"Failed to install: {', '.join(failed_deps)}",
        "metadata": {
            "failed_deps": failed_deps,
            "deps_total": total_deps,
            "deps_installed": total_deps - len(failed_deps),
        }
    }
    raise DependencyInstallationError(f"Failed to install dependencies: {failed_deps}")

中期改进

  1. 添加依赖验证步骤

    async def verify_dependencies(deps: list[str]) -> list[str]:
        """验证依赖是否真正安装成功"""
        missing = []
        for dep in deps:
            pkg_name = dep.split('==')[0].split('>=')[0].split('<=')[0]
            if importlib.util.find_spec(pkg_name) is None:
                missing.append(dep)
        return missing
  2. 添加重试机制

    async def install_with_retry(dep: str, max_retries: int = 3):
        for attempt in range(max_retries):
            returncode, _ = await install_single_async(dep)
            if returncode == 0:
                return True
            await asyncio.sleep(1)  # 等待后重试
        return False
  3. 改进错误反馈

    • 前端显示详细的依赖安装状态
    • 提供"重新安装依赖"按钮
    • 失败时显示具体的 pip 错误输出

长期优化

  1. 依赖预检查

    • 安装前检查依赖冲突
    • 显示将要安装的依赖列表供用户确认
  2. 依赖锁定

    • 支持 requirements.lock 固定版本
    • 避免版本不一致问题
  3. 监控告警

    • 添加依赖安装失败的监控指标
    • 自动告警通知

📝 验证清单

修复后需要验证:

  • 依赖安装失败时,插件安装流程中断
  • 前端正确显示失败原因
  • 日志中记录完整的 pip 错误输出
  • 用户可以查看失败的具体依赖列表
  • 提供手动重试依赖安装的途径

📚 相关文件

文件 作用
langbot_plugin/runtime/plugin/mgr.py 插件管理器,包含 bug 代码
langbot_plugin/runtime/helper/pkgmgr.py pip 包装器
LangBot/src/langbot/pkg/core/bootutils/deps.py LangBot 启动时的依赖检查

⚠️ 注意事项

  1. 清华镜像源:当前使用 pypi.tuna.tsinghua.edu.cn,某些包可能同步延迟
  2. 网络问题:安装失败可能由网络超时导致,但错误被静默忽略
  3. 权限问题:在某些环境下可能存在写入权限问题

报告生成时间: 2026-04-17T17:47:00+08:00
报告版本: v1.0

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions