diff --git a/site/README.md b/site/README.md new file mode 100644 index 0000000..6906bff --- /dev/null +++ b/site/README.md @@ -0,0 +1,61 @@ +# 官网(静态站) + +单文件、零构建、零依赖的落地页。与仓库 WebUI 的做法一致(原生 HTML/CSS/JS,无打包步骤)。 + +## 文件 + +``` +site/ +├── index.html 单文件站点(内联 CSS/JS) +└── assets/ + ├── logo.svg logo(来自 assets/branding/logo-h-he.svg) + └── mascot.webp 看板娘立绘(来自 assets/branding/mascot-xiaozhai.webp) +``` + +资源是**复制**而非引用上级目录,因此 `site/` 可整体拷走独立部署。 + +## 本地预览 + +```bash +cd site && python3 -m http.server 8799 +# 打开 http://127.0.0.1:8799/ +``` + +## 部署 + +纯静态,任意 web 服务器指向 `site/` 即可: + +```nginx +server { + listen 80; + server_name your.domain; + root /path/to/TrueAgent/site; + index index.html; + location / { try_files $uri $uri/ =404; } +} +``` + +## 设计说明 + +- **配色取自品牌指南**:蓝 `#3b82f6` / 青 `#06b6d4` / 金 `#f59e0b`, + 正好对应三层记忆 Context / Document / Graph,因此三层记忆那节直接用了这三色做色条。 +- **立绘按「有意的圆角卡面」呈现**,不做抠图:原图是白底 + 蓝紫渐变外框, + 抠图会连带毁掉白裙子与发丝高光(实测背景连通域分析:白底与裙子同色, + flood-fill 会让 42% 的身体变成透明)。改为圆角 + 发光边框 + 底部渐隐, + 让方形图与深色页面自然衔接。 +- **淡入动画是渐进增强**:内容默认可见,仅当 JS 真的跑起来才加 `.js-reveal` 接管。 + 早期版本把 `opacity:0` 写在默认样式里,结果 JS 未执行时整页永久空白 + (实测 30 个元素里 26 个停在不可见)——现在禁用 JS 也完整可读。 +- 尊重 `prefers-reduced-motion`;架构图的 `
` 在窄屏横向滚动,避免整页撑宽。
+
+## 改内容前请核对事实
+
+页面上的数字(外部插件数、工具数、代码行数、适配器数)都是**实测值**,
+不是估的。改动前建议重新取一遍:
+
+```bash
+ls /home/newqqagent/plugins/ | grep -v hmap | wc -l          # 外部插件
+grep -oE '[0-9]+ tools' $(ls -t /home/newqqagent/log/*.log | head -1) | tail -1
+ls internal/lua/adapters/*.lua | wc -l                        # LLM 适配器
+find . -name '*.go' -not -path './.git/*' -not -path './.go/*' -not -path './third_party/*' | xargs wc -l | tail -1
+```
diff --git a/site/assets/logo.svg b/site/assets/logo.svg
new file mode 100644
index 0000000..e8214ec
--- /dev/null
+++ b/site/assets/logo.svg
@@ -0,0 +1,28 @@
+
+  
+
+  
+    
+    
+    
+    
+
+    
+
+    
+
+    
+    
+
+    
+    
+
+    
+    
+
+    
+    
+
+    
+  
+
diff --git a/site/assets/mascot.webp b/site/assets/mascot.webp
new file mode 100644
index 0000000..9c00640
Binary files /dev/null and b/site/assets/mascot.webp differ
diff --git a/site/index.html b/site/index.html
new file mode 100644
index 0000000..14a6001
--- /dev/null
+++ b/site/index.html
@@ -0,0 +1,862 @@
+
+
+  
+    
+    
+    HomeAgent — 常驻型个人 Agent 框架
+    
+    
+    
+    
+    
+    
+  
+  
+    
+
+ +
+
+ +
+ +
+
+
+ 常驻型个人 Agent 框架 +

一个不会忘记
也不会被一条长任务卡死的管家

+

+ HomeAgent 是内核 + 插件的双层 Agent 框架。内核只管 + LLM 编排、记忆与调度;所有外部能力(消息、文件、网络、设备) + 都是可独立安装、崩溃不牵连内核的插件。 +

+ +
+
+ 看板娘 小宅 +
+
+
+ + +
+
+

四个不那么常见的设计决定

+

+ 大多数框架先写功能再补边界。HomeAgent 反过来:先把 + 边界和调度定死,再往上加能力。 +

+ +
+
+
◇
+

内核零 IO

+

+ 内核不直接读写任何外部世界。收发消息、文件操作、网络请求、硬件交互 + 全部由插件经 PluginSDK 实现。于是「内核有多可信」与「某个插件有多安全」 + 成为两个可独立评估的问题。 +

+
+ +
+
◈
+

插件是独立进程

+

+ 外部插件编译成普通 Go 二进制,由内核 spawn 为子进程,经 + stdio JSON-RPC(控制)+ 共享内存段(数据)+ 事件环(通知)通信。 + 插件崩溃不影响内核,换掉 plugin.bin 即真热重载。 +

+
+ +
+
◉
+

输入是有级别的

+

+ 输入先进调度器,分「排队」与「中断」两类,中断再按“有多不能等”分 L1–L4。 + 高优先级可抢占并保存现场,同级不抢占。L4 只归内核 + —— 所以“停止”按钮真的能立刻停下。 +

+
+ +
+
◆
+

忙时有人顶班

+

+ 主 agent 执行长任务时,后来的消息不会干等十几分钟:内核把积压交给 + 临时分诊助手 —— 简单的直接办完,需要主 agent 的立刻回 + 「忙碌中,请稍候」。 +

+
+
+
+
+ + +
+
+

三层记忆:从「刚才说了什么」到「三年前说过什么」

+

+ 不是一个向量库包打天下,而是三层各司其职、逐层衰减与整合。 + 品牌的蓝 / 青 / 金三色,对应的就是这三层。 +

+ +
+
+
+
+

① Context工作窗口

+

+ 内存中的事件窗口,按与当前输入的相关性评分排序(预训练词向量 → 余弦相似度, + TF-IDF 回退),并保护最近若干条。低分事件自动下沉。 +

+
+
+ +
+
+
+

② Document文件记忆

+

+ JSON + TF-IDF 索引的中间层。支持显式提交与隐式归档; + 冷数据按时间下沉,蒸馏成三元组进入图谱。 +

+
+
+ +
+
+
+

③ Graph图数据库

+

+ SQLite 持久化实体与关系,BFS 遍历召回。蒸馏管道从对话里提取三元组, + 越用越准;这是“几个月前的事还记得”的落点。 +

+
+
+
+ +
+
+

媒体也是一等节点

+

+ 图片/音频不是附件,而是三层里的一类节点:内容寻址存储(相同字节只存一份)、 + 引用计数 GC(有引用绝不删)。 +

+
+
+

描述才是持久语义

+

+ 视觉模型生成的描述以 [mime digest] 描述 写进纯文本记忆并参与检索; + blob 只是可被淘汰的缓存。所以几个月后“那张三色图”仍能搜到。 +

+
+
+

统一多模态空间

+

+ 文本与图像落在同一向量空间(默认 Chinese-CLIP), + 因此可以用一句话搜图,也可以用图找相关记忆。 +

+
+
+
+
+ + +
+
+

一条消息进来之后

+

+ 输入先过调度器,再进处理管道;管道有 7 个阶段钩子,插件可在此改写或短路。 +

+ +
+
+  外部输入(QQ / WebUI / CLI / 邮件 / 设备 …)
+        │
+        ▼
+  输入调度器  两类别 · 四级中断 L1–L4
+        │   ├─ 同级不抢占 → 入队列
+        │   ├─ 更高级     → 抢占(现场压入中断栈,稍后恢复)
+        │   └─ 忙太久     → 转投 临时分诊助手
+        ▼
+  处理管道  on_input → pre_action → post_action → before/after_toolcall → before/after_output
+        │   记忆召回 + 人格注入 + LLM 调用 + 工具循环
+        ▼
+  三层记忆  Context → Document → Graph
+        │
+        ▼
+  输出通道  可寻址到具体 agent(父 ↔ 驻留子)
+
+
+ +

核心组件

+
+
homed常驻内核进程:LLM 编排、记忆管理、输入调度、插件生命周期
+
PluginSDK四通道:注册工具 / 挂阶段钩子 / 订阅事件 / 声明输出通道
+
inputch最基本的输入路由单位,可划给某个 agent(含驻留子)
+
Stage7 个处理阶段钩子,插件可改写或短路消息流
+
resident驻留子 agent:独立调度器 + temp 图记忆,父可查看/收发/压缩/回收
+
hmapdev插件工具链:生成工程、构建 .hmap、安装
+
+ +
+
36
外部插件(实测在跑)
+
340
可用工具
+
110k
Go 代码行
+
10
LLM 协议适配器
+
+
+
+ + +
+
+

跑起来

+

+ 依赖 Go 1.25+ 与 CGo(sqlite3)。内核需 Linux —— Windows 上 + homed 跑在 WSL2 里,只构建 waiter.exe。 +

+ +
# 构建守护进程 + CLI +make build build-cli + +# 启动内核(数据目录自定) +./build/homed -data /tmp/ha + +# 另开一个终端:交互模式,或单条消息 +./build/waiter +echo "你好,记住我喜欢喝咖啡" | ./build/waiter
+ +

+ WebUI 与 API 密钥在 http://localhost:8080 配置,持久化在 SQLite。 +

+ +

开箱可用的插件

+

外部插件经 hmapdev 构建为独立二进制,可单独安装、卸载、热重载。

+
+ qq + wechat + browser + files + memo + calendar + rss + editdoc + ocr + music + bili + ai_image + weather + vikunja + vanblog + deepsearch + mcp + a2a + acp + mc + remotedevice + recoverydiag + …共 36 个 +
+
+
+ + +
+
+

常见问题

+

这些是设计上最容易引起误解的地方。

+ +
+
+ 「内核零 IO」是不是意味着内核很简单? +

+ 恰恰相反——零 IO 是为了让内核能专注做难的部分:输入调度(四级中断、 + 抢占与现场保存)、上下文预算、三层记忆的蒸馏与召回。 + 把 IO 挪出去之后,这些才有清晰的所有权。 +

+
+ +
+ 插件崩了会不会把 Agent 带崩? +

+ 不会。从 v1.0.0 起外部插件是独立子进程,与内核只通过 + stdio JSON-RPC、共享内存段、事件环三个面通信。插件崩溃后内核摘除其 + 注册面(工具/阶段/通道)并按退避重启它,其余插件与内核不受影响。 +

+
+ +
+ 为什么消息会「排队」而不是立即处理? +

+ 因为同一时刻只应该有一个任务在改上下文。同级中断不抢占同级任务—— + 抢了会让两边都做一半。需要立刻插队的场景请用更高级别的中断 + (如 L4:内核与内核级插件),而不是让所有消息都变成抢占者。 +

+
+ +
+ 长任务会不会让用户等很久? +

+ 这正是「分诊助手」要解决的。主 agent 忙超过阈值(默认 5 分钟)且积压够多时, + 内核会拉起一个临时驻留子接手积压:能直接办的办完并回复, + 需要主 agent 的立刻回一句「忙碌中,请稍候」。 +

+
+ +
+ 记忆会不会无限膨胀? +

+ 不会。三层是迁移关系而不是复制:上下文事件被裁剪后归档成文档, + 文档冷掉后蒸馏成图谱三元组。图谱有去重与 UNIQUE 约束, + 媒体则靠引用计数 GC 回收无主内容。 +

+
+ +
+ 能换 LLM 吗? +

+ 可以。内核不绑定任何厂商:每个 LLM 源对应一个 Lua 脚本负责请求/响应转换, + 仓库内置 10 个适配器(OpenAI、Anthropic、Gemini、DeepSeek、Groq、Ollama 等), + 也可以自己写一个接任意兼容 API。 +

+
+
+
+
+
+ + + + + +