dsh-ask-first:让 Agent 先问后干

前言

DeepSeek Harness(DSH)内核已经提供「向用户提问」的能力:ctx.userQuestions 服务、ask_user_question 工具,以及 Web GUI 里的提问卡片。默认也会启用这些组件。实际跑任务时,问题往往不在「能不能问」,而在 Agent 的行为——需求有歧义时不问、方案有取舍时不问、要动不可逆资源时也不问,做完再解释。工具在列表里,不等于模型会主动用。

社区插件 dsh-ask-first(维护者 yinghan-123,分类:工作流)补的是这一层行为约束:在替用户做决定之前先提问。README 把它概括为三层机制——常驻提问纪律、连续变更未提问提醒、不可逆操作硬闸——并自带设置页。下面按安装、机制与配置说明可核对的事实。

这是什么

dsh-ask-first 是 DSH 的 bundle 插件,包名 dsh-ask-first,当前资料中的版本为 1.6.0(MIT)。它不新增提问工具,提问仍走内核的 ask_user_question;也不改客户端提问 UI,只通过系统提示、运行时上下文、工具执行后 notice,以及部分工具的 guard 拦截,把「先问后干」写进 Agent 的日常节奏。

  • 目录页:https://www.skillhub.cn/plugins/yinghan-123/dsh-ask-first
  • 源码与文档:https://github.com/yinghan-123/dsh-ask-first

SkillHub 等社区目录与 DeepSeek / 幻方无官方从属关系;安装前建议自行查看源码与许可证。插件在 DSH 进程权限下运行,硬闸与提醒是插件侧启发式判断,不替代 DSHM 的沙箱或审批策略。

三层机制

一、提示词层(每次请求都带)

向系统提示注入两部分:

  1. 纪律段(app:ask-first,system prompt section):写明什么必须问、什么不该问、怎么问,含例外清单,避免变成「凡事都要问」。
  2. 常驻提醒(app:ask-first-reminder,runtime context):每个模型请求前注入约 150 字的规则(默认可在设置页用 standingReminder 整体改写)。长会话里纪律段注意力衰减时,这条仍会出现在快照里。

可在设置页用 alwaysRemind 单独关闭常驻提醒;关闭后仍保留纪律段、变更提醒与硬闸(若未关总开关)。

二、提醒层

监听 tools/post-execute,按 agent 统计「连续多少次变更性操作却一次都没提问」。达到阈值(默认 3,之后 6、12、24)时,在工具结果后插入 notice,例如:

⚠ ask-first 提醒:本回合你已经连续做了 3 次变更性操作(最近一次:`write`),却还没有向用户确认过任何一次。

以下情况计数清零:调用 ask_user_question;用户发来新消息。

变更性操作包括:默认名单里的结构性工具(如 write、edit、remove、move、publish、spawn_teammate 等);bash / pwsh / terminal_send 里带写入或危险特征的命令;python 通道里带 open(...,'w')、os.remove、shutil.、subprocess. 等特征。只读工具(read、glob、grep、web_fetch 等)不计入。

三、硬闸层(不可逆操作必须先问)

对没有回滚路径的操作注册 tools.guard():本回合尚未按规则「问过」时,拒绝本次调用、不执行,并返回可行动的拒绝理由,引导先 ask_user_question 再重试。

默认按工具名拦截 remove、move、publish;shell / python 文本命中 rm、git reset --hard、git push --force、shutil.rmtree( 等模式时同样拦截。参数里读不出操作目标时按 UNKNOWN 处理,拒绝而不是放行。

放行(满足任一即可):本回合问过且提问内容覆盖本次操作目标;用户当前消息里已点名该目标;本会话由 write 创建的同路径文件(selfCreatedExempt);调用者是子代理。只读沙箱模式下,若 respectSandboxMode 为 true,提醒层与硬闸层静默让位。

总开关 hardGate 关闭后,硬闸不参与。刻意不拦创作型 write / edit 及等价 python 写入,以免卡死正常开发流。

安装与启用

DSHM 端侧一行安装(资料原文):

pnpm add github.com/yinghan-123/dsh-ask-first

手工落盘时,将包放入 profile 的 node_modules,并在 profile 的 package.json 里把包名加入 dsh.profile.bundles:

"dsh": {
  "profile": {
    "bundles": [
      "…",
      "dsh-ask-first"
    ]
  }
}

包通过 dsh.bundle.patch 指向 cordis.patch.yml,仅 insert 自身 bundle 行。README 记载:在 DSHM 0.2.1-rc.2+dshm.73 环境下,bundles 追加后 loader 可 reconcile 出 include:ask-first,下一次请求即可带上纪律段;旧环境若无热挂载,重启 DSHM 一次。兼容范围:dsh >=0.2.0-rc.1 <0.3.0-0,Node >=20。

设置页 client 半部首次加载需重启一次 DSHM,以便扫描 dsh.client 声明;之后改配置为热更新。

回滚:从 bundles 删掉 dsh-ask-first 并重启;或仅在设置页关 hardGate / 总开关 enabled;彻底删除可移除 node_modules/dsh-ask-first/。

设置页

路径:设置 → 插件 → 先问后干(第三方 bundle 由包内 lib/client.js 注册到 settings.section)。五个开关可即时生效:enabled、alwaysRemind、hardGate、selfCreatedExempt、respectSandboxMode;另有 standingReminder 多行文本、threshold(默认 3,最小 1)、以及三份名单:askTool(默认 ask_user_question)、mutatingTools、irreversibleTools。底部「保存」一次写入,「恢复默认」 unset 回内置默认。

典型行为(来自 README)

  1. Agent 连续多次 write / edit 等变更而未调用 ask_user_question → 出现阈值 notice,提示先确认。
  2. Agent 在未问用户时调用 remove 或 shell 里 rm … → 硬闸拒绝,要求先提问并取得同意后再重试。
  3. 用户消息已写「删掉 a.txt」→ 硬闸对 a.txt 放行,不必重复问。
  4. 只读 sandbox + respectSandboxMode: true → 提醒与硬闸不重复拦已在 FS 层失败的变更。

适用场景与边界

适合希望 Agent 在歧义、取舍、不可逆动作前主动确认的工作流场景;阈值与工具名单可在设置页按团队习惯调整。

README 如实声明:shell / python 判断是启发式,可能漏判或多判;硬闸「本回合问过」在实现上未做完整语义绑定,依赖提示词要求问清要动什么;守卫内部异常会放行,避免插件拖死工具链。提问通道的选项、等待与超时仍完全由内核 @deepseek-ai/dsh-user-questions 等组件提供。

结尾

dsh-ask-first 用提示词、变更计数提醒和不可逆硬闸三层,把 DSH 已有的提问能力变成更稳定的行为习惯,而不是依赖模型自觉。安装命令以 README 为准:pnpm add github.com/yinghan-123/dsh-ask-first。更多细节见 GitHub 仓库 与 SkillHub 目录页。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜