mirror of
https://gitcode.com/JianFeeeee/HomeAgent.git
synced 2026-10-03 15:53:56 +00:00
docs: 全面按当前源码更新文档 + 删除已过时文档
## 删除(内容已落地/已被替换,保留只会误导)
- demo.md ................... failback 与 recoverydiag 均已实现,0 引用
- docs/defect-qq-output-send-loop.md .. 已修复(本身也标了「已修复」),0 引用
- docs/embedding-comparison.md ....... 一次性选型报告,仅被 agent 产物引用
- docs/zh/plan.md ............ 描述的旧 nav 布局已重写、死配置已清,全部完成
- docs/zh/plugin-migration-plan.md ... 迁移已上生产,纯过程稿(Part 0~6 全完成)
## 更新(按当前源码核对)
- assets/docs/{zh,en}/ARCHITECTURE.md(README 指向的用户文档,最重要):
把只讲 cancel/intercept 的旧「中断机制」章节重写为「输入调度器与中断机制」——
补上两类别 + 四级中断(L1~L4,默认 L1、外部插件 L4 夹到 L3)+ 抢占/挂起/中断栈
+ 饥饿防护(PreemptCount 提升,封顶 L4)+ 抢占冷却(2s)+ 停止语义(cancelBudget)
+ 驻留子/分诊助手/残余任务;新增「上下文预算」章节(窗口 ≠ 工作面,600K 封顶,
预算是上限非填充目标)。中英章节数现已对齐(各 13 节)。
- assets/docs/{zh,en}/PLUGIN_DEV.md:插件示例表补 6 个缺失项
(acp/deepsearch/plugindev/recoverydiag/vanblog/vikunja);qq 工具数 17 → 20(实测)。
- README.md / README_EN.md:补 v1.3.x 线(此前只到 v1.2.0,而 1.3.x 已发布 12 个 patch)——
驻留式子 agent、输出通道寻址、输入调度器、轻量内核 profile、积压及时反馈。
- plan.md:开头两个「⚠️ 紧急/正在持续污染」是过期告警(实测 残留 = 0),
改为「已解决」并加文档定位说明;§13 仍是活跃路线图故保留。
- docs/zh/plugin-interface-matrix.md + 两处源码注释:清理指向已删文档的断链。
全仓 md 断链检查:仅剩 1 处,位于 third_party 的 oh_modules(第三方依赖,非本项目)。
This commit is contained in:
@ -444,7 +444,64 @@ type Plugin interface {
|
||||
- Relation 扩展:Confidence
|
||||
|
||||
|
||||
## 中断机制
|
||||
## 输入调度器与中断机制
|
||||
|
||||
输入不直接进 LLM —— 它们先进**输入调度器**(`internal/agent/core/scheduler.go`)。
|
||||
设计全文见 [`docs/zh/input-scheduler-design.md`](../../../docs/zh/input-scheduler-design.md)。
|
||||
|
||||
### 两类任务
|
||||
|
||||
| 类别 | 级别 | 语义 |
|
||||
|------|------|------|
|
||||
| `TaskQueued` 排队输入 | 无级别(恒 0) | 待办工作。任何中断(≥ L1)都能抢它 |
|
||||
| `TaskInterrupt` 中断 | L1~L4 | "这件事有多不能等",由来源在 `InjectOptions.Priority` 声明 |
|
||||
|
||||
### 四级中断
|
||||
|
||||
| 级别 | 含义 | 典型来源 |
|
||||
|------|------|----------|
|
||||
| L1 背景 | 完全可等 | QQ/微信消息、批量通知 |
|
||||
| L2 消息 | 一般提醒 | 插件希望尽快看到但不紧急的提示 |
|
||||
| L3 交互 | 需及时处理 | 定时器到达、终端输出、子 agent 汇报 |
|
||||
| L4 关键 | **内核独占** | panic、内核事件、内核级插件的终止按钮 |
|
||||
|
||||
未声明级别时取 **L1**(`DefaultLevel`)——「显式才是特权」,新插件不会默认拿到抢占权。
|
||||
外部插件声明 L4 会被**夹到 L3**(`clampPluginLevel`)。
|
||||
|
||||
### 抢占与挂起
|
||||
|
||||
- **同级不能抢占同级**(`canPreempt` 要求严格大于)——这是日常"消息排队等前面跑完"的成因。
|
||||
- 被抢占的任务压入**中断栈**(LIFO),用 `suspendStack` 保存现场,稍后恢复;
|
||||
栈内不做优先级重排("后被打断的先恢复"才是栈语义)。
|
||||
- **饥饿防护**:被抢占次数会提升有效级别(`effectiveLevel = Level + min(PreemptCount, 2)`,
|
||||
封顶 L4),确保低级别流不会被困。
|
||||
- **抢占冷却**:刚被抢占过的任务在 `preemptCooldown`(2s)内不再被抢,
|
||||
避免高优先级流把同一个任务反复打断到永不完结。
|
||||
- 中断栈帧数有**结构上界**(链条 = 排队 ← L1 ← L2 ← L3 ← L4,最多挂起 4 帧)。
|
||||
|
||||
### 停止(用户按停止按钮 / `/stop`)
|
||||
|
||||
停止 ≠ 空中断。它做两件事:① 立即结束当前 LLM 推理;② 对**停止那一刻已排队**
|
||||
的 x 条消息依次在 pre-action 阶段短路(`cancelBudget` 快照配额),而不是把它们
|
||||
当新输入再跑一遍。停止之后**新到**的输入不受影响。
|
||||
|
||||
`PendingInputs()` 必须把"还停在 `io.inputCh`、没被 `pumpInbox` 搬进队列"的那一段
|
||||
算进来 —— 停止时调度器多半正忙于当前任务,只数 `sched.queue` 会得到 0。
|
||||
|
||||
### 驻留式子 agent 与及时反馈
|
||||
|
||||
设计见 [`docs/zh/resident-subagent-design.md`](../../../docs/zh/resident-subagent-design.md)。
|
||||
|
||||
- **驻留子**是轻量内核的独立 agent:自己的调度器、自己的 temp 图记忆、共享的通道登记表。
|
||||
- 父对子的控制面:`resident_agents`(list / create / send / inspect / compress / reclaim / destroy)。
|
||||
- **积压及时反馈**:主 agent 长时间忙时(默认 > 5m,可配),内核把排队输入交给
|
||||
一个临时**分诊助手**(`offload_*` 配置):简单的直接处理并回复,需要主 agent 的
|
||||
立刻回「忙碌中,请稍候」。这样用户不会干等十几分钟。
|
||||
- 分诊助手**不配 inputch**(不接收插件用户输入)、**持有全部输出通道**(结果要能发回原通道)。
|
||||
- 回收/销毁时它手头的**残余任务由父显式决定**:`residual=keep`(转回父队列,默认)
|
||||
或 `drop`(明确丢弃,逐条记日志)。
|
||||
|
||||
### 旧版三路径(仍存在,但已是调度器之下的一层)
|
||||
|
||||
```
|
||||
interceptLoop (goroutine)
|
||||
@ -454,15 +511,26 @@ interceptLoop (goroutine)
|
||||
└── (c) InjectInput() → 空闲时触发新处理
|
||||
```
|
||||
|
||||
三种投递路径:
|
||||
代码:`internal/agent/core/scheduler.go`(调度器)、`eventloop.go`(拦截循环)。
|
||||
|
||||
| 路径 | 效果 | 时机 |
|
||||
|------|------|------|
|
||||
| cancelLLM | 取消当前 HTTP 请求 | 收到 context.Canceled |
|
||||
| interceptCh | process() 中插入 `[打断消息]` | 每个 LLM call 前 |
|
||||
| InjectInput | eventLoop 空闲时触发新处理 | 无进行中请求 |
|
||||
## 上下文预算
|
||||
|
||||
代码:`internal/agent/core/eventloop.go` — `interceptLoop` / `drainInterrupts`
|
||||
`internal/agent/core/tokenbudget.go` — `ComputeTokenBudget`:
|
||||
|
||||
```
|
||||
maxCtx = provider.MaxContextTokens() // 声明窗口(per-source context_window 优先)
|
||||
targetUsage = min(maxCtx × 0.8, 600000) // 工作面:封顶 600K
|
||||
├── 记忆召回预算 = (targetUsage - 固定开销) / 3
|
||||
└── 上下文事件预算 = 其余 2/3
|
||||
```
|
||||
|
||||
★ **窗口 ≠ 工作面**:源的真实窗口可能到 1M,但接近满窗口时注意力涣散、
|
||||
成本与延迟线性上升,因此 `maxTargetTokens=600000` 把工作面单独封顶。
|
||||
若模型名(如 `AUTO`)推断不出窗口,`ModelContextWindow` 会**打日志提醒**并回退保守值,
|
||||
部署方应用 `core.llm.sources.<name>.context_window` 显式声明。
|
||||
|
||||
**预算都是上限而非填充目标**:记忆按相关度召回(没相关就停),时间线按预算从新到旧取。
|
||||
实测:预算 400K 时实际注入仍只有几百字符。
|
||||
|
||||
|
||||
## 配置系统
|
||||
|
||||
Reference in New Issue
Block a user