- 无人值守长任务设计定稿,含效率与可观测补遗 - u-relay wire 协议规格与五项评估结论 - 新能力引入评估纪律五项清单 - todo 销账与狗粮短板分析登记
5.4 KiB
Namespace 淘汰互踩治理 · 设计(2026-10-04)
✅ 拍板通过(2026-10-04,2/2 按建议:C1 pin 50% 上限/C2 本期仅报告 pin;见 拍板集)
来源:todo.md 子代理深查「P2 namespace 10MB 全局 LRU 淘汰:报告蒸发为『重新调用』死路+多代理共池互踩[需设计]」。 勘察结论(2026-10-04 现场核实,以
crates/df-ai/src/namespace_store.rs全文为准):
NamespaceStore= 纯内存HashMap<key, NamespaceEntry>+ 手动 LRU(evict_if_needed),默认 10MB(:85 default()),单条超容量拒绝入库(:108,返回不可解析引用→展开点落EVICTED_PLACEHOLDER)。- 阈值:
NAMESPACE_BYTE_THRESHOLD=2048/NAMESPACE_LINE_THRESHOLD=50,ALWAYS_LARGE_TOOLS=[read_file, list_directory, grep, diff_files]。- 无淘汰回调/通知:淘汰静默发生,父 LLM 只在下次展开引用时经
EVICTED_PLACEHOLDER(:17)得知「已淘汰,如需请重新调用」。- 展开点:
agentic/context_lifecycle.rs:145-155(压缩路径)、agentic/mod.rs:1632(主循环),均is_namespace_ref检查。- 作用域:store 实例按会话生命周期持有(
ContextManager或 agentic loop 内),子代理 loop 复用同一全局/会话 store——互踩根源。
1. 失败模式拆解
| 模式 | 现状 | 后果 |
|---|---|---|
| F1 报告蒸发死路 | 子代理 A 报告进 namespace → 池满淘汰 → 父 LLM 展开得 EVICTED_PLACEHOLDER → 指引「重新调用对应工具」 | 「重新调用」= 重跑子代理(spawn 新一轮),成本爆炸且非确定性 |
| F2 多代理互踩 | 同会话并发/串行多子代理共用一个 10MB 池,A 的大结果把 B 的挤掉 | 无归属概念,淘汰不看 owner |
| F3 跨会话残留 | 引用路径含 args_hash 不含会话维度,会话切换后引用可能指向别会话条目(或已蒸发) | 语义错乱(EVICTED_PLACEHOLDER 兜底但误导) |
2. 设计目标
- 报告类内容不可淘汰(pin 机制):子代理报告、用户显式产出的长文标记 pin,LRU 跳过;
- 淘汰可感知:淘汰发生时记录「淘汰清单」,下次展开引用时给出结构化提示(含原工具名+参数摘要+淘汰时间),而非裸 EVICTED_PLACEHOLDER;
- 隔离互踩:store 增 owner 维度(conv_id 或子代理 id),淘汰优先跨 owner 不回收他域(软隔离,不引入硬配额复杂度);
- 零 schema 变更:全部内存态增强,不动 DB。
非目标:不做磁盘 spill(超容量落盘另线);不改阈值(2048B/50 行实测合理);不动 ALWAYS_LARGE_TOOLS 名单。
3. 方案
3.1 NamespaceEntry 扩展
pub struct NamespaceEntry {
key, tool_name, content, created_at, access_count, // 现有
+ pinned: bool, // pin 标记,LRU 跳过
+ owner: Option<String>, // 归属 conv_id/agent_id,软隔离
+ evict_hint: Option<String>, // 预生成的淘汰提示(工具名+参数前 80 字),淘汰时留档
}
3.2 pin API
impl NamespaceStore {
+ pub fn store_pinned(&mut self, tool_name, content, owner) -> String // 子代理报告/关键产出走此
+ pub fn pin(&mut self, key) // 事后 pin
+ pub fn unpin(&mut self, key)
}
调用点:sub_agent.rs 统一出口(:495 emit AiAgentFinished 处)把报告 store_pinned;run_command/generate_image 等大产出可选 pin(后续)。
3.3 淘汰清单(EvictionLog)
store 内加 VecDeque<EvictionRecord>(容量上限 50 条):
struct EvictionRecord { key, tool_name, hint(前80字), evicted_at, owner }
evict_if_needed 淘汰时 push。展开点 read_only()=None 时:
- 查 EvictionLog 命中 → 返回富提示:
[结果已淘汰] 原为 read_file(src/main.rs 前 80 字…) 于 3 分钟前因容量淘汰。可重新调用 read_file 取回。 - 未命中(跨会话残留/未知)→ 现 EVICTED_PLACEHOLDER 不变。
3.4 owner 软隔离
evict_if_needed 淘汰顺序改为:先淘无 owner 且未 pin 的最旧 → 再淘他 owner(非当前活跃 conv)未 pin → 最后当前 owner 未 pin。pin 永不淘(除非 pin 总量超 50% 容量,此时最旧 pin 降级可淘——防 pin 滥用撑死池)。
3.5 store 传递 owner
store(tool_name, content) → store(tool_name, content, owner: Option<&str>)。调用方在 agentic loop / sub_agent 处已知 conv_id,传入即可。旧两参签名内部转调 store(.., None) 兼容。
4. 风险与对策
| 风险 | 对策 |
|---|---|
| pin 滥用撑死池 | §3.4 降级规则 + pin 总量监控日志 |
| EvictionLog 内存增长 | 50 条上限 VecDeque,单条 ~200B,可忽略 |
| owner 传错 | 软隔离只影响淘汰顺序,不错即退回现状行为,无正确性风险 |
| 兼容 | 旧 store() 两参保留转调;EVICTED_PLACEHOLDER 文案仅在 Log 命中时升级,未命中原样 |
5. 拍板点(2 项)
- 拍板1:pin 是否上限保护(pin 总量超 50% 降级最旧 pin)?建议加(防失控)。
- 拍板2:报告外的哪些工具产出默认 pin?建议本期仅子代理报告,其余观察后再加。
6. 工作量估算
约 0.5-1 天:entry 扩展+pin API(2h)+ EvictionLog(1.5h)+ owner 软隔离(1.5h)+ 两展开点富提示(1h)+ 单测(2h,现有 6 个 namespace 测试全保留+新增 pin/淘汰清单/隔离顺序 3 组)。