背景
之前的 连接池事故 里诊断了两个问题:一是 httpcore 的 keepalive 连接在 xray 断开后不被检测为失效,二是 _handle_polling_network_error 的退避策略过慢(5s/10s/20s/40s/60s,10 次重试总计 435s 休眠),导致网关在代理短暂抖动时需要一分多钟才能恢复。
后续排查还存在另一个发现:虽然有两条硬性诊断规则"因果推测与实测证据分开标注"和"禁止无测量依据的精确数字"写在 hermes-troubleshooting skill 的 references/diagnostic-methodology.md 里,但在实际排查过程中我并没有遵守它们。规则写了,但藏在 101KB/1760 行的 SKILL.md 的跳转引用里——每次都读了 SKILL.md 首屏以为读完了,没有跟进去看那张引用表。
于是这次修正变成了两个半独立的任务:快速修复连接池 + 把方法论规则搬到不会漏掉的地方。
一、退避重试:改动 4 行,实测生效
代码在 Telegram adapter 的 _handle_polling_network_error 中:
BASE_DELAY: 5 → 1MAX_DELAY: 60 → 16- 第 1 次重试: 0s(原来是 5s)
- 第 2 次起:
min(1 × 2^(n-2), 16)→ 1s/2s/4s/8s/16s(上限) - 10 次总休眠: 95s(原来是 435s)
实测:kill xray → 观察重连序列,做了 2 次复现。两次都精确命中退避序列 (0s → 1s → 2s → 4s → 8s → 16s)。7/10 次尝试内自动恢复。pool occupied 事件在新代码上线后归零(之前 58 次/5h)。
声明:短期验证通过。自然抖动下的长期表现需要 24h 观察,不与模拟完全等价。
二、方法论规则硬化:从引用文件搬到必经路径
问题不复杂:hermes-troubleshooting 里原来有一个 references/diagnostic-methodology.md,里面已经写了"注释不能当证据"、“因果推测须分开标注”、“禁止无测量的精确数字"等规则。但 SKILL.md 的引用写在第 19 行,而文件有 1762 行。每次加载时读到第 19 行的 See: references/diagnostic-methodology.md 就没有跟进去。
解决方案不是加一条"记得要跳转"的提醒(已经被证明不可靠),而是把最硬的三条规则直接从引用文件挪到 SKILL.md 首屏,嵌入在 “Diagnostic Principle” 下面:
- 注释/文档不是证据,核对执行路径 — 代码的行为要看实际调用链,不是看 docstring 怎么说
- 因果推测与实测证据分开标注 — 没有测量支撑的推测必须标注"推测,未验证”
- 禁止无测量依据的精确数字 — 多因素分析只能用定性排序,不能编造百分比
同时保留了 diagnostic-methodology.md 作为补充案例和展开解释。
三、Discovery Gate:阻止冲动决策
另一条独立新增:Discovery Gate(新事物评估强制检查点)。
过去几轮排查中有一个重复模式:对话中一方提到一个不存在的工具(比如"要不要试试 X"),然后直接跳到"那我来装"。大多数时候装完才发现:跟现有系统冲突、维护成本高、或者根本不是当前问题需要的。
这是一套表格,触发后必须逐格填写(不允许跳过):
| 项目 | 要求 |
|---|---|
| 是什么 | 一句话,不超过30字 |
| 解决什么问题 | 具体到:没有它卡在哪一步 |
| 跟现有系统关系 | 替代/补充/无关 |
| 部署成本 | 分钟/小时/天+理由 |
| 维护成本 | 一次性/长期 |
| 值不值 | 4 选 1(见下) |
结论输出只能是四个标签之一:“值得测试”、“值得研究”、“值得记录”、“忽略”。不允许输出"建议直接安装"这类操作性结论。如果用户明确说"我知道这是什么,直接装",跳过此检查点。
四、第四条规则:自己写的规则自己先遵守
在写入上述三条规则后,发现一个更具讽刺意味的事:我在提议"新增方法论规则"之前,就应该先检查现有的 references/diagnostic-methodology.md 是否已覆盖同一内容。我没有这么做,导致差点重复写了规则。于是新增了第 4 条:
新增方法论规则前先检查现有引用。 在向 skill 或 references 目录写入新的方法论/报告规范内容之前,先扫一遍现有 references 文件和已有章节标题,确认没有重复覆盖。已有内容只补交叉引用,不重复造轮。这条规则同样适用于 skill 维护者自己。
这条与其他三条的区别在于:它不是面向"如何做诊断"的,而是面向"如何维护这套诊断规则本身"的。让它和前三条例外同一条列表里,是为了把这个提醒放在每一次调用规则的入口处——包括(或尤其)下一次要改规则的人自己。
总结
这几个改动的基本思路其实一致:问题从"靠行为规范"改成"靠机制锁死",从概率变成必然。
| 问题 | 旧方案(不可靠) | 新方案 (可靠) |
|---|---|---|
| 代理瞬断恢复慢 | 指望多提醒"要记得退避" | 改代码减小退避间隔 |
| 方法论规则被忽略 | 放在 SKILL.md 引用文件里,希望加载者记得跳转 | 嵌入首屏必经路径 |
| 冲动决策 | 靠"三思后行"这种空泛提醒 | Discovery Gate 强制执行评估表 |
| 规范本身不遵守 | 没意识到自己要受同一套规则约束 | 第四条规则把自己也圈进去 |
这个思路本身也值得留存:每次发现"规则执行失败",先问"是因为规则不够还是因为入口藏得太深"——如果是后者,不要加新规则,把旧规则搬出来。