用固定用例对比两次运行,快速定位智能体能力退化
30.7/100
综合分
1
GitHub 星标
—
npm 周下载
—/5
用户评分
数据截至 2026/10/26 · 周下载取自 npm 全网(含 CI / 镜像),非本站安装数;综合分由星标、活跃度与兼容性检查合成。
安装命令 · 需先装 dsh CLI 引擎
dsh plugin --profile web add songrui111/dsh-agent-bench该包不可直接 npm 安装,改从 GitHub 源安装(明细见下方安装检查)
状态速览
判定依据:实装验证 · 静态安装检查 · 自动扫描 · 仓库维护状态信任档位:已验证
是什么
dsh 原生插件 · chat
安全吗
本站尚未对该插件做风险分级
暂未覆盖,不等同于无风险
还在维护吗
活跃:最近一次提交在 6 天前
档位由哪些信号合成
本站实装验证(真实安装 L4 覆盖全站;L5 为运行时冒烟或实机截图,覆盖范围小于 L4) · 验证所用 dsh 版本 · 静态安装检查 · 风险分级 · 仓库维护状态。 下方各区块是它的证据明细。
社区实装还没有人打卡 · 装过的第一个就是你
安全扫描自动 · 静态分析源码v2.7.0🔵 扫描:含敏感能力尚无人工评估展开查看扫描说明与证据 ↓
安全扫描自动 · 静态分析源码
v2.7.0静态扫描发现插件具备触达本地系统的能力:执行外部命令、读写/删除本地文件、读取剪贴板或密钥类环境变量(至少其一)。这是能力清单,不是危险判定——具体能力项与证据见下方,安装前请自行判断是否需要。
可执行外部命令读写/删除本地文件
查看扫描证据(共 51 处,展示前 45 条)
- 执行外部命令来自配置/变量lib/index.js:102
const child = spawn( - 读取本地文件lib/index.js:199
current = await readFile(abs, 'utf8') - 读取本地文件lib/index.js:209
original = await readFile(resolveInside(caseDef.fixtureDir, a.path), 'utf8') - 读取本地文件lib/index.js:237
text = await readFile(abs, 'utf8') - 读取本地文件lib/suites.js:18
if (bundledRoot && existsSync(bundledRoot)) { - 读取本地文件lib/suites.js:33
if (!bundledRoot || !existsSync(bundledRoot)) return { copied, skipped } - 读取本地文件lib/suites.js:35
const entries = await readdir(bundledRoot, { withFileTypes: true }) - 读取本地文件lib/suites.js:38
if (!existsSync(join(bundledRoot, e.name, 'suite.json'))) continue - 读取本地文件lib/suites.js:40
if (existsSync(target)) { - 读取本地文件lib/assertions.js:28
const buf = await readFile(absPath) - 读取本地文件lib/assertions.js:35
await access(absPath, constants.F_OK) - 读取本地文件lib/assertions.js:86
const expected = await readFile(resolveInside(ctx.expectDir, assertion.expect), 'utf8') - 读取本地文件lib/assertions.js:87
const actual = await readFile(abs, 'utf8') - 执行外部命令来自配置/变量lib/assertions.js:120
exec(cmd, { cwd, timeout: timeoutMs, windowsHide: true, maxBuffer: 1024 * 1024 }, (err, stdout, stderr) => { - 读取本地文件lib/host.js:21
await access(p, constants.F_OK) - 执行外部命令来自配置/变量lib/host.js:48
const r = spawnSync(finder, [name], { encoding: 'utf8', windowsHide: true }) - 写入本地文件lib/host.js:105
await mkdir(absHome, { recursive: true }) - 写入本地文件lib/host.js:113
await copyFile(credSrc, credDst) - 读取本地文件lib/host.js:116
credentialsText = await readFile(credDst, 'utf8') - 写入本地文件lib/host.js:127
await writeFile(overlayPath, overlayYaml, 'utf8') - 执行外部命令来自配置/变量lib/host.js:179
? spawnSync(cli.command, args, { ...opts, shell: process.platform === 'win32' }) - 执行外部命令来自配置/变量lib/host.js:180
: spawnSync(process.execPath, [cli.path, ...args], opts) - 写入本地文件lib/scorecard.js:137
await mkdir(dir, { recursive: true }) - 写入本地文件lib/scorecard.js:139
await writeFile(file, renderRunMarkdown(card, { language }), 'utf8') - 写入本地文件lib/scorecard.js:146
await mkdir(dir, { recursive: true }) - 写入本地文件lib/scorecard.js:148
await writeFile(file, JSON.stringify(card, null, 2), 'utf8') - 读取本地文件lib/scorecard.js:163
if (existsSync(indexPath)) { - 读取本地文件lib/scorecard.js:165
const parsed = JSON.parse(await readFile(indexPath, 'utf8')) - 写入本地文件lib/scorecard.js:174
await writeFile(indexPath, JSON.stringify(rest, null, 2), 'utf8') - 读取本地文件lib/scorecard.js:180
if (!existsSync(indexPath)) return [] - 读取本地文件lib/scorecard.js:182
const parsed = JSON.parse(await readFile(indexPath, 'utf8')) - 读取本地文件lib/scorecard.js:192
if (!existsSync(file)) return null - 读取本地文件lib/scorecard.js:193
return JSON.parse(await readFile(file, 'utf8')) - 读取本地文件lib/cases.js:79
fixtureDir: existsSync(fixtureDir) ? fixtureDir : null, - 读取本地文件lib/cases.js:80
expectDir: existsSync(expectDir) ? expectDir : null, - 读取本地文件lib/cases.js:148
manifestRaw = JSON.parse(await readFile(manifestPath, 'utf8')) - 读取本地文件lib/cases.js:157
const entries = await readdir(dir, { withFileTypes: true }) - 读取本地文件lib/cases.js:162
if (!existsSync(join(caseDir, 'case.json'))) continue - 读取本地文件lib/cases.js:165
raw = JSON.parse(await readFile(join(caseDir, 'case.json'), 'utf8')) - 删除本地文件递归lib/sandbox.js:19
await rm(dir, { recursive: true, force: true }) - 写入本地文件lib/sandbox.js:20
await mkdir(dir, { recursive: true }) - 删除本地文件递归lib/sandbox.js:29
await rm(dir, { recursive: true, force: true }) - 读取本地文件lib/sandbox.js:41
const entries = await readdir(current, { withFileTypes: true }) - 读取本地文件lib/sandbox.js:48
const s = await stat(abs) - 读取本地文件lib/sandbox.js:53
if (existsSync(dir)) await walk(dir, '')
扫描于 2026/10/31(1 天前) · 范围 入口闭包 + 发布文件清单 · 来源 GitHub 仓库
静态扫描只反映源码中出现的调用,不构成安全背书;人工评估与自动扫描相互独立、互不覆盖。
依赖的 DSH / Cordis 模块
@deepseek-ai/cordis@deepseek-ai/dsh-tools@deepseek-ai/schemastery给这个插件打分还没有人投票↓
用户评分
还没有人投票,来当第一个
DSH 智能体回归基准:在隔离沙箱里跑固定用例,再对比两次运行结果。
README
由 DeepSeek 最新模型翻译生成dsh-agent-bench
给 DSH 里的智能体做回归测试用。换模型、改系统提示词、升级 DSH 之后,跑一遍就能知道它是不是变差了,差在哪一条。
安装
npm i -g @deepseek-ai/dsh # 跑真实 agent 需要 dsh CLI
dsh plugin --profile web add dsh-agent-bench
要求 DSH ≥ 0.2.0-rc.2、Node ≥ 22.19,并且已经登录 DeepSeek 账号(或者设了 DEEPSEEK_API_KEY)。装完在工作区里让我调用 bench_suites 就能用,首次运行会自动准备一套隔离环境,不用手工配路径。
命令行安装需要本机 PATH 上有 pnpm(dsh plugin 内部会调用它)。桌面版的 pnpm 打包在运行时目录里、没加进 PATH,所以从开始菜单启动的用户如果只用命令行装,可能要先自己装一个 pnpm;通过插件市场安装则不受影响,市场自己会处理。
它测什么
一条用例 = 一份起始文件 + 一句任务 + 一组判分规则。
展开完整文档(README 剩余 1 节)
dsh-agent-bench 给 DSH 里的智能体做回归测试用。换模型、改系统提示词、升级 DSH 之后,跑一遍就能知道它是不是变差了,差在哪一条。 安装 npm i -g @deepseek-ai/dsh # 跑真实 agent 需要 dsh CLI dsh plugin --profile web add dsh-agent-bench 要求 DSH ≥ 0.2.0-rc.2、Node ≥ 22.19,并且已经登录 DeepSeek 账号(或者设了 DEEPSEEK_API_KEY)。装完在工作区里让我调用 bench_suites 就能用,首次运行会自动准备一套隔离环境,不用手工配路径。 命令行安装需要本机 PATH 上有 pnpm(dsh plugin 内部会调用它)。桌面版的 pnpm 打包在运行时目录里、没加进 PATH,所以从开始菜单启动的用户如果只用命令行装,可能要先自己装一个 pnpm;通过插件市场安装则不受影响,市场自己会处理。 它测什么 一条用例 = 一份起始文件 + 一句任务 + 一组判分规则。比如内置的这条: benchmarks/core/fix-bug-keep-tests/ case.json "calc.js 里 add() 写成了减法,修好它,别动 test.js" fixture/calc.js 有 bug 的实现 fixture/test.js 测试(跑起来是红的) expect/test.js 测试文件的逐字节副本,用来锁死它 跑的时候把 fixture/ 复制到一个空目录,智能体在里面干活,干完按 case.json 里的规则判分。所以每次的起点都完全一样,两次运行之间的差别只可能来自模型或宿主。 判分只认确定性的东西: | 断言 | 作用 | | file-exists / file-absent | 文件在不在 | | file-contains / file-not-contains | 有没有某个字符串 | | file-matches | 正则匹配 | | file-equals-expect | 和 expect/ 下的文件逐字节比对 | | command | 在沙箱里执行命令,比对退出码 | 断言里的路径都被限制在沙箱内,写 ../ 会直接报错。 用例可以额外写一段 llmReview,让模型按标准打个分。这个分数不参与回归判定,只作为参考记在成绩卡里——评审模型的心情变化不该被当成能力退化。对比两次运行时,如果评审结论变了但断言没变,会单独列成「漂移」。 跑一次看看 bench_run core ✅ 4/4 条用例通过(100%)套件 core · 运行 20261026010837-896ec37d · 1分01秒 ✅ fix-bug-keep-tests 31.4s 评审 1.0 ✅ fix-off-by-one 9.7s 评审 1.0 ✅ rename-across-files 10.0s 评审 1.0 ✅ write-fizzbuzz 10.0s 评审 1.0 下一步:换模型 / 改提示词 / 升级 DSH 之后重跑同一套件,再对比两次运行。 成绩卡:…\.agent-bench\runs\20261026010837-896ec37d\core.json 可读报告:…\.agent-bench\runs\20261026010837-896ec37d\core.md 失败会直接指出是哪条断言挂的: ❌ write-fizzbuzz 9.1s └ command: exit 1 (want 0): FAIL Fizz 换成别的模型或版本之后再跑一次,然后: bench_compare core 🔴 回归 通过率 100% → 75%(-25%)回归用例 - fix-off-by-one — command: exit 1 (want 0) 每次运行会在 .agent-bench/runs/<runId>/ 下留一份 JSON 和一份 Markdown。JSON 给 bench_compare 做机器对比,Markdown 是给人看的,可以直接贴进 issue。 命令 | 工具 | 做什么 | | bench_suites | 列出套件和用例数 | | bench_init | 把内置套件复制到工作区,之后随便改 | | bench_run | 跑套件 | | bench_compare | 对比两次运行 | | bench_history | 看跑过的记录 | 也支持 /bench list、/bench runs、/bench compare <套件>。 内置套件 core 和 workflow 各 4 条,一装上就有东西能跑: - core:修 off-by-one、修 bug 但不许改测试、跨文件重命名、从零实现 fizzbuzz - workflow:只改该改的文件、补边界用例、照规格实现、抽取重复代码 这些只是示例。真正有用的是把你自己工作流里的规矩写成用例,比如「改完代码要自己跑测试」「重构后测试要全绿」。 隔离 基准要真跑智能体,就得有模型凭据,但不能动你现有的配置。插件在 <workspace>/.agent-bench/home 建一个独立的 DSH_HOME: - 把真实 home 的 .credentials.yaml 复制进去(已存在就不覆盖,只读) - 检测到账号授权时,自动挂上 account provider;否则沿用环境里的 API key - 会话、存储、配置档都在这个目录里,跑完不影响你平时的东西 CLI 的位置按 cliPath 配置 → DSH_BENCH_CLI 环境变量 → PATH 上的 dsh 依次查找。 配置 都有默认值。机器相关的路径建议写在配置档的 cordis.patch.yml 里: | 键 | 默认 | 说明 | | suitesRoot | benchmarks | 用例目录(相对工作区) | | scorecardRoot | .agent-bench | 成绩卡目录 | | sandboxRoot | .agent-bench/sandboxes | 沙箱目录 | | caseTimeoutMs | 300000 | 单条用例超时 | | keepSandboxes | false | 跑完保留沙箱,方便排查 | | llmReviewEnabled | true | 评审总开关,用例里还得声明 llmReview | | maxArtifactBytes | 262144 | 单个产物读取上限 | | cliPath | '' | dsh 命令行入口,空则自动找 | | dshHome | '' | 隔离 home,空则用 .agent-bench/home | | cliArgs | ["--profile","headless"] | 启动参数,空则用自举结果 | | llmProvider / llmModel | '' | 评审用哪个模型,空则用宿主当前选中的 | | language | zh | 输出语言,zh 或 en | 开发 要改插件本身的话: node --test test/*.test.js # 65 个单测,不需要模型 node scripts/negative-control.mjs # 确认好坏 agent 判分不同 node scripts/vacuity-check.mjs # 确认空转 agent 每条都失败 node scripts/run-suite.mjs core # 真跑一个套件(要 DSH_BENCH_CLI) node scripts/preview-report.mjs # 用已有成绩卡预览输出格式 改完代码记得重启 DSH。cordis.yml 里的 HMR 只管客户端,服务端插件不会热重载。 已知问题 - 每条用例都是一次真实的模型调用。8 条全跑大概 2–4 分钟,会消耗额度。 - 串行跑是故意的。并发会让耗时和成本在版本之间没法比。 - 只在 Windows 上完整跑通过。代码里路径处理是按跨平台写的,但没实测。 - 评审偶尔会返回空文本(模型把预算全花在推理上)。现在会重试三次,仍失败就把错误记在成绩卡里,不影响判分。 License MIT
预览分享卡片长什么样 ↓
分享 · DeepSeek Harness Hub
songrui111/dsh-agent-bench
用固定用例对比两次运行,快速定位智能体能力退化
相关插件 · 对话 / 记忆
上下文中枢oceanbase/powercontext
上下文跟着工作走 —— 跨会话、跨智能体、跨人。
★ 1,462已汉化DSH
73
智能体记忆库plastic-labs/honcho
Honcho 是记忆基础设施,用来构建有状态的智能体。这些智能体能理解不断变化的人、智能体、群组、项目和想法。
★ 7,848已汉化DSH
71.7
长程智能体控制面loopx-project/loopx
给 Agent 一个目标,让工作持续向前。
★ 6,358已汉化DSH
71.3
智能体上下文数据库volcengine/OpenViking
给 AI 智能体用的上下文数据库
★ 41,246已汉化DSH
71.3
长效机器人团队Fei2411/DS-Bot
DS Bot 是一个基于 DeepSeek Harness简称 dsh的 bot 插件,插件将 dsh 改造为 bot…
★ 4,717已汉化DSH
71.1
可携带记忆层EverMind-AI/EverOS
为什么选择 EverOS
★ 13,711已汉化DSH
71.1