DSH HUB
HomePlugin StorePlugin PacksCommunityRankingsResourcesPublish Guide
Plugin source
Back to catalog

Ralsei1337 /

Ralsei1337/dsh-huoren

Verified

给 DSH 的模型输出加活人感:分条发、按字数打字、口头语与语气词、受控错别字与自我更正、情绪心流,外带去 AI 腔过滤器

★ 1 Stars0 Forks0 IssuesN/A Community rating0 Confirmed installs
View on GitHub
READMESource: main@7fa35e6e

dsh-huoren

给 DSH 的模型输出加活人感的插件。

活人感不是「加语气词」。活人感是把一个人用手机打字的物理约束加回去: 屏幕小所以话短,手慢所以一条一条发,脑子会走神所以有停顿,会手滑所以打错字, 有情绪所以前后不一致。

灵感来自 MaiBot(麦麦,开源 QQ 机器人)的工程实现: 它的设计原则是一句话——「最像而不是好」。

与 dsh-doubao 的关系:那个加了「人机感的壳」,这个反过来拆壳。 两者语料不重叠,机制也不重叠。


两条通道

通道 机制 管什么
① 系统提示注入 systemPrompt.section({ order: 166 }) 「说什么」——口气、长度、立场、禁止句式
② 输出流后处理 ctx.on('llm/stream', …) 「怎么发」——分条、节奏、毛边,模型管不到的

可以单独关。只留 ① 更像真人但节奏仍是机器;只留 ② 节奏对了但用词还是客服腔。


五个「活人感来源」

这不是五个功能,是五条互相独立的物理事实。缺一条就像 AI。

1. 节奏:人不会一次吐一整段

pacing.js。时间模型对齐 MaiBot 的 calculate_typing_time():

每条耗时 = Σ 单字耗时 × typingSpeed × (1 ± jitter)
单字耗时:中文 charMs(默认 90ms)、英文数字 ×0.5、空白 ×0.15
标点额外:句号/问号 +pausePunctMs ×1.4,逗号 ×0.6
单个中文字 ×3(一个字要犹豫一下)
上限:maxDelayMs(默认 6s),防止把界面冻住

第一条之前是 thinkMs(默认 800ms)——人不会秒回。

三种时序模式:burst(一条一条发,默认)/ token(保留流式只加抖动)/ off。

2. 分条:人不会写小作文

split.js。抄 MaiBot 的 [response_splitter]:句末断句 → 概率性合并 → 压到 splitMax 条。

  • 断句点:。!? 与 ,;、,但不切在引号、括号、代码块中间
  • 英文小数点、数字里的逗号不切
  • 编号列表、表格、引用整块独占一条,不给它加语气词
  • 含代码块 / 表格 / 图片的回复整段不拆(skipCodeBlocks)

3. 毛边:会手滑,也会自己发现

humanize.js + phrase.js。

项 做法 参数
句首口头语 「嗯」「哦对」「等下」「其实吧」「讲真」 fillerRate
句尾语气词 「。」→「吧」「呗」「啊」「嘛」 particleRate
错别字 40 组常用易混词(应该→因该、已经→以经…),一次回复最多一个 typoRate
自我更正 打错后补一条「打错了,是X」「(X)」 correctionRate
摆烂 太长或被问烦了,直接「不知道哦」 lazyChance

保护:代码块、行内代码、结构化块一律不碰。问句不加语气词(「好不好啊?」听着像撒娇过度)。

4. 去 AI 腔:这是反向通道

clean.js。豆包语插件加壳,这里拆壳。

删的:作为 AI 助手,、希望这对你有帮助、如果还有其他问题随时问我、总的来说、综上所述、需要注意的是、以下是、我理解你的感受。

改的:不是A,而是B → 不是A,是B;—— → ,;短句句末 。 → 去掉;emoji → 删。

硬保证:删完如果是空的,退回原文。绝不吞掉模型说的话。

5. 情绪心流:有状态才叫活人

mood.js。两个值,按会话落盘(~/.dsh/dsh-huoren/mood-<session>.json):

  • energy 精力:被催 −3、深夜 −4、干活(工具轮次)−N
  • warmth 热度:被谢 +3、被骂 −8、被分享私事 +3

每轮向基线(60/55)回落 6%,所以不会永久卡在一个状态。 状态最后变成提示词里的一句话:「你现在有点累,回话短,别铺垫」。


档位

参数 关闭 轻度 自然(默认) 浓烈
最多几条 0 2 3 5
每条字数 60 80 45 30
打字速度 1 1.2 1 0.8
首条思考 ms 0 450 800 1100
标点停顿 ms 0 140 240 320
抖动 % 0 30 45 60
口头语 % 0 12 25 40
语气词 % 0 20 40 60
错别字 % 0 10 25 40
自我更正 % 0 40 60 70
摆烂 % 0 0 2 8
情绪强度 0 30 55 75

「关闭」档强制把所有参数清零,残留旧值不会漏进来。


实测

输入(模型原文):
  作为 AI 助手,我先说明一下。这个 bug 已经修好了,改的是配置文件第三行的缩进。
  总的来说不复杂,希望这对你有帮助!

输出(自然档):
  [0] 我先说明一下。这个 bug 已经修好了,
  [1] 其实吧,改的是配置文件第三行的缩进。不复杂,呢

时间戳(burst,charMs=60,thinkMs=300):

302ms  → 日志我看过了,问题出在配…
1653ms → 第三行的缩进错了,YAM…
2605ms → 我改成两个空格就好了。

设置页

设置 → 活人感。所有旋钮实时预览(预览会按 seed 复现同一结果),保存即重载,不用重启 DSH。

预览区直接渲染成气泡,能看到「会拆成几条、每条长什么样、有没有补一条更正」。


与模型无关的部分

这套改造不依赖模型配合。任何模型吐出来的正文都会经过同一套管线, 所以它同样作用于:别的 provider、压缩摘要以外的轮次、以及你自己写的插件产出的文字。

不处理的轮次:session-title、compaction、auto-review、expression(skipPurposes), 以及以工具调用为主的轮次(skipToolTurns)。


开发

npm test          # 33 个测试,不依赖宿主
lib/
  config.js     档位 / 参数 / 归一化
  phrase.js     词库:口头语、语气词、AI 腔黑名单、易混词表
  clean.js      去人机化(代码块 / 列表 / 表格保护)
  split.js      断句 / 合并 / 压条数
  humanize.js   口头语、语气词、错别字、自我更正
  pacing.js     打字时间、思考时间、可中断 sleep
  mood.js       情绪状态机
  prompt.js     系统提示段落
  render.js     管线编排(清理 → 分条 → 毛边)
  transform.js  llm/stream 瀑布:拆块、重排 index、分条发送
  routes.js     设置页同源接口
  index.js      宿主入口
client.js       设置页 UI(web 平台)

踩过的坑

  1. yield* 会静默丢弃 return 值。直通函数如果 return [chunk], 整条工具流会凭空消失。必须 yield。
  2. 必须重排 block index。把一个文本块拆成三条后会占掉 0/1/2, 上游后面的工具块还是 1 号,直接撞号。要维护「上游 index → 我的 index」映射。
  3. 改了 text-delta 就必须改 block-end.block.text。装配器以 block 为准, 只改增量会被覆盖。
  4. 删套话要只删前缀。作为AI助手, 后面那半句是人话, 一整句吃掉就等于吞掉内容。

已知取舍

  • burst 模式会牺牲 token 级流式:一段文字会等打完才出现。这是刻意的——人就是这样发的。 想要流式就切 token 模式。
  • 错别字只在最后一条出现,且一次回复最多一个。多了就是坏掉了,不是人。
  • 情绪状态在提示词通道里读的是 default 会话的状态;输出流通道按 sessionId 分开存。
  • 不做「假装不是 AI」。用户直接问「你是不是 AI」,照实说。活人感是质感,不是欺骗。

License

MIT

—/ 5

No ratings yet

Verified DSH bundle

Commit 7fa35e6e1b4d

Community comments

No comments yet. Be the first to write one.

DSH HUB

A community index for DSH plugins. Not an official GitHub or DeepSeek AI product.

CommunityResourcesAPIAbout