第一章:从 LLM 到 Agent ------ DeepSeek Harness 入门
本章目标
如果你第一次听说 DeepSeek Harness(以下简称 DSH),这一章希望回答五个最基本的问题:
- DSH 到底是什么?
- 为什么有了大模型,还需要 Harness?
- DSH 和普通聊天机器人、Agent Framework 有什么区别?
- DSH 能做什么,怎么运行起来?
- 当我们给 DSH 一条任务时,它大致经历了什么?
本章只建立整体认知,不深入 Cordis、Service、Event、Effect 等内部机制。它们会在后续章节中逐层展开。
1.1 从"会回答问题"到"会完成任务"
过去两年,我们已经非常熟悉这样一种大模型使用方式:
text
用户输入问题
↓
大语言模型
↓
生成回答
例如:
text
用户:
解释一下这个 Python 报错是什么意思。
LLM:
这是由于 xxx 导致的,你可以尝试......
这种模式非常适合知识问答、文本生成、代码解释、内容总结。
但是,如果用户把问题改成:
text
请检查当前项目,
找到所有 TODO,
运行测试,
分析失败原因,
修改能够安全修复的问题,
最后给我一份报告。
事情立刻发生了变化。
这已经不是单纯的"回答问题",而是一个需要观察环境、规划步骤、使用工具、执行操作、读取结果并继续决策的完整任务。
图 1-1:普通 LLM 与任务型 Agent 的差异
#mermaid-svg-PuPEx4BxIfgN7LHu{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-PuPEx4BxIfgN7LHu .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-PuPEx4BxIfgN7LHu .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-PuPEx4BxIfgN7LHu .error-icon{fill:#552222;}#mermaid-svg-PuPEx4BxIfgN7LHu .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-PuPEx4BxIfgN7LHu .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-PuPEx4BxIfgN7LHu .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-PuPEx4BxIfgN7LHu .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-PuPEx4BxIfgN7LHu .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-PuPEx4BxIfgN7LHu .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-PuPEx4BxIfgN7LHu .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-PuPEx4BxIfgN7LHu .marker{fill:#333333;stroke:#333333;}#mermaid-svg-PuPEx4BxIfgN7LHu .marker.cross{stroke:#333333;}#mermaid-svg-PuPEx4BxIfgN7LHu svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-PuPEx4BxIfgN7LHu p{margin:0;}#mermaid-svg-PuPEx4BxIfgN7LHu .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-PuPEx4BxIfgN7LHu .cluster-label text{fill:#333;}#mermaid-svg-PuPEx4BxIfgN7LHu .cluster-label span{color:#333;}#mermaid-svg-PuPEx4BxIfgN7LHu .cluster-label span p{background-color:transparent;}#mermaid-svg-PuPEx4BxIfgN7LHu .label text,#mermaid-svg-PuPEx4BxIfgN7LHu span{fill:#333;color:#333;}#mermaid-svg-PuPEx4BxIfgN7LHu .node rect,#mermaid-svg-PuPEx4BxIfgN7LHu .node circle,#mermaid-svg-PuPEx4BxIfgN7LHu .node ellipse,#mermaid-svg-PuPEx4BxIfgN7LHu .node polygon,#mermaid-svg-PuPEx4BxIfgN7LHu .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-PuPEx4BxIfgN7LHu .rough-node .label text,#mermaid-svg-PuPEx4BxIfgN7LHu .node .label text,#mermaid-svg-PuPEx4BxIfgN7LHu .image-shape .label,#mermaid-svg-PuPEx4BxIfgN7LHu .icon-shape .label{text-anchor:middle;}#mermaid-svg-PuPEx4BxIfgN7LHu .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-PuPEx4BxIfgN7LHu .rough-node .label,#mermaid-svg-PuPEx4BxIfgN7LHu .node .label,#mermaid-svg-PuPEx4BxIfgN7LHu .image-shape .label,#mermaid-svg-PuPEx4BxIfgN7LHu .icon-shape .label{text-align:center;}#mermaid-svg-PuPEx4BxIfgN7LHu .node.clickable{cursor:pointer;}#mermaid-svg-PuPEx4BxIfgN7LHu .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-PuPEx4BxIfgN7LHu .arrowheadPath{fill:#333333;}#mermaid-svg-PuPEx4BxIfgN7LHu .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-PuPEx4BxIfgN7LHu .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-PuPEx4BxIfgN7LHu .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PuPEx4BxIfgN7LHu .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-PuPEx4BxIfgN7LHu .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PuPEx4BxIfgN7LHu .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-PuPEx4BxIfgN7LHu .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-PuPEx4BxIfgN7LHu .cluster text{fill:#333;}#mermaid-svg-PuPEx4BxIfgN7LHu .cluster span{color:#333;}#mermaid-svg-PuPEx4BxIfgN7LHu div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-PuPEx4BxIfgN7LHu .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-PuPEx4BxIfgN7LHu rect.text{fill:none;stroke-width:0;}#mermaid-svg-PuPEx4BxIfgN7LHu .icon-shape,#mermaid-svg-PuPEx4BxIfgN7LHu .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-PuPEx4BxIfgN7LHu .icon-shape p,#mermaid-svg-PuPEx4BxIfgN7LHu .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-PuPEx4BxIfgN7LHu .icon-shape .label rect,#mermaid-svg-PuPEx4BxIfgN7LHu .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-PuPEx4BxIfgN7LHu .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-PuPEx4BxIfgN7LHu .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-PuPEx4BxIfgN7LHu :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 任务型 Agent
用户任务
LLM
调用工具
真实环境
执行结果 / Observation
最终结果
普通 LLM
用户问题
LLM
文本回答
真正的 Agent 通常需要不断经历:
Think → Act → Observe → Think → Act → Observe → ... → Finish
模型负责"想下一步做什么",但大量真正让任务跑起来的工作,都发生在模型之外。
例如:
| 能力 | 单纯 LLM 是否天然具备 | Agent 系统需要额外解决 |
|---|---|---|
| 理解自然语言 | ✅ | - |
| 生成代码 | ✅ | - |
| 读取本地项目文件 | ❌ | 文件系统工具 |
| 修改代码 | ❌ | 文件写入与编辑工具 |
| 执行 Shell / PowerShell | ❌ | 命令执行环境 |
| 获取命令运行结果 | ❌ | Tool Result 回传 |
| 保存多轮任务状态 | ❌ | Session / Persistence |
| 决定是否继续调用工具 | ❌ | Agent Loop |
| 限制危险操作 | ❌ | Approval / Sandbox |
| 运行后台任务 | ❌ | Job Runtime |
| 调用专业能力 | ❌ | Tools / Skills / Plugins |
| 多任务或子任务协作 | ❌ | Delegation / SubAgent |
| 记录完整执行过程 | ❌ | Event Log / Trace |
因此,真正困难的问题并不是:
"怎样让模型再聪明一点?"
而是:
怎样给模型搭建一个稳定、可控、可扩展的运行环境,让它能够持续地在真实世界中工作?
这就是 Harness 要解决的问题。
1.2 什么是 Harness?
DeepSeek 对 Agent 的描述非常直接:
Agent = Model + Harness
可以把它理解成:
text
Agent
┌──────┴──────┐
│ │
Model Harness
"大脑" "运行系统"
模型负责:
- 理解任务;
- 推理;
- 规划下一步;
- 选择工具;
- 根据执行结果调整策略;
- 生成最终答案。
Harness 则负责把模型的"想法"真正变成可以执行的行为。
图 1-2:Model 与 Harness 的职责边界
#mermaid-svg-XSbOPEMzJM1YpaGC{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-XSbOPEMzJM1YpaGC .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-XSbOPEMzJM1YpaGC .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-XSbOPEMzJM1YpaGC .error-icon{fill:#552222;}#mermaid-svg-XSbOPEMzJM1YpaGC .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-XSbOPEMzJM1YpaGC .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-XSbOPEMzJM1YpaGC .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-XSbOPEMzJM1YpaGC .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-XSbOPEMzJM1YpaGC .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-XSbOPEMzJM1YpaGC .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-XSbOPEMzJM1YpaGC .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-XSbOPEMzJM1YpaGC .marker{fill:#333333;stroke:#333333;}#mermaid-svg-XSbOPEMzJM1YpaGC .marker.cross{stroke:#333333;}#mermaid-svg-XSbOPEMzJM1YpaGC svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-XSbOPEMzJM1YpaGC p{margin:0;}#mermaid-svg-XSbOPEMzJM1YpaGC .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-XSbOPEMzJM1YpaGC .cluster-label text{fill:#333;}#mermaid-svg-XSbOPEMzJM1YpaGC .cluster-label span{color:#333;}#mermaid-svg-XSbOPEMzJM1YpaGC .cluster-label span p{background-color:transparent;}#mermaid-svg-XSbOPEMzJM1YpaGC .label text,#mermaid-svg-XSbOPEMzJM1YpaGC span{fill:#333;color:#333;}#mermaid-svg-XSbOPEMzJM1YpaGC .node rect,#mermaid-svg-XSbOPEMzJM1YpaGC .node circle,#mermaid-svg-XSbOPEMzJM1YpaGC .node ellipse,#mermaid-svg-XSbOPEMzJM1YpaGC .node polygon,#mermaid-svg-XSbOPEMzJM1YpaGC .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-XSbOPEMzJM1YpaGC .rough-node .label text,#mermaid-svg-XSbOPEMzJM1YpaGC .node .label text,#mermaid-svg-XSbOPEMzJM1YpaGC .image-shape .label,#mermaid-svg-XSbOPEMzJM1YpaGC .icon-shape .label{text-anchor:middle;}#mermaid-svg-XSbOPEMzJM1YpaGC .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-XSbOPEMzJM1YpaGC .rough-node .label,#mermaid-svg-XSbOPEMzJM1YpaGC .node .label,#mermaid-svg-XSbOPEMzJM1YpaGC .image-shape .label,#mermaid-svg-XSbOPEMzJM1YpaGC .icon-shape .label{text-align:center;}#mermaid-svg-XSbOPEMzJM1YpaGC .node.clickable{cursor:pointer;}#mermaid-svg-XSbOPEMzJM1YpaGC .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-XSbOPEMzJM1YpaGC .arrowheadPath{fill:#333333;}#mermaid-svg-XSbOPEMzJM1YpaGC .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-XSbOPEMzJM1YpaGC .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-XSbOPEMzJM1YpaGC .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XSbOPEMzJM1YpaGC .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-XSbOPEMzJM1YpaGC .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XSbOPEMzJM1YpaGC .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-XSbOPEMzJM1YpaGC .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-XSbOPEMzJM1YpaGC .cluster text{fill:#333;}#mermaid-svg-XSbOPEMzJM1YpaGC .cluster span{color:#333;}#mermaid-svg-XSbOPEMzJM1YpaGC div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-XSbOPEMzJM1YpaGC .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-XSbOPEMzJM1YpaGC rect.text{fill:none;stroke-width:0;}#mermaid-svg-XSbOPEMzJM1YpaGC .icon-shape,#mermaid-svg-XSbOPEMzJM1YpaGC .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-XSbOPEMzJM1YpaGC .icon-shape p,#mermaid-svg-XSbOPEMzJM1YpaGC .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-XSbOPEMzJM1YpaGC .icon-shape .label rect,#mermaid-svg-XSbOPEMzJM1YpaGC .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-XSbOPEMzJM1YpaGC .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-XSbOPEMzJM1YpaGC .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-XSbOPEMzJM1YpaGC :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 回答
读写文件
执行命令
调用工具
调用技能
委派任务
后台执行
User / 用户
Harness
Context
上下文
Model
推理与决策
下一步做什么?
Final Answer
Filesystem
Shell / PowerShell
Tools
Skills
SubAgent
Jobs
Observation
如果把模型比作一个程序员,那么 Harness 很像是同时给它提供了:
- 一台电脑;
- 一个操作系统;
- 一个终端;
- 一个代码编辑器;
- 一套工具接口;
- 一个工作目录;
- 一个任务记录本;
- 一个权限系统;
- 一个沙箱;
- 一个插件系统。
所以 Harness 并不是"另一个模型"。
它更接近:
模型外部的 Agent Runtime(智能体运行时)。
1.2.1 一个更直观的类比
我们可以用"员工"来类比。
一个知识很强、但什么工具都没有的软件工程师:
text
工程师
├─ 知道 Python
├─ 知道 TypeScript
├─ 知道 Git
└─ 知道怎么排查 Bug
但是如果你不给他:
text
电脑
代码仓库
终端
权限
开发环境
日志
测试命令
他仍然无法真正完成项目。
对于 Agent 也是一样:
text
大模型
│
"我知道怎么做"
│
▼
Harness
┌─────────────┼─────────────┐
▼ ▼ ▼
文件系统 Shell Tools
│ │ │
└─────────────┼─────────────┘
▼
真实环境
│
▼
执行结果
│
└────────→ 模型继续决策
因此,Harness 的价值并不是替代模型,而是把模型的推理能力"落地"为持续、可执行的 Agent 行为。
1.3 DeepSeek Harness 是什么?
DeepSeek Harness,命令名为 dsh,是 DeepSeek AI 开源的 Agent Harness。
截至本文撰写时,官方将它定位为 Developer Preview(开发者预览),项目仍在快速迭代,并明确提醒未来可能出现破坏兼容性的变化。
DSH 最核心的两句话可以概括为:
text
Agent = Model + Harness
以及:
text
Everything is a Plugin
第一句话回答:
DSH 为什么存在?
第二句话回答:
DSH 为什么会采用现在这种架构?
DSH 并不是把模型、工具、文件系统、沙箱、Session 等所有东西全部写死到一个巨大的 Agent Core 中。
相反,在 DSH 中,大量能力都可以由插件提供,例如:
text
模型
Tools
Skills
Session
Sandbox
Storage
Agent Loop
Scheduling
UI
......
官方甚至把 Model Adapter、Tool Registry、Session Log 和 Agent Loop 本身都设计成插件能力。
这也是 DSH 和很多传统 Agent Framework 最大的架构差异之一。
图 1-3:第一次理解 DSH
#mermaid-svg-UWLfiRv5maBrAl4t{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-UWLfiRv5maBrAl4t .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-UWLfiRv5maBrAl4t .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-UWLfiRv5maBrAl4t .error-icon{fill:#552222;}#mermaid-svg-UWLfiRv5maBrAl4t .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-UWLfiRv5maBrAl4t .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-UWLfiRv5maBrAl4t .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-UWLfiRv5maBrAl4t .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-UWLfiRv5maBrAl4t .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-UWLfiRv5maBrAl4t .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-UWLfiRv5maBrAl4t .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-UWLfiRv5maBrAl4t .marker{fill:#333333;stroke:#333333;}#mermaid-svg-UWLfiRv5maBrAl4t .marker.cross{stroke:#333333;}#mermaid-svg-UWLfiRv5maBrAl4t svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-UWLfiRv5maBrAl4t p{margin:0;}#mermaid-svg-UWLfiRv5maBrAl4t .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-UWLfiRv5maBrAl4t .cluster-label text{fill:#333;}#mermaid-svg-UWLfiRv5maBrAl4t .cluster-label span{color:#333;}#mermaid-svg-UWLfiRv5maBrAl4t .cluster-label span p{background-color:transparent;}#mermaid-svg-UWLfiRv5maBrAl4t .label text,#mermaid-svg-UWLfiRv5maBrAl4t span{fill:#333;color:#333;}#mermaid-svg-UWLfiRv5maBrAl4t .node rect,#mermaid-svg-UWLfiRv5maBrAl4t .node circle,#mermaid-svg-UWLfiRv5maBrAl4t .node ellipse,#mermaid-svg-UWLfiRv5maBrAl4t .node polygon,#mermaid-svg-UWLfiRv5maBrAl4t .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-UWLfiRv5maBrAl4t .rough-node .label text,#mermaid-svg-UWLfiRv5maBrAl4t .node .label text,#mermaid-svg-UWLfiRv5maBrAl4t .image-shape .label,#mermaid-svg-UWLfiRv5maBrAl4t .icon-shape .label{text-anchor:middle;}#mermaid-svg-UWLfiRv5maBrAl4t .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-UWLfiRv5maBrAl4t .rough-node .label,#mermaid-svg-UWLfiRv5maBrAl4t .node .label,#mermaid-svg-UWLfiRv5maBrAl4t .image-shape .label,#mermaid-svg-UWLfiRv5maBrAl4t .icon-shape .label{text-align:center;}#mermaid-svg-UWLfiRv5maBrAl4t .node.clickable{cursor:pointer;}#mermaid-svg-UWLfiRv5maBrAl4t .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-UWLfiRv5maBrAl4t .arrowheadPath{fill:#333333;}#mermaid-svg-UWLfiRv5maBrAl4t .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-UWLfiRv5maBrAl4t .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-UWLfiRv5maBrAl4t .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UWLfiRv5maBrAl4t .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-UWLfiRv5maBrAl4t .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UWLfiRv5maBrAl4t .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-UWLfiRv5maBrAl4t .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-UWLfiRv5maBrAl4t .cluster text{fill:#333;}#mermaid-svg-UWLfiRv5maBrAl4t .cluster span{color:#333;}#mermaid-svg-UWLfiRv5maBrAl4t div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-UWLfiRv5maBrAl4t .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-UWLfiRv5maBrAl4t rect.text{fill:none;stroke-width:0;}#mermaid-svg-UWLfiRv5maBrAl4t .icon-shape,#mermaid-svg-UWLfiRv5maBrAl4t .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-UWLfiRv5maBrAl4t .icon-shape p,#mermaid-svg-UWLfiRv5maBrAl4t .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-UWLfiRv5maBrAl4t .icon-shape .label rect,#mermaid-svg-UWLfiRv5maBrAl4t .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-UWLfiRv5maBrAl4t .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-UWLfiRv5maBrAl4t .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-UWLfiRv5maBrAl4t :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} DSH Runtime
用户
DeepSeek Harness
Model
Tools
Skills
Session
Filesystem
Shell
Sandbox
Jobs
Agent Loop
UI
任务执行结果
这里暂时不需要关心这些模块如何连接。
只需要记住:
DSH 是模型与真实执行环境之间的一层 Agent Runtime。
下一章我们才会真正进入内部,回答:
如果"Everything is a Plugin",这些插件到底是谁管理的?它们又是怎样组合成一个完整 DSH 的?
答案就是 Cordis。
1.4 DSH 与普通聊天模型到底有什么不同?
很多第一次看到 DSH 的人会产生一个问题:
我直接打开 DeepSeek、ChatGPT 或其他模型聊天,不也可以让它写代码吗?为什么还需要 Harness?
关键区别在于:
聊天模型主要输出"内容",Harness Agent 可以产生"行为"。
表 1-1:Chat LLM 与 Harness Agent 对比
| 维度 | 普通 Chat LLM | DeepSeek Harness |
|---|---|---|
| 输入 | Prompt / 消息 | Task / Session / Workspace |
| 输出 | 文本、代码 | 文本 + Tool Call + 环境操作 |
| 本地文件 | 通常不可直接访问 | 可通过文件能力读取、编辑 |
| 命令执行 | 通常不能 | 可执行 Shell / PowerShell |
| 执行反馈 | 用户手工复制回来 | Tool Result 自动进入循环 |
| 连续任务 | 依赖上下文对话 | Session + Agent Loop |
| 工作区 | 无明确 Workspace | 可绑定项目 Workspace |
| 工具系统 | 平台预定义 | 可通过插件扩展 |
| 权限机制 | 平台内部控制 | Approval + Sandbox 等能力 |
| 可扩展性 | 主要由平台决定 | Everything is a Plugin |
| 任务轨迹 | 通常只看到对话 | 可保留 Session / 执行事件 |
| 面向对象 | 最终用户 | 用户 + Agent / Harness 开发者 |
看一个最简单的例子。
如果我们把下面的任务发给普通模型:
text
帮我运行当前项目的测试,
如果测试失败就找到错误原因。
普通聊天模型最多只能回答:
text
你可以运行:
npm test
然后把报错发给我,我帮你分析。
整个链路是:
text
LLM
↓
告诉用户执行命令
↓
用户手工执行
↓
用户复制结果
↓
LLM 再分析
而 Harness Agent 的目标是把它变成:
text
Agent
↓
执行 npm test
↓
读取 stdout / stderr
↓
判断失败原因
↓
搜索相关代码
↓
修改 / 给出方案
↓
再次运行测试
↓
得到结果
图 1-4:人工闭环与 Agent 闭环
#mermaid-svg-i2jhDTAPtSzycDK0{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-i2jhDTAPtSzycDK0 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-i2jhDTAPtSzycDK0 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-i2jhDTAPtSzycDK0 .error-icon{fill:#552222;}#mermaid-svg-i2jhDTAPtSzycDK0 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-i2jhDTAPtSzycDK0 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-i2jhDTAPtSzycDK0 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-i2jhDTAPtSzycDK0 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-i2jhDTAPtSzycDK0 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-i2jhDTAPtSzycDK0 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-i2jhDTAPtSzycDK0 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-i2jhDTAPtSzycDK0 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-i2jhDTAPtSzycDK0 .marker.cross{stroke:#333333;}#mermaid-svg-i2jhDTAPtSzycDK0 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-i2jhDTAPtSzycDK0 p{margin:0;}#mermaid-svg-i2jhDTAPtSzycDK0 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-i2jhDTAPtSzycDK0 .cluster-label text{fill:#333;}#mermaid-svg-i2jhDTAPtSzycDK0 .cluster-label span{color:#333;}#mermaid-svg-i2jhDTAPtSzycDK0 .cluster-label span p{background-color:transparent;}#mermaid-svg-i2jhDTAPtSzycDK0 .label text,#mermaid-svg-i2jhDTAPtSzycDK0 span{fill:#333;color:#333;}#mermaid-svg-i2jhDTAPtSzycDK0 .node rect,#mermaid-svg-i2jhDTAPtSzycDK0 .node circle,#mermaid-svg-i2jhDTAPtSzycDK0 .node ellipse,#mermaid-svg-i2jhDTAPtSzycDK0 .node polygon,#mermaid-svg-i2jhDTAPtSzycDK0 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-i2jhDTAPtSzycDK0 .rough-node .label text,#mermaid-svg-i2jhDTAPtSzycDK0 .node .label text,#mermaid-svg-i2jhDTAPtSzycDK0 .image-shape .label,#mermaid-svg-i2jhDTAPtSzycDK0 .icon-shape .label{text-anchor:middle;}#mermaid-svg-i2jhDTAPtSzycDK0 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-i2jhDTAPtSzycDK0 .rough-node .label,#mermaid-svg-i2jhDTAPtSzycDK0 .node .label,#mermaid-svg-i2jhDTAPtSzycDK0 .image-shape .label,#mermaid-svg-i2jhDTAPtSzycDK0 .icon-shape .label{text-align:center;}#mermaid-svg-i2jhDTAPtSzycDK0 .node.clickable{cursor:pointer;}#mermaid-svg-i2jhDTAPtSzycDK0 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-i2jhDTAPtSzycDK0 .arrowheadPath{fill:#333333;}#mermaid-svg-i2jhDTAPtSzycDK0 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-i2jhDTAPtSzycDK0 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-i2jhDTAPtSzycDK0 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-i2jhDTAPtSzycDK0 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-i2jhDTAPtSzycDK0 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-i2jhDTAPtSzycDK0 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-i2jhDTAPtSzycDK0 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-i2jhDTAPtSzycDK0 .cluster text{fill:#333;}#mermaid-svg-i2jhDTAPtSzycDK0 .cluster span{color:#333;}#mermaid-svg-i2jhDTAPtSzycDK0 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-i2jhDTAPtSzycDK0 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-i2jhDTAPtSzycDK0 rect.text{fill:none;stroke-width:0;}#mermaid-svg-i2jhDTAPtSzycDK0 .icon-shape,#mermaid-svg-i2jhDTAPtSzycDK0 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-i2jhDTAPtSzycDK0 .icon-shape p,#mermaid-svg-i2jhDTAPtSzycDK0 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-i2jhDTAPtSzycDK0 .icon-shape .label rect,#mermaid-svg-i2jhDTAPtSzycDK0 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-i2jhDTAPtSzycDK0 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-i2jhDTAPtSzycDK0 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-i2jhDTAPtSzycDK0 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Harness Agent 模式
用户
Agent Loop
LLM
Tool Call
真实执行
Tool Result
普通 Chat 模式
用户
LLM
告诉用户执行命令
用户手工执行
复制结果
这就是从:
Human-in-the-loop execution
向:
Agent execution loop
的转变。
当然,人并没有完全消失。
在危险操作、权限提升、敏感文件等场景中,人仍然可以作为 Approval 的一部分参与决策。
1.5 DSH 和 LangChain、LangGraph、AutoGen 是一回事吗?
不是完全一回事。
它们都与 Agent 有关,但关注层级不同。
为了方便理解,可以先用一个不严格但很实用的分层:
图 1-5:Agent 技术栈的不同关注层
#mermaid-svg-FfB7KqVbO9SRKfSo{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-FfB7KqVbO9SRKfSo .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-FfB7KqVbO9SRKfSo .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-FfB7KqVbO9SRKfSo .error-icon{fill:#552222;}#mermaid-svg-FfB7KqVbO9SRKfSo .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-FfB7KqVbO9SRKfSo .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-FfB7KqVbO9SRKfSo .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-FfB7KqVbO9SRKfSo .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-FfB7KqVbO9SRKfSo .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-FfB7KqVbO9SRKfSo .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-FfB7KqVbO9SRKfSo .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-FfB7KqVbO9SRKfSo .marker{fill:#333333;stroke:#333333;}#mermaid-svg-FfB7KqVbO9SRKfSo .marker.cross{stroke:#333333;}#mermaid-svg-FfB7KqVbO9SRKfSo svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-FfB7KqVbO9SRKfSo p{margin:0;}#mermaid-svg-FfB7KqVbO9SRKfSo .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-FfB7KqVbO9SRKfSo .cluster-label text{fill:#333;}#mermaid-svg-FfB7KqVbO9SRKfSo .cluster-label span{color:#333;}#mermaid-svg-FfB7KqVbO9SRKfSo .cluster-label span p{background-color:transparent;}#mermaid-svg-FfB7KqVbO9SRKfSo .label text,#mermaid-svg-FfB7KqVbO9SRKfSo span{fill:#333;color:#333;}#mermaid-svg-FfB7KqVbO9SRKfSo .node rect,#mermaid-svg-FfB7KqVbO9SRKfSo .node circle,#mermaid-svg-FfB7KqVbO9SRKfSo .node ellipse,#mermaid-svg-FfB7KqVbO9SRKfSo .node polygon,#mermaid-svg-FfB7KqVbO9SRKfSo .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-FfB7KqVbO9SRKfSo .rough-node .label text,#mermaid-svg-FfB7KqVbO9SRKfSo .node .label text,#mermaid-svg-FfB7KqVbO9SRKfSo .image-shape .label,#mermaid-svg-FfB7KqVbO9SRKfSo .icon-shape .label{text-anchor:middle;}#mermaid-svg-FfB7KqVbO9SRKfSo .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-FfB7KqVbO9SRKfSo .rough-node .label,#mermaid-svg-FfB7KqVbO9SRKfSo .node .label,#mermaid-svg-FfB7KqVbO9SRKfSo .image-shape .label,#mermaid-svg-FfB7KqVbO9SRKfSo .icon-shape .label{text-align:center;}#mermaid-svg-FfB7KqVbO9SRKfSo .node.clickable{cursor:pointer;}#mermaid-svg-FfB7KqVbO9SRKfSo .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-FfB7KqVbO9SRKfSo .arrowheadPath{fill:#333333;}#mermaid-svg-FfB7KqVbO9SRKfSo .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-FfB7KqVbO9SRKfSo .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-FfB7KqVbO9SRKfSo .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FfB7KqVbO9SRKfSo .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-FfB7KqVbO9SRKfSo .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FfB7KqVbO9SRKfSo .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-FfB7KqVbO9SRKfSo .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-FfB7KqVbO9SRKfSo .cluster text{fill:#333;}#mermaid-svg-FfB7KqVbO9SRKfSo .cluster span{color:#333;}#mermaid-svg-FfB7KqVbO9SRKfSo div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-FfB7KqVbO9SRKfSo .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-FfB7KqVbO9SRKfSo rect.text{fill:none;stroke-width:0;}#mermaid-svg-FfB7KqVbO9SRKfSo .icon-shape,#mermaid-svg-FfB7KqVbO9SRKfSo .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-FfB7KqVbO9SRKfSo .icon-shape p,#mermaid-svg-FfB7KqVbO9SRKfSo .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-FfB7KqVbO9SRKfSo .icon-shape .label rect,#mermaid-svg-FfB7KqVbO9SRKfSo .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-FfB7KqVbO9SRKfSo .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-FfB7KqVbO9SRKfSo .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-FfB7KqVbO9SRKfSo :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} Agent Application
最终业务 Agent
Agent Orchestration
任务图 / 多 Agent / Workflow
Agent Harness / Runtime
工具、环境、Session、执行、安全、扩展
LLM / VLM
推理模型
OS / Files / Network / Process / External Systems
一些 Agent Framework 更强调:
- DAG;
- State;
- Workflow;
- Multi-Agent orchestration;
- Prompt / Chain;
- Graph execution。
而 DSH 强调的是:
- 模型如何接入;
- Tool 如何注册;
- 文件和 Shell 如何提供;
- Session 如何持续;
- Agent Loop 如何运行;
- Sandbox 如何限制执行;
- Approval 如何介入;
- 插件如何扩展;
- 整个 Runtime 如何被重新组合。
所以,与其简单把 DSH 理解成"另一个 LangChain",更准确的理解是:
DSH 更关心一个 Agent 在真实环境中"怎么活起来、怎么持续运行、怎么获得能力以及怎么被扩展"。
这也解释了为什么官方反复使用 Harness 而不是只强调 Framework。
注意:这并不是说不同框架之间存在绝对互斥关系。真实项目完全可能在更高层使用任务编排思想,同时在底层借助 Harness 提供执行环境。这里的划分主要用于理解它们的设计重点。
1.6 DSH 到底能干什么?
DSH 的能力并不应该被理解成一张固定功能清单。
因为它的一个核心思想就是:
能力可以通过插件继续增加。
不过,仅从一个用户的视角,我们可以先把常见能力分成下面几类。
1.6.1 代码与项目分析
例如:
text
分析这个仓库的目录结构,
告诉我核心模块之间的依赖关系。
Agent 可以:
- 浏览目录;
- 搜索文件;
- 读取代码;
- 找到入口;
- 继续读取依赖模块;
- 汇总架构。
流程可以表示为:
#mermaid-svg-dKi39XygJR6T3LYS{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-dKi39XygJR6T3LYS .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-dKi39XygJR6T3LYS .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-dKi39XygJR6T3LYS .error-icon{fill:#552222;}#mermaid-svg-dKi39XygJR6T3LYS .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-dKi39XygJR6T3LYS .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-dKi39XygJR6T3LYS .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-dKi39XygJR6T3LYS .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-dKi39XygJR6T3LYS .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-dKi39XygJR6T3LYS .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-dKi39XygJR6T3LYS .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-dKi39XygJR6T3LYS .marker{fill:#333333;stroke:#333333;}#mermaid-svg-dKi39XygJR6T3LYS .marker.cross{stroke:#333333;}#mermaid-svg-dKi39XygJR6T3LYS svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-dKi39XygJR6T3LYS p{margin:0;}#mermaid-svg-dKi39XygJR6T3LYS .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-dKi39XygJR6T3LYS .cluster-label text{fill:#333;}#mermaid-svg-dKi39XygJR6T3LYS .cluster-label span{color:#333;}#mermaid-svg-dKi39XygJR6T3LYS .cluster-label span p{background-color:transparent;}#mermaid-svg-dKi39XygJR6T3LYS .label text,#mermaid-svg-dKi39XygJR6T3LYS span{fill:#333;color:#333;}#mermaid-svg-dKi39XygJR6T3LYS .node rect,#mermaid-svg-dKi39XygJR6T3LYS .node circle,#mermaid-svg-dKi39XygJR6T3LYS .node ellipse,#mermaid-svg-dKi39XygJR6T3LYS .node polygon,#mermaid-svg-dKi39XygJR6T3LYS .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-dKi39XygJR6T3LYS .rough-node .label text,#mermaid-svg-dKi39XygJR6T3LYS .node .label text,#mermaid-svg-dKi39XygJR6T3LYS .image-shape .label,#mermaid-svg-dKi39XygJR6T3LYS .icon-shape .label{text-anchor:middle;}#mermaid-svg-dKi39XygJR6T3LYS .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-dKi39XygJR6T3LYS .rough-node .label,#mermaid-svg-dKi39XygJR6T3LYS .node .label,#mermaid-svg-dKi39XygJR6T3LYS .image-shape .label,#mermaid-svg-dKi39XygJR6T3LYS .icon-shape .label{text-align:center;}#mermaid-svg-dKi39XygJR6T3LYS .node.clickable{cursor:pointer;}#mermaid-svg-dKi39XygJR6T3LYS .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-dKi39XygJR6T3LYS .arrowheadPath{fill:#333333;}#mermaid-svg-dKi39XygJR6T3LYS .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-dKi39XygJR6T3LYS .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-dKi39XygJR6T3LYS .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dKi39XygJR6T3LYS .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-dKi39XygJR6T3LYS .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dKi39XygJR6T3LYS .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-dKi39XygJR6T3LYS .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-dKi39XygJR6T3LYS .cluster text{fill:#333;}#mermaid-svg-dKi39XygJR6T3LYS .cluster span{color:#333;}#mermaid-svg-dKi39XygJR6T3LYS div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-dKi39XygJR6T3LYS .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-dKi39XygJR6T3LYS rect.text{fill:none;stroke-width:0;}#mermaid-svg-dKi39XygJR6T3LYS .icon-shape,#mermaid-svg-dKi39XygJR6T3LYS .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-dKi39XygJR6T3LYS .icon-shape p,#mermaid-svg-dKi39XygJR6T3LYS .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-dKi39XygJR6T3LYS .icon-shape .label rect,#mermaid-svg-dKi39XygJR6T3LYS .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-dKi39XygJR6T3LYS .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-dKi39XygJR6T3LYS .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-dKi39XygJR6T3LYS :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 分析项目架构
列出目录
搜索入口文件
读取核心代码
继续追踪依赖
形成架构结论
相比一次把整个仓库塞进 Prompt,这种方式更加接近真实工程师的工作过程:
先探索,再定位,再深入。
1.6.2 执行命令
例如:
text
帮我运行单元测试,并分析失败原因。
Agent 可以调用 Shell / PowerShell:
bash
npm test
或者:
bash
pytest
然后根据结果继续推理。
text
运行测试
↓
Exit Code != 0
↓
读取报错
↓
定位文件
↓
分析源码
↓
提出修改
↓
再次测试
这一步很重要,因为它意味着模型获取的不只是"静态文本",而是环境反馈。
1.6.3 文件读取、编辑与项目修改
一个 Coding Agent 不可能只有 Shell。
它还需要直接操作文件,例如:
text
read file
search file
write file
edit file
于是一个 Bug Fix 任务可能形成:
图 1-6:一个典型修复任务
#mermaid-svg-Jm1OMThGTf5kvTt3{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-Jm1OMThGTf5kvTt3 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-Jm1OMThGTf5kvTt3 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-Jm1OMThGTf5kvTt3 .error-icon{fill:#552222;}#mermaid-svg-Jm1OMThGTf5kvTt3 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-Jm1OMThGTf5kvTt3 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-Jm1OMThGTf5kvTt3 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-Jm1OMThGTf5kvTt3 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-Jm1OMThGTf5kvTt3 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-Jm1OMThGTf5kvTt3 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-Jm1OMThGTf5kvTt3 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-Jm1OMThGTf5kvTt3 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-Jm1OMThGTf5kvTt3 .marker.cross{stroke:#333333;}#mermaid-svg-Jm1OMThGTf5kvTt3 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-Jm1OMThGTf5kvTt3 p{margin:0;}#mermaid-svg-Jm1OMThGTf5kvTt3 .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-Jm1OMThGTf5kvTt3 .cluster-label text{fill:#333;}#mermaid-svg-Jm1OMThGTf5kvTt3 .cluster-label span{color:#333;}#mermaid-svg-Jm1OMThGTf5kvTt3 .cluster-label span p{background-color:transparent;}#mermaid-svg-Jm1OMThGTf5kvTt3 .label text,#mermaid-svg-Jm1OMThGTf5kvTt3 span{fill:#333;color:#333;}#mermaid-svg-Jm1OMThGTf5kvTt3 .node rect,#mermaid-svg-Jm1OMThGTf5kvTt3 .node circle,#mermaid-svg-Jm1OMThGTf5kvTt3 .node ellipse,#mermaid-svg-Jm1OMThGTf5kvTt3 .node polygon,#mermaid-svg-Jm1OMThGTf5kvTt3 .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-Jm1OMThGTf5kvTt3 .rough-node .label text,#mermaid-svg-Jm1OMThGTf5kvTt3 .node .label text,#mermaid-svg-Jm1OMThGTf5kvTt3 .image-shape .label,#mermaid-svg-Jm1OMThGTf5kvTt3 .icon-shape .label{text-anchor:middle;}#mermaid-svg-Jm1OMThGTf5kvTt3 .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-Jm1OMThGTf5kvTt3 .rough-node .label,#mermaid-svg-Jm1OMThGTf5kvTt3 .node .label,#mermaid-svg-Jm1OMThGTf5kvTt3 .image-shape .label,#mermaid-svg-Jm1OMThGTf5kvTt3 .icon-shape .label{text-align:center;}#mermaid-svg-Jm1OMThGTf5kvTt3 .node.clickable{cursor:pointer;}#mermaid-svg-Jm1OMThGTf5kvTt3 .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-Jm1OMThGTf5kvTt3 .arrowheadPath{fill:#333333;}#mermaid-svg-Jm1OMThGTf5kvTt3 .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-Jm1OMThGTf5kvTt3 .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-Jm1OMThGTf5kvTt3 .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Jm1OMThGTf5kvTt3 .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-Jm1OMThGTf5kvTt3 .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Jm1OMThGTf5kvTt3 .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-Jm1OMThGTf5kvTt3 .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-Jm1OMThGTf5kvTt3 .cluster text{fill:#333;}#mermaid-svg-Jm1OMThGTf5kvTt3 .cluster span{color:#333;}#mermaid-svg-Jm1OMThGTf5kvTt3 div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-Jm1OMThGTf5kvTt3 .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-Jm1OMThGTf5kvTt3 rect.text{fill:none;stroke-width:0;}#mermaid-svg-Jm1OMThGTf5kvTt3 .icon-shape,#mermaid-svg-Jm1OMThGTf5kvTt3 .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-Jm1OMThGTf5kvTt3 .icon-shape p,#mermaid-svg-Jm1OMThGTf5kvTt3 .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-Jm1OMThGTf5kvTt3 .icon-shape .label rect,#mermaid-svg-Jm1OMThGTf5kvTt3 .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-Jm1OMThGTf5kvTt3 .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-Jm1OMThGTf5kvTt3 .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-Jm1OMThGTf5kvTt3 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
否
是
用户:修复这个 Bug
理解问题
搜索相关代码
读取文件
找到原因?
扩大搜索范围
编辑代码
运行测试
测试通过?
读取新错误
总结修改
这已经是一个典型 Agent Loop,而不是单轮 LLM Completion。
1.6.4 任务规划与持续执行
复杂问题不能一次完成。
例如:
text
1. 分析项目
2. 找到所有 API
3. 检查错误处理
4. 补充测试
5. 运行测试
6. 给出报告
Agent 需要维护任务状态:
text
Task
├── [Done] Repository inspection
├── [Done] API discovery
├── [Doing] Error handling review
├── [Todo] Add tests
├── [Todo] Run tests
└── [Todo] Final report
因此,一个成熟 Agent Runtime 不只是:
text
Prompt → LLM
而需要:
text
Task
↓
State
↓
Plan
↓
Action
↓
Observation
↓
State Update
↓
Next Action
1.6.5 子任务委派
当一个任务变复杂以后,可以出现:
text
Main Agent
│
├── 子任务 A:分析后端
├── 子任务 B:分析前端
└── 子任务 C:检查测试
最终:
text
SubAgent A ─┐
SubAgent B ─┼─→ Main Agent → Final Result
SubAgent C ─┘
这类能力让 Agent 从"一个会调工具的聊天机器人",逐渐变成真正的任务执行系统。
1.6.6 Skills
Tool 解决的问题通常是:
"我能调用什么动作?"
Skill 更接近:
"这个任务应该怎么做?"
例如同一个 Shell 工具可以执行无数命令,但对于某个专业任务,Agent 可能还需要:
text
如何分析一个 Git 仓库
如何执行某类测试
如何完成代码审查
如何生成某种报告
如何操作某个平台
这些方法论、工作流程和任务知识可以通过 Skill 形式提供。
因此可以先粗略理解成:
text
Tool = 能力 / Action
Skill = 方法 / Know-how
第四章会专门解释 Plugin、Tool、Skill、MCP 的关系。
1.6.7 可扩展插件
DSH 最有意思的地方之一,是你并不只能使用官方已有能力。
例如以后完全可以开发:
text
dsh-plugin-feishu
├── feishu_send_message
├── feishu_read_document
├── feishu_search_wiki
└── feishu_create_document
也可以开发:
text
dsh-plugin-database
├── query_database
├── inspect_schema
└── explain_query_plan
还可以开发:
text
dsh-plugin-secure-executor
├── sandbox_exec
├── permission_check
├── audit_log
└── credential_lease
于是 DSH 的能力边界不再完全由官方决定,而变成:
text
DSH
│
┌─────────────┼──────────────┐
│ │ │
官方插件 社区插件 业务插件
│ │ │
└─────────────┼──────────────┘
▼
Agent Capabilities
这也是为什么插件机制会占据本文第四、第五章的大量篇幅。
1.7 DSH 的基本组成
在深入使用之前,我们先建立一个最简单的心智模型。
一个 DSH 运行实例至少可以从下面几个概念理解。
表 1-2:DSH 初学者心智模型
| 概念 | 可以暂时理解成 | 作用 |
|---|---|---|
| Model | Agent 的大脑 | 推理、规划、Tool Calling |
| Harness | Agent 的运行系统 | 连接模型与真实环境 |
| Workspace | Agent 当前工作的项目目录 | 限定项目上下文 |
| Session | 一次持续对话 / 任务 | 保存任务历史 |
| Tool | Agent 可以执行的动作 | 文件、Shell、搜索等 |
| Skill | Agent 可加载的任务知识 | 告诉 Agent 如何完成特定工作 |
| Agent Loop | 任务执行循环 | Model → Tool → Result → Model |
| Sandbox | 执行约束 | 限制部分文件操作等 |
| Approval | 用户审批机制 | 对特定操作进行一次性授权或拒绝 |
| Plugin | DSH 的扩展单元 | 提供或修改 Harness 能力 |
| Cordis | 插件运行内核 | 管理插件装载、卸载和依赖 |
其中最后两个概念:
text
Plugin
Cordis
现在只需要"眼熟"。
第二章会重点讲它们。
1.8 安装并启动 DeepSeek Harness
截至本文撰写时,官方推荐的最简单方式是通过 npx 直接启动。
1.8.1 环境准备
首先确保已经安装:
text
Node.js
可以检查:
bash
node -v
npm -v
如果能正常输出版本号,就可以继续。
1.8.2 一条命令启动
进入你希望让 DSH 工作的项目目录:
bash
cd your-project
然后运行:
bash
npx @deepseek-ai/dsh web
默认情况下,Web UI 服务地址为:
text
http://127.0.0.1:3080
因此最基础的启动链路非常简单:
图 1-7:DSH Web 启动流程
#mermaid-svg-YVzWuT97JXmCRwdv{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-YVzWuT97JXmCRwdv .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-YVzWuT97JXmCRwdv .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-YVzWuT97JXmCRwdv .error-icon{fill:#552222;}#mermaid-svg-YVzWuT97JXmCRwdv .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-YVzWuT97JXmCRwdv .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-YVzWuT97JXmCRwdv .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-YVzWuT97JXmCRwdv .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-YVzWuT97JXmCRwdv .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-YVzWuT97JXmCRwdv .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-YVzWuT97JXmCRwdv .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-YVzWuT97JXmCRwdv .marker{fill:#333333;stroke:#333333;}#mermaid-svg-YVzWuT97JXmCRwdv .marker.cross{stroke:#333333;}#mermaid-svg-YVzWuT97JXmCRwdv svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-YVzWuT97JXmCRwdv p{margin:0;}#mermaid-svg-YVzWuT97JXmCRwdv .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-YVzWuT97JXmCRwdv .cluster-label text{fill:#333;}#mermaid-svg-YVzWuT97JXmCRwdv .cluster-label span{color:#333;}#mermaid-svg-YVzWuT97JXmCRwdv .cluster-label span p{background-color:transparent;}#mermaid-svg-YVzWuT97JXmCRwdv .label text,#mermaid-svg-YVzWuT97JXmCRwdv span{fill:#333;color:#333;}#mermaid-svg-YVzWuT97JXmCRwdv .node rect,#mermaid-svg-YVzWuT97JXmCRwdv .node circle,#mermaid-svg-YVzWuT97JXmCRwdv .node ellipse,#mermaid-svg-YVzWuT97JXmCRwdv .node polygon,#mermaid-svg-YVzWuT97JXmCRwdv .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-YVzWuT97JXmCRwdv .rough-node .label text,#mermaid-svg-YVzWuT97JXmCRwdv .node .label text,#mermaid-svg-YVzWuT97JXmCRwdv .image-shape .label,#mermaid-svg-YVzWuT97JXmCRwdv .icon-shape .label{text-anchor:middle;}#mermaid-svg-YVzWuT97JXmCRwdv .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-YVzWuT97JXmCRwdv .rough-node .label,#mermaid-svg-YVzWuT97JXmCRwdv .node .label,#mermaid-svg-YVzWuT97JXmCRwdv .image-shape .label,#mermaid-svg-YVzWuT97JXmCRwdv .icon-shape .label{text-align:center;}#mermaid-svg-YVzWuT97JXmCRwdv .node.clickable{cursor:pointer;}#mermaid-svg-YVzWuT97JXmCRwdv .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-YVzWuT97JXmCRwdv .arrowheadPath{fill:#333333;}#mermaid-svg-YVzWuT97JXmCRwdv .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-YVzWuT97JXmCRwdv .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-YVzWuT97JXmCRwdv .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YVzWuT97JXmCRwdv .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-YVzWuT97JXmCRwdv .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YVzWuT97JXmCRwdv .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-YVzWuT97JXmCRwdv .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-YVzWuT97JXmCRwdv .cluster text{fill:#333;}#mermaid-svg-YVzWuT97JXmCRwdv .cluster span{color:#333;}#mermaid-svg-YVzWuT97JXmCRwdv div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-YVzWuT97JXmCRwdv .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-YVzWuT97JXmCRwdv rect.text{fill:none;stroke-width:0;}#mermaid-svg-YVzWuT97JXmCRwdv .icon-shape,#mermaid-svg-YVzWuT97JXmCRwdv .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-YVzWuT97JXmCRwdv .icon-shape p,#mermaid-svg-YVzWuT97JXmCRwdv .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-YVzWuT97JXmCRwdv .icon-shape .label rect,#mermaid-svg-YVzWuT97JXmCRwdv .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-YVzWuT97JXmCRwdv .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-YVzWuT97JXmCRwdv .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-YVzWuT97JXmCRwdv :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 安装 Node.js
进入项目目录
npx @deepseek-ai/dsh web
启动 DSH Runtime
Web UI
配置模型
选择 Workspace
创建 Session
开始任务
如果不希望启动后自动打开浏览器,可以使用:
bash
npx @deepseek-ai/dsh web --no-open
1.9 从源码运行 DSH
如果你的目标只是"体验 DSH",npx 足够。
但如果你准备阅读源码、研究架构或者开发 DSH 本体,那么最好直接克隆仓库。
bash
git clone https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
pnpm install
pnpm run build
pnpm dsh web
这条路线特别适合本文后面的章节。
因为从第二章开始,我们会频繁接触:
text
packages/
docs/
profile
bundle
cordis.patch.yml
plugin
ctx
agent loop
tools
session
表 1-3:两种运行方式怎么选?
| 使用目的 | 推荐方式 |
|---|---|
| 第一次体验 | npx @deepseek-ai/dsh web |
| 普通用户使用 | npx |
| 阅读源码 | Clone Repository |
| 修改 DSH 核心包 | Clone Repository |
| 插件开发 | 根据插件开发方式,可使用源码环境辅助调试 |
| 研究 Cordis / Agent Loop | Clone Repository |
1.10 第一次配置模型
启动 Web UI 后,首先需要配置一个可用模型。
官方当前的 Web UI 路径为:
text
Settings
↓
Models
如果使用 DeepSeek:
text
Settings
↓
Models
↓
DeepSeek
↓
填写 API Key
↓
Save
模型配置保存后,后续请求即可使用,通常不需要重启服务器。
DSH 还支持其他 Provider,以及自定义 Provider / OpenAI-compatible endpoint,因此可以把模型层理解成:
text
DSH
│
Model Interface
│
┌────────────┼────────────┐
▼ ▼ ▼
DeepSeek OpenAI Anthropic
│
└────── Custom Provider
这件事非常重要。
它意味着:
Harness 与 Model 在设计上是可以分离的。
DSH 是 DeepSeek 开发的,但"DeepSeek Harness"并不等于"只能运行 DeepSeek 模型"。
后面的架构章节会看到:
连 Model Adapter 都只是插件能力的一部分。
1.10.1 API Key 是怎么保存的?
按照当前官方文档,模型密钥通过 Credentials 机制管理。
例如 DeepSeek API Key 保存后:
- 页面不会重新拿到完整明文;
- Credentials 存储负责保存秘密值;
- Settings 侧保留的是凭据引用。
从架构上看,这比简单写成:
yaml
api_key: sk-xxxxxxxx
更合理。
它体现了一条重要设计思想:
配置描述"使用哪个凭据",而不是到处复制秘密本身。
Credentials 会在后面的插件与安全机制中再次出现。
1.11 选择 Workspace
模型配置完成后,还需要选择 Workspace。
这是初学 DSH 时非常容易忽略的一步。
DSH 运行命令所在目录会成为默认文件系统位置,但新的 Web UI 不会自动替你选择一个 Workspace。
因此需要:
text
Choose workspace
↓
添加项目目录
↓
选择该 Workspace
Workspace 是什么?
可以暂时理解为:
Agent 当前被允许围绕哪个项目目录开展工作。
例如:
text
D:/projects/my-app
一个典型 Workspace:
text
my-app/
├── package.json
├── README.md
├── src/
│ ├── api/
│ ├── services/
│ └── index.ts
├── tests/
└── docs/
当这个目录成为 Workspace 后,Agent 才能够围绕这些项目内容:
text
搜索
读取
编辑
执行命令
分析
测试
因此:
text
Session
│
├── Model
│
└── Workspace
│
├── Files
├── Source Code
├── Tests
└── Runtime Commands
这就是 DSH 从"聊天界面"迈向"工作环境"的第一步。
1.12 运行第一个任务
完成模型和 Workspace 配置后,可以创建一个新的 Session。
建议第一次不要直接给它一个非常危险或者复杂的任务。
可以从一个只读分析任务开始:
text
Summarize this repository and identify its main packages.
或者中文:
text
分析当前仓库的目录结构,
告诉我核心模块分别负责什么,
并给出项目的整体架构说明。
Agent 可能经历:
text
用户任务
↓
查看目录
↓
读取 package.json
↓
搜索入口文件
↓
读取 README
↓
读取关键 package
↓
继续追踪引用
↓
整理结论
图 1-8:第一个 DSH 任务的简化执行过程
Workspace Tools Model DSH User Workspace Tools Model DSH User #mermaid-svg-4Em5j3w0MHgNM4p4{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-4Em5j3w0MHgNM4p4 .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-4Em5j3w0MHgNM4p4 .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-4Em5j3w0MHgNM4p4 .error-icon{fill:#552222;}#mermaid-svg-4Em5j3w0MHgNM4p4 .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-4Em5j3w0MHgNM4p4 .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-4Em5j3w0MHgNM4p4 .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-4Em5j3w0MHgNM4p4 .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-4Em5j3w0MHgNM4p4 .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-4Em5j3w0MHgNM4p4 .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-4Em5j3w0MHgNM4p4 .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-4Em5j3w0MHgNM4p4 .marker{fill:#333333;stroke:#333333;}#mermaid-svg-4Em5j3w0MHgNM4p4 .marker.cross{stroke:#333333;}#mermaid-svg-4Em5j3w0MHgNM4p4 svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-4Em5j3w0MHgNM4p4 p{margin:0;}#mermaid-svg-4Em5j3w0MHgNM4p4 .actor{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4Em5j3w0MHgNM4p4 text.actor>tspan{fill:black;stroke:none;}#mermaid-svg-4Em5j3w0MHgNM4p4 .actor-line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-4Em5j3w0MHgNM4p4 .innerArc{stroke-width:1.5;stroke-dasharray:none;}#mermaid-svg-4Em5j3w0MHgNM4p4 .messageLine0{stroke-width:1.5;stroke-dasharray:none;stroke:#333;}#mermaid-svg-4Em5j3w0MHgNM4p4 .messageLine1{stroke-width:1.5;stroke-dasharray:2,2;stroke:#333;}#mermaid-svg-4Em5j3w0MHgNM4p4 #arrowhead path{fill:#333;stroke:#333;}#mermaid-svg-4Em5j3w0MHgNM4p4 .sequenceNumber{fill:white;}#mermaid-svg-4Em5j3w0MHgNM4p4 #sequencenumber{fill:#333;}#mermaid-svg-4Em5j3w0MHgNM4p4 #crosshead path{fill:#333;stroke:#333;}#mermaid-svg-4Em5j3w0MHgNM4p4 .messageText{fill:#333;stroke:none;}#mermaid-svg-4Em5j3w0MHgNM4p4 .labelBox{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4Em5j3w0MHgNM4p4 .labelText,#mermaid-svg-4Em5j3w0MHgNM4p4 .labelText>tspan{fill:black;stroke:none;}#mermaid-svg-4Em5j3w0MHgNM4p4 .loopText,#mermaid-svg-4Em5j3w0MHgNM4p4 .loopText>tspan{fill:black;stroke:none;}#mermaid-svg-4Em5j3w0MHgNM4p4 .loopLine{stroke-width:2px;stroke-dasharray:2,2;stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);}#mermaid-svg-4Em5j3w0MHgNM4p4 .note{stroke:#aaaa33;fill:#fff5ad;}#mermaid-svg-4Em5j3w0MHgNM4p4 .noteText,#mermaid-svg-4Em5j3w0MHgNM4p4 .noteText>tspan{fill:black;stroke:none;}#mermaid-svg-4Em5j3w0MHgNM4p4 .activation0{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4Em5j3w0MHgNM4p4 .activation1{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4Em5j3w0MHgNM4p4 .activation2{fill:#f4f4f4;stroke:#666;}#mermaid-svg-4Em5j3w0MHgNM4p4 .actorPopupMenu{position:absolute;}#mermaid-svg-4Em5j3w0MHgNM4p4 .actorPopupMenuPanel{position:absolute;fill:#ECECFF;box-shadow:0px 8px 16px 0px rgba(0,0,0,0.2);filter:drop-shadow(3px 5px 2px rgb(0 0 0 / 0.4));}#mermaid-svg-4Em5j3w0MHgNM4p4 .actor-man line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;}#mermaid-svg-4Em5j3w0MHgNM4p4 .actor-man circle,#mermaid-svg-4Em5j3w0MHgNM4p4 line{stroke:hsl(259.6261682243, 59.7765363128%, 87.9019607843%);fill:#ECECFF;stroke-width:2px;}#mermaid-svg-4Em5j3w0MHgNM4p4 :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 分析当前项目结构Task + Context + Tools请求查看目录Tool Call读取目录文件列表Tool Result返回观察结果请求读取关键文件Tool Call读取文件文件内容Tool Result新的上下文最终分析项目架构说明
这张图非常重要。
因为它已经展示出了 DSH 后面所有复杂架构的最小原型:
text
User
↓
Harness
↓
Model
↓
Tool Call
↓
Environment
↓
Tool Result
↓
Harness
↓
Model
无论以后加入多少 Plugin、Skill、Sandbox、SubAgent,本质上都建立在这个循环之上。
1.13 一次 Agent Run 到底发生了什么?
虽然真正的内部实现要到第三章才展开,但第一章可以先建立一个简化模型。
假设任务是:
text
检查这个项目为什么测试失败,
找到原因后修复,并重新运行测试。
整个过程可以抽象成下面几个阶段。
图 1-9:一次任务的完整宏观流程
#mermaid-svg-ci3WhNS6G5VMMJsJ{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-ci3WhNS6G5VMMJsJ .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-ci3WhNS6G5VMMJsJ .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-ci3WhNS6G5VMMJsJ .error-icon{fill:#552222;}#mermaid-svg-ci3WhNS6G5VMMJsJ .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-ci3WhNS6G5VMMJsJ .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-ci3WhNS6G5VMMJsJ .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-ci3WhNS6G5VMMJsJ .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-ci3WhNS6G5VMMJsJ .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-ci3WhNS6G5VMMJsJ .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-ci3WhNS6G5VMMJsJ .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-ci3WhNS6G5VMMJsJ .marker{fill:#333333;stroke:#333333;}#mermaid-svg-ci3WhNS6G5VMMJsJ .marker.cross{stroke:#333333;}#mermaid-svg-ci3WhNS6G5VMMJsJ svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-ci3WhNS6G5VMMJsJ p{margin:0;}#mermaid-svg-ci3WhNS6G5VMMJsJ .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-ci3WhNS6G5VMMJsJ .cluster-label text{fill:#333;}#mermaid-svg-ci3WhNS6G5VMMJsJ .cluster-label span{color:#333;}#mermaid-svg-ci3WhNS6G5VMMJsJ .cluster-label span p{background-color:transparent;}#mermaid-svg-ci3WhNS6G5VMMJsJ .label text,#mermaid-svg-ci3WhNS6G5VMMJsJ span{fill:#333;color:#333;}#mermaid-svg-ci3WhNS6G5VMMJsJ .node rect,#mermaid-svg-ci3WhNS6G5VMMJsJ .node circle,#mermaid-svg-ci3WhNS6G5VMMJsJ .node ellipse,#mermaid-svg-ci3WhNS6G5VMMJsJ .node polygon,#mermaid-svg-ci3WhNS6G5VMMJsJ .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-ci3WhNS6G5VMMJsJ .rough-node .label text,#mermaid-svg-ci3WhNS6G5VMMJsJ .node .label text,#mermaid-svg-ci3WhNS6G5VMMJsJ .image-shape .label,#mermaid-svg-ci3WhNS6G5VMMJsJ .icon-shape .label{text-anchor:middle;}#mermaid-svg-ci3WhNS6G5VMMJsJ .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-ci3WhNS6G5VMMJsJ .rough-node .label,#mermaid-svg-ci3WhNS6G5VMMJsJ .node .label,#mermaid-svg-ci3WhNS6G5VMMJsJ .image-shape .label,#mermaid-svg-ci3WhNS6G5VMMJsJ .icon-shape .label{text-align:center;}#mermaid-svg-ci3WhNS6G5VMMJsJ .node.clickable{cursor:pointer;}#mermaid-svg-ci3WhNS6G5VMMJsJ .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-ci3WhNS6G5VMMJsJ .arrowheadPath{fill:#333333;}#mermaid-svg-ci3WhNS6G5VMMJsJ .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-ci3WhNS6G5VMMJsJ .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-ci3WhNS6G5VMMJsJ .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ci3WhNS6G5VMMJsJ .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-ci3WhNS6G5VMMJsJ .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ci3WhNS6G5VMMJsJ .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-ci3WhNS6G5VMMJsJ .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-ci3WhNS6G5VMMJsJ .cluster text{fill:#333;}#mermaid-svg-ci3WhNS6G5VMMJsJ .cluster span{color:#333;}#mermaid-svg-ci3WhNS6G5VMMJsJ div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-ci3WhNS6G5VMMJsJ .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-ci3WhNS6G5VMMJsJ rect.text{fill:none;stroke-width:0;}#mermaid-svg-ci3WhNS6G5VMMJsJ .icon-shape,#mermaid-svg-ci3WhNS6G5VMMJsJ .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-ci3WhNS6G5VMMJsJ .icon-shape p,#mermaid-svg-ci3WhNS6G5VMMJsJ .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-ci3WhNS6G5VMMJsJ .icon-shape .label rect,#mermaid-svg-ci3WhNS6G5VMMJsJ .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-ci3WhNS6G5VMMJsJ .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-ci3WhNS6G5VMMJsJ .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-ci3WhNS6G5VMMJsJ :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 需要更多信息
任务完成
① User Task
② Session
③ Context Assembly
④ Model Inference
⑤ Model Decision
⑥ Tool Call
⑦ Environment Execution
⑧ Observation / Tool Result
⑨ Update Session
⑩ Final Answer
我们逐个解释。
1.13.1 User Task
用户给出目标:
text
测试失败了,帮我找原因并修复。
注意,"目标"并不一定意味着用户已经把所有操作步骤写好。
Agent 的价值之一就在于:
text
Goal
↓
自主决定下一步 Action
1.13.2 Session
任务不是一个无状态 API 请求。
系统需要知道:
text
用户刚刚说了什么?
模型之前做了什么?
已经执行了哪些 Tool?
Tool 返回了什么?
当前任务进行到哪一步?
因此必须存在持续的 Session。
1.13.3 Context Assembly
在真正请求模型之前,Harness 需要准备模型能够理解的上下文。
它可能包括:
text
System Instructions
Conversation History
Runtime Context
Available Tools
Tool Schemas
Skills
Task State
Environment Information
于是模型收到的并不只是:
text
"测试失败了,帮我修复。"
而更接近:
text
你是谁
+
你当前能做什么
+
你现在在哪个环境
+
用户要求什么
+
之前发生过什么
+
有哪些 Tool 可以使用
1.13.4 Model Decision
模型开始判断:
text
我现在信息够不够?
如果不够:
text
调用 Tool
如果已经足够:
text
生成答案
于是每一步大致可以描述成:
text
Context
↓
Model
↓
Decision
├── Tool Call
└── Final Answer
1.13.5 Tool Call
假设模型选择:
text
run tests
那么 Harness 会把模型生成的结构化 Tool Request 交给真正的工具系统,而不是让模型自己"假装运行"。
例如概念上:
json
{
"tool": "bash",
"arguments": {
"command": "npm test"
}
}
真正发生的是:
text
Model output
↓
Tool Registry
↓
Bash Tool
↓
Shell Executor
1.13.6 Environment Execution
命令真正进入环境:
bash
npm test
得到真实输出:
text
FAIL tests/user.test.ts
Expected: 200
Received: 500
TypeError: Cannot read properties of undefined
...
这一步就是 LLM 与真实世界之间的桥梁。
1.13.7 Observation
执行结果重新交给 Agent。
text
Tool Result
↓
Session
↓
Model Context
模型再根据新的信息判断:
text
错误来自 userService.ts
↓
需要读取对应代码
于是下一轮继续:
text
read file
↓
observation
↓
think
↓
edit file
↓
observation
↓
test
1.13.8 Finish
最终,当模型判断目标已经达到:
text
测试通过
问题已定位
修改已完成
才返回最终回答。
所以整个任务不是:
text
Prompt
↓
Completion
而更像:
text
┌───────────────────┐
│ │
▼ │
User → Context → Model → Action → Observation
│ │
└────── Finish? ────┘
│
▼
Final Answer
这个循环就是理解 Harness 最关键的基础。
1.14 DSH 为什么强调 Everything is a Plugin?
现在我们已经知道 Agent 需要很多能力:
text
Model
Tool
Session
Filesystem
Shell
Sandbox
Storage
Loop
Skill
UI
一个最直接的做法是把它们全部写进一个巨大的 Agent Core:
text
AgentCore
├── ModelManager
├── ToolManager
├── SessionManager
├── FileManager
├── SandboxManager
├── SkillManager
├── JobManager
└── AgentLoop
问题也非常明显。
随着能力增加:
text
AgentCore
↓
越来越大
↓
模块互相引用
↓
扩展困难
↓
替换困难
↓
第三方能力很难干净接入
DSH 选择了另一条路线:
text
Everything is a Plugin
也就是:
text
DSH
│
Plugin Tree
│
┌─────────────┼──────────────┐
▼ ▼ ▼
Model Plugin Tool Plugin Session Plugin
▼ ▼ ▼
Sandbox Plugin Skill Plugin UI Plugin
甚至:
text
Agent Loop
本身也可以作为插件参与整个系统组合。
这意味着 DSH 的理想不是:
"我们把所有 Agent 能力都写好,你直接使用。"
而更接近:
"我们提供一个能够组合 Agent 能力的运行基础,你可以替换、增加和重新组合这些能力。"
这一点会成为后四章的主线。
1.15 DSH 的安全问题:为什么第一次使用不要直接给满权限?
这一节非常重要。
因为前面一直在强调:
text
DSH 可以执行命令
DSH 可以编辑文件
DSH 可以访问工作区
DSH 可以加载插件
这些能力既是 Agent 的价值,也是风险来源。
官方当前明确指出:
DeepSeek Harness 仍属于实验性的 Developer Preview 软件,尚不能被视为已经完成安全审计或适合直接作为生产安全边界的软件。
DSH 可能执行模型生成的代码和命令,也可能访问你向它开放的:
text
Files
Processes
Network
Credentials
Plugins
因此至少要理解以下风险。
表 1-4:Agent 执行环境中的主要风险
| 风险 | 示例 |
|---|---|
| 错误命令 | 模型误删文件 |
| 错误修改 | 大范围覆盖源码 |
| 敏感信息泄露 | 读取 .env 后发送到外部 |
| 恶意 Prompt | 仓库文档中存在 Prompt Injection |
| 第三方插件 | 插件本身具有恶意行为 |
| 权限过大 | Agent 可以访问整个宿主机 |
| 网络风险 | 将本地数据发送到外部服务 |
| 配置错误 | Sandbox 实际未按预期生效 |
1.15.1 Approval
DSH 提供 Approval 机制,用来回答一个问题:
某一个具体操作是否允许继续执行?
可以理解为:
#mermaid-svg-6vITNxQGc7qkGbLF{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-6vITNxQGc7qkGbLF .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-6vITNxQGc7qkGbLF .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-6vITNxQGc7qkGbLF .error-icon{fill:#552222;}#mermaid-svg-6vITNxQGc7qkGbLF .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-6vITNxQGc7qkGbLF .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-6vITNxQGc7qkGbLF .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-6vITNxQGc7qkGbLF .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-6vITNxQGc7qkGbLF .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-6vITNxQGc7qkGbLF .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-6vITNxQGc7qkGbLF .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-6vITNxQGc7qkGbLF .marker{fill:#333333;stroke:#333333;}#mermaid-svg-6vITNxQGc7qkGbLF .marker.cross{stroke:#333333;}#mermaid-svg-6vITNxQGc7qkGbLF svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-6vITNxQGc7qkGbLF p{margin:0;}#mermaid-svg-6vITNxQGc7qkGbLF .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-6vITNxQGc7qkGbLF .cluster-label text{fill:#333;}#mermaid-svg-6vITNxQGc7qkGbLF .cluster-label span{color:#333;}#mermaid-svg-6vITNxQGc7qkGbLF .cluster-label span p{background-color:transparent;}#mermaid-svg-6vITNxQGc7qkGbLF .label text,#mermaid-svg-6vITNxQGc7qkGbLF span{fill:#333;color:#333;}#mermaid-svg-6vITNxQGc7qkGbLF .node rect,#mermaid-svg-6vITNxQGc7qkGbLF .node circle,#mermaid-svg-6vITNxQGc7qkGbLF .node ellipse,#mermaid-svg-6vITNxQGc7qkGbLF .node polygon,#mermaid-svg-6vITNxQGc7qkGbLF .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-6vITNxQGc7qkGbLF .rough-node .label text,#mermaid-svg-6vITNxQGc7qkGbLF .node .label text,#mermaid-svg-6vITNxQGc7qkGbLF .image-shape .label,#mermaid-svg-6vITNxQGc7qkGbLF .icon-shape .label{text-anchor:middle;}#mermaid-svg-6vITNxQGc7qkGbLF .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-6vITNxQGc7qkGbLF .rough-node .label,#mermaid-svg-6vITNxQGc7qkGbLF .node .label,#mermaid-svg-6vITNxQGc7qkGbLF .image-shape .label,#mermaid-svg-6vITNxQGc7qkGbLF .icon-shape .label{text-align:center;}#mermaid-svg-6vITNxQGc7qkGbLF .node.clickable{cursor:pointer;}#mermaid-svg-6vITNxQGc7qkGbLF .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-6vITNxQGc7qkGbLF .arrowheadPath{fill:#333333;}#mermaid-svg-6vITNxQGc7qkGbLF .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-6vITNxQGc7qkGbLF .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-6vITNxQGc7qkGbLF .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6vITNxQGc7qkGbLF .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-6vITNxQGc7qkGbLF .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6vITNxQGc7qkGbLF .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-6vITNxQGc7qkGbLF .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-6vITNxQGc7qkGbLF .cluster text{fill:#333;}#mermaid-svg-6vITNxQGc7qkGbLF .cluster span{color:#333;}#mermaid-svg-6vITNxQGc7qkGbLF div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-6vITNxQGc7qkGbLF .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-6vITNxQGc7qkGbLF rect.text{fill:none;stroke-width:0;}#mermaid-svg-6vITNxQGc7qkGbLF .icon-shape,#mermaid-svg-6vITNxQGc7qkGbLF .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-6vITNxQGc7qkGbLF .icon-shape p,#mermaid-svg-6vITNxQGc7qkGbLF .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-6vITNxQGc7qkGbLF .icon-shape .label rect,#mermaid-svg-6vITNxQGc7qkGbLF .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-6vITNxQGc7qkGbLF .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-6vITNxQGc7qkGbLF .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-6vITNxQGc7qkGbLF :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 否
是
Allow once
Reject
Agent 请求操作
需要审批?
Execute
User Approval
Denied
一个非常重要的特点是:
Approval 更适合"针对这一次动作授权",而不是简单地认为 Agent 从此永久拥有所有权限。
1.15.2 Sandbox
Sandbox 用来限制执行行为。
例如 Workspace Write 模式可以围绕 Workspace 限制文件写入能力。
概念上可以理解成:
text
Host Machine
┌──────────────────────────────────────┐
│ │
│ Workspace │
│ ┌──────────────────────────────┐ │
│ │ Agent 可工作的项目范围 │ │
│ │ │ │
│ │ src/ │ │
│ │ tests/ │ │
│ │ docs/ │ │
│ └──────────────────────────────┘ │
│ │
│ 其他宿主资源 │
│ 尽量不向 Agent 开放 │
│ │
└──────────────────────────────────────┘
不过必须强调:
Sandbox 可以降低风险,但不能把 DSH 当作针对不可信工作负载的唯一安全隔离层。
官方也建议:
- 使用最小权限;
- 优先在容器、虚拟机或专用环境中测试;
- 备份 Agent 可以访问的文件;
- 不要随意暴露敏感凭据;
- 安装第三方插件前检查来源和实现;
- 对拟执行命令保持可见性。
1.15.3 初学者建议
第一次体验 DSH 时,更推荐:
text
测试项目
>
个人重要项目
副本
>
唯一工作目录
Workspace 限定
>
全盘访问
需要审批
>
危险操作自动执行
也就是说:
先让 Agent 有能力,再逐步扩大权限,而不是一开始就把整个电脑交给 Agent。
1.16 一个完整示例:让 DSH 分析项目并运行测试
现在把前面的知识串起来。
假设我们有:
text
demo-project/
├── package.json
├── src/
│ ├── index.ts
│ └── user.ts
└── tests/
└── user.test.ts
用户输入:
text
分析这个项目的结构,
然后运行测试。
如果测试失败,找到最可能的原因,
但先不要修改代码。
这是一条非常适合作为 DSH 入门体验的 Prompt。
第一步:理解任务
模型得到:
text
目标 1:分析项目
目标 2:运行测试
目标 3:分析错误
约束:不要修改代码
第二步:查看项目
Agent 调用文件相关工具:
text
list directory
read package.json
read README
search src
得到:
text
这是一个 TypeScript 项目
测试框架为 xxx
入口为 src/index.ts
第三步:确定测试命令
根据:
json
{
"scripts": {
"test": "vitest"
}
}
Agent 判断:
bash
npm test
第四步:运行测试
text
Tool Call:
bash("npm test")
环境返回:
text
1 test failed
第五步:读取错误信息
例如:
text
user.test.ts:31
Expected:
Alice
Received:
undefined
模型继续判断:
text
可能是 user.ts 的字段读取逻辑错误。
第六步:读取相关源码
Agent 继续调用文件工具:
text
read src/user.ts
第七步:形成结论
由于用户明确说:
text
先不要修改代码
Agent 在找到原因后停止修改行为,输出:
text
项目结构......
测试结果......
错误位置......
最可能原因......
建议修改方式......
图 1-10:该任务的完整轨迹
#mermaid-svg-axFfQqmZqE45QgKh{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#333;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-svg-axFfQqmZqE45QgKh .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-svg-axFfQqmZqE45QgKh .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-svg-axFfQqmZqE45QgKh .error-icon{fill:#552222;}#mermaid-svg-axFfQqmZqE45QgKh .error-text{fill:#552222;stroke:#552222;}#mermaid-svg-axFfQqmZqE45QgKh .edge-thickness-normal{stroke-width:1px;}#mermaid-svg-axFfQqmZqE45QgKh .edge-thickness-thick{stroke-width:3.5px;}#mermaid-svg-axFfQqmZqE45QgKh .edge-pattern-solid{stroke-dasharray:0;}#mermaid-svg-axFfQqmZqE45QgKh .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-svg-axFfQqmZqE45QgKh .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-svg-axFfQqmZqE45QgKh .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-svg-axFfQqmZqE45QgKh .marker{fill:#333333;stroke:#333333;}#mermaid-svg-axFfQqmZqE45QgKh .marker.cross{stroke:#333333;}#mermaid-svg-axFfQqmZqE45QgKh svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-svg-axFfQqmZqE45QgKh p{margin:0;}#mermaid-svg-axFfQqmZqE45QgKh .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#333;}#mermaid-svg-axFfQqmZqE45QgKh .cluster-label text{fill:#333;}#mermaid-svg-axFfQqmZqE45QgKh .cluster-label span{color:#333;}#mermaid-svg-axFfQqmZqE45QgKh .cluster-label span p{background-color:transparent;}#mermaid-svg-axFfQqmZqE45QgKh .label text,#mermaid-svg-axFfQqmZqE45QgKh span{fill:#333;color:#333;}#mermaid-svg-axFfQqmZqE45QgKh .node rect,#mermaid-svg-axFfQqmZqE45QgKh .node circle,#mermaid-svg-axFfQqmZqE45QgKh .node ellipse,#mermaid-svg-axFfQqmZqE45QgKh .node polygon,#mermaid-svg-axFfQqmZqE45QgKh .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-svg-axFfQqmZqE45QgKh .rough-node .label text,#mermaid-svg-axFfQqmZqE45QgKh .node .label text,#mermaid-svg-axFfQqmZqE45QgKh .image-shape .label,#mermaid-svg-axFfQqmZqE45QgKh .icon-shape .label{text-anchor:middle;}#mermaid-svg-axFfQqmZqE45QgKh .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-svg-axFfQqmZqE45QgKh .rough-node .label,#mermaid-svg-axFfQqmZqE45QgKh .node .label,#mermaid-svg-axFfQqmZqE45QgKh .image-shape .label,#mermaid-svg-axFfQqmZqE45QgKh .icon-shape .label{text-align:center;}#mermaid-svg-axFfQqmZqE45QgKh .node.clickable{cursor:pointer;}#mermaid-svg-axFfQqmZqE45QgKh .root .anchor path{fill:#333333!important;stroke-width:0;stroke:#333333;}#mermaid-svg-axFfQqmZqE45QgKh .arrowheadPath{fill:#333333;}#mermaid-svg-axFfQqmZqE45QgKh .edgePath .path{stroke:#333333;stroke-width:2.0px;}#mermaid-svg-axFfQqmZqE45QgKh .flowchart-link{stroke:#333333;fill:none;}#mermaid-svg-axFfQqmZqE45QgKh .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-axFfQqmZqE45QgKh .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-svg-axFfQqmZqE45QgKh .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-axFfQqmZqE45QgKh .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-svg-axFfQqmZqE45QgKh .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-svg-axFfQqmZqE45QgKh .cluster text{fill:#333;}#mermaid-svg-axFfQqmZqE45QgKh .cluster span{color:#333;}#mermaid-svg-axFfQqmZqE45QgKh div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-svg-axFfQqmZqE45QgKh .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#333;}#mermaid-svg-axFfQqmZqE45QgKh rect.text{fill:none;stroke-width:0;}#mermaid-svg-axFfQqmZqE45QgKh .icon-shape,#mermaid-svg-axFfQqmZqE45QgKh .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-svg-axFfQqmZqE45QgKh .icon-shape p,#mermaid-svg-axFfQqmZqE45QgKh .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-svg-axFfQqmZqE45QgKh .icon-shape .label rect,#mermaid-svg-axFfQqmZqE45QgKh .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-svg-axFfQqmZqE45QgKh .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-svg-axFfQqmZqE45QgKh .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-svg-axFfQqmZqE45QgKh :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;} 通过
失败
本例:否
是
用户任务
解析目标与约束
查看项目目录
读取 package.json
读取关键源码
执行 npm test
测试结果
总结项目与测试结果
读取错误
定位相关文件
分析根因
用户是否允许修改?
只输出分析报告
修改代码
重新测试
这张图已经非常接近一个真正 Agent Runtime 的工作方式。
1.17 为什么说 Harness 才是 Agent 工程的核心之一?
模型越来越强以后,人们很容易形成一种错觉:
"只要换一个更强的模型,Agent 就自然会越来越好。"
模型当然非常重要。
但真实 Agent 系统的质量还取决于很多模型外因素:
text
模型能不能看到正确上下文?
Tool 描述是否清楚?
Tool Result 是否可靠?
文件编辑是否安全?
任务状态会不会丢?
长任务如何持续?
失败后如何恢复?
Shell 如何限制?
审批怎么做?
凭据怎么管理?
插件能不能隔离?
Session 能不能 replay?
因此,一个 Agent 的效果可以粗略写成:
text
Agent Quality
=
Model Intelligence
×
Harness Quality
这不是数学公式,而是一种工程直觉:
模型决定智能上限,Harness 决定智能能否稳定地进入真实环境。
一个非常强的模型,如果 Harness 很差,也可能出现:
text
重复调用工具
误读文件
上下文混乱
无限循环
危险执行
状态丢失
工具结果无法追踪
反过来,一个设计良好的 Harness 可以让模型:
text
知道自己在哪里
知道自己有哪些工具
知道刚刚做了什么
知道操作是否成功
知道什么时候需要审批
知道什么时候继续
知道什么时候停止
这就是 Agent Engineering 与单纯 Prompt Engineering 的区别之一。
1.18 第一章总结:先记住这 7 句话
读到这里,还不需要记住 DSH 的所有术语。
只要先记住下面七句话。
① Agent 不等于 LLM
text
Agent = Model + Runtime Capabilities
② Harness 是模型与真实环境之间的执行层
text
Model
↕
Harness
↕
Real World
③ DSH 是 DeepSeek 开源的 Agent Harness
命令名:
text
dsh
④ DSH 的核心理念之一是
text
Agent = Model + Harness
⑤ DSH 的另一个核心理念是
text
Everything is a Plugin
模型、工具、技能、会话、沙箱、存储、Agent Loop、UI 等能力都可以围绕插件体系进行组合。
⑥ Agent 的核心运行方式不是一次 Completion,而是 Loop
text
Model
↓
Action
↓
Environment
↓
Observation
↓
Model
⑦ DSH 不应该被当作已经完成安全审计的生产安全边界
当前仍是:
text
Developer Preview
在真实机器上使用时应坚持:
text
Least Privilege
Sandbox
Approval
Workspace Boundary
Trusted Plugins
Backups
1.19 从第一章到第二章:一个新的问题
第一章结束以后,我们已经能够理解 DSH 的外部形态:
text
DeepSeek Harness
│
┌───────────────┼───────────────┐
▼ ▼ ▼
Model Tools Session
▼ ▼ ▼
Sandbox Skills UI
▼
Files
但是,一个新的问题出现了:
如果模型、Tool、Session、Sandbox,甚至 Agent Loop 本身都可以是插件,那么 DSH 为什么不会变成一堆互相混乱的插件?
进一步说:
text
插件由谁加载?
插件之间怎么发现彼此?
谁负责处理依赖顺序?
Tool 插件怎么拿到 Tool Registry?
Session 插件怎么暴露能力?
插件卸载以后注册内容怎么撤销?
为什么 DSH 可以替换某个能力,而不用修改所谓的"核心"?
Profile 和 Bundle 又是什么?
要回答这些问题,就必须进入 DSH 真正的架构核心:
Cordis
下一章我们将从静态架构角度拆解:
text
DeepSeek Harness
↓
Cordis
↓
Shared Context
↓
Service / Event / Effect
↓
Plugin Tree
↓
Profile / Bundle / Patch
并解释 DSH 最重要的架构命题:
"Everything is a Plugin" 到底是怎么实现的?
参考资料
本章以 DeepSeek Harness 官方仓库与官方文档为主要依据。由于 DSH 当前仍处于 Developer Preview 阶段,接口、命令和架构可能继续变化,建议阅读时以最新官方文档为准。
-
DeepSeek Harness 官方仓库
-
DeepSeek Harness 官方主页
-
DeepSeek Harness Architecture
https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/architecture.md
-
DeepSeek Harness Web UI Guide
https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/guide/index.md
-
DeepSeek Harness Model Provider Guide
https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/user/guide/providers.md
-
DeepSeek Harness Safety
https://github.com/deepseek-ai/deepseek-harness/blob/master/SAFETY.md
-
DeepSeek Harness Sandbox Reference
https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/sandbox.md
-
DeepSeek Harness User Approval Reference
https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/subsystems/approval.md
系列导航
- 第一章:从 LLM 到 Agent ------ DeepSeek Harness 入门 ← 当前章节
- 第二章:DSH 整体架构 ------ Cordis 与插件化微内核
- 第三章:一次 Agent Run 的完整生命周期
- 第四章:DSH 插件机制 ------ Everything is a Plugin
- 第五章:实战 ------ 从零开发一个 DSH 插件