dsh-sensitive-replace:按屏蔽表在出网前替换敏感字符,规避 DeepSeek 官方 API 400

前言

在 DeepSeek Harness(DSH)里跑智能体时,请求会带上用户输入、工具结果、历史消息和 system prompt。DeepSeek 官方 API 对部分字符组合会返回 Content Exists Risk 类 400(常见诱因包括某些 emoji 码位单独出现即命中审核)。这类错误往往在长对话或工具回灌大量外部文本时才暴露,单靠事后改 prompt 很难稳定规避。

社区里已有按码位做中和的插件(例如 dsh-text-guard)。dsh-sensitive-replace 走另一条路径:由你维护一份 YAML 屏蔽表,在内容进入会话上下文之前、以及整份请求出网之前做替换;若仍 400,还可加硬清洗并在同一会话内重试。下面介绍插件定位、三道关口、安装与屏蔽表写法,以及使用时必须接受的边界。

这是什么

dsh-sensitive-replace 是 Short-Arm-Ape 维护的 DSH Profile Bundle 插件(npm 包名 dsh-sensitive-replace,当前资料版本 v0.7.0,MIT 许可)。分类上属于模型推理相关能力:目标不是 PII 脱敏或「不让模型看到某文件」,而是替换会触发官方审核的字符/短语,减少 INVALID_REQUEST / 400,并在漏网时尽量保持对话连续。

包在 package.json 中声明 dsh.bundle.patch,装进 profile 后会自动并入 cordis.patch.yml,一般不必手写插件组合行。

核心功能

三道替换关口

插件在三个钩子上工作,合计覆盖「新进上下文」与「已从日志派生、即将出网」的内容:

关口 钩子 作用
1 agent/pre-step 用户输入、steering 等进入步骤前的消息:返回替换后的消息副本,保留消息 id,不原地改写深冻结对象
2 tools/post-execute 网页抓取、读文件、命令输出等工具结果(含嵌套块):在写入会话日志前替换
3 llm/stream 出网前对整份请求深拷贝并清洗:历史消息、模型已写内容、tool-call 参数、system 等

前两道发生在写入会话日志之前,命中后日志里持久为占位符。第三道只改发往 provider 的副本,可补上「插件安装前已在日志里」的内容;DSH 对消息做深冻结,因此出网前必须拷贝再改,不能原地改 options.messages。

400 自动恢复(recoverOn400)

若屏蔽表未覆盖仍触发 400,插件在 agent/request-error 中可:判定 400 / INVALID_REQUEST;在规则之外临时加硬剥离 emoji、旗帜等码位(持续 aggressiveMs);返回 { kind:'retry' },从日志重新派生请求并重试,同一会话不必重建。重试次数由 maxRecoveries 等配置封顶;也可常开 aggressive: true 做更激进的码位剥离。

规则形态与运维

  • 屏蔽表默认路径:$DSH_HOME/sensitive-blocklist.yaml(默认 ~/.dsh),可用 blocklistPath 覆盖。
  • 支持 global → Provider ID → 模型 三级链;条目可为字形、\u{XXXX}、re: 正则。
  • 保存即生效:按文件 mtime 热重载,增删词无需重启 profile。
  • 屏蔽表形态错误会在加载期告警,避免静默失效。
  • 只读诊断工具 sensitive_replace_status:规则数、各关口清洗次数、规则命中统计、形态警告等(不暴露规则全文)。

替换为单向且不可逆:关口 1/2 写入日志的已是占位符;关口 3 仅改出网副本,界面上可能仍见原文而模型侧见占位符。需要事后对照时,可用 replaceWith: '[BLOCKED:{n}]' 与 hits 明细人工核对。

安装与启用

前置:dsh CLI 在 PATH 上,并确定 profile 名(示例用默认 web)。

方式一:npm / tarball(推荐)

registry 已发布时:

dsh plugin --profile web add dsh-sensitive-replace

或使用本地构建产物:

dsh plugin --profile web add /abs/path/dsh-sensitive-replace-0.7.0.tgz

装完后建议重启该 profile(若 profile 开启 patchReload: live,改 patch 层可热生效,但新增依赖仍建议重启一次)。

方式二:npm 依赖 + 手写 patch 行

npm install /abs/path/dsh-sensitive-replace-0.7.0.tgz

在 profile 的 cordis.patch.yml 用户层增加:

- insert:
    - id: sensitive-replace
      name: 'dsh-sensitive-replace'

准备屏蔽表

将包内 samples/sensitive-blocklist.example.yaml 复制为 $DSH_HOME/sensitive-blocklist.yaml,按环境编辑。保存后自动重载。

配置覆盖示例

在用户 patch 层按 id 覆盖(用户层在 bundle 层之后,后者生效):

- id: sensitive-replace
  config:
    enabled: true
    autoReplace: true
    detectUnfiltered: true
    blocklistPath: /abs/path/to/sensitive-blocklist.yaml
    replaceWith: '[BLOCKED]'

典型用法

最小屏蔽表示例

providers 下的键必须是 DSH Provider 路由 id(如 deepseek-official),不是显示名;写错会导致专属规则不生效。

# 敏感字符屏蔽表(支持注释)
global:
  - '\u{1F600}'             # 举例:emoji 码位,对所有 Provider 生效
providers:
  deepseek-official: []     # 仅对该 Provider id 生效

按 Provider / 模型细分时,可使用 providers.<id>.models.<model>,键尾 * 表示前缀匹配;对象形态下基础规则放在 _ 下。README 中有完整三级链示例与常见写错说明,部署前建议对照。

与 dsh-text-guard 的选型

两者都可做进日志前的中和。本插件额外提供 出网前整份请求清洗(含 system 与历史)、400 同会话重试、YAML 热重载 与诊断工具。若只需零配置的码位级方案,dsh-text-guard 更轻;若要可维护词表 + 出网兜底 + 400 恢复,用本插件。同时挂载一般不冲突,但能力重叠,通常择一即可。

适用场景与注意

适合谁:主要走 DeepSeek 官方 API、经常被 Content Exists Risk 400 打断;希望用自维护屏蔽表精确控制替换范围,并需要在 tool 结果和长上下文出网前最后一道清洗的场景。

务必注意:

  1. 插件以当前 DSH 进程权限运行,安装前请阅读 GitHub 源码 与 MIT 许可证,确认符合你的安全策略。
  2. 未写入屏蔽表的内容不会被规则替换,仍是 400 来源;recoverOn400 主要剥离 emoji/符号类码位,治本仍靠补全屏蔽表。
  3. 规则若匹配 JSON 结构字符,可能改变 tool-call 参数语义;规则宜写内容词,避免写 "command" 等结构片段。
  4. 图片/文件等二进制附件不参与文本替换。
  5. Node 引擎要求 >=20;peer 依赖为 DSH 生态的 @deepseek-ai/cordis、dsh-tools、dsh-llm 等,需与当前 DSH 版本匹配(v0.7.0 说明兼容 DSH 0.2.0-rc.x)。

DSH 社区插件目录由独立站点维护,与 DeepSeek / 幻方无官方从属关系;安装来源以 npm 包或你信任的 tarball 为准。

结尾

dsh-sensitive-replace 把「用户 YAML 屏蔽表 + 三道关口 + 可选 400 重试」串成一条可运维的链路,针对的是官方 API 审核触发的 400,而不是通用隐私脱敏。若你在 DSH 里反复遇到 Content Exists Risk,可先装插件、配好 $DSH_HOME/sensitive-blocklist.yaml,再用 sensitive_replace_status 观察命中与告警。

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

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

Xiaoye