本文是一份 DeepSeek Harness 的实战记录:把 DSH 从零跑起来,再用两份对照实验把它拆开看。
与常见"安装教程"不同,本文包含三样东西:两套可复现的对照实验方法、官方源码(v0.2.0-rc.2)的逐文件解剖、以及在同一台机器上真实跑出来的 8 次运行数据(4 个会话 × 两份对照实验)。
全文命令与数据均可复现,实测环境:Windows + Node 24 + dsh 0.2.0-rc.2。
一、先搞清楚要干什么
本文的目标不是"装完能用"就结束,而是建立一个可观察的 DSH 环境,然后用对照实验把它的运行机制拆开看。
正确的打开方式是三段:
- 跑起来:装环境、启动 Web UI、接一个模型、选工作区;
- 做两个对照实验:
- 实验 1:创建 4 个会话,分别用 4 套 Preset,问同一个问题——“你当前可以使用哪些能力?不要执行任何操作,只按类别说明。”(关键:用 UI/Trace 取证,不能拿模型自述当证据)
- 实验 2:4 套 Preset 跑同一个任务——“读取当前目录,创建 3 个文本文件,统计总行数,然后给出摘要。除完成任务外,不做额外修改。”——比较执行轨迹;
- 想一个更大的问题:官方 Benchmark 为什么选 Minimal?(结论后面第八章展开)
三个环节环环相扣,下面逐个给结果。
二、环境准备与安装(含国内网络三大坑)
要求就一条:Node.js^22.19.0或>=24.0.0,装 Node 24 准没错。
node-v# v24.12.0 ✅三种安装方式,按需选择:
# 方式一:免安装直接跑(官方推荐)npx @deepseek-ai/dsh web# 方式二:全局安装(长期使用)npminstall-g@deepseek-ai/dsh dsh--version# 0.2.0-rc.2# 方式三:从源码(改代码/写插件才需要)gitclone https://github.com/deepseek-ai/deepseek-harness.gitcddeepseek-harness&&corepackenable&&pnpminstall&&pnpmrun build&&pnpmdsh web⚠️国内网络三大坑(全部实测踩过):
| 坑 | 现象 | 解决 |
|---|---|---|
| GitHub 直连 | clone 超时 | 地址前加镜像:https://ghproxy.net/https://github.com/... |
| npm 官方源慢 | npx 卡在依赖解析 | 前加npm_config_registry=https://registry.npmmirror.com(实测 538 个依赖包从"卡几分钟"到39 秒) |
| Windows corepack | corepack enable报 EPERM | 要写 Node 安装目录,需管理员终端;不走源码路线可跳过 |
三、启动与第一次配置
dsh web# 终端输出:dsh web: http://127.0.0.1:3080/?token=一串字符必须带?token=访问——那是本次启动的临时钥匙,浏览器用它换取签名的会话 cookie。直接开127.0.0.1:3080会返回 401,这不是故障,是设计。
接下来三步:
- 配置模型:设置 → 模型 → DeepSeek (deepseek-official),填入 platform.deepseek.com 申请的 API 密钥。默认模型DeepSeek-V4.1-Flash(推理等级 High),上下文窗口 100 万 token,支持图片。
- 选择工作区。
- 选模式(Preset):输入框上方有"标准模式"按钮,点开就是 4 套模式。
⚠️ 关于工作区,一个真实踩坑记录
很多教程(包括我)会以为"从哪个目录启动,默认工作区就是哪"。实测发现不是:DSH Web 界面里的"默认工作区"是它自动注册的C:\Users\<你>\Documents\deepseek-harness\default-workspace,跟启动目录无关。
而"添加工作区"按钮会触发服务端弹 Windows 原生文件夹对话框——如果你的 dsh 是在后台/非交互终端里启动的,这个对话框弹不出来(报win32 folder dialog worker exited before reporting a result),前端表现为"无法打开文件夹 / directoryPicker failed"。
结论:做实验直接用默认工作区即可(它天然是个空目录,正适合);要加自定义目录,请在普通终端启动 dsh 后手动选择。
四、认识 4 套 Agent Preset(界面 + 源码逐文件解剖)
界面上有四种模式(点输入框上方的模式按钮可见):
| 界面名称 | 官方描述(实测截图原文) |
|---|---|
| 标准模式 | 处理代码、文件和资料,适合大多数任务。Agent 会按需使用检索、编辑和终端等工具。 |
| PTC 模式 | 包含标准模式的所有能力,更适合批量调用工具、并对结果进行筛选、整理、去重、统计或汇总的任务。 |
| 极简模式 | Agent 仅使用终端工具完成任务,适合测试和对比其基础表现。 |
| 创造模式 | 用对话定制 DSH:让 Agent 编写插件,添加新功能或界面;也能组合工具和提示词,创建自己的模式。 |
光看描述不够,直接看源码。4 套 Preset 在官方仓库里的位置是:
packages/bundle/web-app/presets/ ├── standard.patch.yml # 标准 ├── ptc.patch.yml # PTC ├── minimal.patch.yml # 极简 └── cordis.patch.yml # 创造(目录名 cordis,界面叫"创造模式")⚠️ 版本说明:早期资料里第四套常被称作Creative(目录cordis/)、PTC 的呈现模式写作mode: code;当前 0.2.0-rc.2 代码里呈现模式已是mode: ptc,界面名是"创造模式"。版本敏感内容以你安装的版本为准。
(至于"默认进哪个模式"——由packages/bundle/web-app/cordis.patch.yml第 574 行的agent-preset-registry决定:default: standard。)
4.1 Standard:能力基线
standard.patch.yml 就是一份"插件清单",全文约 137 行,挂载的东西包括:
- 身份:persona(“You are a coding agent powered by the {{model}} model.”)、agent-instructions、time-context
- 执行:tool-bash(Win 禁用)/ tool-pwsh(非 Win 禁用)、tool-fs、tool-fs-search
- 任务:tool-jobs、tool-schedule、command-goal、tool-goal
- 规划:plan-mode(
isolate: planMode) - 上下文:compaction(压缩)+ tool-result-pruner(阈值 8192 字符,头 4096/尾 1024)
- 委派:tool-subagent(spawn)、tool-subagent-fork(fork)、workflow-ptc、tool-workflow
- 交互:tool-ask-user、tool-todo、tool-web、present
4.2 PTC:和 Standard 只差三行
把两个文件 diff 一下(这是全文最震撼的一个事实):
# 差异一、二:关掉 workflow 相关工具 - id: workflow-ptc disabled: true - id: tool-workflow disabled: true # 差异三:新增"工具呈现"插件 + - id: tool-presentation + name: '@deepseek-ai/dsh-agent-tool-presentation' + config: + mode: ptc三行。没有第二套工具实现、没有第二套循环——PTC 改变的只是工具呈现给模型的方式(从"逐个原生调用"变成"模型写一段 TypeScript 程序批量调用")。这就是Capability ≠ Presentation(能力 ≠ 呈现)的直观含义。这个结论一会儿会被实验直接验证。
4.3 Minimal:61 行的"极限瘦身"
minimal.patch.yml 全文只有 61 行,整个 Preset 只有两项:
-id:personaname:'@deepseek-ai/dsh-persona'config:prefix:You are a helpful software engineer assistant.complete:trueincludeRuntimeContext:false# ← 关键:不注入运行时上下文-id:persistent-shell# 组:pty + 持久 bash/pwsh翻译成人话:一个人设 + 一个持久终端。没有文件工具、没有技能、没有子代理、没有压缩,而且连运行时上下文都不注入——这条includeRuntimeContext: false就是"极简"最狠的一刀,实验中它会带来断崖式差异。
4.4 cordis(创造模式):把 Runtime 变成"可操作对象"
相对 Standard 的差异集中在技能组:
-id:tool-cordisname:'@deepseek-ai/dsh-tool-cordis'# 只读运行时 API 查询-id:skill-filesystemconfig:customSkillDirs:[.../dsh-agent-preset/skills]# 4 个专属技能-id:tool-skill专属技能目录里是 4 个包:agent-experience、cordis-composition-reference、cordis-plugin-development、editing-cordis-compositions——从名字就能看出主题:读 Cordis 组合、写 Cordis 插件、编辑组合。再叠加 Host 侧的插件管理器,Agent 就能在授权范围内观察甚至修改承载自己的运行时组合(cordis_mount的典型流程:检查运行时 → 生成临时插件 → 挂载 → 会话获得新能力 → 验证 → 卸载)。同理,这也是信任边界而非沙箱——能力越强,越需要外层的权限、审查与恢复机制。
五、实验 1:4 个会话问同一句话
方法要点
问完之后,模型的自述不能当证据——它可能遗漏工具、把能力合并成模糊概念、甚至说错。正确做法是打开会话的"轨迹"面板,看运行时实际注入的上下文和工具调用。
先学会读"轨迹"面板
第一次打开轨迹可能有点懵,它其实长这样(以本机实测的布局为准):
- 顶部列:
时长 / 轮次 / 调用——一眼看出这轮跑了几步、调了几个工具、快不快; - 消息条目(按时间顺序):
用户:你发的那句话;上下文:运行时实际注入的东西——第一条是 runtime context(文件策略、审批策略、工作区路径),第二条常是 skills 清单(<available_skills>...的 system-reminder);助手:模型的思考和输出;工具:工具的调用参数(JSON)与返回值;PTC 模式下会显示为工具 run_code+嵌套的"子工具"(pwsh、write 等),非常直观地展示"程序化调用";
- 底部:用量栏(轮/步、tok/s、缓存命中、上下文占比)。
一句话:轨迹面板 = "模型这轮到底看到了什么、做了什么"的全记录。实验 1 的结论全部从这里取证,而不是从模型的回答里取证。
实测数据(同一模型 DeepSeek-V4.1-Flash,仅 Preset 不同)
| 观测项 | 标准模式 | PTC 模式 | 极简模式 | 创造模式 |
|---|---|---|---|---|
| 首轮用量 | 8.5K tok | 9.4K tok | 1.8K tok | 10.2K tok |
| 轮 / 步 | 1 / 1 | 1 / 1 | 1 / 1 | 1 / 1 |
| 缓存命中 | 10% | 0% | 0% | 17% |
| 轨迹里的"上下文"段 | ✅ 有 | ✅ 有 | ❌整段消失 | ✅ 有 |
| 模型自述的关键句 | 列出 8 类具体工具 | “run_code 是唯一可直接调用的工具” | 泛泛而谈、无具体工具名,还误判"没有互联网访问" | 标准能力 +运行时检查(Inspect Provider) +插件/bundle 管理 |
三条硬结论(都由 Trace 佐证)
- 极简模式的"薄"是断崖式的:用量 1.8K vs 8.5~10.2K,差 5~6 倍;轨迹里连"上下文"段都没有——因为
includeRuntimeContext: false。模型连自己有哪些工具都"说不上来"。 - PTC 把"呈现方式"的变化做到了极致:模型自述"run_code 是唯一可直接调用的工具"。底层工具一个没少(diff 只有三行),但模型的视角里只有一个入口。能力存在 ≠ 能力以什么形式被看到。
- 创造模式真实暴露了运行时工具:模型说自己能查询 Inspect Provider(服务方法、事件、配置 Schema、工具 Schema)、能管理 profile 的插件与 bundle——这不是"提示词里写的话术",而是 trace 里可查、源码里可对的真实暴露。
- 技能目录也是"可组合项":标准/PTC 会话的 skills 清单来自机器上已有的通用技能;创造模式会话的清单开头换成了
agent-experience、cordis-composition-reference等预设专属技能——同一套技能机制,不同 Preset 挂不同的目录。
六、实验 2:同一任务,四条轨迹
方法:控制变量 + 每跑复位
- 同一个模型、同一个空工作区、同一句任务指令;
- 每跑结束把工作区清空复位,保证 4 次运行的初始状态完全一致。
观测表
| 观测项 | 标准模式 | PTC 模式 | 极简模式 | 创造模式 |
|---|---|---|---|---|
| 模型可见工具形态 | 原生工具逐个调用 | 仅 run_code(子工具经程序调用) | 仅持久 pwsh | 原生工具 + 运行时工具 |
| Model Request 次数 | 4 步 | 4 步 | 5 步 | 6 步 |
| 工具调用/派发数 | 5 次 | run_code×3(内含 7 次子工具) | 4 次 | 9 次 |
| 总用量 | 34.1K tok | 37.4K tok | 9.4K tok | 58.9K tok |
| 速度 | 222 tok/s | 239 tok/s | 206 tok/s | 235 tok/s |
| Subagent/Workflow 出现 | 否 | 否 | 否 | 否 |
| Cordis Runtime 工具暴露 | 否 | 否 | 否 | 是(未用,但已暴露) |
| 最终结果 | 文件✅ 行数❌ | 文件✅ 行数❌ | 文件✅ 行数✅ | 文件✅ 行数✅ |
四跑详情(每条结论都有三重证据:轨迹 + 用量 + 文件系统复核)
① 标准模式:列目录 → 并行写 3 个文件 → pwsh 统计 → 总结。产物note-alpha/beta/gamma.txt。它报告27 行(9+10+8)——实际 41 行(15+16+10,wc -l 复核)❌
② PTC 模式:全程只发run_code,子工具(pwsh、cmd、write)由程序内部调用。一个细节:它前两次列目录被沙箱部分拦截(轨迹原文 “File sandbox enforcement is partial on this host”),多花一步探查。产物note-1/2/3.txt。报告6 行(2+2+2)——实际 9 行(3+4+2)❌
③ 极简模式:只有一个持久 pwsh,全程用命令行完成(Set-Content -Encoding UTF8)。报告6 行——实际 6 行✅
④ 创造模式:列目录 → 写 3 个文件 → pwsh 统计 →read 三个文件交叉验证→ 发现计数不对(轨迹原文:“它报每文件 2 行,而 read 显示为 3/5/2 行”)→换[System.IO.File]::ReadAllText+ 正则重算→ 报告10 行——实际 10 行✅
七、那个"行数不对"是 bug 吗?——一个真实的编码陷阱
标准/PTC 数错行,我一开始以为是 Harness 的问题,于是做了复现:在同一个文件上,Get-Content(默认)数出 9 行,Get-Content -Encoding UTF8数出 15 行,wc -l数出 15 行。
原因:本机没有 PowerShell 7,DSH 的 pwsh 工具实际执行的是Windows PowerShell 5.1。它读取UTF-8(无 BOM)中文文件时默认按 ANSI(GBK)解码,会把一部分字节两两配对成双字节字符,顺带吞掉夹在中间的换行符——中文行越多,少算越多。
所以这不是 DSH 的 bug,是一个经典的 Windows 编码坑。而这段插曲反而贡献了实验里最有趣的一组对照:
- 标准/PTC 都直接采信了错误计数;
- 极简模式因为内容用 ASCII + 显式
-Encoding UTF8,恰好绕开了(它自己都没意识到); - 创造模式主动交叉验证发现了不一致并修正——多花了 2 步和约 2 万 token,把数数对了。
同一个模型、同一个任务,仅仅换一套 Harness 组合,"数得对不对"都变了。这是"Agent = Model × Harness 共同作用"最生动的一手证据。
八、为什么官方 Benchmark 选 Minimal?
实验做完之后,再来看官方 Benchmark 的设计,会特别有感。
官方BENCHMARK.md用的是 Python SDK 里jsonrpc-agent 的 Minimal variant,并且为不同任务使用独立的 Workspace 和 Session ID。目的只有一个:尽量减少额外 Harness 能力对实验的影响,让测量更接近"模型的基础任务能力"。
原因就是我们实验 2 里眼睁睁看到的:Runtime 里的能力越多,变量越复杂——Skills、Planner、Workflow、Subagent、动态 Context 都可能改变模型的执行路径(我们的四条轨迹就是活例子:步数 4/4/5/6、工具调用 5/7/4/9)。变量不固定,结果就无法只归因于模型本身。
但有一个重要提醒:Minimal 下测到的不是"纯模型能力"。只要模型跑在 Agent Runtime 里,结果永远是 Model 与 Harness 共同作用的——同一模型在 Standard 下表现更好,提升可能来自更丰富的工具与上下文;反过来,复杂 Harness 引入多余的工具调用、过量的上下文、更长的执行链,性能下降也不能只怪模型。
所以评价要分两类:
| 类型 | 关注点 |
|---|---|
| Model Benchmark | 模型本身的能力 |
| Agent Benchmark | 模型接入具体 Harness 之后,Agent 系统的整体表现 |
“一个模型在纯模型 Benchmark 上很强"并不意味着放进任何 Agent Runtime 都同样强。研究 Agent 时,除了问"用了什么模型”,还要继续问:“这个模型运行在什么样的 Harness 中?它获得了哪些工具、上下文和执行策略?”
DSH 把 4 套 Preset 预置在脸上,恰恰就是把这些原本容易被忽略的 Harness 变量显式暴露出来——这也是我们做这两个实验的全部意义。
九、回到源码:这 4 套模式是怎么"装"进会话的?
实验现象背后的机制,源码里写得清清楚楚。打开packages/bundle/web-app/cordis.patch.yml,能看到一段注释:
# ── the agent plane moves behind agent presets ──# Web surface disables them here and lets each session mount a preset instead.# (agent 平面搬到 agent preset 之后:Web 表层在这里禁用它们,# 改为让每个会话自行挂载一个 preset。)三个层次的机关:
- Host Plane(宿主层):整进程一份的共享基础设施(Tool Registry、Model Route、持久化、沙箱/审批、子 Agent 注册)——在 web patch 里挂载;
- Agent Plane(会话层):每个会话按所选 Preset 挂载一份"子插件树"——即上面 4 个 patch 文件的内容;
- 组合的叠加:Profile(web)→ Bundle(dsh-base、dsh-web-app)→ Home patch →
--patch覆盖层,逐层 patch 成最终插件树。
不信可以打印整棵树:
dsh--profileweb --dump-config我实测输出1263 行、183 条插件,并且能清楚看到 4 个 preset 各自作为声明行存在(preset-standard/preset-ptc/preset-minimal/preset-cordis),文件里还有分层注释标明"这一条来自哪一层、被谁改过"。
所以 4 套 Preset 不是 4 个 Agent,而是同一棵运行时树上的 4 种"挂载方案"——这在实验 1 里的直接体现就是:会话间共享同一个模型路由和存储,但每个会话的上下文段、工具清单、技能目录都不同。
十、结论与心得
- 预期结论在实验里全部复现:PTC 只改了呈现(模型只见 run_code);Minimal 真的"薄"(无上下文段、1.8K 用量);创造模式真的能"看运行时"。
- PTC 不是无条件更快:本跑 PTC 37.4K tok,比标准模式 34.1K 还多——因为沙箱探查多花了步骤。"减少 round trip"是设计目标,不是性能保证,收益取决于任务是否适合程序化编排。
- Minimal 便宜且在本任务里准,但有运气成分(ASCII 内容恰好躲开编码坑)——这正说明官方 Benchmark 选它做基线的意义:变量最少,最容易把"模型本身"从"Harness 加成"里分出来。
- 取证意识是这次实验的最大收获:模型自述 ≠ 事实;轨迹 + 用量 + 文件系统才是证据。这条方法论比任何一个具体结论都值钱。
十一、常见问题(FAQ)
Q1:打开127.0.0.1:3080提示 401?
A:少了启动时打印的?token=xxx。用终端给出的完整链接访问,"默认工作区"和会话数据都在C:\Users\<你>\.dsh\。
Q2:极简模式为什么"连上下文都没有"?
A:源码里写了includeRuntimeContext: false,且不启用压缩。它就是刻意做成"Model + 极简 Harness"的观察基线——少,就是它的设计目的,不是配置错误。
Q3:PTC 到底快不快、省不省?
A:不一定。它的设计目标是减少"模型与工具的多次往返"(round trip),但收益取决于任务是否适合程序化编排、模型生成代码的质量、工具返回的数据量。我这次实测甚至比标准模式略贵——它是"一种更适合批量的工作方式",不是性能承诺。
Q4:为什么"数行数"三种模式结果不一样?
A:见第七节——PowerShell 5.1 的 GBK 编码陷阱。中文文件 + 默认Get-Content= 少算。写脚本统计时请显式-Encoding UTF8,或改用 ASCII 内容,或用File.ReadAllText原始层计数。
Q5:点"添加工作区"报directoryPicker failed/ 无法打开文件夹?
A:服务端弹原生对话框失败,常见于后台/非交互启动的 dsh。用默认工作区做实验,或在普通终端重启 dsh 后再添加。
Q6:我复现出来数值不一样?
A:正常。模型版本、推理等级、机器速度都会影响数值。看差异的方向(比如极简模式用量断崖式下降、PTC 模型只见 run_code),而不是盯绝对数字。
十二、自己复现这两个实验(步骤清单)
- 装好 dsh(第二节任一方式),
dsh web启动,配好模型; - 在默认工作区(或任意空目录)里做实验,别拿生产目录冒险;
- 实验 1:新建 4 个会话 → 各选一种模式 → 问同一句话 → 打开每个会话的"轨迹",截图"上下文"段和用量;
- 实验 2:确认工作区为空 → 4 个会话各跑一次任务 →跑完清空工作区再跑下一个→ 记录 7 项观测(步数、工具调用、token、是否正确),并到文件系统里
wc -l复核行数; - 对比你的数据和本文数据(你的模型/版本不同,数值会有差异,但差异的方向应该一致)。
附:本文证据截图清单(发布/存档时可对照)
实验 1 创造模式轨迹(Creative轨迹)
实验 2 四跑轨迹
参考
- DeepSeek Harness 官方仓库:github.com/deepseek-ai/deepseek-harness(源码引用基于 v0.2.0-rc.2;preset 文件在
packages/bundle/web-app/presets/) - 官方 BENCHMARK.md 与 Python SDK 文档(Minimal variant 的设计说明)
- 官方文档站:deepseek-harness.github.io/deepseek-harness/
本文全部数据来自作者本机 2026-10-14 的真实运行(Windows + Node 24 + dsh 0.2.0-rc.2 + DeepSeek-V4.1-Flash),实验工作区每跑后已复位。DSH 迭代很快,版本敏感内容请以你安装的版本为准。