docs: 按 humanizer-zh 规则再改 README 开头

上一版开头四句被指出仍有 AI 味。拆开看问题在:

  · 四句长度接近、每句都是金句,没有一句是普通陈述
  · "说人话:"是元话语,AI 特有的"宣布要通俗化"动作
  · "白天聊过的事,晚上还记得" + "三周前说过的偏好,不会因为上下文窗口
    滚动就丢了" —— 严格对仗,一个口语一个技术解释混在一起
  · "插件崩了它不倒,模型换了它不改" —— 两组四字对仗

用 humanizer-zh 的规则过了一遍,命中三条:

1. **§A.1 不是 X,而是 Y** —— "跟直接调 API 的区别在于它把长期当成了
   基本需求,而不是事后加个向量库",后半句是假想敌。删掉后逻辑没损失。
2. **§A.2 单句收尾** —— "这个仓库从 2026 年 7 月开始开发,现在 1.4.0,
   一千多个提交" 独立成段作收尾。并入上一段。
3. **§A.5 与假想敌辩论** —— 小标题 "它跟别的 Agent 框架哪里不一样"。
   改成 "几个设计决定"。

另外自重写:

- 开头从四句金句改成一句陈述 + 一句具体 + 一段解释。不是排比。
- "## 能力" 从五项 "**类别**:三词·三词·三词" 改成有详有略的散文
  (五项同模板是最密集的 AI 指纹之一)
- "## 几个设计决定" 从五条 "**X,不是 Y。**" 改成一段段长短不一的叙述,
  其中 3 条原本是同一个句式
- 删掉与开头重复的记忆下沉描述

英文版同步,不是直译:`What makes it different` → `Design decisions`,
开头去掉同样的假想敌与收尾句。

## 修掉一处我自己写出来的事实错误

上一版我写了 "微信和 QQ 的文件、语音消息能收发"。核查后:仓库里没有微信
插件,只有 clawhubadapter 注释里提到微信作为通用通道的例子。已删掉微信。

## 验证

- 两版死链检查为空
- 代码块配对(14/14)
- 9 个二级标题中英对齐
This commit is contained in:
JianFeeeee
2026-10-31 11:15:33 +08:00
parent 8c72bd8ec5
commit 28b78e1703
2 changed files with 71 additions and 74 deletions

View File

@ -4,50 +4,46 @@
> **English**: [README_EN.md](./README_EN.md)
一个能自己跑几个月、还记得住事的 Agent 内核。
HologramAgent 是一个跑在自己机器上的 Agent 内核。接上 QQ、WebUI、命令行、文件、
浏览器,它就在这些地方干活。
说人话:你给它接上 QQ、WebUI、命令行、文件、浏览器,它就能在这些地方替你干活。
白天聊过的事,晚上还记得。三周前说过的偏好,不会因为上下文窗口滚动就丢了。
插件崩了它不倒,模型换了它不改。
记忆会往下沉:最近几轮留在上下文里,旧一点的转成文档,再旧蒸馏成三元组进图数据库。
所以它能连续跑几个月,而不用把全部历史塞进 prompt。
```bash
./build/homed -data /tmp/ha # 起来
./build/homed -data /tmp/ha # 起内核
./build/waiter # 跟它说话
```
硬件只需要一台 Linux。API 密钥在 WebUI 里填,存进本地 SQLite。
需要一台 Linux。API 密钥在 WebUI 里填,存本地 SQLite。开发始于 2026 年 7 月,当前 1.4.0。
---
## 它跟别的 Agent 框架哪里不一样
## 几个设计决定
**插件是独立进程,不是动态库。** 插件 panic 带不崩内核,还能自动重启。
换个 `plugin.bin` 就生效,不用重装、不用重启。这不是架构洁癖:`.so` 那套踩过的坑够写一页
(`dlclose` 被 `DF_1_NODELETE` 变成空操作、cgo 超时杀不掉线程、插件一崩整个 homed 陪葬),
所以才改成子进程 + 共享内存。
插件跑在独立进程里。它 panic 了带不崩内核,还会自己重启;换个 `plugin.bin` 就生效。
早先是 C 动态库那套,`dlclose` 被 `DF_1_NODELETE` 变成空操作,cgo 超时杀不掉线程,
插件一崩 homed 陪葬。所以重写成了子进程加共享内存。
**内核自己不碰 IO。** 不发 HTTP、不读文件、不连数据库之外的世界。
WebUI、QQ、命令执行、网络搜索全是插件。好处不是"干净",是你能在不改内核的前提下换掉整个交互层。
内核自己不发 HTTP、不读文件。所有碰外部世界的能力都在插件里:WebUI、QQ、命令执行、
网络搜索、浏览器。这不是为了"干净"好看,是为了换掉整个交互层时不用动内核。
**记忆是会下沉的,不是一直堆在上下文里。** 最近的留在窗口,旧的沉到文档层,
再旧蒸馏进图数据库。所以它能连续跑几个月而不会把历史全塞进 prompt。
同一个 QQ 插件里,群主和路人可以有不同权限;别的 Agent 发来的指令不会写进你的记忆,
但能触发记忆召回。判断由内核的安全模块做,插件只负责声明。
**它记得的是"场面",不是"会话"。** 你把话题从工作切到生活,它按通道、对话对象、
用到的工具、时段自动分场。同一个场面再次出现,上次的结论会被想起来,包括它自己说错过的那些。
**安全是一堵墙,不是每个工具自己随手扫一下。** 内核流出的请求、插件流回的数据都要先过它。
密钥不进 prompt(执行前才回填)、工具黑白名单、敏感词预警、按主体授权
(同一个 QQ 插件,群主和路人的权限可以不同)。
它按"场面"分记忆,不按会话。你从工作聊到生活,它按通道、对话对象、用到的工具和时段
自动分场。下次同一个场面出现,上次的结论会被想起来,包括它自己说错过的那些。
## 能力
不列 API,列你能让它干什么:
说话的地方包括 WebUI、命令行、QQ 群和私聊、其他 Agent(走 A2A 协议),以及在 IDE 里
当 ACP 服务端。能看图片、视频、语音和网页,也能操作真实的 Chrome。
- **说话的地方**:WebUI、CLI/TUI、QQ 群与私聊、其他 Agent(A2A)、IDE 里的 ACP
- **看和听**:图片、视频、语音、屏幕截图、网页
- **动手**:读写文件、跑命令、写代码、浏览器操作(含真实 Chrome)、日程、备忘、RSS、音乐
- **记住**:三层记忆 + 图记忆 + 知识库,支持按场面召回
- **调度**:一边跟人聊,一边把长任务派给子 agent 并行做;用户催了就插队,被打断的工作能接回去
动手的部分是文件读写、跑命令、写代码、日程、备忘、RSS、音乐。QQ 的文件和语音消息能收发。
它维持着三层记忆加一个图数据库和一个知识库,召回按场面走。
手头的活没干完又来新的,会进调度器排队;用户催了能插队,被打断的活保存现场后能接回去。
长任务可以派给子 agent 并行做,不用占着跟你说话的那条线。
28 个内置插件、89 个模型可调工具。外部插件一插件一仓,
见 [github.com/HologramAgent](https://github.com/HologramAgent)。
@ -60,14 +56,15 @@ homed(内核:LLM 编排 + 记忆 + 检索)
插件(WebUI / QQ / CLI / 文件 / 网络 / 一切 IO)
```
内核和插件之间三条通道:stdio JSON-RPC 管控制、共享内存管大块数据、事件环管通知。
大对象不序列化、不拷两遍。
内核和插件之间走三条通道:控制用 stdio 上的 JSON-RPC,大块数据走共享内存,
通知走事件环。大对象不序列化,也就不存在拷两遍的问题。
消息进来先过**调度器**,不直接喂给模型。排队的和插队的分开,插队分四级
("这有多不能等"),高级能抢占低级并保存现场。同级的排队等,不会互相踩。
消息进来先过调度器,不直接喂给模型。这是为了处理"正干着活又来了新指令"的情况:
排队的和插队的分开,插队按紧急程度分四级,高级的能抢占低级,被抢占的保存现场等着恢复。
同级的排队等。
然后进七阶段管道,模型可以连续调工具。同轮多个工具默认**串行**,
要让它们并行,得由工具自己声明安全。批里有一个没声明,整批退回串行。
再往下是七个阶段组成的管道,模型可以在里面连续调工具。同一轮的多个工具调用默认串行,
除非工具自己声明了并发安全。一个批次里只要有一个没声明,整批都退回串行。
## 快速体验

View File

@ -4,58 +4,56 @@
> **中文**: [README.md](./README.md)
An agent kernel that runs for months and still remembers.
HologramAgent is an agent kernel that runs on your own hardware. Connect it to QQ, a web UI,
your shell, your files, a browser, and it works in all of them.
In plain terms: connect it to QQ, a web UI, your shell, your files, a browser, and it gets
work done in all of them. What you discussed this morning, it still knows tonight. A
preference you mentioned three weeks ago doesn't vanish when the context window scrolls.
A plugin crashes and it keeps running. Swap the model and nothing else changes.
Memory sinks: the last few turns stay in context, older ones become documents, oldest get
distilled into triples in a graph database. That is why it can run for months without
stuffing the entire history into every prompt.
```bash
./build/homed -data /tmp/ha # start the kernel
./build/waiter # talk to it
```
All you need is a Linux box. API keys go in through the web UI and live in local SQLite.
You need a Linux box. API keys go in through the web UI and live in local SQLite.
Development started July 2026; currently 1.4.0.
---
## What makes it different
## Design decisions
**Plugins are separate processes, not shared libraries.** A plugin panic can't take the
kernel down, and it restarts on its own. Drop in a new `plugin.bin` and it's live. No
rebuild, no restart. This isn't architectural purity for its own sake: the `.so` approach
burned us badly enough to justify the rewrite (`dlclose` silently no-ops under
`DF_1_NODELETE`, cgo timeouts leave threads alive, one plugin panic dragged the whole
`homed` process down with it).
Plugins run in separate processes. One panics and the kernel stays up; it restarts on its
own. Drop in a new `plugin.bin` and it's live. The earlier version used C shared libraries,
where `dlclose` silently no-ops under `DF_1_NODELETE`, cgo timeouts leave threads alive, and
one plugin panic dragged `homed` down with it. That is why it was rewritten as subprocesses
plus shared memory.
**The kernel touches no IO.** No HTTP calls, no file reads, no reach into the world outside
its database. Web UI, QQ, command execution, web search are all plugins. The payoff isn't
tidiness; it's that you can replace the entire interaction layer without touching the kernel.
The kernel itself makes no HTTP calls and reads no files. Everything that touches the outside
world lives in plugins: the web UI, QQ, command execution, web search, the browser. Not for
tidiness. It means you can swap the entire interaction layer without touching the kernel.
**Memory sinks as it ages; it doesn't pile up in the context window.** Recent turns stay in
the window, older ones settle into a document layer, oldest get distilled into a graph.
That's why it can run for months without stuffing the whole history into every prompt.
Inside one QQ plugin, a group owner and a random member can hold different permissions.
Instructions arriving from another agent don't get written into your memory, though they can
trigger recall. The kernel's security module makes those calls; plugins only declare.
**It remembers scenes, not sessions.** Move from work talk to personal talk and it splits
the context by channel, conversation partner, tools used, and time of day. When a scene
Memory is partitioned by scene, not by session. Move from work talk to personal talk and it
splits context by channel, conversation partner, tools used, and time of day. When a scene
recurs, last time's conclusions come back, including the ones it got wrong.
**Security is a wall, not a line each tool remembers to check.** Everything leaving the
kernel and everything flowing back from plugins passes through it. Secrets never enter the
prompt (they're substituted at execution time), tool allow/deny lists, sensitive-word
alerts, per-principal authorization (the same QQ plugin can grant an owner and a random
group member different powers).
## What it can do
No API listings. What you can point it at:
Places it talks: web UI, shell, QQ groups and DMs, other agents over A2A, and an ACP server
inside your IDE. It can look at images, video, voice, and web pages, and it can drive a real
Chrome.
- **Where it talks**: web UI, CLI/TUI, QQ groups and DMs, other agents (A2A), ACP in your IDE
- **What it sees**: images, video, voice, screenshots, web pages
- **What it does**: read and write files, run commands, write code, drive a real Chrome, calendar, notes, RSS, music
- **What it remembers**: three-layer memory plus graph memory plus a knowledge base, recallable by scene
- **How it schedules**: chat with a human while long jobs run in parallel sub-agents; jump the queue when the user pushes back; resume interrupted work where it stopped
For getting things done it reads and writes files, runs commands, writes code, and handles
calendars, notes, RSS, and music. QQ files and voice messages go both ways.
Behind that sit three memory layers plus a graph database plus a knowledge base, recalled by
scene. When new work arrives mid-task it enters a scheduler; if the user pushes back it can
jump the queue, and interrupted work saves its state and resumes. Long jobs can be handed to
sub-agents so they don't block the line you're talking on.
28 built-in plugins, 89 model-callable tools. External plugins live one-per-repo at
[github.com/HologramAgent](https://github.com/HologramAgent).
@ -68,16 +66,18 @@ homed (kernel: LLM orchestration + memory + retrieval)
plugins (web UI / QQ / CLI / files / network / all IO)
```
Three channels between kernel and plugins: stdio JSON-RPC for control, shared memory for
bulk data, an event ring for notifications. Large objects aren't serialized and copied twice.
Three channels between kernel and plugins: JSON-RPC over stdio for control, shared memory
for bulk data, an event ring for notifications. Large objects aren't serialized, so there's
nothing to copy twice.
Incoming messages hit a **scheduler** first, not the model. Queued work and interruptions
are separate classes; interruptions come in four levels ("how badly can this wait"), and a
higher level preempts a lower one while saving its state. Same level waits its turn.
Incoming messages hit a scheduler first, not the model. This exists for the case where work is
already in flight and a new instruction arrives: queued work and interruptions are separate
classes, interruptions carry four urgency levels, a higher level preempts a lower one and the
preempted work saves its state to resume later. Same level waits.
Then seven pipeline stages, and the model can call tools in a loop. Multiple tool calls in
one turn are **serial by default**; to run them in parallel a tool must declare itself safe.
One undeclared tool in a batch drops the whole batch back to serial.
Below that sits a seven-stage pipeline where the model can call tools in a loop. Multiple tool
calls in one turn are serial by default unless a tool declares itself concurrency-safe. One
undeclared tool in a batch drops the whole batch back to serial.
## Quick Start