Files
DevFlow/docs/02-架构设计/专项设计/namespace淘汰治理-设计-2026-10-04.md
lxy b994cf2c54 文档: 设计定稿与评估纪律登记
- 无人值守长任务设计定稿,含效率与可观测补遗
- u-relay wire 协议规格与五项评估结论
- 新能力引入评估纪律五项清单
- todo 销账与狗粮短板分析登记
2026-10-04 16:27:32 +08:00

5.4 KiB
Raw Permalink Blame History

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. 设计目标

  1. 报告类内容不可淘汰(pin 机制):子代理报告、用户显式产出的长文标记 pin,LRU 跳过;
  2. 淘汰可感知:淘汰发生时记录「淘汰清单」,下次展开引用时给出结构化提示(含原工具名+参数摘要+淘汰时间),而非裸 EVICTED_PLACEHOLDER;
  3. 隔离互踩:store 增 owner 维度(conv_id 或子代理 id),淘汰优先跨 owner 不回收他域(软隔离,不引入硬配额复杂度);
  4. 零 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 时:

  1. 查 EvictionLog 命中 → 返回富提示:[结果已淘汰] 原为 read_file(src/main.rs 前 80 字…) 于 3 分钟前因容量淘汰。可重新调用 read_file 取回。
  2. 未命中(跨会话残留/未知)→ 现 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 组)。