CLAUDE.md · git:20260924.4d9fdfc · 2026-09-24 · sha256 d7bf6296bbb6136b
CLAUDE.md git:20260924.4d9fdfcA
Immutable. This exact content never changes and is served at /api/v1/blob/d7bf6296bbb6136b.
# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## 项目概述 Undefined 是基于 Python asyncio 的高性能 QQ 机器人平台,通过 OneBot V11 协议(NapCat/Lagrange.Core)与 QQ 通信,搭载认知记忆架构、自研 Skills 系统、本地知识库、全局表情包库,以及 Management-first WebUI / Desktop / Android 管理端。 ## 开发命令 ```bash # 依赖安装 / 初始化 uv sync uv run playwright install # 页面截图等能力依赖的浏览器运行时 # 启动 uv run Undefined-webui # 启动 Management-first WebUI(推荐入口) uv run Undefined # 直接启动 Bot # WebUI 自动启动 Bot # 配置 [webui].autostart_bot = true 后,运行 uv run Undefined-webui 会自动拉起 bot 进程 # 默认为 false,保持传统手动启动行为 # 注意:该配置仅在 WebUI 启动时生效,运行时修改需重启 WebUI # 代码质量(提交前必须全部通过) uv run ruff format . uv run ruff check . uv run mypy . # strict=true uv run pytest tests/ uv run pytest tests/test_xxx.py uv run pytest tests/test_xxx.py::test_func -v uv build --wheel # 校验打包与资源包含 # 前端 / 桌面端(仅改动 apps/undefined-console/ 或 apps/undefined-chat/ 或 webui/static/js/ 时需要) cd apps/undefined-console && npm ci && npm run check cd apps/undefined-console && npm run dev cd apps/undefined-console && npm run tauri:dev cd apps/undefined-chat && npm ci && npm run check cd apps/undefined-chat && npm run tauri:dev # Git hooks 安装 bash scripts/install_git_hooks.sh # pre-commit 自动执行:ruff format --check + ruff check + mypy # 含 JS/Tauri 改动时额外执行:Biome + TypeScript + cargo fmt/check ``` ## 代码规范 - **类型注释**:所有 Python 代码必须有完整类型注释,mypy strict 模式 - **异步 IO**:磁盘读写必须走 `utils/io.py`(`asyncio.to_thread` + 跨平台文件锁 + 原子写入),禁止在事件循环中直接阻塞 IO - **Python 版本**:`>=3.11, <3.14`(推荐 3.12) - **测试**:pytest + pytest-asyncio,`asyncio_mode = "auto"` - **前端格式化**:`src/Undefined/webui/static/js/` 由根目录 `biome.json` 管理;`apps/undefined-console/` 和 `apps/undefined-chat/` 走 Biome + TypeScript + Cargo 检查 - **版本号同步**:发布版本时优先使用 `uv run python scripts/bump_version.py <version>`,统一同步 Python 包、console、chat 与 Tauri 版本号 - **Git hooks**:优先通过 `scripts/install_git_hooks.sh` 安装,不要手动维护 `core.hooksPath` ## 架构分层 核心源码位于 `src/Undefined/`,主要模块如下(目录级事实来源是 [docs/development.md](docs/development.md) 的目录树,本表只做职责概览): | 目录 / 文件 | 职责 | |---|---| | `ai/` | AI 运行时核心:`client/`(主入口与 ask 循环)、`llm/`(模型请求与重试)、`prompts/`(Prompt 构建)、`tooling.py`(工具管理)、`multimodal/`(多模态)、`model_selector.py`(模型选择)、`summaries.py`(短期总结)、`retrieval.py`(嵌入/重排请求) | | `services/` | 运行服务:`coordinator/`(协调器 + 队列投递)、`queue_manager.py`(车站-列车队列)、`message_batcher/`(同 sender 短时合并)、`command.py`(命令分发)、`commands/`(命令注册表与目录)、`model_pool.py`(多模型池)、`security.py`(安全防护) | | `skills/` | 热重载技能系统:`tools/`(原子工具)、`toolsets/`(按域分组工具)、`agents/`(智能体)、`commands/`(斜杠指令)、`anthropic_skills/`(SKILL.md 知识注入) | | `cognitive/` | 认知记忆:`service/`(入口)、`vector_store.py`(ChromaDB)、`historian/`(后台史官异步改写+侧写合并)、`job_queue.py`、`profile_storage.py` | | `memes/` | 表情包库:两阶段 AI 管线、异步处理队列、SQLite 元数据、ChromaDB 向量检索 | | `knowledge/` | 本地知识库:文本切分、嵌入、重排、ChromaDB 存储与运行时检索 | | `arxiv/` | arXiv 论文解析、元信息获取、PDF 下载与发送 | | `bilibili/` | B 站链接/BV 解析、视频下载与发送 | | `github/` | GitHub public 仓库解析、API 获取与图片卡片发送 | | `api/` | Runtime API / Management API 相关服务;路由拆分在 `api/routes/`,包含 `chat`、`cognitive`、`health`、`memes`、`memory`、`naga`、`system`、`tools` | | `webui/` | aiohttp 管理控制台;路由拆分在 `webui/routes/`,覆盖配置、日志、运行态、表情包与系统管理 | | `mcp/` | MCP 工具注册、连接与转换 | | `automations/` | 条件驱动的轻量工作流:`AutomationService` 运行时、start 匹配、@ 消费、DAG / 分支 / 循环、旧定时任务迁移 | | `config/` | 配置系统:`loader.py`(TOML 解析+类型化)、`models.py`(数据模型)、`hot_reload.py`(热更新) | | `attachments/` | 富媒体/附件注册、作用域隔离、`<attachment uid="..."/>` 统一标签(`<pic>` 向后兼容)渲染 | | `utils/` | `io.py`(异步 IO)、`history.py`(消息历史)、`paths.py`、`logging.py`、`sender.py` 等通用能力 | ### 消息处理流程 ```text OneBot WebSocket → onebot/ → handlers/ → 附件登记 / 访问控制 / 表情包入库 → SecurityService(注入检测) → CommandDispatcher(斜杠指令,命中即结束后续处理) → skills/pipelines(Bilibili / arXiv / GitHub 并行自动提取) → Automations(pipeline 后接入;consume_ai_loop 时 await 并拦截对应 AI,否则后台执行并立刻放行;发生在 MessageBatcher 之前) → MessageBatcher(同 sender 短时合并;拍一拍/buffer 内 @bot 旁路) → AICoordinator → QueueManager(按模型隔离, 6 条车道) → AIClient → LLM API / Skills / MCP Management / Runtime 请求 → webui/app.py 或 api/app.py → routes/* → 配置、日志、记忆、工具调用、AI Chat 等能力 ``` ### 多模型池分工 - `ai/model_selector.py` — 纯选择逻辑(策略 / 偏好 / compare 状态),无 IO 副作用 - `services/model_pool.py` — 私聊交互服务,持有 ai/config/sender,处理 `/compare`、`选X`、`select_chat_config` - `services/coordinator/` — 持有 `ModelPoolService`(`self.model_pool`),私聊队列投递时通过它选模型 - `handlers/` — 私聊消息只调 `await self.ai_coordinator.model_pool.handle_private_message(user_id, text)`,不直接感知选择细节 - `skills/agents/runner/` — Agent 直接调用 `ai_client.model_selector.select_agent_config(...)`,无 `hasattr` - 默认关闭:`models.pool_enabled = false`;群聊不参与多模型,始终走主模型 ### Skills 系统 - **热重载**:自动扫描 `skills/` 下 `config.json` / `handler.py` 变更并重载 - **自动处理管线**:`skills/pipelines/<name>/` 使用 `config.json + handler.py`,在斜杠命令之后、AI 自动回复之前并行检测/处理;命令输入和命令输出要写入历史,管线输出通过 `MessageSender` 自动写历史并登记本地媒体/文件附件 UID。 - **Skills handler 不引用 `skills/` 外的本地模块**(`Undefined.skills.*` 与同目录相对导入除外),依赖通过 context 注入;跨技能共享的 helper 放 `skills/shared.py`,越界导入由 `tests/test_skills_import_boundary.py` 棘轮校验 - **Agent 标准结构**:`config.json` + `handler.py` + `prompt.md` + `intro.md` + `mcp.json`(可选) + `anthropic_skills/`(可选) - **共享授权**:通过 `callable.json` 将工具或 Agent 白名单暴露给其他 Agent - **Anthropic Skills**:支持 SKILL.md 目录结构与渐进式披露 #### 关键工具说明 - `group.get_member_info`:支持 `brief` 参数(默认 false)。当 `brief=true` 时只返回当前昵称(群名片优先,否则 QQ 昵称),便于快速称呼用户。 - `group.get_avatar`:接受 `user_id` 与可选 `size`(40/100/140/640),下载 QQ 头像并注册为附件,返回 `<attachment uid="..."/>` 标签。 - 统一附件标签:推荐使用 `<attachment uid="..."/>`,系统根据 UID 前缀(`pic_`/`file_`)自动区分图片与文件。旧 `<pic uid="..."/>` 语法向后兼容。 - 远程附件默认按 `[attachments].remote_download_max_size_mb` 限制下载缓存;超过上限或配置为 `0` 时只登记 URL 引用(`source_ref`),避免大文件造成磁盘和延迟压力。 ### 队列模型 车站-列车模型(QueueManager):按模型隔离队列组,6 条车道按序发车(超管私聊 / 群聊超管 / 普通私聊 / 群聊@ / 群聊普通 / 后台请求;前两条为严格优先级,中间三条轮转发车),普通队列自动修剪保留最新 2 条,非阻塞按节奏发车(默认 1Hz)。 ### 同 sender 短时消息合并(MessageBatcher) 同一 sender 在 `[message_batcher].window_seconds` 内连续发送的多条消息会合并到同一轮 AI 调用,AI 一次性看到全部 `<message>` 块自行识别“独立请求/修正/打断”。拍一拍永远旁路立即处理;群聊已有 buffer 时新到的 @bot 也单独立即处理;首条 @bot 进入 buffer 时整批走 mention 队列。可选开启投机预发送 `pre_send_seconds < window_seconds`:静默到该阈值先把 batch 提前发给 LLM 抢时间,新消息在 inflight 未发出任何消息时可取消该调用。`enabled=false` 行为退化回旧版。详见 [docs/message-batching.md](docs/message-batching.md)。 ### 存储与数据 - `data/history/` — 消息历史(`group_*.json` / `private_*.json`,默认 10000 条,可通过 `[history]` 调整,0 = 无限) - `data/cognitive/` — ChromaDB 向量库 + `profiles/` 侧写 + `queues/` 任务队列 - `data/memes/` — 表情包库(`blobs/` 原图、`previews/` 预览图、`memes.sqlite3` 元数据、`chromadb/` 向量检索) - `data/cache/` — 附件、下载、渲染与 WebUI 文件缓存 - `data/attachment_registry.json` — 附件注册表 - `data/memory.json` — 置顶备忘录(500 条上限) - `data/end_summaries.json` — 短期总结存储 - `data/automations.json` — 自动化工作流存储。启动时若无此文件但存在旧 `scheduled_tasks.json`,则读取并转为新格式写入,不删除旧文件、不双写 - `data/faq/` — FAQ 存储 - `data/token_usage.jsonl` — Token 统计(自动 gzip 归档;流式调用可含可选 `ttft_seconds` / `tokens_per_second`) - `knowledge/` — 本地知识库数据目录(`texts/`、`intro.md`、`chroma/` 等) - `res/prompts/` — 系统提示词模板 ## 提示词约定 系统提示词(`res/prompts/undefined.xml`)包含用户识别规则: - 以 QQ 号(`sender_id`)为用户唯一标识,昵称可能随时变动 - 称呼用户时使用当前最新昵称,不确定时可调用 `group.get_member_info(brief=true)` 查询 - 认知记忆(`end.observations`)只写值得日后检索的写实实质事实(宁缺毋滥);必须含稳定实体标识,用户观察格式如:“QQ号12345678(昵称张三)做了某事” ## 配置系统 - 主配置:`config.toml`(从 `config.toml.example` 复制) - 配置热更新:`config.reload()` 触发回调 - MCP 配置:`config/mcp.json`(全局)或 `agents/<name>/mcp.json`(Agent 私有) - 脚本 `scripts/sync_config_template.py` 可将新配置项同步到已有 `config.toml` ## 运维脚本 - `scripts/install_git_hooks.sh` — 安装 Git hooks(设置 `.githooks`) - `scripts/sync_config_template.py` — 同步配置模板新增项(支持 `--dry-run`) - `scripts/reembed_cognitive.py` — 更换嵌入模型后重建认知向量库(支持 `--events-only` / `--profiles-only` / `--batch-size` / `--dry-run`) - `scripts/bump_version.py` — 同步更新 Python / console / Tauri 版本号,并可选择连同 lock 文件一起更新 ## 跨平台控制台 `apps/undefined-console/` 是基于 Tauri v2 + TypeScript + Vite 的管理客户端,支持 Windows / macOS / Linux / Android,连接同一套 Management API 与 Runtime API。 `apps/undefined-chat/` 是原生优先的 WebChat 客户端,基于 Tauri v2 + React,直接连接 Runtime API,面向长期挂起、桌面/移动端聊天使用场景。采用莫兰迪橙色系(Morandi Orange)设计,与 WebUI 保持视觉一致性。它移植 WebUI webchat 的核心聊天功能,并在事件流(SSE 优先 + JSON fallback 双通道)、桌面快捷键、图片查看(缩放/旋转/全屏)、安全存储(系统 keyring / Android Keystore)等方面做了原生增强;HTML 采用 sanitize 内联渲染 + 独立预览窗口隔离运行的双层策略。详见 [docs/undefined-chat.md](docs/undefined-chat.md)。