上一篇我们看了全景图。这一篇深入最底下的地基——pkg/core。它不处理任何业务消息,只干两件事:把所有子系统分阶段组装成一个 Application 对象,以及把所有后台任务作用域化地托管起来。读懂这一篇,你就拿到了理解后续所有子系统「从哪被创建、归谁管」的钥匙。

一、这一层解决什么问题

LangBot 有近 30 个子系统管理器(平台、流水线、模型、插件、沙箱、持久化、各种 HTTP Service……)。它们之间有依赖顺序:配置必须先加载、日志必须先就绪、数据库必须先连上,业务管理器才能初始化。同时,启动后会有一堆永不退出的后台协程(监听平台、消费查询、跑 HTTP 服务……)需要统一创建、监控、按需取消。

pkg/core 用两个机制分别解决这两个问题:

二、入口与启动阶段

2.1 从 main() 到 make_app()

入口在 src/langbot/__main__.py,但真正的组装逻辑在 src/langbot/pkg/core/boot.py。核心是一个写死顺序的阶段列表:

# src/langbot/pkg/core/boot.py:17
stage_order = [
    'LoadConfigStage',
    'GenKeysStage',
    'SetupLoggerStage',
    'BuildAppStage',
    'ShowNotesStage',
]

async def make_app(loop: asyncio.AbstractEventLoop) -> app.Application:
    # ...
    ap = app.Application()
    ap.event_loop = loop

    # Execute startup stage
    for stage_name in stage_order:
        stage_cls = stage.preregistered_stages[stage_name]
        stage_inst = stage_cls()
        await stage_inst.run(ap)

    await ap.initialize()
    return ap

注意几个细节,它们很能体现这个项目的风格:

  1. 顺序是写死的列表,不是隐式依赖解析。 KISS 原则的直接体现——启动顺序就这五步,一眼能读懂,没有 DAG、没有自动拓扑排序。
  2. Application 先被 new 出来,再被各阶段逐步「填充」字段。 ap 是一个贯穿始终的可变上下文对象,每个阶段往里塞东西。
  3. 启动流程跑完后,make_app 返回 ap,由 boot.main() 调用 ap.run() 进入运行态。

2.2 五个阶段做了什么

每个阶段都是 BootingStage 的子类,通过装饰器注册进一个全局字典:

# src/langbot/pkg/core/stage.py:9
preregistered_stages: dict[str, typing.Type[BootingStage]] = {}

def stage_class(name: str):
    def decorator(cls):
        preregistered_stages[name] = cls
        return cls
    return decorator

class BootingStage(abc.ABC):
    name: str = None

    @abc.abstractmethod
    async def run(self, ap: app.Application):
        ...

阶段实现都在 pkg/core/stages/ 目录下,文件名即职责:

flowchart LR
    A["LoadConfigStage<br>load_config.py<br>读 data/config.yaml"]
    B["GenKeysStage<br>genkeys.py<br>生成加密密钥"]
    C["SetupLoggerStage<br>setup_logger.py<br>初始化日志"]
    D["BuildAppStage<br>build_app.py<br>构建所有子系统"]
    E["ShowNotesStage<br>show_notes.py<br>打印启动提示"]
    A --> B --> C --> D --> E

前三个阶段是「准备地基」(配置 → 密钥 → 日志),最后一个是「打印须知」。真正的重头戏是第四个:BuildAppStage。