# 云枢·Agent 会议室架构计划书 > **生成日期**:2026-05-11 > **目的**:从单 Agent 架构升级为"会议室模式"(1 主持 + N 领域专家 + 共享黑板) > **最终目标**:在云枢上验证通过后,移植到 HxClaw(河虾 Claw) --- ## 一、架构总览 ``` 用户 │ ┌──────▼──────────────────────────────────────┐ │ 主持者(dialog-agent)type: main │ │ 人格 + 调度规则 + task + memory 工具 │ │ 唯一入口,用户只和它对话 │ └──────┬───────────────────────────────────────┘ │ task("weather", {city: "北京"}) │ task("earthquake", {region: "通州"}) │ task("memory", {action: "read", ...}) ▼ ┌───────────────────────────────────────────┐ │ 发言人(领域子 Agent)type: sub │ │ weather / earthquake / memory / narrator │ │ 被调才说话,返回文本 + 可选缓存数据 │ │ 各自的 cache / skills / tools 互相隔离 │ └───────────────────────────────────────────┘ │ 读写 ▼ ┌───────────────────────────────────────────┐ │ 记录者(记忆系统) │ │ 共享黑板:用户画像、偏好、异常记录 │ │ memory Agent 负责从对话中提取有价值信息 │ │ 所有 Agent 只读,仅 memory Agent 写入 │ └───────────────────────────────────────────┘ ``` --- ## 二、角色定义 ### 2.1 主持者:dialog-agent(type: main) **职责**: - 用户的唯一入口 - 有血有肉的个人助理,能闲聊 - 识别用户意图,调度对应的子 Agent - 读/写记忆(用户画像、上下文摘要) **工具列表**: - `task` — 调度子 Agent - `memory.read` — 读长期记忆 - `memory.write` — 写长期记忆 **System Prompt 包含**: - 人格(从 `memory.personality` 加载) - 调度规则(何时调哪个子 Agent) - 不含任何领域知识 **System Prompt 不包含**: - 天气知识、地震知识等 - `http-get`、`geocode` 等具体工具 **Session**: - `session.json` 只存 user ↔ dialog 的对话轮次 - 子 Agent 内部的 tool_calls 不写入 ### 2.2 发言人:weather-sub(type: sub) **职责**: - 响应天气查询 - 被 `task` 调才执行,不直接面对用户 - 返回显示文本 + 可选缓存数据 **工具列表**:`http-get`, `geocode`, `skill` **Frontmatter**: ```yaml name: weather type: sub description: 天气查询专家 cache: ttl: 7200 keys: ["city", "forecast_type"] tools: - http-get - geocode - skill ``` ### 2.3 发言人:earthquake-sub(type: sub,预留) **职责**:响应地震信息查询 **Frontmatter**: ```yaml name: earthquake type: sub description: 地震信息查询 cache: ttl: 300 keys: ["region", "time_range"] tools: - http-get - skill ``` ### 2.4 记录者:memory-sub(type: sub) **职责**: - 阅读对话历史,提取用户画像 - 把有价值的信息写入长期记忆数据库 - 响应其他 Agent 的记忆查询 - 记录子 Agent 的异常(如 API 失效) **工具列表**:`memory.read`, `memory.write`, `read-file`, `write-file` **Frontmatter**: ```yaml name: memory type: sub description: 记忆管理员 tools: - memory.read - memory.write - read-file - write-file ``` ### 2.5 汇报员:narrator-sub(type: sub,成熟期) **职责**:把结构化数据翻译成个性化回答 ```yaml name: narrator type: sub description: 个性化回答生成器 tools: - memory.read ``` --- ## 三、核心工具:task ### 3.1 职责 ``` task(agent_name, arguments) │ ├── 1. 加载 {agent_name}-sub.md Frontmatter │ ├── name, type, tools, cache │ ├── cache.keys → ["city", "forecast_type"] │ └── cache.ttl → 7200 │ ├── 2. 拼缓存 key │ ├── 遍历 cache.keys → 从 arguments 提取值 │ ├── 拼接 → "city=北京&forecast_type=today" │ └── hash → "a1b2c3d4e5f6" │ ├── 3. 读缓存文件 ~/.config/yunshu/cache/{agent_name}.json │ ├── HIT → cache_data = {temp: 25, ...} │ └── MISS → cache_data = null │ ├── 4. 调子 Agent LLM │ ├── system = {agent_name}-sub.md 内容 │ ├── user = { │ │ "args": arguments, │ │ "cache_data": cache_data // 有缓存传数据,没有传 null │ │ } │ └── 子 Agent 返回文本 + 可选 ---CACHE--- + JSON │ ├── 5. 处理子 Agent 返回 │ ├── 有 ---CACHE--- → 提取后面的 JSON → 写缓存 │ └── 无 ---CACHE--- → 只传文本 │ └── 6. 返回显示文本给 Host(dialog Agent 的 LLM) ``` ### 3.2 缓存文件格式 ```json // ~/.config/yunshu/cache/{agent_name}.json { "": { "created_at": "2026-05-11T06:00:00+08:00", "ttl": 7200, "data": { "temp": 25, "condition": "晴" }, "raw": { "city": "北京", "forecast_type": "today" } } } ``` - hash 由 `cache.keys` 从 `arguments` 中提取值 → 拼接 → SHA256 取前 12 位 - `raw` 存原始参数,方便调试和遍历 - 每次读缓存时惰性清理过期条目 ### 3.3 传给子 Agent 的参数 ```json { "args": { "city": "北京", "forecast_type": "today", "units": "C" }, "cache_data": { "temp": 25, "condition": "晴" } } ``` - `args` 是 dialog 传过来的原始参数 - `cache_data` 是缓存的数据(有缓存时),子 Agent 据此直接回答,省一次 API 调用 - 两者都是原始数据,不是处理过的文本 --- ## 四、记忆系统 ### 4.1 存储位置 ``` ~/.config/yunshu/memory.db (或 memory.json,MVP 阶段) ``` ### 4.2 数据模型 ```json { "personality": "你是个幽默风趣的北京大妞,说话带点贫", "user_profile": { "location": "北京通州", "unit": "C", "allergies": ["花粉"], "interests": ["户外"], "mood_today": null }, "agent_errors": { "weather": ["msn_api_500 at 2026-05-11T06:00:00"], "earthquake": [] }, "dialog_context": { "last_agent": "weather", "last_topic": "北京天气", "summary": "用户问了北京天气" } } ``` ### 4.3 读写规则 | 操作 | 谁做 | 时机 | |------|------|------| | `memory.read` | dialog / 子 Agent | 需要画像时 | | `memory.write` | 只有 memory Agent | 从对话中提取画像后 | | `memory.write("dialog_context")` | dialog | 每次回答后 | ### 4.4 memory Agent 的工作流 ``` 用户: "我住北京通州,最近花粉过敏厉害" → dialog 聊天回应 → dialog: task("memory", {action: "extract", text: "用户说住通州、花粉过敏"}) → memory: 提取 → memory.write("user_profile.location", "北京通州") memory.write("user_profile.allergies", ["花粉"]) 用户: "今天天气怎么样?" → dialog: task("memory", {action: "read_context"}) → 有 location → dialog: task("weather", {city: "北京通州"}) ``` --- ## 五、文件结构 ``` yunshu/ ├── main.go # CLI 入口 ├── types.go # 核心类型(AgentDef, ToolDef 等) ├── loader.go # .md 解析(Frontmatter + Body) ├── registry.go # Agent 注册中心(扫描 + 按 type 分类) ├── llm.go # LLM API 封装 ├── tool.go # 工具注册表 + ExecuteTool ├── runtime.go # RunAgent 主循环 │ ├── agents/ │ ├── dialog-agent.md # type: main — 主持者 │ ├── weather-sub.md # type: sub — 天气 │ ├── earthquake-sub.md # type: sub — 地震(预留) │ ├── memory-sub.md # type: sub — 记忆管理员 │ └── narrator-sub.md # type: sub — 汇报员(成熟期) │ ├── skills/ │ ├── msn-weather-api/SKILL.md │ └── geocoding/SKILL.md │ ├── docs/ │ ├── taolun.md │ ├── 会议室架构计划书.md │ ├── changelog.md │ ├── architecture.md │ └── AGENTS.md │ └── pkg/ ├── mdprint/ ├── style/ └── termui/ ``` ### 用户配置目录 ``` ~/.config/yunshu/ ├── config.yaml # LLM 配置 ├── session.json # 对话历史(仅 user ↔ dialog) ├── agents/ │ ├── dialog-agent.md # 用户可覆盖对话 Agent │ └── weather-sub.md # 用户可覆盖天气子 Agent ├── skills/ # 用户可扩展知识 ├── cache/ │ ├── weather.json │ ├── earthquake.json │ └── ... ├── data/ │ └── weather/ # 子 Agent 自己的数据目录 └── memory.db # 长期记忆数据库 ``` --- ## 六、调用流程示例 ``` 用户: "北京明天多少度?" HOST(runtime.go): 1. 加载 dialog-agent.md → system prompt 2. 读 session.json → 恢复上下文 3. 调 LLM(session + system + tools) 4. LLM 返回 tool_call: task("weather", {city: "北京", forecast_type: "tomorrow"}) task 工具: 1. 加载 weather-sub.md Frontmatter → cache.keys: ["city", "forecast_type"], ttl: 7200 2. 拼 key → "city=北京&forecast_type=tomorrow" → hash 3. 查 weather.json → MISS(首次查明天) 4. 调子 Agent LLM: system = weather-sub.md user = {args: {city: "北京", forecast_type: "tomorrow"}, cache_data: null} 5. 子 Agent: ├── geocode("北京") → (39.9, 116.4) ├── skill("msn-weather-api") → 接口参数 ├── http-get(URL) → JSON └── 返回: "北京明天 18-31°C,晴" ---CACHE--- {temp_lo: 18, temp_hi: 31, condition: "晴"} 6. task 提取 CACHE → 写 weather.json 7. 返回 "北京明天 18-31°C,晴" 给 dialog HOST(runtime.go): 1. tool 返回 → LLM 继续 2. LLM 生成最终回答: "北京明天 18到31度,大晴天,适合出去浪~" 3. dialog: task("memory", {action: "update_context", agent: "weather", city: "北京"}) 4. 追加 session.json 5. 输出给用户 ``` --- ## 七、实施阶段 ### 阶段一:基础架构(当前 → 1周) | 任务 | 说明 | |------|------| | 1.1 Frontmatter 扩展 | 解析 `type: main\|sub`、`cache` 字段 | | 1.2 Agent 注册中心 | `registry.go` 扫描 `agents/` 和 `~/.config/yunshu/agents/`,按 type 分类 | | 1.3 `task` 工具 | 实现子 Agent 加载、LLM 调用、缓存读写 | | 1.4 Cache 系统 | `cache/` 目录管理、JSON 文件读写、过期清理 | | 1.5 `memory.read/write` 工具 | 简单的 JSON 文件读写 | | 1.6 dialog-agent.md | 重写为主持者(极薄:人格 + 调度规则) | | 1.7 weather-sub.md | 从旧 weather-agent.md 改造 | ### 阶段二:记忆系统(阶段一完成后) | 任务 | 说明 | |------|------| | 2.1 memory-sub.md | 记忆管理员 Agent(从对话提取画像) | | 2.2 记忆数据库 | 结构化存储(画像、偏好、异常记录) | | 2.3 画像自动提取 | memory Agent 定期从对话中提取有用信息 | ### 阶段三:扩展(可选) | 任务 | 说明 | |------|------| | 3.1 earthquake-sub | 地震信息查询 | | 3.2 narrator-sub | 个性化回答生成 | | 3.3 更多数据源 | 台风、核电、火山... | --- ## 八、与 PicoClaw 的对比 | 维度 | PicoClaw | 云枢·会议室模式 | |------|----------|----------------| | 入口 | 单 Agent(用户直接对话) | 对话 Agent(唯一入口)+ 背后一堆子 Agent | | 上下文 | 所有轮次 + 系统 prompt 混在一起 | session 只存 user↔dialog,子 Agent 用完即毁 | | 知识 | 预置或长 prompt | skill 按需加载 | | 工具 | 所有工具混着用 | 按角色过滤,dialog 只有 task + memory | | 记忆 | 无 | 共享黑板,memory Agent 管写入 | | 扩展 | 改代码或改 prompt | 加一个 .md 文件 | | 失败隔离 | 坏 tool_call 可能污染全部 | 子 Agent 独立,坏就坏一个 | | 用户自定义 | 不可能 | 在 `~/.config/yunshu/agents/` 放 .md 即可 | --- ## 九、设计原则 1. **主持者保持极薄** — 只有人格 + 调度规则,不做领域知识 2. **子 Agent 不自知** — 不知道缓存存在、不管理自己的 session,只回答当前问题 3. **机械化的不做 LLM** — 缓存 key 拼装、文件读写都是 Go 代码,LLM 不参与 4. **数据隔离** — 子 Agent 的 cache 文件、data 目录互相独立 5. **记忆共享** — 黑板机制,所有 Agent 可读,仅 memory Agent 可写 6. **一个入口** — 用户永远只和 dialog-agent 对话,感受不到子 Agent 的存在