mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-09-21 17:38:10 +00:00
- 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
9.7 KiB
9.7 KiB
HomeAgent 架构参考
基于 NextAgent 认知解耦架构 + TrulyMEM 自主图记忆 + OneBot 协议。
一、分层架构
┌──────────────────────────────────────────────────────────┐
│ IO 抽象层(唯一输入路径) │
│ Device(Mic/Speaker/Camera/GPIO/OneBot-QQ/PluginDevice) │
│ 所有外部输入 → InputEvent → inputCh │
│ 输出通道: 能力声明(text/file/image/audio/structured) │
│ 路由表: 输入源 → 默认输出通道 │
└──────────────────────────┬───────────────────────────────┘
│
┌──────────────────────────▼───────────────────────────────┐
│ Agent 操作层(核心编排器) │
│ eventLoop() consume inputCh │
│ ├─ RelevanceContext(TF-IDF 相关性管理) │
│ ├─ 工具循环(Provider.Chat → tool_calls → Execute → ...) │
│ ├─ 记忆索引注入(图索引 + 文档摘要) │
│ └─ 心跳蒸馏(30min:向量同步 + 冷归档 + 同义合并) │
└──────────────────────────┬───────────────────────────────┘
│
┌──────────────────────────▼───────────────────────────────┐
│ API 抽象层(唯一输出路径) │
│ Provider.Chat() → DeepSeek API / OpenAI / Ollama │
│ LuaAdapter 做请求/响应格式转换 │
└──────────────────────────────────────────────────────────┘
三条核心规则:
- 所有外部输入 → 必须通过
IOManager.InjectInput()/InjectText()注入 - 所有 LLM 调用 → 必须通过
Provider.Chat()发出 - Agent 不直接操作记忆系统,只发射
memory_candidate事件,由 Memory Pipeline 异步消费
二、子系统详解
2.1 IO 抽象层(唯一输入路径)
所有外部输入必须通过此层进入系统。
Device(Microphone) ─┐
Device(OneBot-QQ) ─┤
Device(Plugin) ─┤──→ IOManager → InputEvent → inputCh → Agent
Device(GPIO) ─┤
HTTP API ─┘
核心类型:
| 类型 | 说明 |
|---|---|
InputEvent |
Source + Type + Payload — 所有外部输入的标准化格式 |
OutputEvent |
Target + Type + Payload + OutputChannel — 输出路由 |
Device |
接口:Name/Type/Description/Tools/Execute/Start/Stop/OutputCapabilities |
DeviceType |
Input / Output / IO |
ToolDef |
Name + Description + Parameters + Handler — 与 LLM 函数调用同构 |
OutputCapability |
位掩码:text, file, image, audio, structured |
内置设备:
| 设备 | 方向 | 工具 |
|---|---|---|
| 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 声明
OutputCapabilities()→ 位掩码 output_send工具发送前校验通道是否支持文本output_list_channels只列出有输出能力的通道
2.2 API 抽象层(唯一输出路径)
Agent Core → Provider.Chat()
│
┌───────┴───────┐
▼ ▼
OpenAIProvider LuaAdapter
(DeepSeek API) (格式转换)
| 实现 | 说明 |
|---|---|
OpenAIProvider |
标准 OpenAI API 格式,DeepSeek v4 flash 默认 |
LuaAdaptedProvider |
通过 Lua 脚本转换请求/响应的适配 wrapper |
Lua 适配器位于 {dataDir}/adapters/*.lua,每个适配器返回 name + transform_request + transform_response。
2.3 Agent 操作层(核心编排器)
eventLoop() → select on inputCh
│
▼
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
人格注入: personal.md 加载一次,固定在 system prompt 最前,永不漂移。
工具分发:
executeToolCall(tc)
├─ memory_* → executeMemoryTool
├─ knowledge_* → executeKnowledgeTool
├─ doc_* → executeDocTool
├─ output_* → executeOutputChannel/Send/ListChannels
└─ 其他 → io.ExecuteTool → Device.Execute
2.4 记忆系统
三层分级,自顶向下逐渐持久化、抽象化:
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
│
▼
TF-IDF 向量索引(字符 bigram)
│
▼
工具: 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(): 原子化重载
热插拔流程:
- 扫描
plugins/目录 - 原生工厂优先,无工厂则 LoadSKILL.md
- 新设备 Start(预先启动)
IOManager.AtomicSwapDevices()原子替换设备表 + 路由表- 旧设备 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 层
│
▼
Device(internal/onebot/device.go)
├─ Tools: qq_send_private_msg, qq_send_group_msg, etc.
├─ Execute → Client.SendAction
└─ Start → Connect + 注册事件 handler
2.8 变更追踪器
Overlayfs 文件变更追踪:
PreAction(tool) → 记录文件 hash
PostAction(tool) → diff → ChangeSet{ID, Tool, Files[]SHA256}
Rollback() → 用 overlayfs 下层恢复
健康检查失败 → tracker.Rollback()。
2.9 Supervisor 守护进程
Daemon:
├─ SetTracker() → 绑定变更追踪器
├─ RegisterAgent("main") → 注册主 agent
└─ 健康检查周期 → LLM API 可达性
└─ 连续失败 → tracker.Rollback()
三、配置
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/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/config |
配置查看 |
六、构建与部署
make build # 编译主二进制
make run # 编译 + 启动(数据 /tmp/homeagent)
make install # 安装到系统
make test # 运行测试
依赖:Go 1.19+ (CGo enabled for go-sqlite3)。单二进制部署。