DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

G1en-114 /

dsh-failbook

Verified

失败账本:DeepSeek Harness 工具失败自动记录·签名聚类·跨会话持久化 + 失败感知重试拦截,让 Agent 越用越少犯错,含 Web UI 面板

★ 1 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@cdcb4db6

🧾 dsh-failbook · 失败账本

让 DeepSeek Harness 的 Agent 越用越少犯错:记录每次工具调用失败,按失败原因自动聚类,持久化账本,并在同一错误反复出现时拦住 Agent 的重试——换参数犯同一个错也拦得住。

DeepSeek Harness (DSH) 插件 · 宿主端(Cordis)+ 浏览器端(设置面板) · MIT · 零配置开箱即用

English · 安装 · 配置 · 工作原理 · 对比 · Roadmap


为什么做这个

Agent 干活时最烧钱、最烦人的场景:同一个错误反复重试。

  • command not found: pipx —— 换个写法再来一遍,还是 127;
  • 沙箱拒绝 —— 策略不给权限,硬重试 5 次;
  • npm ERR! —— 依赖没装对,重装 N 遍。

官方 repeat-tool-reminder 只抓参数完全相同的连续重复,换参数犯同一个错就抓不住。dsh-failbook 按失败签名聚类:只要失败原因一样,不管参数怎么换,都记进同一个账本,攒够次数就注入提醒,告诉模型"别重试了,原因在这,建议这样做"。

功能

能力 说明
📥 自动记录 挂钩 tools/post-execute,捕获每次工具调用失败:结构化错误、非零退出码、沙箱拒绝、常见错误文本
🗂️ 签名聚类 同一失败原因(如 bash:command-not-found)自动归为一桶,不因参数不同而散落
💾 跨会话持久化 通过官方 ctx.storageDomain 存储,重启不丢;无该服务时自动降级为内存账本
🛑 失败感知重试拦截 同一签名近窗口内失败 ≥ N 次(默认 2 次)→ 注入一段建议性提醒,附失败原因和改法建议
🖥️ Web UI 面板 设置页「失败账本」:Top 失败签名表、次数/近窗口/最近时间、静音、单删/清空
🔇 静音与排除 误报桶一键静音;excludeTools/patterns 精细控制
🧮 保守检测 漏判 > 误判:只认确凿的失败标记,可选扩展错误模式

演示

┌────────────────────────────────────────────────────────┐
│ 用户: 帮我跑一下 pipx 装好的工具                        │
│ 模型: bash pipx list        → ❌ command not found      │
│ 模型: bash pipx --version   → ❌ command not found      │
│ 模型: bash pipx install ... → ❌ command not found      │
│ 插件: ⚠️ [dsh-failbook] 该调用此前已失败 3 次            │
│       (command-not-found)。重试大概率仍会失败。          │
│       建议:确认命令已安装且 PATH 正确…                  │
│ 模型: 我先检查一下 PATH 和环境变量…                     │
└────────────────────────────────────────────────────────┘

安装

# 安装到你的 web 配置
dsh plugin --profile web add "github:G1en-114/dsh-failbook#main"

或手动编辑配置目录的 cordis.patch.yml:

- insert:
    - id: failbook
      name: dsh-failbook
      config:
        enabled: true

重启 dsh web 后,打开 设置 → 失败账本 即可看到面板。

配置

配置项 默认 说明
enabled true 总开关
retryGuardThreshold 2 近窗口内同一签名失败 ≥N 次触发提醒;0 关闭提醒(只记录)
reminderCooldownSec 300 同一桶两次提醒的最小间隔(秒),防刷屏
reminderLocale 'zh' 提醒文案语言:zh / en
exitFailureMin 2 退出码 ≥ 此值记为失败(1 常是 grep 无匹配等正常负结果)
recentWindowSec 86400 "近窗口"滚动窗口(秒)
maxArgsChars / maxDetailChars 160 / 400 参数/输出预览截断长度
patterns [] 额外错误模式,格式 分类:正则,如 build-fail:BUILD FAILED
excludeTools ['todo_write'] 不追踪的工具名(支持 * 通配)
maxBuckets 1000 账本桶上限,超出按最近使用淘汰

示例:把退出码 1 也当失败,并拦截得更激进:

- insert:
    - id: failbook
      name: dsh-failbook
      config:
        exitFailureMin: 1
        retryGuardThreshold: 1
        reminderLocale: 'en'

工作原理

工具调用 ──▶ tools/post-execute 瀑布
                │
                ▼
        detectFailure(exec, result)        结构化错误?沙箱拒绝?退出码?错误文本?
                │
                ▼
        签名 = tool:category                如 bash:command-not-found
                │
                ▼
        ledger.record() ──▶ ctx.storageDomain(跨会话持久化)
                │
                ▼
        recentCount ≥ 阈值 且 未静音 且 冷却期外?
                │
                ▼ 是
        createUserMessage 注入 additionalContexts
        (下一轮请求模型可见,0 额外 token 的提醒)
  • 失败检测:result.isError(结构化错误)→ 沙箱 [sandbox: …] 标记 → 保守错误文本(command not found / ENOENT / EACCES / npm ERR! / fatal: 等)→ 退出码兜底。取消(ABORTED)不计为失败。
  • 提醒通道:与官方 repeat-tool-reminder 相同的 additionalContexts 机制——不修改工具结果、不打断管线,模型下轮请求自然看到。
  • 安全边界:Web API 仅回环地址可访问;账本只存截断预览,完整命令输出永不离开宿主。

与现有方案对比

官方 repeat-tool-reminder dsh-fail-logger dsh-failbook
检测维度 参数完全相同的连续重复 失败记录 失败签名聚类(换参数也拦)
持久化 内存 skill 文件 storageDomain 跨会话
重试拦截 ✅(仅相同调用) ❌ ✅(签名 + 冷却 + 静音)
Web UI ❌ ❌ ✅ 设置面板
跨会话统计 ❌ 部分 ✅ 聚合/趋势

Roadmap

  • 失败记录 + 签名聚类 + 持久化
  • 失败感知重试拦截(阈值/冷却/静音)
  • Web UI 面板(Top 签名、静音、清空)
  • 会话开场简报:新会话注入本工作区 Top 失败模式
  • 失败趋势图(按天/工具)
  • 一键导出账本(JSON/CSV)

常见问题

Q: 会不会误报? 默认只认确凿标记:[exit code: N]、[sandbox: …] 是 DSH 自己生成的;文本模式全部带词边界且保守。误报桶可以直接在面板静音,或加进 excludeTools。

Q: 提醒会不会刷屏 / 烧 token? 每个桶默认 5 分钟冷却 + 阈值后才提醒,提醒文本有截断上限,且只在工具调用失败时产生。

Q: headless 模式能用吗? 能。没有 storageDomain 服务的配置会自动降级为进程内账本(重启清空),记录与拦截功能不变。

开发

npm install
npm run typecheck        # 类型检查
npm test                 # 构建 + 27 个单元测试
npm run test:integration # 真机集成验证(见下)
npm run build            # tsc(宿主) + esbuild(客户端 bundle)

集成验证(已在本仓库实测通过)

scripts/integration-harness.mjs 用真实 DSH 运行时(cordis + tools 管线 + storage-json + storage-domain)跑完整链路:

  1. 注册一个固定返回 [exit code: 2] 的假工具;
  2. 以 agent 身份连续执行 3 次 → 第 2 次起注入重试拦截提醒(含失败原因与建议);
  3. 断言账本以签名 fake_fail:exit:2 落盘(count=3、remindersSent=2);
  4. 读取存储介质文件验证跨进程持久化——与 dsh web 重启后 /api/dsh-failbook/ledger 读到的是同一份数据。

实测结果(curl /api/dsh-failbook/ledger,服务器重启后):

{"buckets":[{"signature":"fake_fail:exit:2","category":"exit:2","count":3,
  "recentCount":3,"remindersSent":2,...}],"storage":"domain"}

仓库结构:

src/
├── index.ts        # 宿主入口:post-execute 观察者 + 路由注册
├── signature.ts    # 失败检测与签名提取
├── store.ts        # 账本(storageDomain / 内存双后端)
├── reminder.ts     # 提醒构造与注入
├── routes.ts       # /api/dsh-failbook/* 回环 API
├── shared.ts       # 宿主/客户端共享类型
└── client/         # 浏览器半:设置面板(React + fetch)

English

dsh-failbook — a failure ledger for DeepSeek Harness: every failed tool call is recorded, clustered by failure signature (not by arguments), and persisted across sessions via ctx.storageDomain. When the same failure mode recurs past a threshold, the failure-aware retry guard injects a short advisory into the agent's next request — catching "same mistake, different arguments" loops that identical-args guards miss.

  • Install: dsh plugin --profile web add "github:<you>/dsh-failbook#main"
  • UI: Settings → 失败账本 (Failbook) — top failure signatures, counts, mute, clear
  • Detection: structured errors, non-zero exits (default ≥2), sandbox denials, conservative error-text signatures; cancellations are never counted
  • Safety: loopback-only API; only truncated previews are stored
  • License: MIT

License

MIT © 2026 dsh-failbook contributors

—/ 5

No ratings yet

Verified DSH bundle

Commit cdcb4db6c08d

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout