架构决策记录 — 2026-07-23
本文记录今日的架构调研结论、设计决策和实现产出。
事件 :deepseek-lhh API key governor 故障
现象:今日 1092 个任务失败(过去1小时813失败、0完成),错误签名 "error result: success"。
根因:deepseek-lhh API key 被 DeepSeek 侧 governor 拒绝(认证失败)。
处置:
- 确认新 key 写入 DB(
sk-8cb106e6...),直连 DeepSeek 测通 - 批量 reset:排除3条真实内容问题(iteration-limit / corpus-qc),reset 1004 条为 queued,81条超大书回 paused
- 验证:重排后3分钟内零新增 governor 失败,系统恢复
教训:模型层故障需要更快熔断——参考 litellm-thinking-400 事故(thinking-400 incident),1338 任务失败19小时无熔断的教训。
调研:grow 阶段上下文与 token 消耗
阶段执行机制确认
每个 grow phase 是独立 Claude Agent SDK 会话,上下文不跨 phase 共享。跨 phase 的状态桥是磁盘文件(GROW.md / grow_state.json / 页面文件)。
下面是当时旧 grow 流程的事实记录。Service 现已统一使用 Life step:不设置默认
max_turns,step 内按上下文窗口自动 compact,step checkpoint 后开启新 session,
不再用“600 turns + 同会话 resume”管理长任务。详见
生命周期执行、模型路由与并发。
同一旧 phase 内曾有两种续跑机制(均延续同一会话,上下文累积):
- max_turns 续跑(已废弃):跑满600轮未收尾 →
resume=session_id续同一会话 - verify-at-exit 补写(旧流程):phase 收尾验收发现缺产物 → resume 补写一次
语料加载:已经是按需检索,非预加载
结论:doc_final.md(可达 13MB+)不会被整份读入上下文。
引擎通过 corpus_search.py + pn-source.json 实现按 需检索:
- NEW1 建页时调
corpus_search.py "{实体名}" --max 10,只返回10段命中文本(~1K) pn-source.json是预建的段落索引,查找速度快- 建页 max=10(不是 20,20 是选页阶段用的)
影响:语料侧已优化到位,"语料读取是 token 黑洞"的假设错误,无需继续在此方向优化。
真正的 token 消耗来源
| 来源 | 量级 | 可优化 |
|---|---|---|
| GROW.spec 当前 phase 段(phase 2 约950行) | 中 | Sub-stage 化可降 |
| pages.json 反复加载(全量719K,1442页) | 大 | 改用 pages.lite.json 可省350K/轮 |
| 多轮 resume 上下文累积 | 大书最痛 | Sub-stage 化切断 |
| corpus_search 多次调用 | 已优化 | — |
优化机会:pages.json → pages.lite.json(未实施)
调研发现 pages.lite.json(347K)已经存在且含查重/wikilink 所需全部字段(type/label/aliases/path),但 spec 里所有查重调用都用 pages.json(719K)。
切换收益:1442页大书 phase 2 后期,每轮 pre-flight + 查重调用省约350K,几百轮累计巨大。
决策:未实施,待后续 RFC 推入引擎层。
调研:多 agent 架构现状
三层 agent 架构(均已存在)
层1 — job 级并行:调度器同时运行多个 wiki job,互不干扰。
层2 — 会话内 Task fan-out:
- 每个 grow/butler 会话
allowed_tools含Task MEMEX_MAX_SUBAGENTS=4控制并发上限subagent_model支持子 agent 使用不同(cheaper)模型- 当前 spec 主动选择串行(NEW1 spec 明确"禁止并行"),Task 工具虽开放但未 fan-out
层3 — 监工 supervisor:独立 LLM 判定层,带防抖和审计的护栏执行。
grow 串行建页的原因(推测)
grow spec 选择串行建页(非 Task fan-out)可能的原因:
- 质量可控:逐页串行便于保持"每句有据"铁律一致性
- 写冲突:并行写 pages.json 可能导致注册表冲突
- 历史决策,尚未有 RFC 评估 fan-out 的可行性
决策:fan-out 建页是潜在优化方向 ,但需 RFC 论证,本次不实施。
设计与实现:幻觉检测模块
背景
引擎 W7 幻觉控制框架(H1-H5)设计完整,但执法工作散落:
- H1 出处核验(W7)已实现但只在 butler 会话内手动触发
- H2-H5 全部未实现
- Harness 侧的确定性检测器(HCK14/20/9)没和 W7 分层对齐
- 没有自动触发机制
关键设计决策
决策1:Harness 侧执法,引擎零改动
信号来源:引擎已写的 logs/butler/actions.jsonl(每次 NEW1/RCH 建页后记录)。
Harness 通过 watermark 机制增量读取,不依赖引擎推送通知。
决策2:异步队列,不阻塞主流程
NEW1 建页完成后立刻继续建下一页,幻觉检测异步处理。队列攒批(默认5页),由 scheduler_tick 的 sweep_hallucin_queue 后台线程触发。
决策3:确定性优先,LLM 仅处理灰色地带
coverage < 0.1 → 确定性错误,直接标红(0 token)
0.1~0.3 → UNCERTAIN,进 LLM deep queue(按需)
coverage ≥ 0.3 → 通过(0 token)
大量明显幻觉(coverage 极低)被免费抓住,LLM 只处理真正模糊的案例,节省90%+ 以上的检测 token。
决策4:修复任务直接用引擎 gene 代码
RepairWriter 写入 queue.md P2 时使用引擎认识的 gene 代码(FIX9-quote-attribution-audit、COR9-offline-citation-integrity 等),butler 直接执行,无需额外映射层。
实现产出
新增文件:
src/memex/hallucin/
├─ __init__.py
├─ models.py # PendingItem / ScanFinding / DeepPendingItem / SweepResult
├─ queue.py # HallucinQueue + HallucinDeepQueue
├─ scanners.py # CitationScanner + PnScanner + Quo23Scanner + ScannerRegistry
├─ sweep.py # HallucinSweep(run / run_deep / verify_repaired)
└─ repair.py # RepairWriter
src/memex/agent/hallucin.py
config/harness/hallucin-sweep/SKILL.md
集成改动:
api/scheduler.py:新增sweep_hallucin_queue(),挂入scheduler_tick
后续待办
| 事项 | 优先级 |
|---|---|
| 真实 wiki 上跑第一次扫描,验证 coverage 阈值是否合理(0.1 / 0.3 可能需调参) | P0 |
| H2-H5 gene 补全(引擎侧 RFC) | P1 |
| pages.json → pages.lite.json 切换(引擎侧 RFC) | P1 |
| grow sub-stage 化(大书 phase 2 context 优化) | P2 |
| fan-out 建页 RFC(Task 工具并行评估) | P3 |