Agent 工程 · 开源插件

我把 DeepSeek Harness 的日志变成了 Agent 的自诊断医生:loop-doctor 插件家族开源

日志不是写来存档的,是写来被读的。loop-doctor 让 DeepSeek Harness 读自己的 SessionEvent 日志做自诊断——确定性弯路检测、回放验证的建议、人审之后的修复沉淀。

2026-08-20 约 4600 字 阅读约 13 分钟 DeepSeek Harness 插件 自诊断 开源
Agent 核心通过诊断透镜检查 SessionEvent 日志,并把验证后的修复反馈到下一次运行
loop-doctor 的目标不是给 Agent 多一层“智能”,而是让已经发生的运行事实可测、可审、可复盘。

DeepSeek Harness(dsh)有一个很扎实的设计:它把每一次运行事实——重试、工具调用、上下文压缩、子代理委派——原原本本地写进一条只追加的 SessionEvent 日志。但很长一段时间里,我意识到一个尴尬的事实:日志写了,却没有人读

Agent 可以疯狂重试、反复调用同一个失败的函数、把上下文搅成一团、把提示词撑得越来越臃肿——而唯一「看见」这些问题的,只有月底账单上的 Token 消耗和越来越慢的响应。没有人在日志层回答那个最基本的问题:这次会话,到底浪费在了哪里?

所以我把这件事做成了一个插件家族 loop-doctor:让 harness 读自己的日志,做自诊断。项目已开源:Hubert-hwk/dsh-loop-doctor(已打 dsh-plugin topic)。

先给结论:loop-doctor 不尝试“让模型猜自己哪里错了”。它把诊断拆为四个可审计的职责:日志折叠出确定性信号、精确日志上的反事实回放、人工把关的写入、以及让 Agent 按需读取诊断的工具面。

核心思路:观察在前、建议在中、写入在后

整个家族遵守一条铁律:观察在前,建议在中,写入在后;写操作永远置于人工复核之后。它不是一个「全自动自我修复」的黑魔法,而是一套把「诊断」变成工程闭环的系统:

SessionEvent
追加日志
detector
确定性折叠
DetourSignal
带证据事件
advisor
建议 + 回放
人审台账
修复沉淀
loop_doctor_diagnose 可按需读取信号;被采纳的修复热重载回 advisor,影响下一次匹配,但不会越过人工写入边界。

日志流进入 detector,折叠成弯路信号;信号交给 advisor,映射成建议并做回放验证;建议进入 apply,走人工复核台账;被采纳的修复沉淀下来,下次匹配时自动注入——同时,agent 还能通过 tool 提供的 loop_doctor_diagnose 按需诊断自己。

四个包:detector / advisor / apply / tool-diagnose

detector:确定性规则,不调用 LLM

检测是纯函数式的:patterns.ts 把日志流折叠成五类 DetourSignal——retry-storm(重试风暴)、tool-misuse(工具误用)、context-thrash(上下文抖动)、prompt-bloat(提示词膨胀)、effect-churn(效果空转)。全程没有一次模型调用:弯路是机械事实,不该由 LLM 来「感觉」。规则先行,是这条链路的信任基石。

这里“确定性”有两个很实际的含义。第一,同一份事件流永远产出同一组信号,事故复盘时团队不用争论模型当天的采样温度;第二,每个信号都带着按日志顺序排列的证据事件,审阅者可以一路点回 tool/calltool/resultllm/retry。诊断结论不是一段像解释的自然语言,而是一条可回放的证据链。

五类弯路,分别在抓什么?

信号日志上的机械证据它真正提醒的风险默认阈值
retry-storm单 turn 多次 llm/retry,或连续相同的工具与参数模型没有吸收上一次结果,或者重试预算失控重试 ≥ 2;相同调用 ≥ 3
tool-misuse同一工具跨 turn 重复失败,且失败后仍继续复用“工具报错”不等于误用;关键是失败模式在复发错误 ≥ 2
context-thrash频繁 compaction、非用户注入、或委派/hook 事件异常多上下文预算被系统性挤爆,而非某个回答偶然变长3 / 15 / 20
prompt-bloat连续的 request/header 中 system prompt 严格增长注入策略在积累,模型可见信封越来越臃肿连续增长 ≥ 3 次
effect-churn同一 step 同时出现 retry 与工具错误副作用反复回滚,重试和工具失败在互相放大事件组合触发

阈值不是藏在代码里的魔数。插件把它们做成部署可配置项,并且会对非法配置 fail-loud。比如把“重试风暴”从 2 改成 5,表达的是团队接受更大的重试预算;这应是一项可评审的运营策略,而不是检测器悄悄改变了标准。

面试常问:为什么不用 LLM 做日志异常检测,反而写规则?

回答:两者分工不同。重复调用、错误复发、header 连续增长都可以由事件事实严格判定,用 LLM 会引入不稳定、额外成本和不可复现性。LLM 可以在“如何解释、如何写建议”这一层参与,但不能成为“是否真的发生弯路”的裁判。对于未知模式,可把 LLM 放在离线挖掘候选规则的位置,再经人审固化进确定性检测器。

advisor:回放验证——verified 和 simulated 严格区分

信号只是「你绕了路」,建议要回答「这么改能省多少」。advisor 用修复模式表把信号映射成 Suggestion,再对精确日志做一次回放模拟:能量化出可测量节省的,标记为 replay-verified;只按策略上限估算的,标记为 simulated——两者绝不混同,后者也永远不会驱动自动应用。

这里的 replay 不是“再跑一遍 Agent,希望它表现更好”。它从已经发生的那条日志出发,对一个具体规则做反事实计数:例如连续相同工具调用从第 2 次开始提醒,原日志中第 3、4 次调用就被计为可避免;把 retry budget 固定为 2,超过预算的等待时间就可以精确相减。输入仍是同一份日志,所以 before、after 和 avoided 都可追溯。

两种证据必须分开标:
  • replay-verified:修复规则能对精确日志做行为级重放,得到可测的调用数或 retry 延迟节省;
  • simulated:例如把 compaction 上限设为 2,能算出“超出政策上限多少次”,但不能诚实地声称 Agent 在新政策下必然会怎样行动;
  • expert / unproven:经验上合理、却不能从日志量化收益的模式,只能作为待审建议,绝不能借 verified 的名义自动落盘。

面试追问:replay-verified 是否等于因果证明?

回答:不等于。它证明“在这条已发生日志和这个明确的规则模型下,某个可计数指标会减少”;它不证明真实世界里模型会以同样方式重规划。因此项目把行为可重放、政策算术模拟和专家经验分层展示。这个边界正是把可观测性工具做得可信的关键。

apply:写入面——人审台账 + 自动应用闸门 + 修复沉淀

整个家族唯一的持久化写入在这里:一份人工复核台账、一道默认关闭的自动应用闸门(只放行 replay-verified 且置信度 ≥ 0.9 的修复)、以及一份会增长的「已采纳修复」沉淀(accepted-fixes.jsonl)。沉淀会热重载进 advisor 的实时模式集——改一次,之后的会话都受益

“写入面集中”是一个容易被忽略的架构决定。detector 可以实时订阅 event firehose,advisor 可以反复给建议,但它们都不修改 Agent 行为。只有 apply 拥有台账和沉淀文件的写权限,于是一次修复天然具有审计记录:谁批准、依据哪个信号、回放节省多少、最终写入什么策略。

自动应用闸门默认关闭也不是保守姿态,而是承认“节省 token”和“提高任务成功率”不是同一个目标。一个更激进的 retry budget 可能节省等待,却提前放弃了偶发可恢复的请求;只有在可测收益、置信度、影响范围和回滚方案都达到门槛时,自动化才有资格跨过人审边界。

tool:模型面——loop_doctor_diagnose

一个面向模型的工具:agent 可以随时对自己当前会话调用 loop_doctor_diagnose,拿到「检测到的弯路 + 建议 + 验证状态」的结构化报告。诊断是 on-demand 的,不阻塞主循环。

这一步把“运维人员看 dashboard”延伸为“Agent 在合适的时候也能看自己的运行病历”。但它仍是只读工具:模型看到的是结构化信号、证据摘要与建议,不是拥有写配置或修改台账的权限。这样即使 Agent 误判了自己的处境,也最多多读一次诊断,而不会把一次幻觉升级为一次不可审计的配置变更。

安全基线:为什么它不敢「确定」

自诊断系统最危险的失败不是“漏报一次重复调用”,而是把自己的一次猜测包装成事实,再自动写回运行环境。所以 loop-doctor 把事实、估计和决定刻意拆开:事件日志是事实;signal 是确定性规则对事实的解释;replay outcome 是带前提的估计;批准和应用才是人或受控策略做出的决定。

  • 规则先于 LLM:检测路径确定性执行,不经过任何模型调用;
  • 置信度上限 0.9:规则引擎从不声称「确定」,专家标注的模式显式标记为未验证;
  • replay-verified ≠ simulated:只有基于真实日志、量化出节省的回放才算 verified;
  • 写操作在人审之后:自动应用默认关闭,仅限 replay-verified 且达置信度上限的修复,且每一条都进台账供审计;
  • 两层诚实:keyless 快照证明的是 pipeline;「真实模型自然绕路」的涌现性证明需要带 key 运行,文档按配方说明、绝不声称已验证。

面试常问:这个系统最重要的不变量是什么?

回答:“检测和写入解耦”。检测只消费追加日志并返回带证据的信号;建议和回放不改 Agent;所有持久化决策集中在 apply,并且自动应用默认关闭。这样即使检测阈值调坏,影响也停留在建议质量,而不是直接污染生产策略。

验证:140 个测试与 keyless 快照

独立性是第一位的:仓库 clone 下来 pnpm install 即可复现——typecheck 全绿、140 个测试全过(detector 35 / advisor 54 / apply 35 / tool 10,覆盖规则折叠、回放验证、台账、沉淀重载等)。

端到端还有一个 keyless 快照examples/headless-agent/loop-doctor.cordis.snapshot.yml):用一个确定性后端在真实 harness 循环里强制制造三次真实弯路,然后在快照内断言完整链路——信号 → 建议 → 台账 → 人工批准 → 沉淀 → 第二次诊断「看见」已采纳修复 → auto-apply 与 reload 闭环。不需要任何 API key 就能复现整条流水线。

我把验证拆成两层,是为了不混淆“系统接线正确”和“模型行为真的被改善”。前者应该在无 key、可重复的快照里做:同样的事件必然得到同样的 signal、suggestion 和 ledger。后者必须在带真实模型、真实工具和真实延迟的评测里做,至少同时看任务成功率、端到端时延、token、工具错误率与误报率;项目不把后一类尚未完成的实验伪装成前一类单测已经证明的结论。

如果把它接到生产,我会加四个 dashboard 指标:
  • 信号触发率与人工确认率:判断阈值是否太松或太紧;
  • 每类修复的采纳率、回滚率和真实收益:验证建议是否有用;
  • Auto-apply 覆盖面:确保它始终只占极窄、可控的区间;
  • 按模型版本 / 工具版本切片的 detour 分布:避免把一次上游回归藏在总体平均里。

上手

git clone https://github.com/Hubert-hwk/dsh-loop-doctor.git
cd dsh-loop-doctor
pnpm install
pnpm run typecheck   # tsc 全家族
pnpm test            # 140 tests

四个包本就按 harness 单体仓库的 workspace 包编写,未来上游开放贡献时可以直接 rebase 回去。

面试里怎样讲清这个项目

面试常问:这和 LangSmith / tracing 平台有什么区别?

回答:Tracing 解决“把发生了什么记录和展示出来”,是必要底座;loop-doctor 在它之上,把特定的 SessionEvent 语义折叠成可执行的 detour 信号,再连接回放、建议、人审和沉淀。它不是替代 observability 平台,而是把 observability 往“可审计诊断闭环”推进了一层。

面试常问:为什么不让 Agent 直接根据诊断自己修 prompt?

回答:因为诊断到修复之间隔着因果不确定性和权限边界。诊断信号只证明某种运行模式出现过,并不自动证明某个 prompt 改动是最优修复。项目允许模型读诊断来调整当前策略,但持久化修复必须经过 replay 标记、置信度门槛和人审台账,保证可解释、可回滚。

面试追问:如何避免规则越来越多、维护失控?

回答:每条规则必须有明确事件语义、可配置阈值、最小证据集、稳定的去重键,以及至少一个正例/反例测试。新增规则先以观察模式上线,记录人工确认率;只有在误报和收益达到门槛后,才绑定 fix pattern 或进入 auto-apply 候选。规则库不是“经验 if-else 堆”,而是一份带证据契约的策略资产。

开源与社区

这个家族最初是作为对 deepseek-ai/deepseek-harness 的上游贡献写的,但官方目前不接受外部 PR(见其 CONTRIBUTING.md),所以先以社区独立仓库的形式开源,让想用的人用得上、想讨论的人有地方讨论:

  • 仓库:Hubert-hwk/dsh-loop-doctordsh-plugin topic);
  • 社区帖:DeepSeek Harness GitHub Discussions 的 Show Your Plugins! 分类;
  • 设计笔记:仓库内的 Agent Note(.agents/notes/implemented/feature/2026-08-19-loop-doctor-self-diagnosis)。

我一直觉得,「让系统看见自己」是 Agent 工程里被低估的一环——日志不是写来存档的,是写来被读的。如果你也在做类似的观测、诊断、自优化方向,欢迎到 Discussions 或 GitHub 上一起聊。

参考资料

  1. dsh-loop-doctor:项目 README、包结构、测试与端到端快照。
  2. DeepSeek Harness:宿主运行时与 SessionEvent 日志语义。
  3. DeepSeek Harness CONTRIBUTING:上游当前的外部贡献策略。
  • Copyrights © 2024-2026 Hwk