172 lines
10 KiB
Markdown
172 lines
10 KiB
Markdown
# 「上下文到量 ⇒ 开接续会话」机制 · 为什么没运行 + 强化
|
||||
|
|
|
|||
|
|
> 时间:2026-09-30 18:27–18:45(本机)|会话:`6ecf6d98`
|
|||
|
|
> 用户原话:「**那个上下文到达一定量 就开接续会话的机制 没运行,强化一下**」
|
|||
|
|
> 产出:本文件 + 改 `settings.json`(补钩子)+ 改 `state.py`(加闸门自检)
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 0. 一句话结论
|
|||
|
|
|
|||
|
|
**机制一行代码都没坏 —— 是它的「触发源」被人整段删掉了。**
|
|||
|
|
|
|||
|
|
`stop-dialog-guard.py`(唯一负责「到量就提醒收口」的钩子)挂在 `UserPromptSubmit` 事件上;
|
|||
|
|
**2026-09-26 21:17 那次改 `settings.json` 把整个 `hooks` 段清空了**,之后三天只补回了两个别的钩子,
|
|||
|
|
**它再也没被注册回去** ⇒ 从 **09-26 19:19** 起静默失效 **4 天**,直到今天你发现。
|
|||
|
|
|
|||
|
|
已修:钩子已补回 + 实测注入正确;并给 `state.py`(开工第 0 步)加了 **【闸门】自检**,让它不可能再静默失效。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 1. 根因(全部为实物证据,非推断)
|
|||
|
|
|
|||
|
|
| # | 证据 | 读数 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| 1 | 备份文件 `settings.json.bak-decision-20260927-233116` | mtime = **2026-09-26 21:17**,**`hooks` 段 = 空** ⇒ 那一刻被整段清掉 |
|
|||
|
|
| 2 | 钩子日志 `.workbuddy/stop-dialog-guard.log` | 最后一条 = **2026-09-26 19:19:29**(09-26 21:17 之后再无任何记录) |
|
|||
|
|
| 3 | 对照工作区 `ai1net-dsh-desktop` 同名日志 | 最后一条 = **2026-09-26 17:01:10**(同一时段一起停) |
|
|||
|
|
| 4 | 本工作区日志事件分布 | **`UserPromptSubmit` × 115 / `Stop` × 0** ⇒ 这个钩子修好后要挂 `UserPromptSubmit`,`Stop` 在本机**从未被调用过** |
|
|||
|
|
| 5 | 另外三个闸门的日志 | `skill-load-guard.log` 停在 09-26 19:19|`bash-guard.log` 停在 09-26 19:22|`lock-hook.log` 停在 09-28 10:47 ⇒ **四个闸门一起停** |
|
|||
|
|
| 6 | 水位档位文件 `.workbuddy/.budget-alert-level` | 仍是 `b303ef70…\t2`(09-26 那次报的第二级)⇒ 之后没人再写过 |
|
|||
|
|
|
|||
|
|
**结论**:不是脚本坏了、不是水位算错了 —— **只是没挂上去**。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 2. 为什么整整 4 天没人发现(三道自检全瞎)
|
|||
|
|
|
|||
|
|
| 自检 | 本该发现 | 为什么没发现 |
|
|||
|
|
|---|---|---|
|
|||
|
|
| guard 自带的 `path_health()`(钩子路径体检) | 钩子指向的文件/配置异常 | 🔴 它读配置用的是 `WORKBUDDY_CONFIG_DIR` / `~/.workbuddy`,**本机真实配置根是 `CODEBUDDY_CONFIG_DIR = E:\ProgramData\.workbuddy`** ⇒ 读的是不存在的文件 ⇒ 异常被吞 ⇒ **恒返回空、永远静默** |
|
|||
|
|
| `state.py` 开机快照 | —— | ❌ **根本没有"钩子注册"这一节**(它只管锁 / git / 入口 / 收口) |
|
|||
|
|
| 「日志里有行数」 | —— | ⚠️ 没人在意;且它**静默之后连行都不写了**,越静默越像"没事" |
|
|||
|
|
|
|||
|
|
⇒ 这是典型的 **fail-silent**:机制死了,但所有会说话的东西一起死了。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 3. 已落地的修复与强化
|
|||
|
|
|
|||
|
|
### 3.1 修(把触发源接回去)
|
|||
|
|
|
|||
|
|
`E:/ProgramData/.workbuddy/settings.json` 的 `hooks.UserPromptSubmit` 补回一条:
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{ "hooks": [ { "type": "command", "timeout": 10,
|
|||
|
|
"command": "\"…python.exe\" \"D:/github/dsh_shenxian/dsh-server-docs/07-scripts/stop-dialog-guard.py\"" } ] }
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- ⛔ **未加 `-E`**(guard 的 docstring 明写:`-E` 会屏蔽 `PYTHONUTF8` ⇒ 含中文的载荷解码即炸,09-15 实测让它"看起来从没被调用"一整天)。
|
|||
|
|
- 已备份原文件:`settings.json.bak-restoreGuard-20260930-183244`。
|
|||
|
|
- 模式闸刀 `.workbuddy/stop-guard-mode` = `inject` **本来就在**(✅ 无需改)。
|
|||
|
|
- 急停闸刀 `.workbuddy/stop-guard.disabled` **不存在**(✅ 没被误关)。
|
|||
|
|
|
|||
|
|
### 3.2 强化(让它不可能再静默失效)
|
|||
|
|
|
|||
|
|
`state.py` 新增 **§5.5 【闸门】自检**(开工第 0 步就会跑,1 次调用):
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
[闸门] ✅ 关键闸门在册 | PreToolUse×2 SessionEnd×2 SessionStart×1 UserPromptSubmit×3
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
- **关键闸门清单**(当前只有一条):`stop-dialog-guard.py` 必须挂在 `UserPromptSubmit` —— 缺失就显红并打印「该机制现在不会运行」。
|
|||
|
|
- 顺带做 **路径自检**:把 `settings.json` 里每个钩子指向的 `.py` 逐个 `exists` —— **补掉了 guard 那个读错目录的洞**。
|
|||
|
|
- 读配置认 `CODEBUDDY_CONFIG_DIR`(⛔ 不重蹈 `path_health` 的覆辙)。
|
|||
|
|
- 全部 fail-open:读不到配置就打印一行 ⚠️,绝不抛异常。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 4. 实测证据(端到端,⛔ 不认"配置改完了")
|
|||
|
|
|
|||
|
|
把一份**模拟宿主载荷**直喂 guard(`hook_event_name=UserPromptSubmit` + 本会话真实 `transcript_path`):
|
|||
|
|
|
|||
|
|
```json
|
|||
|
|
{"hookSpecificOutput": {"hookEventName": "UserPromptSubmit",
|
|||
|
|
"additionalContext": "⚠️ 上下文已过 **20 万**,本轮收口后建议开新会话。…💰 【会话预算告警】本会话已到
|
|||
|
|
**上下文 245218 token**(一级阈值 120000 token / 80 次工具调用)…"}}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
⇒ **注入通道通、水位算得准**(本会话 245,218 token / 600 次工具调用 ⇒ 二级)。日志同时留痕(`invoked(user-prompt)|mode=inject|…|预算告警=True`)。
|
|||
|
|
自测用的水位档位文件已**还原**,不影响真实首次告警。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 5. 仍然存在的两个洞(本次**未动**,需你拍板)
|
|||
|
|
|
|||
|
|
### 🔴 洞 A:机制末段是"软"的,没有任何检查
|
|||
|
|
|
|||
|
|
链路:`[硬] 到量 → 注入收口指令` → `[软] 模型写接续包` → `[软] 模型调工具登记接续棒` → `[硬] 宿主到点开新会话`。
|
|||
|
|
**中间那两步全靠模型自觉,钩子查不了。** ⇒ 模型一忘,链条就断在倒数第二步,而且**看起来一切正常**。
|
|||
|
|
→ 可强化为:钩子在三级(30 万)时**顺带查一下这条工作线有没有已登记的接续棒**,没有就继续施压(带节流+次数上限)。
|
|||
|
|
|
|||
|
|
### 🔴 洞 B:另外三个闸门至今不在册
|
|||
|
|
|
|||
|
|
`lock-guard-hook.py`(锁纪律)、`skill-load-guard.py`(技能加载)、`bash-output-guard.py`(输出限流)——
|
|||
|
|
**当前 `settings.json` 里一个都没有**(它们的日志全部停在 09-26~09-28)。
|
|||
|
|
本次**只补了你要的接续机制那一个**;其余三个会改变**所有**会话的行为,属"额外发现",按纪律**先报告再动手**。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 6. 泳道图:机制在哪一格断的
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
人/用户 宿主(UserPromptSubmit) stop-dialog-guard.py 模型
|
|||
|
|
────────────────────────────────────────────────────────────────────────────────────────────
|
|||
|
|
发消息 ──▶ 派发钩子 ──▶ 读 settings.json 的 hooks 表
|
|||
|
|
❌【红】09-26 21:17 起这里是空的 ⇒ 钩子根本没被拉起
|
|||
|
|
(后面三格整条悬空:脚本没跑、水位没算、注入没发生)
|
|||
|
|
✗ 模型永远收不到「该收口了」
|
|||
|
|
|
|||
|
|
修复后:
|
|||
|
|
发消息 ──▶ 派发钩子 ──▶ ✅ 表里有它 ──▶ 算水位(245218) ──▶ 注入「已过 20 万,建议收口」
|
|||
|
|
✅ 模型收到
|
|||
|
|
────────────────────────────────────────────────────────────────────────────────────────────
|
|||
|
|
⚠️ 末段(写接续包 → 登记接续棒)仍是**软环节**,钩子看不到 → 见 §5 洞 A
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 7. 事故链:为什么会"静默"失效 4 天
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
改 settings.json(09-26 21:17,别的事) ← 无意之举
|
|||
|
|
↓ 缺防线①:改这个文件前没有"hooks 段不许清空"的护栏
|
|||
|
|
hooks 段被整段清空
|
|||
|
|
↓ 缺防线②:没有"改完回读校验"(改完 settings.json 后没人确认关键钩子还在)
|
|||
|
|
stop-dialog-guard 等四个闸门一起不在册
|
|||
|
|
↓ 缺防线③:guard 自带的 path_health 读错配置目录 ⇒ 自检恒静默
|
|||
|
|
机制死了,但"会说话的东西"一起死了
|
|||
|
|
↓ 缺防线④:没有独立于钩子的"注册表体检"(state.py 当时没有这一节)
|
|||
|
|
4 天无人察觉,直到用户肉眼发现"机制没运行"
|
|||
|
|
✅ 已补:state.py §5.5 【闸门】自检(独立于钩子,开工第 0 步必跑)
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**本该拦住的两道防线**:① 改 `settings.json` 前后做 **hooks 段 diff + 回读校验**;② **独立于钩子的注册表体检**(现已落在 `state.py`)。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 8. 待拍板(一轮一问)
|
|||
|
|
|
|||
|
|
**问题**:另外三个闸门(锁纪律 / 技能加载 / 输出限流)现在**都不在册**,它们的日志同样停在 09-26~09-28。要不要一并补回?
|
|||
|
|
|
|||
|
|
- **A. 一并补回** —— 优点:这四个是同一批、同一根因停的,一次补齐最省事,锁纪律与输出限流都是天天要用的;缺点:它们会作用在**本机所有会话**上,行为变化面比"只补接续机制"大,且需要一次实测确认没误伤。
|
|||
|
|
- **B. 先只保接续机制**(现状)—— 优点:改动面最小、已实测通过;缺点:锁纪律/输出限流继续处于"我以为是开的、其实是关的"状态(和这次同一个坑)。
|
|||
|
|
|
|||
|
|
**我的默认(已按此执行)**:**B**。理由:你这次的要求是"接续机制",A 属额外发现,按 R7 先报告后动手。
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 9. 出处与可复现命令
|
|||
|
|
|
|||
|
|
```
|
|||
|
|
# 看机制到底跑没跑(有行 = 跑了;最后一行时间 = 什么时候停的)
|
|||
|
|
tail -5 E:/ProgramData/AIProject/ai1net-dsh-server/.workbuddy/stop-dialog-guard.log
|
|||
|
|
# 看闸门在不在册(开工第 0 步就会打这一行)
|
|||
|
|
"E:/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe" state.py
|
|||
|
|
# 手动自测(模拟宿主载荷;⛔ 别加 -E)
|
|||
|
|
"E:/ProgramData/.workbuddy/binaries/python/versions/3.13.12/python.exe" \
|
|||
|
|
"D:/github/dsh_shenxian/dsh-server-docs/07-scripts/stop-dialog-guard.py" < <载荷.json>
|
|||
|
|
# 机制规范与成本口径
|
|||
|
|
docs/会话与接续/会话接续规范_20260916.md (§3.2.2 硬/软链路 · §3.2.1 prompt 模板 · §4 机制配合表)
|
|||
|
|
D:/github/dsh_shenxian/dsh-server-docs/04-调整方案/125-会话接续机制-问题复盘与修复.md
|
|||
|
|
```
|