Skip to content

🏗 02 - 系统架构 ​

本章把 XiaoQing 的内郚架构和工䜜原理拆匀诎明。

NOTE

本章偏向框架内郚实现。只写普通插件时可以先阅读 03-plugin-development.md。


🔭 架构总览 ​

XiaoQing 的栞心架构分成䞉层。

  1. 协议接入层server.py 和 onebot.py 莟莣接收 OneBot 事件、绎技 WebSocket 连接和发送 OneBot API 请求。
  2. 框架调床层app.py、dispatcher.py、router.py、plugin_manager.py、session.py、scheduler.py 莟莣生呜呚期、消息分发、呜什匹配、插件加蜜、倚蜮䌚话和定时任务。
  3. 插件䞚务层plugins/ 内的插件实现具䜓胜力。蜻量插件通垞只需芁 plugin.json + main.py倧型插件劂 xiaoqing_chat、pendo 和 codex 拥有自己的服务层、状态层、Web/API、LLM 子系统或后台任务队列。

栞心框架䞍盎接理解 Pendo 的莊本暡型也䞍盎接生成 xiaoqing_chat 的拟人回倍也䞍调床 Codex CLI 的内郚任务队列。它提䟛统䞀的事件、䞊䞋文、路由和发送胜力䞚务插件圚这䞪蟹界内自行组织曎倍杂的内郚架构。

                              ┌─────────────────┐
                              │   QQ 服务噚     │
                              └────────┬────────┘
                                       │
                              ┌────────▌────────┐
                              │  OneBot 实现    │
                              │  (NapCat等)     │
                              └────────┬────────┘
                                       │
              ┌────────────────────────┌────────────────────────┐
              │                        │                        │
              ▌                        ▌                        ▌
    ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
    │   HTTP POST     │    │   WebSocket     │    │   HTTP API      │
    │  (事件掚送)     │    │  (双向通信)     │    │  (发送消息)     │
    └────────┬────────┘    └────────┬────────┘    └────────▲────────┘
             │                      │                      │
             │                      │                      │
┌────────────┌──────────────────────┌──────────────────────┌────────────┐
│            │         XiaoQing 框架    │                      │            │
│            â–Œ                      â–Œ                      │            │
│  ┌─────────────────┐    ┌─────────────────┐             │            │
│  │ InboundServer   │    │ OneBotWsClient  │             │            │
│  │ (server.py)     │    │ (onebot.py)     │             │            │
│  └────────┬────────┘    └────────┬────────┘             │            │
│           │                      │                      │            │
│           └──────────┬───────────┘                      │            │
│                      │ 事件                             │            │
│                      â–Œ                                  │            │
│           ┌──────────────────────────────────────────────            │
│           │         Dispatcher (dispatcher.py)          │            │
│           │  • 消息解析                                 │            │
│           │  • 觊发条件刀断                             │            │
│           │  • 䌚话管理                                 │            │
│           │  • 呜什/闲聊路由                           │            │
│           └────────────────┬────────────────────────────┘            │
│                            │                                         │
│                            â–Œ                                         │
│           ┌─────────────────────────────────────────────┐            │
│           │            Router (router.py)               │            │
│           │  • 呜什觊发词匹配                           │            │
│           │  • 䌘先级排序                               │            │
│           └────────────────┬────────────────────────────┘            │
│                            │                                         │
│                            â–Œ                                         │
│           ┌─────────────────────────────────────────────┐            │
│           │       PluginManager (plugin_manager.py)      │            │
│           │  • 插件加蜜/卞蜜                            │            │
│           │  • 热重蜜监控                               │            │
│           │  • Context 构建                             │            │
│           └────────────────┬────────────────────────────┘            │
│                            │                                         │
│                            â–Œ                                         │
│           ┌─────────────────────────────────────────────┐            │
│           │           Plugin.handle()                    │            │
│           │           䜠的插件代码                       │            │
│           └────────────────┬────────────────────────────┘            │
│                            │                                         │
│                            │ 消息段                                  │
│                            â–Œ                                         │
│           ┌─────────────────────────────────────────────┐            │
│           │        OneBotHttpSender (onebot.py)         ├────────────┘
│           │           发送响应消息                       │
│           └─────────────────────────────────────────────┘
│
│  ┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐
│  │ SessionManager  │    │ SchedulerManager│    │ ConfigManager   │
│  │ (session.py)    │    │ (scheduler.py)  │    │ (config.py)     │
│  │ 倚蜮对话管理    │    │ 定时任务管理    │    │ 配眮热重蜜      │
│  └─────────────────┘    └─────────────────┘    └─────────────────┘
│
└──────────────────────────────────────────────────────────────────────┘

⚙ 栞心组件 ​

圚圓前项目䞭core/ 的职莣蟹界保持皳定。它倄理所有插件共享的通甚问题䞍把某䞪䞚务插件的规则写进栞心。smalltalk_provider = "xiaoqing_chat" 时栞心先调甚插件的 observe_message() 观察消息只有通过 dispatcher 闚控并萜到 smalltalk 回萜时才由聊倩插件刀断是吊实际回倍。

1. XiaoQingAppapp.py 侎 app_* 暡块 ​

职莣app.py 只保留应甚入口、组件装配、启劚/停机䞎配眮发垃 app_plugin_watch.py、app_delivery.py、app_ingress.py、app_scheduling.py 分别拥有插件 watcher 监督、OneBot 投递、入站端点重协商和排皋发垃。app_identity.py 侭的 AppIdentityService 独立拥有管理员集合䞎 principal authorityapp_support.py 保留无状态解析和生呜呚期记圕。XiaoQingApp 莟莣装配并委托这些职莣对倖类名和 调甚契纊䞍变。

python
class XiaoQingApp:
    def __init__(self, root: Path):
        # 初始化配眮
        self.config_manager = ConfigManager(...)
        
        # 初始化各组件
        self.router = CommandRouter()
        self.plugin_manager = PluginManager(...)
        self.scheduler = SchedulerManager(...)
        self.session_manager = SessionManager(...)
        self.dispatcher = Dispatcher(...)
        
    async def start(self):
        # 1. 初始化并发控制
        concurrency = self.config.get("max_concurrency", 5)
        self.dispatcher.semaphore = asyncio.Semaphore(concurrency)

        # 2. 创建 HTTP 䌚话
        self.http_session = aiohttp.ClientSession()
        
        # 3. 加蜜所有插件
        self.plugin_manager.load_all()
        
        # 4. 启劚通信服务
        if enable_ws_client:
            self.ws_client.connect_and_listen(...)
        if enable_inbound_server:
            self.inbound_server.start()
            
    async def stop(self):
        # 䌘雅关闭所有组件
        if self.ws_client:
            await self.ws_client.stop()
        # ...

关键属性

  • config - 配眮字兞
  • secrets - 敏感配眮
  • is_admin(user_id) - 刀断是吊管理员

2. Dispatcherdispatcher.py ​

职莣消息分发的栞心。Dispatcher 䜿甚单䞪线性流皋倄理消息倄理状态保存圚 MessageContext 䞎局郚控制流䞭。

python
class Dispatcher:
    async def _process_event(self, event: dict[str, Any]) -> list[dict[str, Any]]:
        ctx = self.parser.parse(event)
        if ctx is None:
            return []

        await self._observe_message(ctx)

        if ctx.is_url_only:
            return await self._invoke_url_parser(ctx, ctx.clean_text.strip()) or []

        should_process = (
            ctx.is_private
            or not config.get("require_bot_name_in_group", True)
            or ctx.has_prefix
            or has_active_session(ctx)
        )
        if not should_process:
            return []

        if ctx.is_only_bot_name:
            return await self._handle_bot_name_only(ctx)

        resolved = self.router.resolve(ctx.clean_text)
        if resolved:
            return await self._execute_command(resolved, ctx) or []

        if ctx.has_command_prefix:
            return unknown_command_hint(ctx)

        if ctx.cached_session:
            return await self._try_handle_session(ctx) or []

        if self.is_muted(ctx.group_id):
            return []

        return await self._handle_smalltalk(ctx)

关键解析信号

  • has_prefix 衚瀺消息以呜什前猀默讀 /匀倎或包含 bot_name任意䜍眮或包含 @机噚人任意䜍眮。
  • has_command_prefix 单独标识䞥栌以呜什前猀匀倎。未知呜什提瀺只看这䞪字段。
  • URL 倄理改甚 ctx.is_url_only仅圓 clean_text strip 后敎䜓匹配 ^https?://\S+$ 时调床到 url_parser。文本䞭倹垊 URL 䞍䌚觊发 URL 短路。

线性倄理顺序

Step A: 倄理闚控私聊、require_bot_name_in_group=False、has_prefix、掻跃 session
        · 先 router.resolve再按敏感类别决定是吊 observe_message
Step B: is_url_only → url_parser圚闚控䞎静音之后静音时跳过
Step C: is_only_bot_name → 默讀回应 / call_bot_name_only
Step D: 掻跃 session → 蜬 session 插件
Step E: router 呜䞭 → 执行呜什
Step F: has_command_prefix 䞔呜什未呜䞭䞔銖字母䞺字母 → 未知呜什提瀺
Step G: 回萜 smalltalk providermute 仅圚歀步及普通矀闲聊阻塞

xiaoqing_chat 圚呜什解析之后、按敏感类别通过 observe_message() 观察消息呜什、URL、掻跃䌚话和呜什前猀蟓入䞍进入观察是吊实际回倍由插件内郚的 attention gate、硬频控、普通矀聊插话抂率、heartflow 和 PFC planner 决定。


3. Routerrouter.py ​

职莣根据觊发词匹配呜什。

python
@dataclass
class CommandSpec:
    plugin: str       # 所属插件名
    name: str         # 呜什名
    triggers: List[str]  # 觊发词列衚
    help_text: str    # 垮助文本
    admin_only: bool  # 是吊仅管理员
    handler: Handler  # 倄理凜数
    priority: int     # 䌘先级

class CommandRouter:
    def register(self, spec: CommandSpec):
        """泚册呜什"""
        self._commands.append(spec)
        
    def resolve(self, text: str) -> Optional[Tuple[CommandSpec, str]]:
        """解析呜什"""
        # 按䌘先级和觊发词长床排序长的䌘先
        for spec in sorted_commands:
            for trigger in spec.triggers:
                if text.startswith(trigger):
                    args = text[len(trigger):].strip()
                    return spec, args
        return None

䌘先级规则

  1. priority 数倌越倧越䌘先
  2. 同䌘先级时觊发词越长越䌘先避免 help 抢走 helpme 的匹配

4. PluginManagerplugin_manager.py 侎 plugin_* 暡块 ​

职莣plugin_manager.py 是装配䞎呜名空闎所有权闚面富入屏障和共享事务记圕䜍于 plugin_manager_support.py生呜呚期/代际发垃䜍于 plugin_generation.py目圕扫描䞎 watcher 䜍于 plugin_watcher.py执行 gate/服务绑定䜍于 plugin_runtime.py倖眮数据 目圕䜍于 plugin_data.py。所有暡块共享同䞀组状态和事务没有第二套加蜜或回滚路埄。

python
class PluginManager:
    def load_all(self):
        """加蜜 plugins/ 䞋所有插件"""
        for plugin_dir in self.plugins_dir.iterdir():
            if self._is_plugin_dir(plugin_dir):
                self.load_plugin(plugin_dir)
    
    def load_plugin(self, plugin_dir: Path):
        """加蜜单䞪插件"""
        # 1. 读取 plugin.json
        definition = self._load_definition(plugin_dir)
        
        # 2. 富入 main.py 暡块
        module = self._load_module(plugin_dir, definition)
        
        # 3. 构造呜什规范候选插件通过党郚校验后再原子发垃到 Router
        command_specs = self._build_command_specs(definition, module)
        self.router.replace_plugin(definition.name, command_specs)
        
        # 4. 调甚 init() 钩子劂果存圚
        #    若返回协皋䌚被纳入 init task 跟螪并等埅完成
        if hasattr(module, "init"):
            result = module.init()
            if asyncio.iscoroutine(result):
                ...
    
    async def reload_plugin(self, name: str):
        """热重蜜插件"""
        await self.unload_plugin(name)
        self.load_plugin(self.plugins_dir / name)
        await self.wait_inits()
    
    async def watch(self):
        """监控插件文件变化自劚重蜜"""
        while True:
            await asyncio.sleep(self._poll_interval)
            # 检查 mtime劂有变化则重蜜

诎明应甚启劚时䌚自劚创建配眮 watcher插件 watcher 仅圚 config.json 里启甚 enable_plugin_watcher 䞔圓前解释噚通过暡块富入屏障行䞺探针后才䌚启劚。探针倱莥 䞍圱响进皋启劚和銖次插件加蜜䜆插件变曎只胜通过重启生效手劚 reload 也䌚明确 报告 restart-only 暡匏。插件匂步 init() 圚重蜜路埄䞊䌚被等埅劂果初始化倱莥 半加蜜插件䌚被立即卞蜜避免继续接流量。

插件加蜜流皋

plugins/echo/
    │
    ├── plugin.json ──> PluginDefinition
    │                   (name, version, commands, schedule...)
    │
    └── main.py ──────> Module
                        (handle, init, shutdown...)
                             │
                             ▌
                      Router.register(CommandSpec)

5. SessionManagersession.py ​

职莣管理倚蜮对话的䌚话状态。

python
@dataclass
class Session:
    user_id: int
    group_id: Optional[int]  # None = 私聊
    plugin_name: str         # 所属插件
    session_id: str          # create/replace 时生成普通 update 保留
    data: Dict[str, SessionValue]  # 有界、字笊䞲键的 JSON-like 倌树
    timeout: float           # è¶…æ—¶æ—¶é—Ž
    
    def get(self, key, default=None): ...
    def set(self, key, value): ...
    def is_expired(self) -> bool: ...

class SessionManager:
    # 䌚话存傚(user_id, group_id) -> Session
    _sessions: Dict[tuple, Session]
    
    async def create(self, user_id, group_id, plugin_name, initial_data, timeout):
        """创建新䌚话"""
        
    async def get(self, user_id, group_id) -> Optional[Session]:
        """获取隔犻快照、刷新空闲超时自劚枅理过期"""

    async def update(self, user_id, group_id, callback):
        """圚受控倌树克隆的工䜜副本䞊执行䞀次可回滚事务"""
        
    async def delete(self, user_id, group_id) -> bool:
        """删陀䌚话"""

䌚话生呜呚期

1. 甚户发送呜什劂 /猜数字
       │
       ▌
2. 插件调甚 context.create_session()
       │
       ▌
3. 䌚话创建存傚初始数据
       │
       ▌
4. 甚户后续消息被路由到 handle_session()
       │
       ▌
5. Dispatcher 圚 SessionManager.update() 工䜜副本䞭调甚插件插件䜿甚 session.set()
       │
       ├─ 继续对话 ──> 回到步骀 4
       │
       └─ 对话结束 ──> context.end_session()
                           │
                           ▌
                      䌚话被删陀

关键䞍变量正匏䌚话从䞍盎接暎露给插件读取返回隔犻快照曎新只圚每键事务锁内 提亀䞀次。倌树限制深床、节点数和内建类型星匏拒绝匕甚环及自定义 __deepcopy__这是防止插件状态砎坏回滚或造成无界资源消耗的安党蟹界。事务 callback 被取消时管理噚䌚先取消并 drain 唯䞀的实际 Future再决定回滚避免请求返回后仍有 后台 callback 提亀“幜灵状态”。这些纊束属于正确性契纊䞍应䞺简化代码而移陀。


6. SchedulerManagerscheduler.py ​

职莣管理定时任务。

python
class SchedulerManager:
    async def shutdown_async(self, *, wait: bool = True):
        """停止接纳取消协皋任务并有界等埅真实 Future 收敛"""
    
    def replace_prefix(self, prefix: str, specs: Iterable[ScheduledJobSpec]):
        """验证敎批声明后事务匏替换倱莥时恢倍原快照"""
    
    async def reset_async(self, timezone: str | None = None):
        """旧代完敎关闭后才发垃新时区 scheduler"""

APScheduler 的公匀关闭 API 无法证明抵抗取消的协皋或线皋任务已经真正结束。䞺保持 “旧代未排空就䞍埗发垃新代”的所有权䞍变量scheduler_compat.py 把 3.x 的私有锁、 Future 泚册衚、timer 和事件字段隔犻圚䞀䞪适配噚内并圚每䞪真实 scheduler 䞊先探测 完敎垃局。探测通过时继续执行可重试的粟确 drain探测倱莥时记圕版本䞎猺倱胜力 降级䞺 APScheduler 公匀 shutdown䞍䌚圚暡块富入期拒绝启劚。䟝赖范囎是 apscheduler>=3.11,<4升级时必须运行胜力探针、公匀降级、取消、线皋任务 drain、 枅理倱莥重试和事务回滚测试。

Cron 衚蟟匏瀺䟋

python
# 每倩 8:00
{"hour": 8, "minute": 0}

# 每 2 小时
{"hour": "*/2"}

# 工䜜日 9:00
{"day_of_week": "mon-fri", "hour": 9}

# 每月 1 号 0:00
{"day": 1, "hour": 0, "minute": 0}

7. OneBot 通信onebot.py + server.py ​

䞀种通信方匏

OneBotHttpSender - 发送消息 ​

python
class OneBotHttpSender:
    async def send_action(self, action: Dict):
        """发送 OneBot Action"""
        url = f"{self.http_base}/{action['action']}"
        await self.session.post(url, json=action['params'], headers=headers)

OneBotWsClient - WebSocket 双向通信 ​

python
class OneBotWsClient:
    async def connect_and_listen(self, handler):
        """按讀证代际连接并圚断匀后执行有界退避。"""
        while self._running:
            connected_seconds = await self._connect_once(handler)
            await self._wait_for_reconnect(self._next_backoff(connected_seconds))
    
    async def send_action(self, action: Dict):
        """通过 WS 发送"""
        await self._ws.send(json.dumps(action))

连接噚圚启劚和热曎新后的䞋䞀次连接前检查 websockets.connect 的真实筟名䞎参数类型新版通过 additional_headers、旧版通过 extra_headers 发送 Bearer token无法证明讀证倎胜䜜䞺关键字参数䌠递时盎接 fail closed。正垞关闭䞎匂垞关闭共甚垊连续抖劚的 5–60 秒指数退避皳定运行 30 秒才倍䜍地址/token 代际变化䌚同时唀醒退避和连接阶段。每䞪 socket、close task 侎 connection attempt 郜按对象/代际独立拥有旧代拒绝取消或关闭倱莥时进入隔犻集合䞍䌚阻塞新代连接并圚停机的单䞀绝对期限内并发回收。

讀证状态还包含“凭据来源可信”䜍。VALID secrets 䞭猺省或明确的空字笊䞲衚瀺操䜜者选择匿名 OneBotsecrets 䞺 MISSING/INVALID/UNAVAILABLE/INCONSISTENT或 token 䞍是粟确字笊䞲时则衚瀺撀权HTTP 䞍发请求、WebSocket 䞍调甚 connect盎到新的 VALID revision 恢倍。同步安党发垃䌚验证每䞪 holder 确实执行了 endpoint/token/trust 曎新仅返回成功䜆未改变状态的旧实现䌚立即被摘陀或隔犻。Inbound token 䞎管理员列衚也只读取同䞀䞪可信 secrets 视囟来源匂垞时分别进入党拒绝和空权限状态。

InboundServer - 被劚接收 ​

python
class InboundServer:
    """HTTP 服务噚接收 OneBot 掚送"""
    
    async def post_event(self, request):
        """POST /event - 接收事件"""
        payload = await request.json()
        actions = await self.handler(payload)
        return web.json_response({"actions": actions})
    
    async def ws_handler(self, request):
        """WebSocket 端点"""
        # 持久连接倄理

🔄 数据流诊解 ​

完敎请求流皋 ​

1. OneBot 掚送事件
   POST http://127.0.0.1:12000/event
   {
     "post_type": "message",
     "message_type": "group",
     "group_id": 123456,
     "user_id": 789,
     "message": [{"type": "text", "data": {"text": "/echo hello"}}]
   }

2. InboundServer 接收
   └─ 验证 Authorization Token
   └─ 解析 JSON
   └─ 调甚 handler(event)

3. Dispatcher 倄理
   └─ MessageParser.parse() 构建 MessageContext
   └─ ctx.has_command_prefix=Truectx.clean_text="echo hello"
   └─ Step A 倄理闚控通过has_prefix=True
   └─ ctx.is_url_only=False跳过 Step B URL 解析
   └─ router.resolve("echo hello") 埗到 (echo插件, "hello")
   └─ 权限检查通过
   └─ 构建 context
   └─ 调甚 echo.handle("echo", "hello", event, context)

4. 插件倄理
   └─ 返回 [{"type": "text", "data": {"text": "hello"}}]

5. 构建响应
   └─ build_action(segs, user_id, group_id)
   └─ {
        "action": "send_group_msg",
        "params": {
          "group_id": 123456,
          "message": [{"type": "text", "data": {"text": "hello"}}]
        }
      }

6. 返回给 OneBot
   └─ InboundServer 返回 {"actions": [...]}
   └─ OneBot 执行 action发送消息到 QQ

䌚话倄理流皋瀺䟋 ​

1. 甚户发送 /guess 启劚猜数字枞戏
   └─ guess.handle() 创建䌚话
   └─ context.create_session(initial_data={"target": 42})

2. 甚户后续消息 "50"
   └─ Dispatcher 倄理
   └─ Step D 发现掻跃䌚话
   └─ 调甚 guess.handle_session("50", event, context, session)
   └─ 返回 ["倪倧了"]

3. 甚户猜测正确 "42"
   └─ Step D 䌚话倄理
   └─ guess.handle_session() 刀断正确
   └─ context.end_session() 删陀䌚话
   └─ 返回 ["恭喜䜠猜对了"]

⚡ 并发控制 ​

XiaoQing 䜿甚 asyncio.Semaphore 控制并发

python
# app.py
concurrency = int(config.get("max_concurrency", 5))
self.dispatcher = Dispatcher(..., semaphore=asyncio.Semaphore(concurrency))

# dispatcher.py
async def handle_event(self, event):
    async with self.semaphore:  # 最倚同时倄理 5 条消息
        return await self._handle_event(event)

🧩 插件内嵌服务 ​

郚分插件可以圚框架之倖独立运行附加服务。兞型案䟋是 pendo 插件

XiaoQing 䞻进皋
├── 正垞消息倄理流皋Dispatcher → Plugin
└── pendo 插件main.py
        ├── PendoRuntimeService数据库、配眮订阅、Web 生呜呚期所有权
        └── 插件初始化或 /pendo web start
                └── FastAPI Web Serveruvicorn
                        ├── /api/*  # REST APIJWT 鉎权、CRUD、统计、Bundle、widget
                        └── /*      # 静态 SPA 文件

特点

  • Web Server 圚独立后台线皋䞭运行䞍阻塞消息倄理
  • PendoRuntimeService 是内郚 service boundary数据库、配眮订阅和自劚 Web 生呜呚期按同䞀插件代获取䞎释攟main.py 只做插件钩子猖排
  • 插件初始化䌚尝试自劚启劚也可以通过 /pendo web start 手劚重试通过 /pendo web stop 关闭
  • 应甚退出、插件卞蜜或 Ctrl+C 时䌚先请求 Pendo Web 䌘雅停止再枅理数据库和运行时状态
  • 支持通过 nginx 圚子路埄劂 /pendo/䞋反向代理访问
  • Pendo Web 䞎聊倩呜什共甚 plugins/pendo/services/db.py、utils/validators.py 和事件囟/提醒服务避免 Web 侎 CLI 各自绎技䞀套字段语义

这仍是单进皋郚眲蟹界Bot 重启䌚重启 Pendo Web。内郚 service boundary 甚来隔犻所有权、回滚和测试䞍宣称进皋故障隔犻若未来确实需芁独立扩容或发垃可圚保持共享服务契纊的前提䞋再拆独立进皋。

及䞀类独立服务是 codex 插件的后台队列。它䞍䜿甚 SessionManager 捕获甚户后续消息而是圚插件内郚绎技 label -> session/thread/queue

  • /codex create <label> [cwd:<path>] 创建䞚务䌚话标筟
  • /codex <label> <任务> 将任务攟入该标筟队列handler 立即返回“已收到”
  • 同䞀标筟内任务䞲行执行䞍同标筟受 max_parallel_jobs 限制并行执行
  • 任务完成后通过 context.send_action() 䞻劚发送文字和囟片结果底层仍走统䞀 OneBot 发送铟路
  • 䌚话玢匕保存圚 data/codex/sessions.json每䞪标筟的记圕、囟片和任务 artifacts 保存圚 data/codex/session/<label>/删陀䌚话时旧目圕䌚園档到 data/codex/deleted_sessions/

arxiv_filter 的每日摘芁就是这䞪暡匏的䞚务化甚法筛选插件先返回论文列衚再通过后台䟧路把所有 positive arXiv 铟接投递到 Codex astro-ph 䌚话。astro-ph 銖次没有 Codex thread 时䌚先执行静默初始化任务之后摘芁任务倍甚同䞀 thread 和工䜜目圕䞭的 arxiv-summary-methodology.md。历史结果和圚途任务只有圚 arXiv 源列衚日期及规范化论文集合郜盞同时才䌚倍甚。

这种方匏适合耗时蟃长䜆䞍应占甚 bot 倚蜮䌚话的后台工䜜。


➡ 䞋䞀步 ​

基于 MIT 讞可发垃

加蜜䞭...