🎁 福利专区全网大模型免费应用 + 新用户福利 + 注册活动入口,低成本玩转 AI

客服台 lzaPro/dsh-cs-agent

DeepSeek Harness
lzaPro11 天前有提交已提供中文文档扫描:含敏感能力

接入 QQ 自动应答客户,答不了转人工与运维派单

30/100
综合分
0
GitHub 星标
—
npm 周下载
—/5
用户评分

数据截至 2026/10/24 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。

安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add lzaPro/dsh-cs-agent
该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)

状态速览

判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态
信任档位:仅索引
是什么[目录]—
dsh 原生插件 · platform
暂无时间戳·判据 →
装得上吗[实装验证]—
本站尚未做安装检查
暂无时间戳·判据 →
安全吗[自动扫描]—
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
数据截至 2026/11/05·判据 →
还在维护吗[仓库]✓
活跃:最近一次提交在 11 天前
暂无时间戳·判据 →
图例:✓ 通过! 需注意— 未判定 / 无数据· 「未判定」= 本站尚无数据,不代表插件有问题
档位由哪些信号合成

本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。

验证判据与等级说明 →

可信度证据

安全扫描自动 · 静态分析源码
v2.7.0
🔵 扫描:含敏感能力尚无人工评估
展开查看扫描说明与证据 ↓

静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。

可执行外部命令读写/删除本地文件读取剪贴板或密钥环境变量发起外部网络请求
查看扫描证据(共 81 处,展示前 76 条)
  • 发起网络请求
    cs-agent/adapter/cli.js:54
    const response = await fetch(url, {
  • 读取本地文件
    cs-agent/adapter/env.js:22
    text = readFileSync(file, 'utf8')
  • 读取本地文件
    cs-agent/auth.js:72
    text = readFileSync(file, 'utf8')
  • 读取本地文件
    cs-agent/auth.js:77
    const mode = statSync(file).mode & 0o777
  • 读取本地文件
    cs-agent/db/migrate.mjs:39
    const names = (await readdir(MIGRATIONS_DIR)).filter(name => name.endsWith('.sql')).sort()
  • 读取本地文件
    cs-agent/db/migrate.mjs:42
    const sql = await readFile(path.join(MIGRATIONS_DIR, name), 'utf8')
  • 写入本地文件
    cs-agent/gateway-smoke.mjs:374
    writeFileSync(healData, JSON.stringify({
  • 写入本地文件
    cs-agent/gateway-smoke.mjs:394
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    cs-agent/gateway-smoke.mjs:396
    writeFileSync(
  • 写入本地文件
    cs-agent/gateway-smoke.mjs:433
    mkdirSync(dir, { recursive: true })
  • 写入本地文件
    cs-agent/gateway-smoke.mjs:440
    writeFileSync(
  • 读取本地文件
    cs-agent/gateway-smoke.mjs:519
    const last = readFileSync(path.join(temp, 'mention-outbox.jsonl'), 'utf8').trim().split('\n').pop()
  • 写入本地文件
    cs-agent/gateway-smoke.mjs:577
    writeFileSync(dataFile, JSON.stringify({
  • 读取本地文件
    cs-agent/gateway-smoke.mjs:626
    const last = readFileSync(path.join(temp, 'speaker-outbox.jsonl'), 'utf8').trim().split('\n').pop()
  • 读取本地文件
    cs-agent/gateway-smoke.mjs:677
    check(existsSync(dir) === true, 'delete keeps the session files for DSH')
  • 读取本地文件
    cs-agent/gateway-smoke.mjs:704
    const last = readFileSync(path.join(temp, 'drift2-outbox.jsonl'), 'utf8').trim().split('\n').pop()
  • 读取本地文件
    cs-agent/gateway-smoke.mjs:737
    check(existsSync(envPath), 'env file is written')
  • 读取本地文件
    cs-agent/gateway-smoke.mjs:738
    check(readFileSync(envPath, 'utf8').includes('QQ_APP_SECRET=topsecret'), 'secret is persisted')
  • 读取本地文件
    cs-agent/gateway.js:232
    const adapterCommand = existsSync(adapterCandidate) ? adapterCandidate : undefined
  • 读取本地文件
    cs-agent/gateway.js:408
    text = readFileSync(file, 'utf8')
  • 请求外部主机api.bot.qq.com
    cs-agent/gateway.js:460
    const response = await fetch('https://api.bot.qq.com/app/getAppAccessToken', {
  • 发起网络请求
    cs-agent/gateway.js:460
    const response = await fetch('https://api.bot.qq.com/app/getAppAccessToken', {
  • 发起网络请求
    cs-agent/gateway.js:608
    const response = await fetch(item.url, { signal: AbortSignal.timeout(15_000) })
  • 发起网络请求
    cs-agent/gateway.js:1063
    const response = await fetch(replyWebhook, {
  • 发起网络请求
    cs-agent/gateway.js:1614
    const response = await fetch(adapterHealth, { signal: AbortSignal.timeout(2000) })
  • 写入本地文件
    cs-agent/install/setup.mjs:33
    mkdirSync(target, { recursive: true })
  • 读取本地文件
    cs-agent/install/setup.mjs:34
    for (const entry of readdirSync(source, { withFileTypes: true })) {
  • 读取本地文件
    cs-agent/install/setup.mjs:42
    if (options.skipExisting && existsSync(dst)) continue
  • 写入本地文件
    cs-agent/install/setup.mjs:43
    copyFileSync(src, dst)
  • 写入本地文件
    cs-agent/install/setup.mjs:50
    mkdirSync(join(root, name), { recursive: true })
  • 读取本地文件
    cs-agent/install/setup.mjs:68
    const existing = existsSync(kbTarget) ? readdirSync(kbTarget).filter(name => name.endsWith('.json')) : []
  • 读取本地文件
    cs-agent/install/setup.mjs:68
    const existing = existsSync(kbTarget) ? readdirSync(kbTarget).filter(name => name.endsWith('.json')) : []
  • 读取密钥环境变量
    cs-agent/install/setup.mjs:79
    let appSecret = flag('app-secret') ?? process.env.QQ_APP_SECRET
  • 读取本地文件
    cs-agent/install/setup.mjs:93
    const existingEnv = existsSync(envFile) ? readFileSync(envFile, 'utf8') : ''
  • 读取本地文件
    cs-agent/install/setup.mjs:93
    const existingEnv = existsSync(envFile) ? readFileSync(envFile, 'utf8') : ''
  • 写入本地文件
    cs-agent/install/setup.mjs:97
    writeFileSync(envFile, [
  • 读取本地文件
    cs-agent/lease-smoke.mjs:39
    check(existsSync(`${dataFile}.lock`), 'file lease writes a lock file')
  • 读取本地文件
    cs-agent/lease-smoke.mjs:40
    check(JSON.parse(readFileSync(`${dataFile}.lock`, 'utf8')).pid === process.pid, 'file lease records the pid')
  • 读取本地文件
    cs-agent/lease-smoke.mjs:45
    check(!existsSync(`${dataFile}.lock`), 'release removes the lock file')
  • 读取本地文件
    cs-agent/lease-smoke.mjs:47
    check(existsSync(`${dataFile}.lock`), 'a released lock can be taken again')
  • 写入本地文件
    cs-agent/lease-smoke.mjs:51
    writeFileSync(`${dataFile}.lock`, JSON.stringify({ pid: 999_999, at: new Date().toISOString() }))
  • 读取本地文件
    cs-agent/lease-smoke.mjs:53
    check(JSON.parse(readFileSync(`${dataFile}.lock`, 'utf8')).pid === process.pid, 'a dead holder is taken over')
  • 写入本地文件
    cs-agent/lease-smoke.mjs:57
    writeFileSync(`${dataFile}.lock`, 'not json')
  • 写入本地文件
    cs-agent/lease.js:39
    writeFileSync(lockPath, JSON.stringify({ pid: process.pid, at: new Date().toISOString() }))
  • 删除本地文件
    cs-agent/lease.js:40
    return () => rmSync(lockPath, { force: true })
  • 写入本地文件
    cs-agent/lease.js:42
    mkdirSync(path.dirname(lockPath), { recursive: true })
  • 写入本地文件
    cs-agent/lease.js:44
    writeFileSync(lockPath, JSON.stringify({ pid: process.pid, at: new Date().toISOString() }), { flag: 'wx' })
  • 删除本地文件
    cs-agent/lease.js:45
    return { kind: 'file', path: lockPath, release: () => rmSync(lockPath, { force: true }) }
  • 读取本地文件
    cs-agent/lease.js:51
    holder = JSON.parse(readFileSync(lockPath, 'utf8'))
  • 读取本地文件
    cs-agent/ocr-smoke.mjs:42
    if (existsSync(sampleSource) && existsSync(visionBinary)) {
  • 写入本地文件
    cs-agent/ocr-smoke.mjs:55
    writeFileSync(fake, '#!/bin/sh\necho "错误码 -122 disk quota exceed"\n')
  • 写入本地文件
    cs-agent/ocr-smoke.mjs:56
    chmodSync(fake, 0o755)
  • 读取本地文件
    cs-agent/ocr.js:83
    if (!existsSync(resolved)) throw new Error(`ocr_image: file not found: ${resolved}`)
  • 读取本地文件
    cs-agent/ocr.js:112
    if (process.platform === 'darwin' && typeof config?.visionBinary === 'string' && existsSync(config.visionBinary)) {
  • 发起网络请求
    cs-panel/client.js:33
    const response = await fetch('/channel/sessions')
  • 发起网络请求
    cs-panel/client.js:46
    const response = await fetch(path, {
  • 发起网络请求
    cs-panel/client.js:124
    const response = await fetch(url)
  • 发起网络请求
    kb-core/embed.js:219
    const response = await fetch(`${baseURL}/embeddings`, {
  • 写入本地文件
    kb-core/tools-schema-smoke.mjs:31
    await mkdir(kbDir, { recursive: true })
  • 写入本地文件
    kb-core/tools-schema-smoke.mjs:50
    await writeFile(path.join(kbDir, `${entry.id}.json`), `${JSON.stringify(entry, undefined, 2)}\n`)
  • 删除本地文件递归
    kb-core/tools-schema-smoke.mjs:255
    await rm(root, { recursive: true, force: true })
  • 发起网络请求
    ops-agent/client.js:39
    fetch('/ops/status'),
  • 发起网络请求
    ops-agent/client.js:40
    fetch('/ops/incidents'),
  • 发起网络请求
    ops-agent/client.js:165
    await fetch(next ? '/ops/enable' : '/ops/disable', {
  • 执行外部命令来自配置/变量
    ops-agent/cluster.js:105
    execFile(
  • 写入本地文件
    ops-agent/dispatcher.js:127
    await mkdir(workspace, { recursive: true })
  • 写入本地文件
    ops-agent/dispatcher.js:446
    await mkdir(path.dirname(stateFile), { recursive: true })
  • 写入本地文件
    ops-agent/dispatcher.js:447
    writeFileSync(stateFile, `${JSON.stringify({ enabled, changedAt, changedBy, note: changeNote }, null, 2)}\n`, 'utf8')
  • 写入本地文件
    ops-agent/dispatcher.js:460
    await mkdir(path.dirname(ledger), { recursive: true })
  • 写入本地文件
    ops-agent/dispatcher.js:462
    await appendFile(ledger, `${JSON.stringify({ at, ...row })}\n`, 'utf8')
  • 读取本地文件
    ops-agent/dispatcher.js:468
    const raw = await readFile(ledger, 'utf8')
  • 读取本地文件
    ops-agent/dispatcher.js:535
    const raw = await readFile(ledger, 'utf8')
  • 读取本地文件
    ops-agent/dispatcher.js:598
    const raw = JSON.parse(readFileSync(file, 'utf8'))
  • 读取密钥环境变量
    ops-agent/metrics.js:53
    : process.env.GRAFANA_TOKEN ?? ''
  • 读取本地文件
    ops-agent/probe.mjs:18
    for (const line of readFileSync(join(here, '.env.local'), 'utf8').split('\n')) {
  • 发起网络请求
    ops-agent/probe.mjs:34
    const response = await fetch(url, { headers, signal: AbortSignal.timeout(timeout) })
扫描于 2026/11/5(0 天前) · 范围 全包扫描 · 来源 GitHub 仓库
涉及外部主机:api.bot.qq.com

静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。

社区实装还没有人打卡 · 装过的第一个就是你
给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个

DSH 客服台:QQ 接入、知识库、人工接管、运维派单

README

由 DeepSeek 最新模型翻译生成
DSH 客服台 在 DeepSeek Harness 上跑一套接 QQ 的客服系统:客户消息进来自动答,答不了转给运维智能体,人工随时可以接管。 三个 npm 包,一层渠道网关,全部挂在 DSH 原生插槽上,不改 DSH 源码。 客户 QQ ──► 适配器 ──► 渠道网关 ──► 客服智能体 ──► 知识库 │ └──► 运维智能体(可选,只和客服/管理员对话) 包 | 包 | 作用 | | cs-agent | 渠道网关、知识库工具(kb_search / kb_get / kb_propose)、OCR、客服预设、QQ 适配器、安装脚本 | | cs-ops | 运维预设 + 派单调度器:每个故障开一个独立运维会话,等结论,超时通知管理员 | | cs-panel | DSH 界面:设置左栏入口、会话标题栏的「接管 / 回复」、侧栏「人」标记 | 工作台是一个独立页面(/channel/panel):会话列表、搜索、归档、备注、人工接管、QQ 凭证配置。
展开完整文档(README 剩余 1 节)
DSH 客服台

在 DeepSeek Harness 上跑一套接 QQ 的客服系统:客户消息进来自动答,答不了转给运维智能体,人工随时可以接管。

三个 npm 包,一层渠道网关,全部挂在 DSH 原生插槽上,不改 DSH 源码。

客户 QQ ──► 适配器 ──► 渠道网关 ──► 客服智能体 ──► 知识库 │ └──► 运维智能体(可选,只和客服/管理员对话)

包

| 包 | 作用 |
| cs-agent | 渠道网关、知识库工具(kb_search / kb_get / kb_propose)、OCR、客服预设、QQ 适配器、安装脚本 |
| cs-ops | 运维预设 + 派单调度器:每个故障开一个独立运维会话,等结论,超时通知管理员 |
| cs-panel | DSH 界面:设置左栏入口、会话标题栏的「接管 / 回复」、侧栏「人」标记 |

工作台是一个独立页面(/channel/panel):会话列表、搜索、归档、备注、人工接管、QQ 凭证配置。

快速开始

1. 装依赖(三个包都没有运行时依赖,直接链进 profile 即可)在 DSH 里用 plugin_manager 装上这三个目录,或复制到 profile 的 node_modules

2. 初始化运行目录(问你要 AppID / Secret,建目录,写 600 的 .env.local)
node cs-agent/install/setup.mjs

3. 启动 QQ 适配器 cs-agent/adapter/qq.sh start

4. 打开 DSH:设置 → 客服 → 打开工作台

完整步骤(QQ 开放平台配置、OCR、部署模式)见 INSTALL.md。

配置

所有路径都有默认值,落在 ~/.dsh/cs-runtime:

~/.dsh/cs-runtime/
├── adapter/ QQ 适配器 + .env.local(AppID / Secret) ├── kb/ 知识库 JSON ├── data/ 会话映射、发件箱、任务日志 ├── customer-private/ 客户私聊会话工作区 ├── customer-group/ 客户群聊会话工作区 ├── eval/ 评测隔离工作区 └── ops/ 运维会话工作区

换位置只改一个环境变量:export DSH_CS_ROOT=/data/cs-runtime。

QQ 凭证可以在「设置 → 客服」的配置页里填,也可以跑 setup.mjs。改完要重启 dsh(适配器在启动时读环境文件)。

测试

./scripts/verify-all.sh

255 项检查:知识库、网关(含配置读写)、接管、OCR、适配器、QQ 签名与事件、运维调度、运行时迁移、保留策略、安装器、客户端插槽渲染。

目录

cs-agent/ 客服包 + adapter/ + install/ + kb-starter/ cs-ops/ 运维包 cs-panel/ 界面插件(client.js) scripts/ 导入、迁移、保留策略、会话对账、验证 docs/ 渠道契约、部署模式、事故台设计 tools/ macOS Vision OCR 的 Swift 源码(可选)

已知限制

- OCR:macOS 走自带的 Vision(tools/build-ocr.sh 编译),其它平台用 tesseract,配置里把 backend 改成 tesseract。
- QQ 主动消息:需要开放平台给「主动消息」权限;没有权限时,超过 5 分钟被动回复窗口的回复会失败,错误会显示在工作台里。
- 群消息:默认只推送 @机器人 的消息;要收全部图片消息,需要在开放平台开启「接收所有消息」。
- 运维只读:运维智能体只有读权限的工具,写操作要人批准(结论里写清楚动作、影响、回滚)。

许可

MIT,见 LICENSE。三个包 cs-agent、cs-ops、cs-panel 各自也带一份。
预览分享卡片长什么样 ↓lzaPro/dsh-cs-agent
分享 · DeepSeek Harness Hub
lzaPro/dsh-cs-agent

接入 QQ 自动应答客户,答不了转人工与运维派单

这个插件是你维护的吗?
作者本人可认领并核对本条目;认领通过后,详情页会显示「作者已认领」标记。
认领条目 →
回到顶部