dsh-emotion-feedback:每轮判定助手自身情绪并在下一轮静默注入

前言

在 DSH 里跑多轮对话时,助手上一轮的语气往往不会自动「带进」下一轮:模型只看到 transcript,没有一条显式的「我此刻处于什么状态」的通道。常见做法是让用户侧情绪感知插件去改回复风格;方向相反的是,把判定对象换成工作模型自己在上一轮输出里流露的状态,再在下一轮开始前悄悄写进请求,让行为随状态延续,而不把判定过程暴露给用户。

下面介绍社区插件 dsh-emotion-feedback(维护者 A-f-ish,分类:模型推理)。它在一包内同时提供宿主侧 bundle(dsh.bundle)与浏览器面板(dsh.client),无需构建步骤。

这是什么

dsh-emotion-feedback 是 DeepSeek Harness 插件:每轮结束时判定当前工作模型自身的情绪,并在下一轮开始前静默重新注入,形成「自观测 → 状态携带 → 行为偏移」的闭环。判定步骤不会进入用户可见的 transcript;用户感知到的是下一轮 tone 的变化,而不是判定 machinery。

工作循环

先做判定,再做注入;两阶段挂钩在 agent 生命周期上。

① turn 结束    agent/turn-stopping(串行、await)
   取本轮最后一条 assistant 消息
        ↓ 本地关键词层优先(命中则 0 次模型调用)
        ↓ 否则在 useLlm=true 时 → 一次轻量 llm.stream 判定
          (temperature 0,单行 JSON,协议 EMOTION_TONE_JUDGE v1)
   结果更新本会话情绪状态;不追加 session 事件,判定对用户不可见

② 下一轮开始   agent/pre-step({ prepend: true })
   将当前状态渲染为一条 synthetic user 消息
   (source.kind = 'emotion-feedback')并 append 到本次请求
        ↓
   工作模型带着该状态作答,并被要求不要解释状态来源

同一会话同一轮注入是幂等的;强度低于 minIntensity 时整段注入跳过。

关键词层命中时不调用模型;未命中且允许 LLM 判定时,仅一次轻量调用。

情绪状态与混合规则

判定结果在进程内维护,结构大致如下(标签不在词表内时保留原文并标记 outOfList: true,不再改写为「平静」):

{
  emotion: '愧疚',
  intensity: 0.62,        // 0-1
  reason: '关键词「抱歉」',
  source: 'rule',         // 'rule' | 'llm'
  outOfList: true,
  turn: 7,
  history: [{ turn: 7, emotion: '愧疚', intensity: 0.62 }, /* … */],
}

要点(与默认配置行为一致):

  • 否定 guard:关键词附近出现否定词(如 不、没、无 等,列表可配 negations;设为 [] 可关闭)时丢弃该命中,避免「不确定」「风险可控」等反向误触。
  • 混合而非覆盖:旧强度先按 turnDecay ^ (turns-elapsed) 衰减;同情绪取 max(old, new);切换情绪时取 max(old × takeoverRetain, new)。
  • 空闲衰减已禁用:原 halfLifeMinutes 相关逻辑在代码中注释保留,当前强度仅通过 blend() 变化。

安装与启用

安装会执行 pnpm add、校验 package.json 中的 dsh.bundle,并将 cordis.patch.yml 合并进 profile。合并内容仅一行 insert:

- insert:
    - id: emotion-feedback
      name: 'dsh-emotion-feedback'

官方 README 给出的安装方式如下(路径请换成你的本机目录;npm 发布后可改用包名):

# from npm (once published)
dsh plugin --profile <profile> add dsh-emotion-feedback

# from a local checkout — the path is recorded as a junction, so editing the
# checkout is the same as editing the installed plugin
dsh plugin --profile <profile> add "C:\path\to\dsh-emotion-feedback"

必须完整重启 DSH。安装只合并 bundle patch;插件模块加载与 apply() 发生在宿主组装 plugin generation 时。浏览器半部分是静态 bundle、无 HMR,新开浏览器标签不够。

也可在 DSH 会话内让 agent 通过 plugin_manager 工具的 install_bundle 指向插件目录。中文逐步说明见仓库 INSTALL.md;README 中文版为 README.zh.md。

安装前请自行审阅源码与 MIT 许可证;插件以当前 DSH 进程权限运行。

配置

在 profile patch 里给插件行增加 config:,各字段均有默认值。完整 schema 见 lib/types/index.d.ts 中的 Config。

- id: emotion-feedback
  config:
    minIntensity: 0.3     # injection threshold (default 0.2)
    judgeModel: ''        # judge model; empty = the session's default model
    judgeProvider: ''     # same, for the provider
    useLlm: true          # allow the model judge when keywords miss
    inject: true          # false = judge and keep state, never inject
    includeReason: false  # true = append the judge's reason to the injected text
    timeoutMs: 6000       # single judge timeout; on timeout the old state stays
    turnDecay: 0.9        # per-turn intensity decay
    takeoverRetain: 0.35  # retained fraction of the old intensity on emotion switch
    disabled: false       # emergency switch: true = silences everything (wins over enabled)
    debug: false          # true = print the judge result each turn
字段 默认 作用
enabled / inject true 总开关 / 是否注入(关 = 仅判定)
disabled false 紧急开关,优先于 enabled
minIntensity 0.2 注入阈值
judgeProvider / judgeModel '' 判定模型;空则回退 session 默认
useLlm true 是否允许模型判定层
timeoutMs 6000 单次判定超时;超时保留旧状态
turnDecay / takeoverRetain 0.9 / 0.35 混合规则
halfLifeMinutes 10 未生效(仅保留字段)
injectPerStep false 是否在同轮后续 step 也注入
emotions / rules / prompt / template 内置 词表(15 标签)/ 关键词规则 / 判定 prompt / 注入模板
negations 见 README 否定词表;[] 关闭 guard
panelEvent / panelRoute / statusTool true 会话事件 / 只读 HTTP 路由 / emotion_status 工具
persistHistory true 会话历史落盘(保留 30 天)

界面与只读接口

浏览器面板

挂在 conversation.composer.dock,标签为「情绪」。收起时为色点 + 情绪 + 强度;展开后显示强度条、最近一次判定(时间、上一情绪、原因、来源「关键词」/「模型判定」、词表外标记等)、40 点强度曲线与最近 8 次判定。

面板不依赖额外专用 endpoint:每次注入写入 session log 为 user/message,且 source.kind = 'emotion-feedback'、surfaceOp: 'append';客户端通过 slot prop useChat((s) => s.legacy.nodes) 读对话节点,曲线反映的是模型实际收到的内容。可选 GET /emotion-feedback/state?sessionId=…(Web 部署)补充宿主侧细节;不可达时面板静默降级。

emotion_status 工具

只读工具,供模型查询当前情绪、强度、原因、来源(rule / llm)与近期轨迹,与面板读同一进程内状态。依赖 @deepseek-ai/dsh-tools 懒加载注册;宿主无该包时仅失去工具,其余不受影响。

历史文件

路径:<DSH_HOME>/emotion-feedback/history/<sessionId>.json,按轮记录判定,保留 30 天。persistHistory: false 可关闭。

典型用法与适用场景

  1. 在 profile 中安装插件并重启 DSH,按需调整 minIntensity、useLlm、inject。
  2. 多轮对话中观察 composer 上方「情绪」面板;需要排查时可开 debug: true 看每轮判定输出。
  3. 若只希望维护状态、不向模型注入,设 inject: false。
  4. 临时关闭整条链路而不卸载: disabled: true。

适合希望在不增加用户可见「情绪分析」话术的前提下,让助手跨轮保持与上一轮自我表述一致语气倾向的 DSH 开发者。不适合把判定过程展示给终端用户的场景——设计上刻意对用户隐藏判定步骤。

README 中有本地 injection ON/OFF 对照实验描述(正文在仓库内,此处不展开未完整抓取的数据)。使用前请自行评估额外 LLM 判定调用(关键词未命中时)的成本与延迟;timeoutMs 超时不会更新状态。

依赖与环境

  • Node:^22.19.0 || >=24.0.0(见 package.json engines)
  • peer:@deepseek-ai/cordis >=4.0.4 <5.0.0,@deepseek-ai/dsh >=0.2.0-rc.2 <0.3.0-0(dsh 为 optional peer)

社区插件目录 skillhub.cn 独立于 DeepSeek / 幻方,并非官方应用商店;选型与安装责任在使用者。

结尾

dsh-emotion-feedback 把判定方向从「用户情绪」换成「助手自身状态」,用 turn 末判定 + 下轮 pre-step 注入完成闭环,并配合关键词零调用路径与可选轻量 LLM 判定。进一步细节、中文安装清单与变更记录见 GitHub 仓库与 INSTALL.md。

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

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

小夜