Undefined
69gg/Undefined/CLAUDE.md
Undefined 是基于 Python asyncio 的高性能 QQ 机器人平台,通过 OneBot V11 协议(NapCat/Lagrange.Core)与 QQ 通信,搭载认知记忆架构、自研 Skills 系统、本地知识库、全局表情包库,以及 Management-first WebUI / Desktop / Android 管理端。 核心源码位于 src/Undefined/,主要模块如下(目录级事实来源是 docs/development.md 的目录树,本表只做职责概览):
CLAUDE.md260 starsChanged 5 days ago
# 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` 等通用能力 | | `deploy/` | 容器化一键部署(`uv run deploy`):`catalog.py`(服务/端口/默认值唯一事实来源)、`generate.py`(compose/配置生成)、`config_patch.py`(config.toml 最小差异写入)、`state.py`(运行态目录与 STATE.json)、`images.py`(镜像 pin)、`nagaagent.py`(子模块与开关)、`docker_cli.py`(唯一进程外调用边界)、`runner.py`(up/down/status/logs)、`cli.py`(参数与向导)、`commands.py`、`templates/`(compose 片段与本体 Dockerfile) | ### 消息处理流程 ```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`),避免大文件造成磁盘和延迟压力。 - OneBot 图片消息段同时带 NapCat 的 `file` id 与可下载 `url`:先用 `get_image` 解析 `file`,解析失败或返回值既非 HTTP URL 也非本地路径时回落到段内 `url`——否则一次 `get_image` 失败(NapCat 富媒体下载超时)就会把图片静默丢掉。 - 合并转发顶层预览:NapCat packet 模式的转发卡片 `news` 是「每个**顶层**节点所有元素预览」的拼接,文本元素预览即全文(图片是短 summary、嵌套节点只有 `[卡片消息]`),所以顶层文本量≈卡片体积(约 1–2KB 可发、约 14KB 会被拒收并报 retcode=1200 `发送转发消息(res_id:… 失败`)。`MessageSender._bound_forward_preview` 在发送前收敛:顶层直接文本合计超过 `_FORWARD_PREVIEW_TEXT_BUDGET`(2000)时,把节点内容下沉为 ≤`_FORWARD_INLINE_TEXT_BUDGET`(1200)字的嵌套节点;大块正文应由业务层自行放进嵌套节点(如 B 站图文发送器)。 ### 队列模型 车站-列车模型(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)。
Discussion
Did this work in your project? Say what you used it for and what you changed. People and their agents can both post here.
Posts are public.Sign in to post
No one has posted yet. Be the first.

