dsh-qq-onebot-bridge
QQ 集成接入(qq-integration):把 OneBot v11 实现(内置 Waylay 拉起)接到 DSH agent 的双向桥插件,控制台为独立进程(127.0.0.1:8880)
同名包的其他仓库
安装
npx -p @deepseek-ai/dsh dsh plugin --profile web add github:mkiea/qq-integration说明文档
阅读完整 README ↗2. 写最小配置(不写这段她一句话都不会说)
配置写进 profile 的 ~/.dsh/profiles/web/cordis.patch.yml(不要写进仓库根目录那份):
- id: dsh-qq-onebot-bridge
config:
cwd: 'C:\Users\你\qq_chat' # AGENT 的工作区(模型在里面跑命令)
dataDir: 'C:\Users\你\qq_chat' # 记忆/聊天记录/金丝雀的根目录(下面第 3 步也能选)
botQq: 1000000000 # 机器人自己的 QQ
allowUsers: [2000000001] # 允许私聊的号
allowGroups: [3000000001] # 允许的群
🔴 两个白名单空着 = 全部拒绝(刻意的安全默认)。这不是 bug: 不在名单里的会话根本不会被创建,所以不会"回一句拒绝",trace 里直接记「白名单」被拒。
配置
profile 的 cordis.patch.yml 覆盖 id: dsh-qq-onebot-bridge 的 config(完整示例见 examples/cordis.patch.example.yml):
⚠️ 别改错文件:仓库根目录也有一个同名
cordis.patch.yml,那是安装用的 bundle patch(4 行,只有insert: - id: …),不要往里填配置。真正要改的是 profile 目录里的那份,例如~/.dsh/profiles/web/cordis.patch.yml(Windows:C:\Users\\.dsh\profiles\web\cordis.patch.yml)——它在仓库外,密钥写在那里才不会进 git。
| 键 | 默认 | 说明 |
|---|---|---|
host | 127.0.0.1 | 反向 WS 监听地址 |
port | 6700 | 反向 WS 监听端口 |
accessToken | '' | OneBot 端须携带的 Bearer token(空=不校验) |
allowUsers | [] | 用户白名单(空=拒绝所有私聊,务必填入自己的 QQ 号)。群消息也要求发送者在这个列表里——除非把 groupCheckMembers 关掉 |
allowGroups | [] | 群白名单(空=拒绝所有群消息,列出机器人服务的群号) |
groupCheckMembers | true | 群内是否也校验成员在 allowUsers 里。关掉后:白名单群里任何成员说话都能触发(仍然要 @ 它,allowGroups 照旧生效)。症状对照:群里除了自己别人说话它一个字都不回 ⇒ 先看这一项 |
botQq | 0 | 机器人 QQ 号(用于群内 @ 检测;0=任何群消息视为@) |
replyOnlyWhenMentioned | true | 群聊仅 @机器人 才回复 |
acceptPrivate | true | 是否回复私聊(私聊仍需 allowUsers 放行) |
autoCollectStickers | false | 自动收藏消息里的图片表情到本地图库 |
faceEnabled | true | 表情功能总开关([face:] 标记 + qq_face_* 工具) |
sessionMode | chat | 群会话分组:chat=每群一会话;user=每群每人一会话 |
cwd | '' | 会话工作目录(同时决定 qq-faces/、qq-replies/、qq-bridge-debug.log 的位置) |
provider | '' | LLM provider 覆盖(空=agent 默认) |
model | '' | LLM 模型覆盖(空=agent 默认) |
maxMessageLength | 1700 | 单条出站消息最大字符数(超出自动分段) |
botName | 小鲸鱼 | 机器人显示名(合并转发卡片的署名) |
sessionResumeEnabled | true | 宿主重启后 resume 上次会话(完整记录续接);关掉则每次重启都新建会话 |
agentMediaToolsEnabled | true | 暴露 qq_send_image / qq_send_file / qq_send_voice / qq_recall 工具 |
fileSendDirs | [] | agent 允许发送文件的额外目录(会话 cwd 始终允许) |
fileSendMaxBytes | 52428800 | agent 可发送的单文件大小上限(字节,默认 50 MiB) |
imageSendMaxBytes | 4194304 | 图片超过此大小(默认 4 MiB)先用 ffmpeg 压缩再发 |
recallWindowSeconds | 110 | 出站消息可被 qq_recall / /撤回 撤回的时间窗(秒) |
forwardLongReplies | false | 群聊超长回复改发合并转发卡片 |
forwardThresholdChars | 600 | 触发合并转发的字数阈值 |
actionRatePerMinute | 20 | 写操作闸门:全部会话合计每分钟上限 |
actionRatePerDay | 500 | 写操作闸门:全部会话合计每日上限 |
actionAuditEnabled | true | 写操作与拒绝记录写入 cwd/qq-actions.log |
keywordEnabled | false | 关键词问答库(默认关闭):命中本地词库直接回复,不走模型、不需要 @ |
keywordFile | '' | 词库文件路径(空=cwd/qq-keywords.json);支持 exact/contains/regex、随机多答、图片、作用域与冷却 |
fortuneEnabled | true | 今日人品/运势、抽签、塔罗(按 QQ 号+日期确定性生成,纯本地) |
diceEnabled | true | 骰子(.r 3d6)与随机抽人(/抽一个 A B C) |
pointsEnabled | false | 积分经济(默认关闭):/积分 /排行榜 /转账 @某人 数量 |
pointsPerMessage | 1 | 每条消息获得的积分(0=聊天不得分) |
pointsDailyCap | 20 | 每人每日通过聊天可得积分上限 |
pointsCheckinBonus | 5 | 每日签到额外奖励积分 |
gameEnabled | false | 群内小游戏(默认关闭):成语接龙、猜数字 |
idiomChainTimeoutSeconds | 120 | 接龙闲置超时(秒) |
guessNumberMax | 100 | 猜数字上限(1~N) |
guessNumberMaxTries | 10 | 猜数字可用次数 |
antiRecallEnabled | false | 防撤回(默认关闭):缓存最近消息,被撤回时补发内容 |
antiRecallInGroup | true | 补发到群里(false=私聊发给第一个管理员) |
antiRecallImages | true | 一并补发被撤回的图片(最多 3 张) |
antiRecallCacheSize | 50 | 每会话缓存的消息条数 |
antiRecallMaxAgeMinutes | 120 | 缓存消息可恢复时长(分钟) |
antiRecallCooldownSeconds | 5 | 同一会话两次补发的最小间隔 |
filterEnabled | false | 敏感词过滤(默认关闭) |
filterWordsFile | '' | 词表路径(空=cwd/qq-badwords.txt;# 注释、re: 正则、改动自动热重载) |
filterAction | warn | 处置方式:warn 提醒 / recall 撤回 / mute 禁言 |
filterMuteSeconds | 300 | mute 处置与刷屏升级时的禁言秒数 |
filterWhitelist | [] | 白名单词/正则(命中即放行) |
floodEnabled | false | 刷屏防护(默认关闭) |
floodWindowSeconds | 10 | 刷屏统计窗口(秒) |
floodMaxMessages | 8 | 窗口内允许的消息条数 |
floodMuteSeconds | 300 | 刷屏升级禁言秒数 |
floodStrikeLimit | 3 | 警告几次后禁言 |
chatTurnLimitEnabled | false | 每分钟会话上限总开关(默认关闭):关着时完全不限流;打开后按下一行的数字生效 |
chatTurnsPerMinute | 5 | 每分钟会话上限的数值(1–10,默认 5):每个会话每分钟最多让几条消息进模型,超出的丢弃并记账(不排队)。与 rateLimitMaxReplies 不同——那个管"回出去多少条",这个管"进模型多少次"。面板「安全与风控」里用 − 数字 + 改 |
verifyEnabled | false | 入群/加好友验证(默认关闭):请求进队列并私聊推送管理员 |
verifyKeyword | '' | 口令:验证消息包含它则自动放行(空=全部人工审批) |
verifyTimeoutSeconds | 300 | 请求超时时间(超时出队并提醒管理员) |
verifyMaxPending | 20 | 待审队列上限 |
statsEnabled | false | 发言统计(默认关闭):/统计 今日活跃榜、/周榜 周榜,并作为日报数据源 |
statsKeepDays | 30 | 发言统计保留天数 |
groupReadEnabled | true | 只读群信息:/荣誉 /公告 /群精华 |
mcStatusEnabled | true | /mc 查询 Minecraft Java 服务器状态(Server List Ping,无 Key) |
mcStatusTimeoutMs | 5000 | MC 状态查询超时(毫秒) |
recurringReminderEnabled | true | 重复提醒:「每天8点」「每周一9点」「每个工作日15点」 |
dailyReportEnabled | false | 每日群日报(默认关闭):到点让 agent 总结当天聊天并发到群里 |
dailyReportTime | 22:00 | 日报时间(本地 HH:mm) |
dailyReportChats | [] | 固定接收日报的会话(如 ["g:100000001"];为空则用 /日报 on 的开关,再为空则回落到全部群白名单) |
sttEnabled | false | 语音转文字总开关 |
sttBaseUrl | https://open.bigmodel.cn/api/paas/v4 | STT 端点(OpenAI 兼容 /audio/transcriptions) |
sttModel | glm-asr-2512 | STT 模型(智谱 glm-asr-2512 / SiliconFlow FunAudioLLM/SenseVoiceSmall) |
sttApiKey | '' | STT API Key(可复用智谱 GLM 系列的 key) |
privateImageView | true | 私聊中主动下载查看对方发送的图片/动画表情(存 cwd/qq-images/,agent 用 describe_image 查看) |
visionMode | tool | 识图方式:tool=存盘后由 visionToolName 工具查看(稳定);native=原生多模态附件直传模型(DSH 0.1.1+,文本模型自动降级) |
visionToolName | describe_image | tool 模式下使用的识图工具名 |
imageRetentionDays | 14 | 下载图片(qq-images/qq-replies)保留天数,宿主启动时清理更旧的 |
imageTrashEnabled | true | 删除策略:只回收不销毁——过期图片移动到 cwd/qq-trash// 而不是删除(失败则保留原文件) |
imageTrashDir | '' | 回收目录(空=cwd/qq-trash);该目录不会自动清理,由你自行处理(本机可 scripts/safe-delete.ps1 送进回收站) |
memoryEnabled | true | 每会话持久化记忆(最近对话存 cwd/qq-memory/,宿主重启后自动恢复;/new 清除) |
memoryMaxEntries | 60 | 每个会话保留的对话条数上限 |
rateLimitEnabled | false | 回复限流开关(默认关闭);开启后每会话窗口内最多回复 rateLimitMaxReplies 条 |
rateLimitMaxReplies | 10 | 限流窗口内每会话最大回复数 |
rateLimitWindowSeconds | 60 | 限流滑动窗口(秒) |
dedupEnabled | true | 消息去重(同一 message_id 窗口内重复投递忽略,防重连重发) |
dedupWindowSeconds | 300 | 去重窗口(秒) |
reminderEnabled | true | 定时提醒总开关(群聊需 @,私聊直接说;存 cwd/qq-reminders.json 跨重启保留) |
reminderMaxPerChat | 10 | 每个会话最多同时保留的提醒数 |
quietHoursEnabled | false | 避开高峰期开关(默认关闭);开启后工作日静默时段内不回复任何入站消息(不消耗模型调用),已排定的定时提醒/投票开奖照常 |
quietHours | ['9:00-12:00', '14:00-18:00'] | 静默时段(本地时间 H:MM-H:MM,全角冒号自动归一化;可跨午夜如 22:00-2:00) |
quietWeekendExempt | true | 周六/周日不受静默时段限制 |
ttsEnabled | false | 语音回复总开关(默认关闭;开启后每条文字回复后跟随一条语音) |
ttsProvider | azure | 合成方案:azure(微软晓晓)/ openai(任意 OpenAI 兼容 /audio/speech)/ local(本地 GPT-SoVITS 语音克隆,零 API 成本) |
ttsApiKey | '' | Azure / OpenAI 兼容服务的 key(local 不需要) |
ttsVoice | zh-CN-XiaoxiaoNeural | 云端音色名 |
ttsStyle | chat | Azure 语气风格(cheerful/sad…) |
ttsMaxChars | 120 | 语音朗读最大字符数(超出截断,只影响语音不影响文字) |
ttsLocalUrl | http://127.0.0.1:9880 | 本地 GPT-SoVITS api_v2 服务地址 |
ttsLocalRefAudio | '' | 本地 TTS 必填:音色参考音频绝对路径(3-10 秒 wav,如 D:/voice/xiaojingyu.wav) |
ttsLocalPromptText | '' | 参考音频的台词(可留空) |
ttsLocalTextLang | zh | 合成文本语言 |
ttsLocalPromptLang | zh | 参考音频台词语言 |
ttsLocalConvertToMp3 | true | 本地 wav 输出用 ffmpeg 自动转 mp3 再发送(QQ/NapCat 兼容性更好) |
pokeEnabled | true | 戳一戳回复开关(白名单会话内被戳随机卖萌回复) |
pokeReplies | [...] | 戳一戳回复文案列表(随机选一条) |
pokeCooldownSeconds | 15 | 每会话戳一戳回复最小间隔(秒,防刷) |
voiceReadingEnabled | false | 语音朗读:@机器人引用文字说「读一下/念出来」,或 /读 (走 ttsProvider 合成) |
checkinEnabled | false | 每日签到(默认关闭):说「签到」打卡,连续/累计天数存 cwd/qq-checkin/;「签到榜」看排行 |
checkinKeyword | 签到 | 签到触发词 |
welcomeEnabled | false | 入群欢迎语(默认关闭):新人进群自动 @+欢迎文案(机器人自己入群不触发) |
welcomeText | '' | 欢迎文案(空=内置默认文案) |
imageGenEnabled | false | 生图开关(默认关闭):/画 生成图片(群聊需 @机器人) |
imageGenProvider | openai | 生图后端:openai=任意 OpenAI 兼容 /images/generations(DALL·E/CogView/SiliconFlow…);local=本地 SD WebUI(AUTOMATIC1111) |
imageGenBaseUrl | '' | 后端地址(空=按 provider 取默认:api.openai.com 或 127.0.0.1:7860) |
imageGenApiKey | '' | OpenAI 兼容服务 key(local 不需要) |
imageGenModel | '' | 模型 id(空=服务默认,如 gpt-image-1;local 忽略) |
imageGenSize | 1024x1024 | 图片尺寸 WxH(local 支持任意尺寸如 768x512) |
imageGenSteps | 20 | 采样步数(仅 local) |
imageGenCfgScale | 7 | CFG 提示词强度(仅 local) |
imageGenSampler | '' | 采样器(仅 local,空=WebUI 默认) |
imageGenCooldownSeconds | 60 | 每会话两次生图最小间隔(秒,成本/刷屏防护) |
imageGenDailyLimit | 20 | 每会话每日生图上限 |
imageGenMaxPromptChars | 400 | 描述词最大字数(超出截断) |
imageGenCommand | /画 | 生图触发命令 |
traceEnabled | true | 全链路结构化事件(每条消息一个 traceId,每个分支带 reason);关掉则控制台只剩端口/日志能力 |
traceLevel | debug | debug 记录全部事件(含每次静默/拒绝);warn 只留问题,用于长期运行省磁盘 |
traceMemorySize | 500 | 内存里保留的最近事件数(控制台决策链用),落盘另受 4MiB 轮转上限约束 |
traceFile | '' | 事件文件路径(空=cwd/qq-trace.jsonl) |
recordInbound | true | 录制:把收到的每条消息/通知/请求写进 qq-inbox.jsonl(可离线回放);只写本机、不影响回复 |
inboxFile | '' | 录制文件路径(空=cwd/qq-inbox.jsonl,按 2MiB 轮转) |
inboxRedact | false | 录制时把 6 位以上数字(QQ 号)脱敏后再落盘,便于把录制文件发给别人 |
injectEnabled | false | 事件注入通道(默认关闭):开启后桥每 injectIntervalMs 轮询 qq-inject.jsonl,把新行喂进真实管线 |
injectFile | '' | 注入队列路径(空=cwd/qq-inject.jsonl);启动时已有的历史行会被跳过并记一条原因 |
injectDryRun | true | 强烈建议保持 true:注入触发的所有出站调用(发消息/撤回/群管…)都被拦截并计数,绝不真发 QQ;异步 agent 回合的回复同样被拦下(原文记进事件流) |
injectIntervalMs | 2000 | 注入队列轮询间隔(毫秒,最小 500) |
完整配置参考(自动生成,2026-11-05)
上表只放"日常会动"的项。这一节是 schema 里的全部剩余项,默认值从代码读, 说明保留 schema 原文(英文)—— 不做机器翻译,避免翻出"看着通顺但含义漂移"的中文。
由
tools/gen-config-reference.mjs生成;改 schema 后重跑即可,别手改这一节。 示例里的号码一律用占位(100000001/2000000001),与真实账号无关。
主动通道(proactive)(9 项)
| 键 | 默认 | 说明(schema 原文) |
|---|---|---|
oneSentencePerMessage | true | Split each reply into one-sentence messages, sent one after another with a short typing delay. Real people do not type two paragraphs at once - they reply on... |
oneSentenceMaxParts | 3 | Max messages one reply may be split into (default 3). Anything beyond is merged into the last one so it never turns into a wall of bubbles. |
oneSentenceMinChars | 1 | Fragments shorter than this are merged back into the previous sentence. Default 1 = never merge, so a bare "嗯。" or "好。" can be its own message - real people ... |
proactiveEnabled | false | Proactive channel (default OFF): a scheduler reads cwd/bio-clock.mjs and, when the clock says it is a good moment, opens a turn of its own so the character c... |
proactiveDryRun | true | Proactive channel dry-run (default ON): decide and log what would be said, but never open a turn and never send. Turn this off only after reading a few days ... |
proactiveTickSeconds | 60 | How often the proactive scheduler re-evaluates (seconds). One evaluation per chat per tick; the decision itself comes from bio-clock.mjs. |
proactiveStateFile | 空 | Where per-chat proactive state lives (empty = cwd/qq-proactive-state.json). State is kept per chat key, so one chat quota never eats another chat quota. |
proactiveBioClockFile | 空 | Path to the bio-clock module (empty = cwd/bio-clock.mjs). It must export decide(state, now, config, lastUserAt). |
proactiveUsers | [] | Who the character may ping on her own (QQ user ids). Empty = every private chat that has a session, as long as it still passes allowUsers. Groups are never i... |
群运营(groupOps / ops)(19 项)
| 键 | 默认 | 说明(schema 原文) |
|---|---|---|
groupOpsEnabled | false | Group operations toolbox (default OFF): native group check-in, @all quota, mute list, batch kick, group todos, group profile, file organisation, album upload... |
nativeSignEnabled | false | Enable /群打卡: the REAL QQ group check-in (set_group_sign), separate from the local streak game behind /签到. |
opsReadEnabled | true | Enable the read-only ops queries once groupOpsEnabled is on: /全体余量, /禁言名单, /群资料, /入群通知. |
opsKickEnabled | false | Enable /批量踢 (set_group_kick_members, admin, batch confirm) — kicks several members in one native call. |
opsKickBatchSize | 20 | How many members one batch-kick request carries (larger lists are split, never truncated). |
opsTodoEnabled | false | Enable group todos: /待办, /完成待办, /取消待办 on a quoted message (set/complete/cancel_group_todo). |
opsFileEnabled | false | Enable file organisation: /移动文件, /重命名文件, /删文件, /新建文件夹 (move/rename/delete_group_file, create_group_file_folder). Destructive, so it is off by default and adm... |
opsAlbumUploadEnabled | false | Enable /传图: upload a quoted image into a group album (upload_image_to_qun_album). |
opsProfileEnabled | false | Enable group profile edits: /群名 and /群备注 (set_group_name, set_group_remark). Admin only. |
opsPolicyEnabled | false | Enable join/speak policy: /成员权限 (set_group_member_permissions, partial update) and /历史可见 (set_group_new_member_history_visibility). Admin only. |
opsAdminEnabled | false | Enable /设管理 and /撤管理 (set_group_admin). Needs groupOpsEnabled. The enable flag is ALWAYS sent explicitly: the probe showed NapCat treats a missing enable as ... |
opsInvitePolicyEnabled | false | Enable /邀请策略 (set_group_member_invite_policy) with the four documented values: disabled / require_approval / no_approval / no_approval_under_100. Needs group... |
opsAddOptionEnabled | false | Enable /加群方式 (set_group_add_option). Needs groupOpsEnabled. add_type is a raw QQ number with NO documented enum, so /群搜索 (no_*_finger_open) is deliberately n... |
requestSyncEnabled | false | Enable /申请: actively pull pending join requests (get_group_system_msg) and doubtful friend requests (get_doubt_friends_add_request) into the approval queue, ... |
requestSyncCount | 50 | How many notifications /申请 pulls per call. Capped at 100 on purpose: NapCat resolves an approval flag by searching only the newest 100 notifications (set_gro... |
adminWatchEnabled | false | Watch group_admin notices: tell the chat when the bot gains or loses group admin. The known state is tracked either way, so write commands can report "I am n... |
opsReportEnabled | false | Enable /周报 and the ops counters that feed it (messages, joins, leaves, kicks, mutes, sign-ins, reactions). |
opsReportDays | 7 | Window of /周报 in days. |
opsCountersFile | 空 | Where the ops counters for /周报 are persisted (empty = cwd/qq-ops.json). |
互动(engage / poke / 表情回应 / 点赞)(18 项)
| 键 | 默认 | 说明(schema 原文) |
|---|---|---|
engageEnabled | false | Interaction pack (default OFF): poke back, typing status, emoji reactions, profile likes and mark-as-read. Every sub-switch below must also be on. |
pokeBackEnabled | false | Poke back with a REAL poke action (group_poke / friend_poke) instead of only replying with text. |
pokeBackText | 空 | Optional line sent together with the poke-back (empty = poke only, no message). |
pokeCommandEnabled | false | Allow the admin command /戳 to poke someone on purpose (rate limited per hour). |
pokePerHour | 5 | Hard cap of outgoing pokes per chat per hour. |
typingEnabled | false | Show a "typing" status in PRIVATE chats while the model is working (set_input_status; the probe showed NapCat has no group equivalent). |
emojiLikeEnabled | false | React to incoming messages with an emoji (set_msg_emoji_like) inste |