跳转到内容

架构概览

Lingchu Bot 是一个以 NoneBot2 为基础的应用侧机器人项目。当前代码将核心插件、命令处理、配置、存储和数据库辅助能力拆分在 src/plugins/nonebot_plugin_lingchu_bot 下。

  • pyproject.toml:声明插件目录、依赖、适配器和 NoneBot 插件配置,是当前本地插件加载配置的来源。
  • Dockerfile / docker-compose.yml:容器运行入口,构建阶段通过 nb-cli 生成运行用 /tmp/bot.py
  • nonebot_plugin_lingchu_bot:核心插件包,声明插件元数据并加载共享能力。
  • 文件夹src/plugins/nonebot_plugin_lingchu_bot/
    • 文件夹core/
      • async_utils.py
      • bot_state.py
      • config.py
      • handle_config_manager.py
      • http_security.py
      • menu_config.py
      • mutable_settings.py
      • schemas.py
      • 文件夹handle_config_defaults/
      • 文件夹subplugins/
        • 文件夹llm_chat/
        • 文件夹novelai_image/
    • 文件夹database/
      • _dialect_compat.py
      • 文件夹models/
      • 文件夹orm_crud/
      • 文件夹toml_store/
    • 文件夹handle/
      • menu.py
      • 文件夹qq/
        • 文件夹commands/
          • triggers.py
          • mute.py
          • member.py
          • block.py
          • announcement.py
          • remote.py
        • 文件夹adapters/
          • 文件夹onebot11/
            • 文件夹default/
            • 文件夹napcat/
    • 文件夹hooks/
      • adapters.py
      • interfaces.py
      • 文件夹handlers/
    • 文件夹i18n/
      • init .py
      • babel.cfg
      • 文件夹locales/
        • 文件夹en_US/
        • 文件夹zh_CN/
    • 文件夹migrations/
      • 30f5a01259cd_initial_schema.py
      • a1b2c3d4e5f6_permissions_schema.py
      • b7c8d9e0f1a2_event_policy_partitions.py
      • c3d4e5f6a7b8_scheduler_jobs.py
      • cf2c06d51a17_blocklist_unique_constraint.py
    • 文件夹permissions/
      • init .py
      • admin.py
      • bootstrap.py
      • config.py
      • platforms.py
      • service.py
      • subject_policy.py
      • types.py
    • 文件夹platforms/
      • registry.py
      • 文件夹qq/
        • permissions.py
    • 文件夹repositories/
      • init .py
      • blocklist.py
      • message_store.py
      • permissions.py
      • registry.py
      • scheduler_jobs.py
    • 文件夹services/
      • message_store.py
      • protocol_restart_feedback.py
      • scheduler.py
      • 文件夹llm/
    • 文件夹start/
      • startup.py
  • 文件夹apps/docs/
    • 文件夹content/
    • 文件夹src/
  • 文件夹apps/lingc-cli/
    • 文件夹src/
    • 文件夹tests/
  • pyproject.toml
  • Taskfile.yml
  • turbo.json
  • Dockerfile
模块 职责
core/config.py 仅包含部署字段的 Config pydantic 模型,由 NoneBot get_plugin_config() 解析
core/mutable_settings.py 面向在线可编辑 MutableRuntimeSettings 的 typed localstore 仓库
core/handle_config_manager.py HandleConfigManager —— 基于 pydantic 校验的 per-command TOML 配置
core/handle_config_defaults/ 通过 register_handle_defaults() 注册的 per-command pydantic BaseModel 默认值
core/schemas.py Schema 定义与供 CLI 显式调用的安装支持
core/bot_state.py BotStateFile(BaseModel) 支持的 bot_state.toml 持久化
core/subplugins/ 子插件契约、加载器与内置子插件(llm_chat、novelai_image)
database/toml_store/ TOML 文件存储包
database/models/ ORM 模型包(message、blocklist、registry、identity)
database/orm_crud/ 异步 CRUD 辅助(session 首参签名;参见存储与 ORM
migrations/ Alembic 数据库迁移
handle/menu.py 菜单系统(页面、分区、功能、可用性)
handle/qq/commands/ 共享 QQ 命令定义(Alconna 匹配器、触发词)
handle/qq/adapters/onebot11/ OneBot V11 处理器(default、napcat)
hooks/ NoneBot 事件生命周期处理器(lifecycle、bot_connection、message_store、api_audit)
i18n/__init__.py gettext/Babel 翻译辅助、locale 读取和异步 catalog 预热
platforms/registry.py 平台能力与具体适配器的映射、优先级选择和同平台互斥校验
platforms/qq/permissions.py QQ 默认身份组与运行时平台身份解析
permissions/ UID 身份、平台账号、身份组成员、命令授权和 SUPERUSERS API
repositories/blocklist.py 黑名单数据访问
repositories/message_store.py 消息存储仓库
repositories/permissions.py 权限系统 ORM 仓库
services/message_store.py 消息事件、处理结果、Bot 生命周期和平台 API 调用摘要记录
services/llm/ LLM 服务抽象(后端、能力、运行时、安全)
start/ 启动钩子

插件按平台能力声明适配器,而不是把所有导入的具体适配器都视为可用。当前已实现 QQ 平台 profile,启动流程中仅 ~onebot.v11 可用。其他适配器 ID(如 ~milky~qq~onebot.v12)未实现;配置其中任何一个会以清晰的 PlatformAdapterUnknownError 退出。未配置时默认启用 OneBot V11。

~onebot.v11 启用中 ~milky~qq~onebot.v12 已移除

同一平台显式配置多个已知适配器会抛出 PlatformAdapterConflictError。Lingchu Bot 不控制 NoneBot 实际导入或注册哪些适配器;它只校验被选中的适配器已经由 NoneBot 加载/注册。未配置时默认选择 ~onebot.v11,如果 OneBot V11 未加载会抛出 PlatformAdapterNotLoadedError。其他同平台适配器即使被导入或注册,也会被视为未启用,不参与平台识别、消息存储或 API 调用记录。LINGCHUAdapter 中显式声明 Lingchu 未实现或无法识别的适配器会启动失败;运行时额外出现的未知适配器不会被 is_adapter_enabled() 判定为已启用,消息存储会把它们归入统一的 unknown 平台。其他平台 profile 和非群管理能力以后续实现和测试为准。

平台权限模块现在通过适配器注册表中的 PlatformProfile.permission_module 字段动态发现,消除了硬编码的模块路径。这实现了平台标识的统一管理。

项目倾向使用 NoneBot 插件配置、localstore 和 ORM 插件提供的能力,而不是在业务代码中硬编码路径或数据库连接。

文件存储、TOML 解析、deepcopy、命令解析和翻译 catalog 加载等潜在阻塞路径会放到 worker thread 执行,避免阻塞 NoneBot 事件循环。

插件启动不会创建部署配置文件,也不会安装 JSON Schema 文件。需要编辑器 schema 时,请手动用 pydantic 的 model_json_schema() 生成,或交由 nonebot 配置管理处理。

Lingchu Bot 以 pydantic 作为部署配置、运行时可变设置、handle 与 bot-state 配置的真源。NoneBot 通过 get_plugin_config(Config) 解析部署字段;在线可编辑设置使用独立的 typed localstore 仓库。

场面 Pydantic 模型 备注
插件 env / .env core/config.py::Config(继承 DeploymentSettings NoneBot get_plugin_config() 是部署字段的唯一解析入口。
在线可编辑设置 _lingchu_bot_contracts::MutableRuntimeSettings core/mutable_settings.py 持久化到 localstore 管理的 runtime-overrides.toml
Per-command handle 配置 core/handle_config_defaults/<command>.py::<Model>(BaseModel) 通过 register_handle_defaults() 注册;HANDLE_DEFAULTS_REGISTRY 类型为 dict[str, type[BaseModel]]HandleConfigManager.get_config() / update_config() 使用 type_validate_python(model_cls, toml_dict)HandleConfig dataclass 仍持有 dict[str, Any] 以保留 frozen-dataclass 接口;_build_handle_config 通过 model_dump(mode="json") 桥接 pydantic ↔ dict 边界。
Bot 状态 core/bot_state.py::BotStateFile(BaseModel) 使用 Field(alias="global") + populate_by_name=True 桥接 global Python 关键字;_save_bot_state()model_dump(mode="json", by_alias=True) 序列化。
JSON Schema 文件 手动用 pydantic model_json_schema() 生成 pydantic 负责 JSON Schema 输出;启动过程不会安装 schema。
  1. core/handle_config_defaults/<command>.py 中声明 pydantic.BaseModel 子类。
  2. 通过 register_handle_defaults("<command_key>", <Model>) 注册。
  3. 运行 task db:check;需要编辑器 schema 时,再用 pydantic 重新生成。
  4. 对应的 <command_key>.toml 在首次读取时创建;用户可以编辑它,HandleConfigManager.get_config(<command_key>) 会通过 pydantic 校验。

不要返回裸 dict 默认值 —— 校验和 JSON Schema 输出由 pydantic 拥有。HandleConfigManager.validate_config() 已移除;非法输入由 pydantic 直接抛错。