Files
HomeAgent/docs/zh/kernel-performance.md
JianFeeeee cf14b840ef docs: 补齐文档状态分类 + 校正两轮代码改动后的失真
## 背景

上一次文档校订(b9b5ac0)之后又有两次代码提交(5194a96 / 8293282),
把 future-plan §1.1 整节变成了错的 —— 它还写着「档位没有生效点」
和「在 prepareInputTask 里加一次 activateSecurityProfile 调用」,
而后者正是被后来的收敛**否定掉的方案**。

## 新增 docs/zh/README.md(文档索引)

32 篇文档此前混着三种时态(当时实测 / 历史推演 / 设计规划),外观相同。
索引给出**状态分类与可信度规则**:

| 状态 | 能不能当事实用 |
|---|---|
| 已实现并部署 | ✅ 直接信 |
| 部分实现 | ⚠️ 只信标了"生效"的部分 |
| 设计 / 未实现 | ❌ 只能当设计意图 |
| 归档说明 | ❌ 不要改、也不要信 |

并写死**判据名可信度规则**:文档里的 `TestXxx` 不保证还存在。
给了核对命令,以及当前基线(27 条缺失的分布 —— 18 条属"设计未实现"类
文档的规划名、7 条是 §2.7.3 有意保留的历史对照表左栏、2 条属视频能力
未纳入契约)。判定标准:**在"已实现"类文档正文里找不到才是缺陷**。

## 重写 future-plan §1.1(已结案)

原节写的是错的方案。改成记录**真正的缺陷分三层**:

```
第 3 层(表面):activateSecurityProfile 零调用方
第 2 层:agent/core 在替 security 做策略决策
         (自己抠 security_profile / 自己选判定链 /
           自己写 Kind:"resident" 声明主体类别 —— 提权口子)
第 1 层(根因):security 缺少「输入接入点」
```

并补上「每 agent 一个实例」的最终形态(共享注册表 + per-agent 执行视图,
sessionProfile / longtimeProfile 两层,优先级 session > longtime 本身是安全语义)。

§〇「机制 ≠ 接线」表格里档位那一条从 🔴 改为 ✅。

## 各文档状态行

此前 14 篇缺状态行(runbook / 实测报告 / 计划类)。逐篇补上**符合实际内容**
的声明,而不是统一套一句。特别地:

- `commondev-design.md` 标题本就写「设计 · 未实现」→ 归到"设计"类
- `live-run-evidence-2026-10-04.md` → 明确标注"历史证据快照,不要用它的
  结论覆盖现在的实现判断"
- `legacy-issues.md` → 写明它与 future-plan 的分工(前者收已知问题,
  后者收能力缺失与零调用方)

## 正文里两处判据名漂移

- `TestBootCtxCloseAllIsReverseOrder` → 实际是
  `TestKernelStateCloseAllIsReverseOrder`(`BootCtx` 改名时判据跟着改的)
- `TestNilTypedBusSafety` → 标注为"规划名,仓库中不存在"

## 新增 §2.7.5 模块产物的实例化粒度

依赖图保证"设施已就绪",但没说该有几个实例 —— 这是独立决策。
记下 security 的两个答案:全局基线共享(否则插件声明对部分 agent 不生效)、
轮次状态 per-agent。并给出给未来新模块的两条判断标准。

## 安全文档

状态头补「架构形态」段(防火墙定位、per-agent 视图、两层档位);
接线状态表里 `ActivateProfile` 从 🔴 改为 ✅(2026-10-31 接通)。

## README

文档列表加索引与 future-plan 入口 —— 此前从 README 找不到 docs/zh 的任何指引。

## 核对

- docs/zh 32 篇全部有状态行
- 索引里列的文档全部存在,无遗漏
- 分类与各文档自述一致(逐篇抽查)
- go build 仍通过(纯文档改动)
2026-10-31 07:50:58 +08:00

6.3 KiB
Raw Blame History

内核性能指标(实测基线)

状态:实测基线。 数据来自标注的日期/版本;引用前先确认它是否仍对应当前版本。

本文记录实测数据,不是估算。每条都标出测量方法与采集时间, 便于复现与追回归。

采集环境:main @ ecffb8a,Linux amd64,Go 1.27.1, 生产实例 /home/newqqagent(21.4GB 数据目录), 22 个外部插件 + 5 层 / 17 模块内核。 采集时间:2026-10-18 18:12(冷启动)。


1. 冷启动

systemctl restart homeagent → 内核装配完成。

阶段 时刻 累计 说明
启动 18:12:15 0s 依赖图加载(depgraph.bin,digest 2067c913)
第 0 层完成 18:12:15 ~0.1s 2 个:config, kernel-api
第 1 层完成 18:12:18 3.1s 9 个:doc-store, knowledge-migration, lua, memory, migration, multimodal, onnx-parser, supervisor, tracker
第 2 层完成 18:12:18 3.2s 3 个:knowledge-store, llm, text-memory
第 3 层完成 18:12:18 3.3s 1 个:stage-host
第 4 层完成 18:12:20 5.5s 2 个:agent, plugin-host
装配完成 18:12:30 15.4s 含 22 个外部插件建链

峰值并发 4(原为 17 步串行)。

耗时分布

第 0→1 层  3.1s  ████████████████  20%   内存/ONNX/文档存储初始化
第 1→4 层  2.4s  ████████████      16%   LLM/知识库/agent 装配
第 4→完成  9.9s  ████████████████  64%   22 个插件子进程建链
```text

**结论**:启动时间主要由**插件建链**决定(64%),不是内核模块本身。
每多一个 proc 插件约 +0.45s。

> ⚠️ 与早期记录(1538–1709ms)的差异:那是**纯内核**(5 层 17 模块)
> 的装配时间,不含插件。两者口径不同,不要混用。

### 复现

```bash
systemctl restart homeagent
journalctl -u homeagent --since "1 min ago" \
  | grep -E "启动顺序来自|第 [0-9] 层完成|内核装配完成"
```text

---

## 2. 资源占用

稳态(启动完成、空闲):

| 指标 | 值 |
| --- | --- |
| 内核 RSS | **26 MB** |
| 内核 VSZ | 2104 MB(含 Go 保留地址空间,非常驻) |
| 插件子进程数 | 12(其余按需加载) |
| 二进制体积 | 84 MB(未 strip,含 debug_info) |

> 12 而非 22:13 个插件声明了 `auto_start: false`(按需加载),
> 只有被 `plugin_enable` 拉起时才起进程。

---

## 3. 超时与容量

这些是**硬约束**,决定"一个任务最多能占用多久"。

### 工具超时(三层)

| 层 | 值 | 位置 |
| --- | --- | --- |
| `cmd_run` 自身 ctx | 默认 **30s**,可由参数调 | `internal/plugins/cmd/plugin.go` |
| 内核工具等待 | `max(声明值, 参数值)` | `internal/agent/core/toolcall.go:37` |
| 硬上限 | **10m** | `toolcall.go:28` `maxToolTimeout` |

计算规则(`resolveToolTimeout`):

```text
base = 60s(默认)
     ↓ 若 ToolDef 声明了 Timeout
base = 声明值
     ↓ 若调用参数带 timeout 且 > base
base = 参数值
     ↓ 若 base > 10m
base = 10m
```text

**实测验证**:

```text
cmd_run command="sleep 200"(不传 timeout)
→ 工具 cmd_run 失败: 命令执行超时(30s)
```text

⚠️ **参数可以合法绕过默认值**:模型传 `timeout="2m"` 时,
`cmd_run` 的 30s 保护被提高到 2 分钟。这是设计允许的(长命令确有需要),
但也意味着**单个工具最长可占用 10 分钟**,期间调度器只能等。

### 上下文预算

运行时日志(`task.go:599`):

```text
tool call loop start, max_ctx=1048576 target=600000 fixed=3004 mem=198998 ctx=397
```text

| 项 | 值 | 含义 |
| --- | --- | --- |
| `max_ctx` | 1048576 | 模型上下文上限(1M) |
| `target` | 600000 | 目标使用量(60 万,留 40% 余量) |
| `fixed` | 3004 | 固定开销(system prompt 等) |
| `mem` | 198998 | 记忆注入占用 |
| `ctx` | 397 | 当前对话占用 |

### 记住-遗忘阈值

| 键 | 值 | 说明 |
|---|---|---|
| `core.agent.offload_busy_after` | **1m** | 忙超过此时长则转投 offload 子 agent |

---

## 4. 安全层开销

| 项 | 值 |
| --- | --- |
| 密钥来源 | `embedded`(构建期注入,指纹 `0db8e9c5`) |
| 变量条数 | 8 |
| 加密算法 | AES-GCM(`enc:v1:` 前缀) |
| 出向/入向扫描 | 每次工具调用与工具返回各一次(`security.Patterns`) |
| 日志脱敏 | `scrubForLog`(幂等,nil-store 安全) |

扫描是**纯内存正则匹配**,未观测到成为瓶颈(工具调用耗时由工具本身主导)。

---

## 5. 插件建链

| 指标 | 值 |
| --- | --- |
| 建链数(本次启动) | 11 |
| `loaded` 事件 | 28 |
| 单插件建链均摊 | ~0.45s(9.9s / 22) |

协议版本:`sdk=1.4.0 core=1.4.0`。

---

## 6. 已知的性能陷阱

以下都是**实测踩过**的,不是理论风险。

### 6.1 长工具执行期间 `stop` 无法生效

`stop` 请求只在 `pre_action` 被消费:

```text
[agent] stop requested by webui (queued=1 will be short-circuited at pre-action)
```text

若 agent 正卡在 `sleep 150` 这类长命令里,**没有 pre_action 可以插入** ⇒
停止按钮要等到当前工具跑完才生效。

现场(2026-10-18):`task#3` 跑了 10 分钟,期间 `task#4`~`task#8`
全部堵在队列,两次 stop 请求都无效,最后只能重启。

### 6.2 同阶段重复注册 = 静默覆盖

插件侧 `stageHandlers` 是 `map[阶段名]handler`,同阶段注册两次后者覆盖前者。
除了功能丢失,还意味着**权限门可能被覆盖掉**。hmapdev 在构建期告警。

### 6.3 `before_output` 有两条触发路径

一轮结束 vs 单次 `output_send__`。误用会让"正在输入"漏触发,
或让状态归位过于频繁(干活期间反复跳回空闲)。

详见 SDK README「阶段钩子」一节。

---

## 7. 复现与回归

```bash
# 冷启动
systemctl restart homeagent && sleep 20
journalctl -u homeagent --since "1 min ago" | grep "内核装配完成"

# 资源
ps -o rss= -p $(pgrep -f "homed" | head -1) | awk '{printf "RSS: %.0f MB\n", $1/1024}'

# 插件进程
pgrep -c -f "plugin.bin"

# 工具超时(应 30s 失败)
# 经 agent 调:cmd_run command="sleep 200"
```text