LIN-F1SH/dsh-prompt-lint

LIN-F1SH/dsh-prompt-lint

读你的历史会话,找出反复踩的提问坑(缺路径与版本、没定输出格式、漏说前置条件导致工具失败),每条给一段可直接粘贴的改写;输入框右侧一键把草稿改成更短的带约束版本。

도구 및 기능deepseek-harnessdshprompt-engineering

提示词体检 · dsh-prompt-lint

预览

*示意图,非实拍:实际界面跟随宿主主题,按钮位于输入框右侧。*

读你自己的历史会话,找出你反复踩的提问坑(缺路径、没定格式、漏前置条件),每条给一段可以直接粘贴的改写;输入框旁边可以一键把草稿改成更短的带约束版本。

它不做什么:不提升模型准确度(我没有证据支持这个说法),也不替你想任务本身。它做的是把你已经知道的约束固定下来,让你不必每次重复交代。

值不值得装

你的情况 · 值不值 老在重复交代同一批约束(输出格式、范围、「只改这个文件」) · 值 —— 模板化后省掉每次重复敲的字,也降低漏交代的概率 提问本来就清楚,返工主要来自网络中断或模型能力 · 不太值 —— 实测这类返工改提示词救不回来 想看看自己的提问习惯 · 值一次 —— 跑一遍复盘,看那几条画像,之后不必常驻

成本:一次复盘约 5,000 tokens(已看过的会话不会重发),点一次优化约 2,400 tokens。

它做什么

你大概遇到过这些:指令没说清楚,来回返工三轮;输出格式交代过一次,下次又忘了交代;工具调用失败,其实是因为你没说前置条件。

复盘历史提问 —— 扫本机会话记录(只取你自己打的字,系统注入的不算),找出指令模糊、反复交代的约束、漏说的前置条件;每条给出出现次数、证据(哪个会话第几条)和一段可直接粘贴的改写草稿。

改写正在写的草稿 —— 输入框右侧 ✨ 优化,按上面找到的问题改写草稿,一次给 简洁 / 标准 / 严谨 三档,可以只复制,也可以直接替换输入框。

把好用的问法存下来 —— 采纳的改写自动归档、按任务类型打标签;下次输入相似内容时,输入框上方提示「你上次补上这条约束后效果更好,要不要带上」。

能力 · 怎么用 · 你得到什么 复盘历史提问 · 设置页「开始复盘」 · 一份改进清单,每条带可直接粘贴的改写草稿 改写当前草稿 · 输入框右侧 ✨ 优化 · 简洁 / 标准 / 严谨 三档,任选一档替换或复制 好问法归档 · 采纳时自动 · 按任务类型打标签的模板,输入时主动推荐

安装

桌面客户端(Electron)

桌面端读的是 desktop profile,dsh plugin 命令行按设计拒绝碰它。让宿主自己装:

请使用内置的 plugin_manager 安装 github:LIN-F1SH/dsh-prompt-lint。

或本地开发:

请用内置 plugin_manager 安装 link:。

Web(dsh web)

# 跟随 main(会拿到最新提交)
dsh plugin --profile web add github:LIN-F1SH/dsh-prompt-lint

# 钉住某个版本(推荐用于生产)
dsh plugin --profile web add github:LIN-F1SH/dsh-prompt-lint#v0.1.1
⚠️ 宿主代码改动后必须重启应用。插件以 link: 安装时,改 lib/* 不会热重载(ESM 模块缓存);禁用再启用也只会重跑 apply(),不会重载代码。客户端 client/client.js 的改动刷新页面(Ctrl+F5)即可。
⚠️ 不要在 `link:` 安装之上再试 `file:` 安装。 link: 在 node_modules/ 建的是指向源码目录的 junction;pnpm 装 file: 时会先"移除旧包目录",它会顺着 junction 把你源码目录里的文件删掉(实测把 .git 元数据掏空了)。要换安装方式请先卸载并手工删掉那个 junction。

怎么用

  1. 先复盘:设置 → 「提示词工作台」→「开始复盘」。它读最近 reviewWindowDays 天内的会话(默认 14 天、最多 8 个),只分析你自己打的字,调一次模型产出改进项。
  2. 再优化:回到对话,在输入框打一句话,点 ✨ 优化。它拿你档案里 active 的改进项来改写,并列出「这次补了哪几条」。
  3. 点「替换输入框」:改写稿写回草稿,同时这条被采纳的提示词自动归档进资产库。
  4. 之后输入时,输入框上方会出现提示:「你上次做类似任务时补上这条约束后效果更好,要不要带上?」

设置

设置 →「提示词工作台」→ 设置 页。改完点「保存」;非法值会被自动收敛(档位过滤、数值夹到区间),不会写坏档案。

项 · 作用 · 范围 启用插件 · 关掉后不再自动推荐,手动优化仍可用 · 开关 生成哪几档 · 优化时生成哪些版本,档位越少越快越省 · 简洁 / 标准 / 严谨,至少留一档 默认版本 · 排在最前并标「推荐」的那一档 · 必须在已选档位内 输入时自动推荐 · 边打字边匹配历史模板与待补约束 · 开关 推荐灵敏度 · 越小越容易触发 · 0–20 复盘回看天数 · 只看最近这么多天的会话 · 1–365 单次复盘会话数 · 越多越慢、越费 token · 1–20 优化时参考哪些改进项 · 只带任务类型匹配的,或全部生效中 · matched-only / ll-active 清空档案 · 删除全部改进项与资产(二次确认) · —

设置就存在同一份档案的 settings 字段里,接口:POST /pwb/profile {"action":"update-settings","settings":{…}}。

数据与隐私

项 · 说明 档案位置 · $DSH_HOME/prompt-workbench/profile.json(默认 ~/.dsh) 读取什么 · 本机 ~/.dsh/sessions/**/session.v4.jsonl.zstd,只读 过滤规则 · 只取 user/message 且 source.kind === 'user' —— 系统注入的运行时上下文、审批通知、技能目录一律排除,否则分析结论全是噪声 运行要求 · Node ≥ 22.15(会话日志是 zstd 压缩的,老版本 Node 没有 zstd API) 联网 · 只有调模型时;读会话与分析不访问任何第三方接口 凭据 · 不存任何 key。模型调用走宿主 llm 服务,用你当前选择的默认模型 诊断文件 · 模型输出解析失败时,原文会落到 $DSH_HOME/prompt-workbench/last-*.txt,仅本机 写接口 · 只接受本机回环来源(127.0.0.1 / localhost / ::1),局域网写入一律 403

HTTP 接口

前缀 /pwb。读接口不限来源,写接口仅本机。

方法 · 路径 · 作用 GET · /pwb/ping · 自检 GET · /pwb/health · 环境体检:llm / 默认模型 / 档案 / 可复盘会话,ready 一句话回答"现在能不能跑复盘" GET · /pwb/profile · 读档案(改进项 / 资产 / 复盘记录 / 设置) POST · /pwb/profile · 改设置、改改进项状态、删条目(用 action 区分) GET · /pwb/sessions · 列出可复盘的时间窗口 POST · /pwb/review · 启动复盘,返回 reviewId(异步,避免 HTTP 超时) GET · /pwb/review?id= · 轮询复盘进度与结果 POST · /pwb/optimize · 按档案改写草稿,返回 3 个版本(options[],另带兼容字段 rewritten) POST · /pwb/recommend · 按草稿推荐资产/改进项(纯本地匹配,不调模型) POST · /pwb/assets · 把一条提示词沉淀进资产库

目录结构

dsh-prompt-lint/
├── package.json          # dsh.bundle.patch + dsh.client(platform: web)
├── cordis.patch.yml      # 挂载声明
├── lib/
│   ├── index.js          # 宿主入口:装配
│   ├── routes.mjs        # /pwb/* 路由与信任边界
│   ├── profile.mjs       # 档案层:原子写 / 损坏保护 / 合并去重
│   ├── sessions.mjs      # 读历史会话:多帧 zstd 解压 + 提问/失败提取
│   └── analyze.mjs       # 提示词工程 + 模型输出校验
├── client/client.js      # 客户端半区(手写、零构建)
├── scripts/              # 三套自检
└── docs/DESIGN.md        # 设计文档:为什么是这些字段

开发

npm run smoke          # 98 项:宿主 15 + 档案 28 + 分析 34 + 会话 9 + 客户端 12

客户端半区不需要浏览器也能验:scripts/smoke-client.mjs 桩掉 window.__ModuleLoader__、document 和 require('react'),直接跑 factory 与 apply(),断言 id 与包名一致、返回 cordis 插件、三个插槽名真实存在、组件可渲染、清理函数可用,并覆盖两种降级:语言包注册抛错时插槽仍注册、缺少 useInput/inputActions 时组件不抛。

重启宿主后,一条命令验证真机闭环:

node scripts/verify-live.mjs          # 默认 http://127.0.0.1:19387
node scripts/verify-live.mjs 3080     # 或指定 dsh web 的端口

它会依次打印环境体检、跑一次真实复盘、列出改进项与改写草稿、试跑一次优化、复核档案。

三个踩过的坑(写这类插件的人会再踩一遍)

  1. 会话文件是 `session.v4.jsonl.zstd`,而且是多帧拼接的。zlib.zstdDecompressSync 只解第一帧 → 你只会读到一行头部,看起来「这个会话是空的」。必须按魔数 28 B5 2F FD 逐帧解(见 lib/sessions.mjs)。
  2. `user/message` 里大部分不是你打的字。实测 300 条里只有 62 条 source.kind === 'user';其余是 ptc-mode、runtime-context、skill-catalog 等系统注入。不过滤就会把系统模板当成你的提问习惯来分析。
  3. `tool/result` 的 `error` 字段只覆盖约 1/3 的真实失败(32/1195)。真实的内层工具失败在 tool/ptc-dispatch,另外还要叠加文本启发式([exit code: N]、STDERR:、ToolCallError…)。

验证记录

在 9 个真实会话(约 9 天、8.4 MB 压缩日志)上的实测:

环节 · 结果 复盘 · 8 个会话 / 60 条真人提问 / 98 次工具失败 → 5 条改进项,每条带证据与改写草稿 重复复盘 · 第二批结果 新增 0 / 合并 5,次数累加(8/8/6/6/6),标题更新为更具体的措辞 —— 不会越跑越脏 优化 · 引用档案中全部 active 改进项改写草稿,列出本次补了哪几条,并给出任务分类与标签 资产 · 采纳后归档、按任务类型打标签;相似草稿能命中推荐

这套数字来自 scripts/verify-live.mjs 的真实输出,脚本可随时重跑。

token 成本(实测,不是估算)

powershell node scripts/measure-tokens.mjs

它在你的真实会话上量四件事:复盘实际要发出去的材料、模型自报的历史 usage、重复提交的两种成因、以及单条提示词的增量。

本机 8 个会话 / 60 条真人提问的实测结果:

项 · 数字 · 含义 复盘实际发送 · 7,982 字符 ≈ 5.0 千 tokens · 只取真人提问 + 失败聚合摘要 事件全文 · 30.7 MB ≈ 2000 万 tokens · 若把整段对话直接塞给模型 压缩比 · ≈ 4000 : 1 · 这是插件最硬的省 token 点 历史总消耗 · input 2.30M + output 1.34M · 模型自报 缓存命中读取 · 179.5M · 每次请求重读上下文前缀,按缓存价计费 失败后重发 · 6 次 · 上一轮 error/borted(网络/服务故障) 真·返工 · 1 次 / 60 轮 ≈ 0.1% tokens · 上一轮正常完成却要重说

结论要老实说:

  • 省 token 的地方在复盘输入的压缩(4000:1),以及增量复盘:已经复盘过、文件之后没变的会话不再重发,重复点「开始复盘」几乎零成本(要强制重跑传 {"force":true})。
  • 复盘材料从早期的 16,209 字符压到 7,982 字符(-51%):失败记录从"逐条贴原文"改成按 工具+错误码 聚合(曾占材料的 71%),连续重复的提问折叠成「同一句 ×N」,只说过一两句的会话直接跳过。
  • 单条提示词会变长(加约束,通常 +30~200 字 ≈ +20~130 tokens),这是明面上的成本;而且它进入上下文后每一步都会被重读,所以有放大效应。
  • 「更好的提示词能否省 token」取决于返工是否减少。在你这批数据里,真·返工只占 0.1% —— 你 9 天里的重复提交,6 次是 provider 502/传输错误造成的,那类 token 靠改提示词省不掉。
  • 换句话说:这个插件的主要价值不是省 token,而是让问题有据可查、让约束不再漏。如果你的返工主要来自提问含糊,收益会明显;如果主要来自网络与模型能力,收益有限。
每次复盘/优化的响应里都带 okens 字段(模型自报的 input/output/cacheRead),可以在界面上核对真实开销。

DSH 升级与版本兼容

插件架在若干宿主契约上。下表是已知耦合点、升级后可能出现的症状、以及现在的兜底——不是保证永不坏,而是坏的时候你能一眼定位。

契约 · 用在哪 · 变了会怎样 · 现在的兜底 会话日志 session[.vN].jsonl[.zstd] · 复盘读取 · 新格式读不到 → 报「时间窗口内没有可复盘的会话」 · 按版本发现:取最高版本、压缩与否看魔数而不信后缀、未压缩也能读 多帧 zstd 拼接 · 同上 · 只读到头部 → 会话看起来「是空的」 · 按 28 B5 2F FD 逐帧解压 user/message.source.kind · 复盘过滤 · 系统注入被当成提问 → 结论全是噪声 · 只认 kind === 'user',未知 kind 一律排除 tool/ptc-dispatch、tool/result.error · 失败检测 · 失败数被低估 · 结构化字段 + 文本启发式双通道 llm.stream()、agentDefaultModel.currentSelection() · 复盘 / 优化 · 调用抛错 · 服务缺失时给明确提示,不崩;没选模型也提示 webServer.register() · 全部 API · 路由全 404 · 注入失败只报错,不拖垮宿主 __ModuleLoader__.load、dsh.client · 界面三处插槽 · 界面完全不出现 · bundle 内每步注册独立 try/catch,单点失败只少一块 插槽名 conversation.input.right 等 · 界面位置 · 按钮不出现 · 注册失败降级,不影响另外两块 useInput / inputActions · 读写草稿 · 按钮变灰 / 插入无效 · 类型守卫;缺失时按钮禁用而不报错

升级后先看体检:

curl http://127.0.0.1:19387/pwb/health

它会报 sessions.formats(实际读到的格式,如 ["v4.zstd"])、compat.zstd、compat.services(llm / agentDefaultModel / webServer 是否在位)、profile.exists、ready。ready: false 就说明某条链路断了,再按上表定位。

已知限制

  • 复盘一次只发一个模型请求,材料已压缩(只取真人提问 + 失败摘要),但仍受窗口大小限制;输出被截断时插件会明确报 TRUNCATED 并重试一次,而不是静默失败。
  • 复盘的问题合并靠三条判据:模型复用 id(提示词里会要求)→ 标题归一化后完全相同 → 引用了同一条证据(同 session 同 seq)。纯字符串相似度阈值定得很高(0.85),因为「问题 1 / 问题 2」这种只差一个数字的标题会被误并。
  • 资产推荐用字符 bigram 相似度做本地匹配,不做语义检索——够用、零成本、可预测。
  • 会话压缩(compaction)后,被折叠的早期事件仍在日志里,本插件按时间顺序读取,不区分「模型当前可见」的 surface。
  • 只支持 session.v4(并按最高版本发现);将来格式升到 v5,解析层会忽略未知事件类型、不会崩,但新字段的语义需要人工适配。

许可

MIT © 2026 LIN-F1SH