自托管记忆引擎大检修 - 9 模型大战、僵尸定时任务,与“上限只是保险”哲学
TL;DR
- 我花了三天对自托管记忆引擎(Honcho)的召回回路(dialectic)做全面翻修:9 模型实测大战 → 僵尸定时任务事故 → 配置哲学之争
- 最终架构:记录用 glm-5.3-flash(包月免费),日常召回用 haiku-5.5(实测 $0.0135/次),深度研究(max)单独换成 glm-5.3+thinking MAX(免费,实测 178 秒)
- 上限(轮数、输出 Token)不是省钱工具,而是防发散的保险 -- 统一设为服务器允许的最大值才是正解
- 最大的教训:源码默认值里藏着"每个等级用不同模型"的隐含假设。 一旦打破这个假设,默认值就变成毒药
背景:赢下基准测试只是前一半
在上一篇文章里,haiku-5.5 赢下了 6 路召回后端实测。但基准夺冠只完成了一半。落地生产 → 扛过事故 → 确立配置原则,自己管服务器就是这么回事。本文是后半场的记录。
9 模型大战的完整记分板
用同一协议(3 事实召回 × 10 次)打真实的 dialectic 管线:
| 实验 | 模型 | 结果 | 判定 |
|---|---|---|---|
| EXP3 | recursive/flint-v1.0:free | 准确率 71% | 免费的代价 - 不推荐 |
| EXP3b | mistral-nemo ($0.03/M) | 事实准确率 0%(合成失败) | 弃用 |
| EXP3c | nemotron-3-ultra-550b(本地网关) | 9 次中 5 次 120 秒超时 | 单次调用稳定性在多次调用放大下崩塌 |
| EXP3d | qwen3.5-flash | 因诚实的"无信息"拒绝在筛选出局 | → 触发 haiku 复测:带上上下文一切都不同 |
| EXP3e | haiku-5.5 | 20.9s · 事实 30/30 · $0.0135/次 | 👑 夺冠 |
| EXP3f | haiku + Anthropic 原生缓存 | 缓存无效 | cache_control 标记只挂在 system 上,覆盖不到主体 |
| EXP3g | gpt-6-luna | 13.7s 破纪录,成本仅 18% | 质量不达标 - 速度冠军毫无意义 |
| EXP3h | haiku + thinking off | 13.1s 但准确率 100→62% | 实证 thinking 是合成质量的核心 |
最令人印象深刻的是 EXP3e 的元诚实:它在召回回答里主动识别出"F1 0.92 这个数字来自 Honcho 实验提示词原文",并与我的原话区分开。在筛选阶段让它出局的那种诚实拒绝,在挂上真实记忆上下文后升华为准确性。
贯穿全部实验的教训:单发筛选 ≠ 管线性能。 单发 3.8s 的免费模型在 16K 上下文的 dialectic 上平均 86 秒、超时率 20%。选型必须用真实负载跑 10 次端到端。
僵尸定时任务:自动化倒转了自己的配置
整个战役中最毛骨悚然的一幕。为实验监督搭的 n8n 门控早已草草收场,但它内部的5 分钟定时任务还活着,晚上 9 点 20 分自己复活,把进行中的实验的 .env"恢复"(=回滚)了。正在复现的实验被一个本不该存在的配置杀掉。
对策就是源头切断:
- 停掉 n8n + 清扫所有僵尸执行
- 给
.env上chattr +i(不可变)- 文件级防火墙 - 基准设施从 n8n 迁到 Windmill(Postgres 持久队列、步骤级并行)
教训:自动化监督者必须有寿命。 一次性任务的门控以永久定时任务的形式存活下来,早晚会咬主人一口。
落地阶段的两个坑
- API Key 路径:
MODEL_CONFIG__API_KEY_ENV会被静默忽略 - 必须写OVERRIDES__API_KEY_ENV。症状(401)离病因(配置位置错误)十万八千里,排查花了很久 - thinking 上限:关掉 thinking,haiku 崩到 62%(见表)。"默认最优"已写进注释刻死
验证工具本身的坑
docker exec -e VAR=x覆盖测试不生效 - 应用启动时执行load_dotenv(override=True),挂载的/app/.env永远赢。要确认生效值只能在容器内直接内省 settings- 在 env 里写
MAX_OUTPUT_TOKENS=null(想要全局回退)会因未设置env_parse_none_str而验证崩溃、服务器拒绝启动。写同值显式覆盖才是正解
源码默认值的隐含假设:被倒转的轮数阶梯
Honcho dialectic 各等级(minimal–max)的源码默认轮数是 1/5/2/4/10 - 一个 low 比 medium 高 2.5 倍的非单调阶梯。翻出引入提交后发现:
# TODO: Fill in appropriate values for each reasoning level
作者本人留下的注释承认这些是手工调的临时值。而这些值的前提是每个等级不同的模型+thinking(最初 low = 用便宜快模型搜 5 次的档位)。当我统一模型后,等级只剩下轮数差异 - 阶梯当场倒转。"等级越高越好"的预期在配置层面不再成立。
上限哲学:保险就该放在模型极限附近
在此我确立了自己的原则:上限不是省钱工具,是防发散的保险。
- 压低输出 Token 上限省不了钱 - 计费按实际生成为准,一旦截断,input+推理费用照付、可见回答为零。OpenAI、Anthropic、Gemini 官方文档都在警告这一点;Gemini 更是直说"别压 max_output_tokens,去降 thinking 档位"
- haiku-5.5 官方最大输出 128K,但 Honcho 配置校验上限
le=100000→ 全等级统一 100000(设 128000 服务器会拒绝启动) - 轮数同理:校验上限
le=50(工具循环硬上限 100)→ 全等级统一 50。现代模型会自适应地在 1–3 轮内自己收尾,实际开销不变,50 纯粹是最坏情况的天花板
出发点是这个信念:现代模型自己就能选好合适的推理量和轮数。 既然如此,上限不该是调教模型的工具,而应该只在真正发散时兜底的保险网。
effort 默认值是有官方明文的(但是……)
我一直知道"haiku 用默认 thinking 最优",但默认到底是多少?官方文档回答:haiku-5.5(和 opus 5.5)默认 effort 为 medium - 其他模型默认 high。thinking 永远开启(adaptive)。
有趣的是这个实测矛盾:官方声称"设为默认值与省略完全相同",但 dialectic 实测中显式 medium 96.8s vs 省略 20.9s - 差了 4.5 倍。我的推测:adaptive 的本质是连"要不要思考"都由模型自掸,显式指定 effort 会把这个掸子固定住。无论如何,保持不指定的结论被双重确认了。
最终架构与成本
| 角色 | 模型 | 成本 | 实测 |
|---|---|---|---|
| 记录(deriver/summary/dream) | glm-5.3-flash + thinking max | 包月免费 | 常驻 |
| 日常召回(low) | haiku-5.5(不指定 thinking) | $0.0135/次 | 15–21s |
| 深度研究(max) | glm-5.3 + thinking MAX | 免费(包月) | 178s |
| 搜索嵌入 | qwen3-embedding:4b | 本地 Ollama 免费 | - |
日常召回便宜又快,"真往深了挖"的请求走免费慢速档。轮数 50 / 输出 100000 是全链路共用的保险。
遗留事项
- 每轮自动注入(perTurn)关闭的 2 周实验 - 11 月 13 日前后复评
- Honcho v3.0.3 → v3.0.9(145 commits)升级 - 因构建/迁移问题继续搁置
通用化的要点
- 模型基准要用真实管线负载跑 10 次端到端。 单发筛选只会给出错误答案
- 给自动化管线设寿命。 活下来的定时任务早晚会回滚你的配置
- 源码默认值里藏着假设。 打破这些假设的部署(例如统一模型)值得重新审查默认值
- 上限是保险。 算好保费(所需 Token),把它设在模型极限附近 - 而不是低得危险
- 验证要看应用的生效值。 env 变量覆盖在
dotenv override=True面前毫无还手之力


