From e450edf865295a3079d4cd3e19395bfcf89bece6 Mon Sep 17 00:00:00 2001 From: root Date: Thu, 2 Jul 2026 12:18:46 +0800 Subject: [PATCH] docs: rewrite DESIGN.md and ARCHITECTURE.md matching current architecture - Plugin = container with embedded IO channel - OneBot QQ protocol support - Output channel capability validation - Atomic hot-reload (plgreload) - Three-layer memory (TF-IDF relevance pruning) - Remove all Docker/snapshot/multi-agent outdated content --- DESIGN.md | 365 +++++++++++++------------- docs/ARCHITECTURE.md | 603 ++++++++++++++----------------------------- 2 files changed, 370 insertions(+), 598 deletions(-) diff --git a/DESIGN.md b/DESIGN.md index 93e836a..ed4ee25 100644 --- a/DESIGN.md +++ b/DESIGN.md @@ -1,241 +1,188 @@ -# HomeAgent 架构设计 v2 +# HomeAgent 架构设计 v3 ## 一、核心理念 -24 小时陪伴用户、随时待命的智能管家。**单会话·单 Agent**(可分身/调用其他 Agent),身份不漂移。 +24 小时陪伴用户、随时待命的智能管家。**单会话·单 Agent**,身份不漂移。 ### 设计原则 -- 所有输入走 IO 抽象层(中断模式),不直调 agent 方法 -- DeepSeek v4 flash 为默认 LLM,thinking 模式关闭 -- 人格固定(personal.md),记忆分层管理防止性格突变 -- 知识独立于记忆,agent 主动学习 +- **所有输入走 IO 抽象层(中断模式)**,不直调 agent 方法 +- **所有 LLM 调用走 Provider 接口**,不直连 API +- **DeepSeek v4 flash** 为默认 LLM,thinking 模式关闭 +- **人格固定**(personal.md),记忆分层管理防止性格突变 +- **知识独立于记忆**,agent 主动学习 +- **插件 = 容器**,IO 通道是插件的内嵌组件 --- -## 二、人格内核(Personality Core) +## 二、核心抽象 + +### IO 抽象层(唯一输入路径) ``` -personal.md ──→ 固定注入 system prompt +外部设备 (Mic/Camera/OneBot/GPIO/HTTP) + │ + ▼ +IOManager + ├─ Device 接口(每个设备实现) + │ ├─ Name() / Type() / Description() + │ ├─ Tools() → 给 LLM 的 Function Calling 工具 + │ ├─ Execute() → 工具调用分发 + │ ├─ Start() / Stop() + │ └─ OutputCapabilities() → 输出能力声明 + ├─ InputEvent{Source, Type, Payload} → inputCh + ├─ OutputEvent{Target, Type, Payload} → outputCh + └─ 路由表: 输入源 → 默认输出通道 ``` -- 纯文本 Markdown 文件,定义 agent 的人格、行为准则 -- 加载一次永不改变(不随对话漂移) -- 放在 prompt 最前面,优先级最高 +**输出通道能力声明**(`OutputCapability` 位掩码): +| 能力 | 说明 | +|------|------| +| CapText | 文本输出 | +| CapFile | 文件传输 | +| CapImage | 图片输出 | +| CapAudio | 音频输出 | +| CapStructured | 结构化数据(JSON/卡片) | + +**Agent 可调用通道工具**: +- `output_list_channels` — 查看所有可用通道及其能力 +- `output_set_channel` — 切换当前回复的输出通道 +- `output_send` — 通过指定通道异步发送消息(校验能力) + +### API 抽象层(唯一输出路径) + +``` +Agent Core → Provider.Chat() → LLM API + │ + ┌───────┴───────┐ + ▼ ▼ + OpenAIProvider LuaAdapter + (DeepSeek API) (格式转换) +``` + +### 插件系统(OpenClaw 兼容) + +``` +Plugin(容器) + ├─ 元数据: name, version, author, description + ├─ IOConfig(可选): 声明 IO 端口 + ├─ Device(可选): 原生 Go IO 设备实现 + └─ Tools: 给 LLM 的工具定义 +``` + +插件来源: +- `plugins/` 目录热加载,agent 通过 `plgreload` 工具显式控制重载 +- 有原生工厂注册的(如 QQ/OneBot)→ 构造原生设备 +- 纯 SKILL.md → 用 PluginDevice 包装为 IO 设备 +- 原子化替换:新设备 Start → 原子换路由 → 旧设备 Stop --- -## 三、记忆体系(Memory System) - -三层分级架构,自顶向下逐渐持久化、抽象化: +## 三、记忆体系(三层) ``` - 用户输入 - │ - ▼ - ┌─────────────────────┐ - │ Layer 1: 上下 文 │ RelevanceContext - │ 基于相关性保留 │ 30 条活跃,TF-IDF 排序 - │ 最不相关的→文档记忆 │ - └────────┬────────────┘ - │ 相关性裁剪(每次响应后) +用户输入 → Context(内存, 30条, TF-IDF排序) + │ 每次响应后裁剪最不相关的 ▼ - ┌─────────────────────┐ - │ Layer 2: 文档记忆 │ document.Store - │ 全文 + TF-IDF 向量 │ JSON 持久化 - │ 冷文档→图数据库 │ 72h 未访问→Graph - └────────┬────────────┘ + Document(JSON + TF-IDF向量, 冷72h→图) │ 心跳蒸馏(30min) ▼ - ┌─────────────────────┐ - │ Layer 3: 图数据库 │ memory.GraphDB (SQLite) - │ 实体-关系三元组 │ 向量索引(实体名) - │ 定期重整+同义合并 │ bigram Jaccard - └─────────────────────┘ + Graph(SQLite三元组, 定期重整+同义合并) ``` -### Layer 1: 上下文(RelevanceContext) +| 层 | 存储 | 容量 | 裁剪策略 | +|---|---|---|---| +| Layer 1: 上下文 | `RelevanceContext`(内存环形缓冲) | 30 条 | TF-IDF 余弦相似度排序,低分→文档 | +| Layer 2: 文档 | `document.Store`(JSON 文件 + 向量索引) | 无上限 | 72h 未访问 + ≤2 次命中→图 | +| Layer 3: 图 | `memory.GraphDB`(SQLite 三元组) | 无上限 | 定期重整 + bigram Jaccard 同义合并 | -**不再使用固定条数裁剪。改为:** - -1. 每次用户输入后,计算**模型输出**与每条上下文的 TF-IDF 余弦相似度 -2. 按相关性从高到低排序,保留 topK(默认 30) -3. 最不相关的上下文 → 归档到文档记忆(Layer 2),保留全文+向量 -4. 活跃上下文中只保留最近且相关性高的内容 - -**相关文件:** `internal/agent/core/context.go` - -### Layer 2: 文档记忆(Document Store) - -**作用:** -- 存储被上下文裁剪下来的事件摘要、agent 主动提交的文档、图记忆同步的索引 -- 每个文档包含:摘要、全文、标签、实体、来源、访问计数、最后访问时间 -- TF-IDF 向量索引(字符 bigram),支持向量相似度搜索 - -**冷文档归化:** -- 心跳检测(每 30min):找出 72h 未访问且访问次数 ≤ 2 的文档 -- 转为图数据库三元组(文档→包含内容、提及实体、标签、来源) -- 清理已归化的冷文档 - -**相关文件:** `internal/memory/document/document.go` - -### Layer 3: 图数据库(Graph Memory) - -**存储:** SQLite 三元组(实体-关系-实体),每个关系带置信度、会话 ID、日期桶 - -**注入方式(区分于文档注入):** -- 用户消息到达时,先对实体名做**向量相似度搜索**(TF-IDF) -- 找到相关实体名 → 查询图数据库 -- 只注入**节点索引**(实体名+类型+提及次数+关系类型)到 prompt,不注入全文 -- 需要更多细节时,agent 调用 `memory_recall` 工具查询 - -**定期重整(心跳触发,每 30min):** -1. 同步实体名到向量索引(`Indexer.Sync()`) -2. 文档记忆向量索引重建 -3. 冷文档→图归化 -4. 实体同义合并(bigram Jaccard > 0.5) - -**相关文件:** `internal/memory/graph.go`, `internal/memory/indexer.go` - -### Agent 可用记忆工具 - -| 工具 | 作用 | 操作对象 | -|------|------|----------| -| memory_recall | 检索图记忆 | GraphDB | -| memory_commit | 写入三元组 | GraphDB | -| memory_introspect | 查看记忆统计 | GraphDB | -| doc_query | 向量查询文档记忆 | Document Store | -| doc_commit | 提交文档 | Document Store | +**注入策略**: +- 只注入**图索引**(实体名+类型+提及数)到 prompt,不注入全文 +- agent 通过 `memory_recall` 主动查询详情 +- 文档摘要按相关性注入前 3 条 --- -## 四、知识体系(Knowledge System) +## 四、知识体系 -独立于记忆系统,用于 agent 学习知识: +独立于记忆,agent 主动学习。 ``` knowledge/ - smart_home/ - content.md ← 原始知识文件 - cooking/ - content.md - ... + smart_home/content.md + cooking/content.md │ ▼ - TF-IDF 向量索引 ← 知识目录扫描时自动构建 + TF-IDF 向量索引(字符 bigram) │ ▼ - knowledge_search(query) → 返回相关内容 + knowledge_search / knowledge_create / knowledge_list ``` -**知识来源:** -1. **agent 主动学习**:调用 `knowledge_create` 工具,生成知识→写入目录+向量化 -2. **用户上传**:HTTP 文件上传端点 → 写入目录+向量化 -3. **预置知识**:`knowledge/` 目录下的 content.md - -**相关文件:** `internal/knowledge/knowledge.go` - -### Agent 可用知识工具 - -| 工具 | 作用 | -|------|------| -| knowledge_search | 向量搜索知识库 | -| knowledge_list | 列出知识分类 | -| knowledge_create | agent 主动创建知识 | - --- -## 五、数据流总览 +## 五、人格内核 + +```personal.md``` → 加载一次 → 固定在 system prompt 最前 → 永不漂移。 + +--- + +## 六、OneBot QQ 通道 ``` -用户消息 - │ - ▼ -IO 输入中断 (channel.go) - │ - ▼ -eventLoop → processTextInput - │ - ├─ 1. 追加上下文 (RelevanceContext.Append) - │ └─ 计算向量,缓存 - │ - ├─ 2. 构建 prompt: - │ ├─ 人格设定 (personal.md) - │ ├─ 图记忆索引 (Indexer.BuildContext → 向量搜索实体名 → Recall → 摘要注入) - │ ├─ 文档记忆摘要 (DocStore.Query → 注入前3条摘要) - │ ├─ 工作记忆上下文 (RelevanceContext.Format) - │ ├─ 技能注入 (skills) - │ └─ 工具说明 (indexer + doc + knowledge tools) - │ - ├─ 3. 工具循环 (process) - │ ├─ 调用 LLM (DeepSeek v4 flash) - │ ├─ 解析 tool_calls - │ ├─ 执行工具 (memory_*/knowledge_*/doc_*/设备工具) - │ └─ 返回结果,循环直到无 tool_calls +go-cqhttp / Lagrange(OneBot 前端) + │ Reverse WebSocket + ▼ +OneBot Client(internal/onebot/) + ├─ 事件循环 → Event → IO InputEvent + ├─ Action 调用 → send_private_msg / send_group_msg / ... + └─ 自动重连 + 心跳检测 + │ + ▼ +Device 注册 → IOManager → Agent +``` + +--- + +## 七、数据流 + +``` +用户消息 → IO InputEvent → eventLoop │ + ├─ 1. 追加到 RelevanceContext + ├─ 2. 构建 prompt: + │ personal.md + 图索引 + 文档摘要 + 上下文 + 工具 + ├─ 3. 工具循环(最多 10 轮) + │ LLM → tool_calls → Execute → 结果 → LLM → ... ├─ 4. 追加响应到上下文 - │ - ├─ 5. 相关性裁剪 (RelevanceContext.Prune) - │ └─ 最不相关的 → 文档记忆归档 - │ - ├─ 6. IO 输出响应 - │ - └─ 7. 记忆候选事件 - └─ → TextMemory (JSONL 持久化) - └─ → Distiller → GraphMemory (三元组萃取) + ├─ 5. 相关性裁剪(Prune → 不相关的归档到文档) + ├─ 6. OutputEvent → 输出通道 + └─ 7. 记忆候选 → TextMemory(JSONL) + Distiller → GraphDB -心跳线程 (每 30min): - ├─ distillContext: 安全裁剪兜底 - ├─ syncGraphToDocs: 图→文档索引同步 - ├─ reorgGraph: - │ ├─ Indexer.Sync(): 实体名→向量索引 - │ ├─ DocStore.Reindex(): 文档向量重建 - │ ├─ 冷文档→图归化 - │ └─ 同义实体合并 - └─ (后续) GraphDB 向量索引生成/重整 +心跳(30min): + ├─ Indexer.Sync() — 图→向量 + ├─ DocStore.Reindex() — 文档向量重建 + ├─ 冷文档→图归化 + └─ 图同义合并 + +插件重载(plgreload): + ├─ 扫描 plugins/ 目录 + ├─ 加载新插件,Start 新设备 + ├─ 原子替换 IOManager 设备表 + 路由表 + └─ Stop 旧设备 ``` --- -## 六、关键文件 - -``` -cmd/homed/main.go — 入口:组装所有子系统 -internal/agent/core/agent.go — Agent 核心:事件循环、工具循环、心跳 -internal/agent/core/context.go — RelevanceContext:基于 TF-IDF 的上下文管理 -internal/agent/personal.go — Personality:personal.md 加载 -internal/agent/api/provider.go — LLM Provider:DeepSeek API 封装 -internal/agent/io/channel.go — IO 抽象层:中断输入、设备注册 -internal/api/handler.go — HTTP API:REST + OpenAI 兼容端点 -internal/knowledge/knowledge.go — 知识系统:目录扫描、向量索引、搜索 -internal/memory/graph.go — 图数据库:SQLite 三元组 CRUD -internal/memory/indexer.go — 图索引器:向量搜索实体名、摘要注入 -internal/memory/vector/store.go — 向量存储:TF-IDF + 倒排索引 + 余弦相似度 -internal/memory/document/doc.go — 文档记忆:存储、查询、冷文档检测 -internal/memory/text/text.go — 文本记忆:JSONL 原始日志持久化 -internal/memory/pipeline/ — 蒸馏器:原始日志→图记忆 -internal/tracker/tracker.go — Change Tracker:overlayfs 文件变更追踪 -internal/plugin/plugin.go — 插件平台:SKILL.md 加载 -internal/supervisor/daemon.go — 守护进程:健康检查、自动 rollback -internal/lua/vm.go — Lua 适配器 VM -config/config.go — 配置加载 -pkg/types/ — 类型定义 -``` - ---- - -## 七、配置示例 +## 八、配置 ```yaml daemon: listen_addr: ":8080" data_dir: "/var/lib/homeagent" heartbeat_interval: 15s - check_interval: 30s - llm: - provider: "openai" model: "deepseek-v4-flash" - base_url: "https://api.deepseek.com" + base_url: "https://api.deepseek.com/v1" api_key: "${DEEPSEEK_API_KEY}" temperature: 0.7 max_tokens: 4096 @@ -243,15 +190,51 @@ llm: --- -## 八、对比原设计 +## 九、关键文件 -| 维度 | 旧设计 | 新设计 | -|------|--------|--------| -| 上下文裁剪 | 固定 20 条 FIFO | TF-IDF 相关性排序,保留最相关 | -| 上下文→文档 | 蒸馏器每周期 flush | 每次响应后按相关性裁剪归档 | +``` +cmd/homed/main.go — 入口:组装所有子系统 +internal/agent/core/agent.go — Agent 核心:事件循环、工具循环、心跳 +internal/agent/core/context.go — RelevanceContext:TF-IDF 上下文管理 +internal/agent/personal.go — 人格加载 +internal/agent/api/provider.go — Provider 接口 + DeepSeek 实现 +internal/agent/io/channel.go — IO 抽象层:Device/InputEvent/OutputEvent/路由 +internal/api/handler.go — HTTP API 端点 +internal/knowledge/knowledge.go — 知识系统 +internal/memory/graph.go — SQLite 图数据库 +internal/memory/indexer.go — 图索引器 +internal/memory/vector/store.go — TF-IDF 向量存储 +internal/memory/document/doc.go — 文档记忆 +internal/memory/text/text.go — 文本记忆(JSONL) +internal/memory/pipeline/ — 蒸馏器 +internal/onebot/ — OneBot V11 协议实现 +internal/plugin/plugin.go — 插件系统 +internal/tracker/tracker.go — 变更追踪 +internal/supervisor/daemon.go — 守护进程 +internal/lua/vm.go — Lua 适配器 VM +plugins/ — 插件目录 + qq/SKILL.md — QQ 插件 SKILL.md + qq/skill.json — QQ 插件 JSON 元数据 +config/config.go — 配置加载 +pkg/types/ — 类型定义 +DESIGN.md — 本架构文档 +``` + +--- + +## 十、与旧设计的核心区别 + +| 维度 | 旧设计 (v1) | 当前设计 (v3) | +|------|-------------|---------------| +| 上下文裁剪 | 固定 FIFO 20 条 | TF-IDF 相关性排序 top-K | | 图记忆注入 | 关键词 LIKE 查询 | 向量搜索实体名,只注索引 | | 文档→图 | 无 | 72h 冷文档自动归化 | -| 图重整 | 无 | 心跳:向量同步+同义合并 | -| 知识系统 | 无 | `knowledge/` 目录+向量索引+工具 | +| 图重整 | 无 | 向量同步 + bigram Jaccard 同义合并 | +| 知识系统 | 无 | `knowledge/` 目录 + TF-IDF 向量 | | 人格 | 无 | `personal.md` 固定注入 | -| 向量引擎 | 无 | 自研 TF-IDF + 倒排索引 | +| 向量引擎 | 无 | 自研 TF-IDF + 倒排索引(字符 bigram) | +| 部署 | Docker 容器 + 快照 | 单二进制 + overlayfs 追踪 | +| Agent 模型 | 多 Agent 编排 | 单 Agent + 工具循环 | +| 输出通道 | 无 | 能力声明 + 路由 + 校验 | +| 插件系统 | 无 | OpenClaw SKILL.md + 原生工厂 | +| QQ 通道 | 无 | OneBot V11 Reverse WS | diff --git a/docs/ARCHITECTURE.md b/docs/ARCHITECTURE.md index feb5710..ac0dc05 100644 --- a/docs/ARCHITECTURE.md +++ b/docs/ARCHITECTURE.md @@ -1,79 +1,50 @@ -# HomeAgent 架构设计文档 +# HomeAgent 架构参考 -> 基于 NextAgent 认知解耦架构,结合图记忆与工具调用系统的单二进制 AI 家庭助手。 -> 参考设计:NextAgent — 严格的边界划分 + 工具调用;TrulyMEM — 自主图记忆系统 +> 基于 NextAgent 认知解耦架构 + TrulyMEM 自主图记忆 + OneBot 协议。 ---- - -## 一、核心设计原则 - -### 1. 认知解耦架构(源自 NextAgent) - -系统分为三个严格边界层: +## 一、分层架构 ``` -┌──────────────────────────────────────────────────────────────────┐ -│ 外层:IO 抽象层(唯一输入路径) │ -│ IOManager ── Microphone / Camera / GPIO / HTTP / Sensors │ -│ 所有外部输入 → InputEvent → inputCh │ -└──────────────────────────┬───────────────────────────────────────┘ +┌──────────────────────────────────────────────────────────┐ +│ IO 抽象层(唯一输入路径) │ +│ Device(Mic/Speaker/Camera/GPIO/OneBot-QQ/PluginDevice) │ +│ 所有外部输入 → InputEvent → inputCh │ +│ 输出通道: 能力声明(text/file/image/audio/structured) │ +│ 路由表: 输入源 → 默认输出通道 │ +└──────────────────────────┬───────────────────────────────┘ │ -┌──────────────────────────▼───────────────────────────────────────┐ -│ 中层:Agent 操作层(核心编排器) │ -│ Agent Core ── 事件循环 consume inputCh │ -│ ├─ 构建上下文(记忆索引 + 技能注入 + ToolDef) │ -│ ├─ Provider.Chat() → CompletionResponse │ -│ └─ 通过 IO 层输出 text + memory_candidate 事件 │ -└──────────────────────────┬───────────────────────────────────────┘ +┌──────────────────────────▼───────────────────────────────┐ +│ Agent 操作层(核心编排器) │ +│ eventLoop() consume inputCh │ +│ ├─ RelevanceContext(TF-IDF 相关性管理) │ +│ ├─ 工具循环(Provider.Chat → tool_calls → Execute → ...) │ +│ ├─ 记忆索引注入(图索引 + 文档摘要) │ +│ └─ 心跳蒸馏(30min:向量同步 + 冷归档 + 同义合并) │ +└──────────────────────────┬───────────────────────────────┘ │ -┌──────────────────────────▼───────────────────────────────────────┐ -│ 内层:API 抽象层(唯一输出路径) │ -│ Provider ── OpenAI / Ollama / LuaAdaptedProvider │ -│ 所有 LLM 调用通过 Provider.Chat() / ChatStream() │ -└──────────────────────────────────────────────────────────────────┘ +┌──────────────────────────▼───────────────────────────────┐ +│ API 抽象层(唯一输出路径) │ +│ Provider.Chat() → DeepSeek API / OpenAI / Ollama │ +│ LuaAdapter 做请求/响应格式转换 │ +└──────────────────────────────────────────────────────────┘ ``` **三条核心规则:** -1. 所有外部输入 → 必须通过 `IOManager.InjectInput()` / `InjectText()` 注入 -2. 所有 LLM 调用 → 必须通过 `Provider.Chat()` / `ChatStream()` 发出 -3. Agent Core 不直接操作记忆系统,只发射 `memory_candidate` 事件,由 Memory Pipeline 异步消费 +1. **所有外部输入** → 必须通过 `IOManager.InjectInput()` / `InjectText()` 注入 +2. **所有 LLM 调用** → 必须通过 `Provider.Chat()` 发出 +3. **Agent 不直接操作记忆系统**,只发射 `memory_candidate` 事件,由 Memory Pipeline 异步消费 -### 2. 自主记忆系统(源自 TrulyMEM) +## 二、子系统详解 -``` -User Input ──→ Agent Core ──→ Provider ──→ LLM Response - │ - ▼ - IO 层发射 memory_candidate 事件 - │ - ▼ - Memory Pipeline Distiller 消费 - │ - ▼ - 周期蒸馏 → Graph Memory (SQLite) - │ - ▼ - 删除原始会话文件 -``` +### 2.1 IO 抽象层(唯一输入路径) -**关键约束:** -- Agent 上下文中只注入**记忆索引 + 摘要**,**永远不**注入原始文本 -- Agent 必须通过 `memory_recall` tool call **主动查询** 获取完整记忆细节 -- 记忆蒸馏完全异步、自主运行,不阻塞主流程 - ---- - -## 二、系统层次详解 - -### 2.1 IO 抽象层(`internal/agent/io/channel.go`) - -**唯一输入路径。** 所有外部输入必须通过此层进入系统。 +所有外部输入必须通过此层进入系统。 ``` Device(Microphone) ─┐ -Device(Camera) ─┤ -Device(GPIO) ─┤──→ IOManager.InjectInput() → InputEvent → inputCh → Agent Core -Device(RobotArm) ─┤ +Device(OneBot-QQ) ─┤ +Device(Plugin) ─┤──→ IOManager → InputEvent → inputCh → Agent +Device(GPIO) ─┤ HTTP API ─┘ ``` @@ -82,297 +53,175 @@ HTTP API ─┘ | 类型 | 说明 | |------|------| | `InputEvent` | Source + Type + Payload — 所有外部输入的标准化格式 | -| `OutputEvent` | Target + Type + Payload — 所有输出的标准化格式 | -| `Device` | 接口:Name() / Type() / Tools() / Execute() | +| `OutputEvent` | Target + Type + Payload + OutputChannel — 输出路由 | +| `Device` | 接口:Name/Type/Description/Tools/Execute/Start/Stop/OutputCapabilities | | `DeviceType` | Input / Output / IO | -| `ToolDef` | Name + Description + Parameters — 与 LLM Function Calling 同构 | +| `ToolDef` | Name + Description + Parameters + Handler — 与 LLM 函数调用同构 | +| `OutputCapability` | 位掩码:text, file, image, audio, structured | -**内置设备(目前为桩实现,待真正硬件接入):** +**内置设备:** -| 设备 | 方向 | ToolDef 暴露 | -|------|------|-------------| -| Microphone | Input | `{name}_capture` — 录音 | -| Speaker | Output | `{name}_speak` — 语音播放 | -| Camera | Input | `{name}_capture` 拍照 + `{name}_stream` 视频流 | -| RobotArm | IO | `{name}_move` 移动 + `{name}_grip` 夹爪 | -| GPIO | IO | `{name}_gpio_write` + `{name}_gpio_read` | +| 设备 | 方向 | 工具 | +|------|------|------| +| Microphone | Input | capture — 录音 | +| Speaker | Output | speak — 语音播放 | +| Camera | Input | capture 拍照 | +| OneBot QQ | IO | send_private/send_group/get_group_member_info/get_group_list | +| PluginDevice | IO | 插件声明工具 | +| GPIO | IO | gpio_write/gpio_read | -**Device 与 Tool 同构原则:** -- 所有 Device 的 `Tools()` 返回 `[]ToolDef`,格式与 LLM Function Calling 完全一致 -- Agent Core 自动收集所有 Device 的 ToolDef 合并到请求的 `tools` 字段 -- Agent 通过 Function Calling 调用设备 capability +**输出通道能力校验:** +- 每个 Device 声明 `OutputCapabilities()` → 位掩码 +- `output_send` 工具发送前校验通道是否支持文本 +- `output_list_channels` 只列出有输出能力的通道 -### 2.2 API 抽象层(`internal/agent/api/provider.go`) - -**唯一输出路径。** 所有 LLM 请求通过此层发出。 +### 2.2 API 抽象层(唯一输出路径) ``` -Agent Core ──→ ProviderManager ──→ Provider.Chat() - │ - ┌─────────┼─────────┐ - ▼ ▼ ▼ - OpenAI Ollama LuaAdaptedProvider - │ - ┌───────┴───────┐ - ▼ ▼ - Lua Adapter Base Provider - (transform) (OpenAI/Ollama) -``` - -**Provider 接口:** - -```go -type Provider interface { - Name() string - Chat(ctx, req) → (*CompletionResponse, error) - ChatStream(ctx, req) → (<-chan StreamChunk, error) -} +Agent Core → Provider.Chat() + │ + ┌───────┴───────┐ + ▼ ▼ + OpenAIProvider LuaAdapter + (DeepSeek API) (格式转换) ``` | 实现 | 说明 | |------|------| -| `OpenAIProvider` | 标准 OpenAI API 格式,支持 /chat/completions | -| `OllamaProvider` | Ollama /api/chat 格式,本地部署 | +| `OpenAIProvider` | 标准 OpenAI API 格式,DeepSeek v4 flash 默认 | | `LuaAdaptedProvider` | 通过 Lua 脚本转换请求/响应的适配 wrapper | -**Lua 适配器机制:** -- 适配器文件位于 `{dataDir}/adapters/*.lua` -- 每个适配器返回 Lua table 包含 `name` + `transform_request` + `transform_response` -- 首次运行时自动从 embed.FS 复制捆绑适配器(openai / deepseek / ollama / custom) -- 支持热重载(`POST /api/v1/adapters`) -- 用于兼容不同 API 供应商的请求/响应格式差异 +Lua 适配器位于 `{dataDir}/adapters/*.lua`,每个适配器返回 `name` + `transform_request` + `transform_response`。 -### 2.3 Agent 操作层(`internal/agent/core/agent.go`) - -**纯编排器,不涉及张量运算。** +### 2.3 Agent 操作层(核心编排器) ``` -eventLoop() - │ - ▼ select on inputCh -handleInput(evt) +eventLoop() → select on inputCh │ ▼ -process(input) - ├─ indexer.BuildContext(input) → 仅摘要+索引 - ├─ buildSystemPrompt() → 拼接 system prompt - ├─ buildToolDefs() → 收集 IO 工具 + 记忆工具 - ├─ provider.Chat(req) → LLM 调用 - ├─ 记忆候选事件 → IO 层 EmitOutput("memory", "memory_candidate", ...) - └─ 输出 → IO 层 EmitOutput(source, "text", ...) +handleInput(evt) → processTextInput(input) + │ + ├─ 1. RelevanceContext.Append(input) + ├─ 2. 构建 prompt: personal.md + 图索引 + 文档摘要 + 上下文 + 工具 + ├─ 3. 工具循环(最多 10 轮) + │ LLM → tool_calls → Execute → 结果注入 → 下一轮 + ├─ 4. 追加响应到上下文 + ├─ 5. RelevanceContext.Prune() → 低分事件→文档记忆归档 + ├─ 6. OutputEvent → 输出通道 + └─ 7. memory_candidate → TextMemory + Distiller → GraphDB ``` -**关键设计决策:** -- Agent 不直接持有 `memory.GraphDB` 引用 — 只通过 `Indexer` 构建上下文 -- Agent 不直接调用 `memory.Commit()` — 只发射事件让 Pipeline 异步处理 -- `Indexer.BuildContext()` 只返回内存索引摘要,不返回原始数据 -- `buildSystemPrompt()` 中注入 `memory_recall` / `memory_commit` / `memory_introspect` 工具说明 -- **所有输出走 IO 层** — 文本输出和记忆事件都通过 EmitOutput +**人格注入:** personal.md 加载一次,固定在 system prompt 最前,永不漂移。 -### 2.4 图记忆系统(`internal/memory/graph.go`) - -SQLite 三元组存储,支持实体-关系-实体的图遍历。 - -**数据库 Schema:** - -```sql -entities(id PK, name UNIQUE, type, mention_count, created_at, updated_at) -relations(id PK, source_id FK→entities, target_id FK→entities, - relation_type, confidence, status, session_id, turn_id, - created_at, updated_at, date_bucket) +**工具分发:** +``` +executeToolCall(tc) + ├─ memory_* → executeMemoryTool + ├─ knowledge_* → executeKnowledgeTool + ├─ doc_* → executeDocTool + ├─ output_* → executeOutputChannel/Send/ListChannels + └─ 其他 → io.ExecuteTool → Device.Execute ``` -**核心操作:** +### 2.4 记忆系统 -| 操作 | 说明 | -|------|------| -| `Commit(triples, sessionID, turnID)` | 写入三元组 → 自动 upsert 实体 + 插入关系 | -| `Recall(keywords, seedEntities, depth, session)` | 关键词搜索 → 图遍历 → 返回实体+关系 | -| `Purge(criteria, mode)` | 软/硬删除匹配的关系 | -| `Introspect()` | 统计信息:实体数、关系数、热点实体 | -| `Archive(days)` | 归档超过指定天数的关系 | - -**Context Injection 机制(`internal/memory/indexer.go`):** -- `BuildContext(userInput)` → 关键词提取 → `GraphDB.Recall()` → 构建摘要 -- `FormatContext(context)` → 输出格式如: - `【记忆索引】关联 N 个记忆实体,高频:A、B、C 索引: A, B, C | 需更多细节请用 memory_recall 查询` -- `BuildToolPrompt()` → 生成 `memory_recall/commit/introspect/purge` 工具的 prompt 说明 -- `GetToolDefinitions()` → 返回 LLM Function Calling 格式的工具定义 - -### 2.5 记忆管道(`internal/memory/pipeline/pipeline.go`) - -自主异步蒸馏管线。 +三层分级,自顶向下逐渐持久化、抽象化: ``` -Agent Core → EmitOutput("memory", "memory_candidate", {input, response}) +Layer 1: 上下文(RelevanceContext) + 内存环形缓冲,TF-IDF 余弦相似度排序 + 每次响应后保留 top 30,低分→文档记忆 + +Layer 2: 文档记忆(document.Store) + JSON 文件 + TF-IDF 向量索引(字符 bigram) + 冷文档(72h 未访问 + ≤2 次)→ 图数据库 + +Layer 3: 图数据库(memory.GraphDB) + SQLite 三元组(实体-关系-实体) + 只注入索引(实体名+类型+提及次数)到 prompt + 定期重整:向量同步 + bigram Jaccard 同义合并 +``` + +### 2.5 知识系统 + +独立于记忆,agent 主动学习。 + +``` +knowledge/{category}/content.md │ ▼ -onMemory(input, response) 回调 +TF-IDF 向量索引(字符 bigram) │ ▼ -Append() → records[] 内存缓冲区 - │ - ▼ 每 10 分钟触发 -distillLoop() +工具: knowledge_search / knowledge_create / knowledge_list +``` + +### 2.6 插件系统 + +OpenClaw SKILL.md 兼容。 + +``` +Plugin(容器) + ├─ 元数据: name, version, author + ├─ IOConfig(可选): 声明 IO 端口 + ├─ Device(可选): 原生 Go 设备 + └─ Tools: LLM 工具定义 + +Registry: + ├─ NativeFactory: "qq" → onebot.NewDevice + ├─ SetIOManager: 绑定 IO 管理器 + └─ Reload(): 原子化重载 +``` + +**热插拔流程:** +1. 扫描 `plugins/` 目录 +2. 原生工厂优先,无工厂则 LoadSKILL.md +3. 新设备 Start(预先启动) +4. `IOManager.AtomicSwapDevices()` 原子替换设备表 + 路由表 +5. 旧设备 Stop(后台 goroutine) + +### 2.7 OneBot QQ 通道 + +``` +OneBot 前端(go-cqhttp/Lagrange) + │ Reverse WebSocket + ▼ +OneBot Client(internal/onebot/) + ├─ 事件: message/notice/request → IO InputEvent + ├─ 动作: send_private_msg / send_group_msg / get_group_info / ... + ├─ 自动重连(指数退避 1s→30s) + └─ 事件 handler 注入 IO 层 │ ▼ -extractKeyTriples() → GraphDB.Commit() - │ - ▼ -cleanupRawFiles() 删除超期原始文件 +Device(internal/onebot/device.go) + ├─ Tools: qq_send_private_msg, qq_send_group_msg, etc. + ├─ Execute → Client.SendAction + └─ Start → Connect + 注册事件 handler ``` -**配置:** -- `Interval: 10m` — 每 10 分钟蒸馏一次 -- `RetentionDays: 7` — 原始记录保留 7 天 -- `BatchSize: 50` — 每批处理 50 条 +### 2.8 变更追踪器 -### 2.6 技能系统(`internal/skill/manager.go`) - -兼容 OpenClaw 格式的技能管理。 - -**技能格式:** -- `{skillsDir}/{name}/SKILL.md` — Markdown 描述文件 -- `{skillsDir}/{name}/skill.json` — 可选的元数据文件 - -**注入机制:** -- `GetInjectedPrompt()` → 收集所有已启用的技能内容注入到 system prompt -- 支持安装/卸载/启用/禁用 - -### 2.7 Supervisor 守护进程(`internal/supervisor/daemon.go`) - -```go -type Daemon struct { - cfg *types.Config - cm *container.Manager // Docker 容器管理 - nm *network.Monitor // 网络监控 - sm *snapshot.Manager // 快照管理 - agents map[AgentID]*agentInstance -} -``` - -**职责:** -- Agent 生命周期管理(launch / restart / shutdown) -- 健康检查循环(心跳间隔 15s) -- 自动快照循环(快照间隔 10m) -- 故障恢复:失败 MaxRetries(3) 次后自动回滚到最近快照 -- 网络监控:检查 LLM API 可达性,影响 Agent 健康状态 - -### 2.8 快照与回滚(`internal/snapshot/manager.go`) - -基于 Docker commit/save/load 的版本管理。 - -**快照流程:** -`Docker Commit(container → image) → SaveImage(image → .tar) → 记录快照元数据` - -**回滚流程:** -`Stop(container) → Remove(container) → LoadImage(.tar) → 创建新容器 → Start` - -**策略:** -- 定时快照(每 10m) -- 操作前快照(PreAction — 可选) -- 限制最大保留(默认 20 个) -- 溢出时自动删除最旧的 - -### 2.9 网络监控(`internal/network/monitor.go`) - -异步定时检查 LLM API 端点可达性。 - -**监控方式:** -- HTTP HEAD 请求到配置的 endpoints -- 并发检查(goroutine per endpoint) -- DNS 解析检查(fallback: google.com → baidu.com) -- 结果聚合:`LLMAPIReachable` + `DNSResolving` + 平均延迟 - -**影响:** -- 网络不可达 → Agent 状态变为 `HealthDegraded` -- 持续不可达 → 触发回滚策略 - -### 2.10 Lua 虚拟机(`internal/lua/vm.go`) - -纯 Go 的 gopher-lua 5.1 VM,用于 API 格式适配器。 - -**功能:** -- 加载 `{adapterDir}/*.lua` 适配器脚本 -- `CallTransform(name, input)` — 调用 adapter 的 transform_request -- `CallResponseTransform(name, raw)` — 调用 adapter 的 transform_response -- `ReloadAll()` — 热重载所有适配器 -- 内置 mock 函数:`log()`, `json_encode()`, `http_get()`, `http_post()` - -### 2.11 Embedder(`internal/embed/embedder.go`) - -向量嵌入接口,支持文本相似度计算。 - -| 实现 | 说明 | -|------|------| -| `OllamaEmbedder` | 通过 Ollama API 获取嵌入向量(默认: nomic-embed-text, 768d) | -| `HashEmbedder` | 基于字符哈希的本地嵌入(无需外部依赖),用于备选方案 | - -**可用性:** Embedder 已定义但尚未集成到记忆系统中。 - -### 2.12 Tokenizer(`internal/tokenizer/jieba.go`) - -中文分词工具,基于 gojieba。全局单例,线程安全。 - -**功能:** -- `ExtractKeywords(text, topK)` — 提取关键词(TF-IDF 加权) -- `Cut(text)` — 分词 -- `Tag(text)` — 词性标注 - ---- - -## 三、数据流全景 - -### 3.1 正常交互流程 +Overlayfs 文件变更追踪: ``` -外部输入(HTTP POST / voice / GPIO 事件) - │ - ▼ -IOManager.InjectInput() - → InputEvent{Source, Type, Payload} - → 推入 inputCh - │ - ▼ -Agent Core eventLoop() - 1. consume InputEvent - 2. Indexer.BuildContext(input) → 记忆摘要(仅索引+摘要) - 3. buildSystemPrompt() → 拼接 system + 记忆 + 技能 + 工具 - 4. buildToolDefs() → IO 工具 + 记忆工具 - 5. Provider.Chat(req) → LLM 响应 - 6. EmitOutput(target, "text", response) - 7. EmitOutput("memory", "memory_candidate", {input, response}) - │ - ┌─────┴─────┐ - ▼ ▼ -IO 输出 Memory Pipeline(异步) - │ │ - ▼ ▼ -HTTP Append() → 周期蒸馏 -Response → GraphDB.Commit() -Speaker → 清理原始文件 +PreAction(tool) → 记录文件 hash +PostAction(tool) → diff → ChangeSet{ID, Tool, Files[]SHA256} +Rollback() → 用 overlayfs 下层恢复 ``` -### 3.2 记忆查询流程 +健康检查失败 → `tracker.Rollback()`。 + +### 2.9 Supervisor 守护进程 ``` -Agent 推理中决定调用 memory_recall - │ - ▼ -LLM 返回 tool_call: {name: "memory_recall", args: {query_intent: "..."}} - │ - ▼ -Agent Core 解析 tool_call → 调用 GraphDB.Recall(keywords) - │ - ▼ -返回实体+关系数据 → 注入后续 LLM 请求上下文 +Daemon: + ├─ SetTracker() → 绑定变更追踪器 + ├─ RegisterAgent("main") → 注册主 agent + └─ 健康检查周期 → LLM API 可达性 + └─ 连续失败 → tracker.Rollback() ``` ---- - -## 四、配置系统 - -配置文件: `/etc/homeagent/config.yaml`(YAML)。若文件不存在则使用默认配置。 +## 三、配置 ```yaml daemon: @@ -380,116 +229,56 @@ daemon: data_dir: "/var/lib/homeagent" heartbeat_interval: 15s check_interval: 30s - log_level: "info" - -defaults: - image: "homeagent/agent-base:latest" - llm_endpoints: - - "https://api.openai.com/v1" - snapshot_policy: - interval: 10m - max_snapshots: 20 - pre_action: true - post_action: false - rollback_policy: - max_retries: 3 - health_threshold: 3 - cooldown_period: 30s - auto_rollback: true - openclaw_enabled: true - -agents: [] +llm: + provider: "openai" + model: "deepseek-v4-flash" + base_url: "https://api.deepseek.com/v1" + api_key: "${DEEPSEEK_API_KEY}" + temperature: 0.7 + max_tokens: 4096 ``` ---- +## 四、数据目录 + +``` +{dataDir}/ +├── memory/ +│ ├── graph.db # SQLite 图数据库 +│ ├── text/ # JSONL 文本记忆 +│ ├── documents/ # JSON 文档记忆 +│ └── raw/ # 原始记录(蒸馏后删除) +├── knowledge/ # 知识库 +│ └── {name}/content.md +├── plugins/ # 插件 +│ └── {name}/ +│ ├── SKILL.md +│ └── skill.json +├── skills/ # 技能 +├── adapters/ # Lua 适配器 +├── personal/ # 人格 +│ └── personal.md +├── changesets/ # 变更追踪记录 +└── snapshots/ # 快照 +``` ## 五、HTTP API | 方法 | 路径 | 说明 | |------|------|------| +| POST | `/v1/chat/completions` | OpenAI 兼容对话 | +| GET | `/api/v1/knowledge` | 知识查询/列表 | +| POST | `/api/v1/knowledge` | 创建知识 | +| DELETE | `/api/v1/knowledge?name=` | 删除知识 | | GET | `/api/v1/status` | 系统状态 | -| GET | `/api/v1/agents` | Agent 列表 | -| POST | `/api/v1/agents` | 创建 Agent | -| GET | `/api/v1/agents/{id}` | Agent 详情 | -| POST | `/api/v1/agents/{id}/start/stop/restart` | 操作 | -| GET | `/api/v1/agents/{id}/snapshots` | 快照列表 | -| POST | `/api/v1/agents/{id}/rollback/{snap}` | 回滚 | -| GET | `/api/v1/memory?q=关键词` | 记忆检索 | -| POST | `/api/v1/memory` | 写入三元组 | -| DELETE | `/api/v1/memory` | 删除记忆 | -| GET | `/api/v1/memory/context?q=...` | 获取上下文注入 | -| GET | `/api/v1/memory/tools` | 记忆工具定义 | -| GET | `/api/v1/skills` | 技能列表 | -| POST | `/api/v1/skills` | 安装技能 | -| DELETE | `/api/v1/skills?name=...` | 卸载技能 | -| GET | `/api/v1/adapters` | 适配器列表 | -| POST | `/api/v1/adapters` | 安装适配器 | -| DELETE | `/api/v1/adapters/{name}` | 删除适配器 | -| GET | `/api/v1/network` | 网络状态 | | GET | `/api/v1/config` | 配置查看 | -| PUT | `/api/v1/config` | 配置更新 | -| GET | `/` | WebUI 仪表盘 | ---- - -## 六、数据目录结构 - -``` -{dataDir}/ -├── config.yaml # 系统配置 -├── memory/ -│ ├── graph.db # SQLite 图记忆数据库 -│ └── raw/ # 原始会话记录文件 -│ └── raw_*.jsonl -├── skills/ # 安装的技能 -│ └── {name}/ -│ ├── SKILL.md -│ └── skill.json -├── adapters/ # Lua API 格式适配器 -│ ├── openai.lua -│ ├── deepseek.lua -│ ├── ollama.lua -│ └── custom.lua -└── snapshots/ # Docker 快照 - └── {agent_id}/ - └── snap_*.tar -``` - ---- - -## 七、构建与部署 - -**构建:** +## 六、构建与部署 ```bash -make build # 编译主二进制(~15MB) -make install # 编译 + 安装到 /usr/local/bin +make build # 编译主二进制 +make run # 编译 + 启动(数据 /tmp/homeagent) +make install # 安装到系统 make test # 运行测试 -make fmt # gofmt -make lint # golangci-lint ``` -**部署:** - -- 单二进制:`homed -config /etc/homeagent/config.yaml -data /var/lib/homeagent` -- systemd:`deploy/homeagent.service` -- 依赖:Go 1.19+(CGo enabled,用于 go-sqlite3);Docker 可选(快照/回滚) - ---- - -## 八、设计限制与后续计划 - -### 已知限制 -1. Agent Core 目前是单轮 tool_call 处理,尚未实现完整的多轮 tool 执行循环 -2. Embedder 已定义但未接入图记忆 — 缺失向量相似度排序和 ANN 索引 -3. 记忆蒸馏器使用简单启发式三元组提取,生产环境应调用 LLM 进行结构化抽取 -4. Linux namespace 隔离(overlayfs)尚未实现作为 Docker 替代方案 -5. Speaker / Microphone / Camera 均为桩实现,无实际 ALSA/PulseAudio/Video4Linux 驱动 -6. 无真正的唤醒词检测 -7. LuaAdaptedProvider 失败时无重试/降级逻辑 -8. 无持久化消息历史管理(目前仅内存中保留最近 50 条) - -### 路线图 -- **近期**:完成 tool_call 执行循环 → 设备真正驱动 → 向量记忆增强 -- **中期**:单二进制 namespace 隔离 → 唤醒词检测 → CI/CD 流水线 -- **远期**:多 Agent 协作 → 分布式部署 → 联邦记忆 +依赖:Go 1.19+ (CGo enabled for go-sqlite3)。单二进制部署。