DeepSeek Harness Hub
← 返回列表

KakaruHayate/dsh-degen-heal

DeepSeek Harnessspec-screened在 GitHub 查看 ↗
未验证

Detect and self-heal LLM output degeneration loops inside a…

尚未跑自动兼容性验证,可查看页面内的依赖与入口分析。 · 最近上游提交 2026/8/25 · 已提供中文文档

Detect and self-heal LLM output degeneration loops inside a DeepSeek Harness agent session.(有死锁,别用)

综合分
28.3
GitHub 分
28.3
用户评分
★ Stars
1
周下载量
安装插件(需先安装 dsh CLI 引擎:npm install -g @deepseek-ai/dsh)
dsh plugin --profile web add KakaruHayate/dsh-degen-heal
该插件未发布到 npm,走 GitHub 源安装(pnpm 若拦截 prepare 脚本,按其提示在 pnpm-workspace.yaml 的 allowBuilds 中放行后重跑)
数据截至 2026/9/18(元数据每日更新 · 实装验证按队列轮转,单条结论的验证时间见上方)
依赖的 DSH / Cordis 模块
@deepseek-ai/dsh-agent@deepseek-ai/dsh-llm@deepseek-ai/dsh-session@deepseek-ai/dsh-tools
用户评分
还没有人投票,来当第一个
订阅周报,不错过优质插件更新
每周一封 · 高评分插件 + 新用户活动

README

@dsh-external/llm-degen-heal

检测并自愈 DeepSeek Harness 代理会话中的 LLM 输出退化循环。
检测并自愈 DeepSeek Harness 代理会话中的 LLM 输出退化循环。

纯插件实现:挂接 Harness 文档化的扩展点,不修改任何核心 routing / session / serialize 逻辑。纯 fail-open 设计——自身不可能陷入死锁。
纯插件实现:挂接 Harness 文档化的扩展点,不修改任何核心 routing / session / serialize 逻辑。纯 fail-open 设计——自身不可能陷入死锁。

目录 / 目录

1. 应用场景 / 应用场景
2. 架构与接线点 / 架构与接线点
3. 触发规则 / 触发规则
4. 自愈动作 / 自愈动作
5. 状态机与安全 / 状态机与安全
6. 配置 / 配置
7. 诊断 / 诊断
8. 安装 / 安装
9. 验收自测 / 验收自测
10. 已知限制 / 已知限制
11. 许可证 / 许可证

应用场景 / 应用场景

长代理会话中,上下文被工具输出、CMake 日志、快照等内容塞满后,模型在收尾阶段容易陷入退化循环:

长代理会话中,上下文被工具输出、CMake 日志、快照等内容塞满后,模型在收尾阶段容易陷入退化循环:

- 连续多轮只输出无意义短碎词("Let me commit / Execute / Now / 跑" 等),从不真正发出工具调用;
连续多轮只输出无意义短碎词("Let me commit / Execute / Now / 跑" 等),从不真正发出工具调用;
- 偶有"调用"也常缺参数(JSON 被碎词截断)。
偶有"调用"也常缺参数(JSON 被碎词截断)。

这是典型的退化重复失效模式。本插件在流式输出中实时检测,通过修正注入 / 有界重试来自愈;若升级仍然失败,则对当前会话进入 fail-open lockout,确保不会把会话锁死在重试循环里。

这是典型的退化重复失效模式。本插件在流式输出中实时检测,通过修正注入 / 有界重试来自愈;若升级仍然失败,则对当前会话进入 fail-open lockout,确保不会把会话锁死在重试循环里。

何时需要 / 何时需要

| 场景 / 场景 | 无插件 / 无插件 | 有插件 / 有插件 |
|---|---|---|
| 模型连发 20 次 "Let me commit" 后卡死 / 模型连发 20 次 "Let me commit" 后卡死 | 用户手动中断 / 用户手动中断 | 自动检测 → 修正注入 + 重试 / 自动检测 → 修正注入 + 重试 |
| 交替对循环 "OK. OK. OK." / 交替对循环 "OK. OK. OK." | 耗尽 token 才停 / 耗尽 token 才停 | 第 2 次触发即中断并调整 temperature / 第 2 次触发即中断并调整 temperature |
| 模型把"我的思路是…"当作可见输出 / 模型把"我的思路是…"当作可见输出 | 推理内容泄漏到回复 / 推理内容泄漏到回复 | 检测到泄漏 → 注入引导消息 / 检测到泄漏 → 注入引导消息 |
| 3+ 个空转 turn 无工具调用 / 3+ 个空转 turn 无工具调用 | 会话永久卡住 / 会话永久卡住 | 空转仪表强制工具调用引导 / 空转仪表强制工具调用引导 |

架构与接线点 / 架构与接线点

插件标识 / 插件标识

name:    '@dsh-external/llm-degen-heal'
inject:  ['agents', 'sessions']
插件消费两个 Cordis 服务:

- agents — 访问当前 Agent、其 Session,并通过 agent.steer() 注入空转仪表引导。
- sessions — 按 id 解析活跃会话,记录事件(session.append)。

使用的 Harness 扩展点

插件在 六个 文档化的 Harness waterfall / 串行事件上注册监听器:

| 事件 | 类型 | 用途 |
|---|---|---|
| llm/stream | waterfall | 逐 chunk 分词、滚动窗口更新、流内分类、升级中断 |
| agent/pre-step | waterfall | 空转 turn 聚合、修正消息注入(每 epoch 一次) |
| agent/request | waterfall | Temperature 重写(每 epoch 一次,可选) |
| agent/request-error | waterfall | LLM_DEGENERATION 中断原因的有界重试 |
| agent/turn-stopping | serial | 空转仪表:连续空转 turn 超阈值时升级 |
| ctx.tools.register | injection | 注册 dev_loop_status 诊断工具 |

外加一个生命周期钩子:

| 钩子 | 用途 |
|---|---|
| ctx.effect(() => cleanup) | fiber 释放时清空所有进程内状态 |

内部模块结构

src/
index.ts      — Plugin entry: listeners + tool registration (497 lines)
detect.ts     — Pure detection primitives: tokenize, classifyWindow, assessTurn (297 lines)
state.ts      — Per-session state machine: epoch, cooldown, lockout, ring (153 lines)
validate.ts   — Fail-loud config validation (65 lines)
lib/            — tsc build output (entry points mirror src/)

| 模块 | 依赖 | 纯度 | 可测性 |
|---|---|---|---|
| detect.ts | 无(纯函数) | 纯函数 | 可独立单测 |
| state.ts | 仅类型 | 纯状态转换 | 可独立单测 |
| validate.ts | 无 | 纯校验 | 可独立单测 |
| index.ts | cordis + 以上全部 | 事件驱动 | 自测用 fake adapter |

触发规则

四个独立信号作用于每会话的滚动 token 窗口(默认 256 token)。信号仅在真正的连续重复时触发——全局频率和普通中文语篇中的离散共现被明确排除。

信号 1:碎词循环(tokenLoop)
同一短词(≤ shortTokenMaxLen 字符,默认 32)连续出现 ≥ repeatThreshold 次(默认 8)触发。

触发示例:

- 跑跑跑跑跑跑跑跑(8 次)
- OK OK OK OK OK OK OK OK(8 次)
- Execute Execute Execute Execute Execute Execute Execute Execute(8 次)

不触发示例:

- 正常中文中的 的的的的的的的的——的 是自然出现的高频虚词;但 跑跑跑… 作为实词不自然地重复会触发。
- 长窗口中离散散布的 的——不是连续 run。

信号 2:交替对循环(pairLoop)

两个不同短词的严格交替 A B A B A B…,run 长度 ≥ 2 × repeatThreshold − 1(默认 15 token = 7.5 对)触发。

触发示例:

- 高 的 高 的 高 的 高 的 高 的 高 的 高 的 高 的 高(15 token,7 对)
- OK . OK . OK . OK . OK . OK . OK . OK . OK . OK . OK . OK . OK . OK(15 token)

不触发示例:

- 语篇中的离散共现如 "高的评价是高的标准"——不是严格交替 run。

信号 3:熵骤降(entropyDrop)

unique-tokens / total-tokens  0 启用。                      │
│  每个 epoch 一次。幂等。                                      │
├─────────────────────────────────────────────────────────────┤
│  第 3 层:流中断 + 有界重试                                  │
│                                                              │
│  同一 epoch 内达到 escalateAt(默认 2)次触发时:              │
│    - Yield finish chunk with reason.code = LLM_DEGENERATION  │
│    - agent/request-error grants 1 retry (maxRetriesPerEpoch) │
│    - Stream window cleared for fresh slate                   │
│                                                              │
│  达到 lockoutAt(默认 3)次且未恢复时:                        │
│    - Set lockoutUntil = now + lockoutMs                      │
│    - All detection silenced for this session                 │
│    - No interrupt, no retry, no steer — FAIL OPEN            │
├─────────────────────────────────────────────────────────────┤
│  第 4 层:Lockout(死锁逃逸舱口)                            │
│  第 4 层:Lockout(死锁逃逸舱口)                            │
│                                                              │
│  独立于 epoch 冷却。当升级持续失败时,检测会完全暂停——       │
│  会话不会被困在自我延续的中断/重试循环中。                   │
│                                                              │
│  恢复:任何健康输出、用户消息或冷却到期都会调用              │
│  recover() 并清除 lockout。                                  │
│  独立于 epoch 冷却。升级反复失败时完全暂停检测——会话不会陷入    │
│  自我维持的中断/重试循环。恢复条件:健康输出、用户消息、冷却到期。│
└─────────────────────────────────────────────────────────────┘

重试语义 / 重试语义

当 agent/request-error 看到 failure.code === 'LLM_DEGENERATION' 时:

- 退化流的结束块携带 { reason: { kind: 'error', failure: { code: 'LLM_DEGENERATION', message: '...' } } }
- 如果 retryUsedInEpoch = idleTurns && inEpoch && !injectedThisEpoch):

- agent.steer(healMessageUserMessage()) 将纠正消息作为高优先级系统风格的用户消息注入
- source: { kind: 'plugin', plugin: '@dsh-external/llm-degen-heal', form: 'notice', summary: 'degeneration self-heal' }
- 消息内容默认为内置的 DEFAULT_HEAL_MESSAGE;可通过 healMessage 配置覆盖

空转仪表触发时,通过 agent.steer() 注入高优先级系统级用户消息,强制模型在下一轮发出真实工具调用。

状态机 / 状态机

┌──────────────────────────────────┐
│                                  │
▼                                  │
┌──────────────┐                           │
│   IDLE       │◄── recover() ──┐           │
│   (正常)    │                 │           │
└──────┬───────┘                 │           │
│ detect                 │           │
▼                         │           │
┌──────────────┐                │           │
│  IN_EPOCH    │                │           │
│  (干预中)   │                │           │
│  cooldown    │                │           │
└──────┬───────┘                │           │
│                        │           │
┌─────────┼─────────┐              │           │
│         │         │              │           │
▼         ▼         ▼              │           │
inject    config    retry              │           │
(1/epoch) (1/epoch) (maxRetries)        │           │
│         │         │              │           │
└─────────┼─────────┘              │           │
│ triggers >= lockoutAt  │           │
▼                        │           │
┌──────────────┐                │           │
│  LOCKOUT     │                │           │
│  (fail-open) │                │           │
└──────────────┘                │           │
│           │
┌────────────────────────────────────┘           │
│                                                 │
│  healthy output / user message / cooldown expiry │
│                                                 │
└─────────────────────────────────────────────────┘

每会话状态字段
typescript
interface SessionDegenState {
window: string[]              // 滚动 token 缓冲(最大 windowTokens)
// Rolling token buffer (max windowTokens)
turn: number                  // 当前代理 turn(来自 agent/pre-step)
// Current agent turn (from agent/pre-step)
step: number                  // 当前模型调用 step(来自 agent/request)
// Current model call step (from agent/request)
steps: StepFacts[]            // 空转评估的每步事实
// Per-step facts for idle-turn assessment
consecutiveIdle: number       // 连续空转 turn 计数
// Consecutive idle turn count
epoch: number                 // 当前治愈 epoch(每轮递增)
// Current healing epoch (increments per round)
epochAt: number               // Epoch 起始时间戳(毫秒)
// Epoch start timestamp (ms)
cooldownUntil: number         // Epoch 冷却边界(毫秒)
// Epoch cooldown boundary (ms)
triggersInEpoch: number       // 当前 epoch 内触发计数
// Triggers counted in current epoch
injectedEpoch: number         // 上次注入修正消息的 epoch
// Last epoch that injected the corrective message
configAppliedEpoch: number    // 上次重写 temperature 的 epoch
// Last epoch that rewrote temperature
retryUsedInEpoch: number      // 当前 epoch 已授权重试次数
// Retries granted in current epoch
lockoutUntil: number          // Lockout 到期时间(毫秒);0 = 未 lockout
// Lockout expiry (ms); 0 = not locked out
ring: DegenRecord[]           // 有界观察环(最多 64 条)
// Bounded observation ring (max 64 entries)
// 有界观察环(最多 64 条)
lastVerdict?: WindowVerdict   // 最近一次分类结果
// 最近一次分类结果
}

幂等保证

| 动作 | 保护 | 范围 |
|---|---|---|
| 纠正消息注入 | 注入前检查 injectedEpoch === epoch | 每 epoch |
| 温度重写 | 重写前检查 configAppliedEpoch === epoch | 每 epoch |
| 重试授予 | retryUsedInEpoch  cooldownUntil 重置所有每 epoch 计数器 | 冷却边界 |
| 锁定 | locked(st) 静默所有检测 + 中断 + 引导 | 全会话 |

恢复条件

以下情况调用 recover():

- 流式 chunk 以 degenerate: false 结束且上次 verdict 为 degeneration: true(窗口已清)
- agent/pre-step 中出现 user 消息(用户手动干预)

恢复会重置 epoch、冷却、触发计数、连续空转和 lockout——会话立即恢复完整检测灵敏度。

配置

所有参数在插件加载时校验(非法值报错)。在你的 profile 的 cordis.patch.yml、cordis.yml 或 inject 配置中覆盖。

完整配置
yaml
plugins:
'@dsh-external/llm-degen-heal':
── 总开关 ──
enabled: true                    # true = 生效;false = 纯透传,无日志
true = 生效;false = 纯透传,无日志

── 检测 ──
providers: []                    # Provider 白名单;空 = 全部
Provider 白名单;空 = 全部
windowTokens: 256                # 滚动 token 窗口大小
滚动 token 窗口大小
shortTokenMaxLen: 32             # "短词"分类的最大 token 长度
"短词"分类的最大 token 长度
repeatThreshold: 8               # 触发碎词循环的连续相同短词数
触发碎词循环的连续相同短词数
entropyRatio: 0.35               # unique/total 低于此值(无结构)→ 熵骤降
unique/total 低于此值(无结构)→ 熵骤降
detectAlternating: true          # 检测 A B A B… 交替对循环
检测 A B A B… 交替对循环
leakMarkers: [...]               # 自定义思维/规划泄漏短语(内建默认值)
自定义思维/规划泄漏短语(内建默认值)
leakThreshold: 2                 # 窗口内标记命中数达到此值后触发泄漏
窗口内触发泄漏的标记命中次数
idleTurns: 2                     # 仪表触发前的连续空转 turn 数
仪表触发前的连续空转 turn 数
idleTurnWords: 60                # "空转" turn 分类的词数上限
"空转" turn 分类的词数上限

── Self-healing / 自愈 ──
temperatureDelta: 0              # 每 epoch 的 temperature 调整;0 = 关闭,范围 [-2, 2]
每 epoch 的 temperature 调整;0 = 关闭,范围 [-2, 2]
cooldownMs: 30000                # 治愈 epoch 冷却(毫秒);此窗口内的触发归入同一 epoch
治愈 epoch 冷却(毫秒);此窗口内的触发归入同一 epoch
escalateAt: 2                    # epoch 内达到此触发数时中断流
epoch 内达到此触发数时中断流
maxRetriesPerEpoch: 1            # 每 epoch 最大重试授权数(0 = 仅检测,不重试)
每 epoch 最大重试授权数(0 = 仅检测,不重试)
lockoutAt: 3                     # epoch 内触发数超过此值进入 fail-open lockout
epoch 内触发数超过此值进入 fail-open lockout
lockoutMs: 180000                # Lockout 持续时间(毫秒);180000 = 3 分钟
Lockout 持续时间(毫秒);180000 = 3 分钟

── Corrective message / 修正消息 ──
healMessage: |                  # 检测到退化时注入的消息
Degeneration detected: your previous output either repeated the same
short fragments without making progress, or leaked your thinking/planning
as visible prose instead of concise final answers. Stop writing fragments
and stop writing your thought process into the reply. Truncate and rephrase
from your last meaningful step, then make exactly ONE tool call now to make
concrete progress. If the task is genuinely complete, say so in one short
sentence and stop.

Quick-Tune Presets / 快速调参

Observe-only (no intervention / 仅观察,不干预):

plugins:
'@dsh-external/llm-degen-heal':
enabled: true        # still logs; set false to silence entirely
maxRetriesPerEpoch: 0
temperatureDelta: 0

Aggressive (interrupt early / 激进,尽早中断):

plugins:
'@dsh-external/llm-degen-heal':
repeatThreshold: 5
escalateAt: 1
maxRetriesPerEpoch: 2
temperatureDelta: 0.3

Lenient (high tolerance / 宽松,高容忍):

plugins:
'@dsh-external/llm-degen-heal':
repeatThreshold: 12
entropyRatio: 0.25
idleTurns: 4
lockoutAt: 5

Diagnostics / 诊断

dev_loop_status Tool / 诊断工具

通过 ctx.tools.register 注册——会话内可作为可调用工具使用。

通过 ctx.tools.register 注册——会话内可作为可调用工具使用。

{
"enabled": true,
"sessions": [
{
"sessionId": "abc-123",
"turn": 5,
"step": 3,
"windowTokens": 142,
"inEpoch": true,
"epoch": 2,
"triggersInEpoch": 1,
"consecutiveIdle": 1,
"locked": false,
"lastReasons": ["token-loop: run \"跑\" x 9"],
"recent": [
{ "at": 1693001234567, "kind": "trigger", "reasons": ["token-loop: run \"跑\" x 9"], "action": "armed" },
{ "at": 1693001234789, "kind": "heal", "action": "message", "step": { "turn": 5, "step": 2 } }
]
}
]
}

| Field / 字段 | Meaning / 含义 |
|---|---|
| enabled | Plugin master switch / 插件总开关 |
| sessionId | Session identifier / 会话 ID |
| turn / step | Current agent turn and model-call step / 当前代理 turn 和模型调用 step |
| windowTokens | Tokens currently in the rolling window / 滚动窗口中的 token 数 |
| inEpoch | Whether the session is inside an active healing epoch / 是否在活跃治愈 epoch 中 |
| epoch | Current epoch number / 当前 epoch 编号 |
| triggersInEpoch | Triggers counted in this epoch / 本 epoch 内触发次数 |
| consecutiveIdle | Consecutive idle turns / 连续空转 turn 数 |
| locked | Whether the session is in lockout / 是否在 lockout 中 |
| lastReasons | Human-readable trigger reasons / 人类可读的触发原因 |
| recent | Last 10 ring records (trigger / heal / escalate / recover) / 最近 10 条环记录 |

Session Log Events / 会话日志事件

Two custom event types are declared via cordis module augmentation and appended to the session's event log:

两个自定义事件类型通过 cordis 模块扩充声明,追加到会话事件日志:

| Event / 事件 | Data / 数据 | When / 时机 |
|---|---|---|
| llm/degen-trigger | turn, step, sessionId, reasons[], action (armed/escalate/lockout), stats (tokens, unique, uniqueRatio, topToken, topCount, structured, runMax, altMax) | Detection fires / 检测触发 |
| llm/degen-heal | turn, step, sessionId, kind (message/config/retry/meter), epoch | Intervention taken / 执行干预 |

Harness Logger / Harness 日志

All actions log via ctx.logger.info() with the [llm-degen-heal] prefix:

所有动作通过 ctx.logger.info() 记录,前缀 [llm-degen-heal]:

[llm-degen-heal] trigger session=abc-123 action=armed reasons=token-loop: run "跑" x 9
[llm-degen-heal] heal session=abc-123 kind=message epoch=2
[llm-degen-heal] escalate interrupt session=abc-123 epoch=2 attempt=2
[llm-degen-heal] grant degenerate retry session=abc-123 round=1
[llm-degen-heal] idle meter session=abc-123 turn=5 consecutive=2 (123 words, no tool call, degenerate window)
[llm-degen-heal] heal session=abc-123 kind=meter epoch=2

Installation / 安装

Prerequisites / 前置要求

- A DeepSeek Harness checkout (J:\deepseek-harness monorepo) — for type-check deps and tsc.
DeepSeek Harness  checkout——用于类型检查和编译。
- Node.js 20+ and pnpm (harness standard).
Node.js 20+ 和 pnpm(harness 标准)。
- Bash (the build script is POSIX sh; use Git Bash on Windows).
Bash(构建脚本为 POSIX sh;Windows 使用 Git Bash)。
- gh CLI or git to fetch this repo.
gh CLI 或 git 拉取本仓库。

1. Clone / 克隆

git clone https://github.com/KakaruHayate/dsh-degen-heal.git
cd dsh-degen-heal

2. Build / 构建

Linux / macOS
DSH_CHECKOUT=/path/to/deepseek-harness bash scripts/build.sh
Windows (Git Bash)
DSH_CHECKOUT=Z:/path/to/deepseek-harness bash scripts/build.sh

scripts/build.sh 探测 DSH_CHECKOUT,将插件类型检查所需的 harness 包做 junction 链接,然后用 checkout 的 tsc 编译 src/ → lib/。

3. Harness Profile Integration / 接入 Harness Profile

添加到你的 profile 的 package.json 依赖和 bundles 中:

{
"dependencies": {
"@dsh-external/llm-degen-heal": "link:C:/path/to/dsh-degen-heal"
},
"dsh": {
"profile": {
"bundles": [
"@deepseek-ai/dsh-base",
"@deepseek-ai/dsh-web-app",
"@dsh-external/llm-degen-heal"
]
}
}
}

或者在不修改 profile 文件的情况下热注入:

dev_inject_plugin --dir /abs/path/to/dsh-degen-heal

插件默认 enabled: true。设为 false 为仅观察模式(透传 + 日志)。

4. Verify / 验证

pnpm test          # Run the self-test from the plugin root
or
dsh web            # Start harness; check dev_loop_status tool

Testing / 验收自测

tests/self-test.mjs — Synthetic Deterministic Self-Test

无需真实 provider 调用。使用进程内 cordis.Context + ScriptedAdapter(可编程的 LlmAdapter,其 stream() 回放预编写的 chunk 序列)。

Test scripts / 测试脚本:

| Script / 脚本 | Purpose / 用途 |
|---|---|
| DEGEN_SCRIPT | 40 个 Word0 Word1 Word2 循环 chunk——经典碎词循环退化输出 |
| HEALTHY_SCRIPT | 散文 + 代码块 + 工具调用——结构化、有产出 |

Test cases / 测试用例:

| # | Case / 场景 | Assertion / 断言 |
|---|---|---|
| 1 | Token-loop detection (DEGEN_SCRIPT) | tokenLoop = true, degeneration = true |
| 2 | Entropy-drop + no structure | entropyDrop = true on unstructured low-diversity window |
| 3 | Leak-out detection | leakOut = true when marker phrases appear ≥ threshold |
| 4 | Healthy passthrough (HEALTHY_SCRIPT) | degeneration = false, no injection, no interrupt |
| 5 | Disabled passthrough | enabled: false → zero intervention, zero log |
| 6 | Arm → escalate → LLM_DEGENERATION → bounded retry | Stream interrupted on trigger #2, retry granted, retryUsedInEpoch capped |
| 7 | Disposal cleanup | ctx.effect cleanup runs; states Map cleared |
| 8 | Lockout deadlock escape | After lockoutAt triggers with no recovery → locked = true, all detection silenced |

Manual Verification / 手动验证

在实时 harness 会话中:

1. Start harness
dsh web

2. Open dev tools or run the diagnostic tool
dev_loop_status
→ { enabled: true, sessions: [...] }
3.(可选)通过追加补丁强制触发退化场景:
- 在测试 agent prompt 中插入一段短重复 token 的循环
- 在 dev_loop_status 输出中观察 trigger → heal → recover 循环

Extension Points for Future Integration / 未来集成扩展点

LlmRuntime Waterfall(tool-cordis api-catalog.ts)

Harness 在 packages/extensions/tool-cordis/src/api-catalog.ts(LlmRuntime)中为每次流式模型调用提供了一个 waterfall。当前插件直接挂接 llm/stream,该事件是此 waterfall 的公开别名。如果 Harness 后续暴露更多 waterfall 阶段(如 pre-token hooks、post-stream analysis),插件可在不改变核心检测逻辑的前提下扩展监听。

repetition_penalty / presence_penalty Wire Fields

在当前 Harness 版本中,packages/llm/llm-deepseek/src/serialize.ts 只透传 temperature、max_tokens、stop 和 reasoning 字段。GenerateOptions 和 LlmCallConfig 中没有 repetition_penalty、frequency_penalty 或 presence_penalty 字段。

变通方案: 插件用 (a) 修正消息注入(第 1 层)和 (b) temperature 调整(第 2 层)替代。两者均与 provider 无关,适用于任何 LLM 后端。

真正 penalty 注入所需的核心改动:

在 packages/llm/llm/src/types.ts(LlmCallConfig 接口)中添加一行,并在 packages/llm/llm-deepseek/src/serialize.ts 中做相应透传,即可实现:
typescript
// packages/llm/llm/src/types.ts — add to LlmCallConfig:
repetition_penalty?: number
presence_penalty?: number
typescript
// packages/llm/llm-deepseek/src/serialize.ts — add to serialize() output:
...(call.repetition_penalty !== undefined ? { repetition_penalty: call.repetition_penalty } : {}),
...(call.presence_penalty !== undefined ? { presence_penalty: call.presence_penalty } : {}),

此改动有意不在插件内完成——按插件不修改核心包的约束。如需此功能,是一行核心改动,任何 DSH maintainer 可独立审核合并。

dev_router_mode Band Escalation

插件不自行调用 dev_router_mode。Band escalation(如 weak → strong)留给:
- 操作员:在 dev_loop_status 中看到 lockout 或反复触发后,可以手动调用 dev_router_status / dev_router_mode
- 未来的 Harness 扩展点:暴露一个程序化的 "escalate band" 信号

插件不主动调用 dev_router_mode。Band 升级(如 weak → strong)留给:

- 操作员:在 dev_loop_status 中看到 lockout 或反复触发后手动调用 dev_router_status / dev_router_mode
- 未来 Harness 扩展点:暴露程序化的 "escalate band" 信号

Known Limitations / 已知限制

| # | Limitation / 限制 | Severity / 严重程度 | Workaround / 变通 |
|---|---|---|---|
| 1 | 无 wire-level 的 repetition_penalty / presence_penalty 透传 | Medium / 中 | Temperature delta + 纠正性消息注入(Layers 1 + 2) |
| 2 | 无真正的历史回滚("revert to previous assistant message") | Low / 低 | Interrupt + steer 在上下文中给模型一个全新的开始 |
| 3 | 不调用 dev_router_mode 进行 band 升级 | Low / 低 | 由操作员通过 dev_loop_status 发现后驱动 |
| 4 | 检测窗口是按流的,而非跨会话的 | Low / 低 | 状态是按会话的(SessionDegenState 以 sessionId 为键);跨会话聚合将是未来的功能 |
| 5 | CJK 分词按字符拆分(而非按词) | Info / 提示 | 有意为之的设计选择:能捕获按空白分词会漏掉的字符级循环(跑跑跑…)。对于词级 CJK 检测,可以添加基于词典的分词器。 |
| 6 | lockoutMs 最大 3 分钟可防止永久静默,但对于非常长的会话可能太短 | Info / 提示 | 按部署调整 lockoutMs;设为 0 可完全禁用 lockout(不推荐) |

License / 许可证

BSD-3-Clause。参见 package.json。

上游仓库有新提交时邮件通知你(每天最多一封,无更新不打扰),随时一键退订。

💬 加入 DPharness 群聊

插件用法、部署报错、新插件第一时间同步——群里问,比一个人翻文档快。

点击加入 QQ 群
DPharness 群聊二维码,手机 QQ 扫码进群
扫码进群