DeepSeek Harness:一个把所有东西都做成插件的开源智能体框架
完整的智能体技术栈,直接扔到 GitHub 上
2026 年 8 月 13 日,DeepSeek 放出 DeepSeek Harness(简称 dsh)的开发者预览版。仓库在 deepseek-ai/deepseek-harness。发布当天已经有 1.6k star、12,293 次提交、19 位贡献者——这不是周末随便写写的 demo。代码里 97.1% 是 TypeScript,1.6% CSS,0.7% Python。发布版本号 0.1.0-rc.5。
产品主页在 deepseek.com/harness,开发者文档在 deepseek-harness.github.io/deepseek-harness。
MIT 协议。
一句话讲清楚它是什么
README 原文:“Agent = Model + Harness”(智能体 = 模型 + 套壳/Harness)。
模型是灵魂。Harness 让智能体理解环境、调用工具、在真实环境里持续工作。DeepSeek 的做法:模型、工具、技能、会话、沙箱、存储、循环、调度、UI——所有能力都是一个可替换的插件。
这不是 slogan,是架构强制约束出来的。
Cordis:底层的插件内核
DeepSeek Harness 构建在 Cordis 之上(一个 vendored 的插件框架)。Cordis 的设计哲学写在论文《A Programming Paradigm for Spatiotemporal Composability》里。
整个框架可以压缩成 5 条:
- 一个 plugin = 一个实现 Service 的对象。 可以是带
inject+apply(ctx)的函数,也可以是Service子类。 - 一个 context = 一个 service 仓库。 插件占据一个稳定 key,比如
ctx.tools、ctx.llm、ctx.sessions。其他插件通过 key 发现能力,而不是 import 具体实现。 - 依赖通过
inject声明。 声明了哪些 service,框架就等它们全部就绪后再加载——不需要手写启动顺序。 - 类型化事件做通信。 四种派发:
emit(发射不等待)、waterfall(中间件风格,带next())、parallel(并行广播)、serial(顺序执行、带回值)。 - 注册即可逆副作用。 prompt 片段、工具 schema、适配器、监听器——全通过
ctx.effect()注册,reload / teardown 时按顺序自动撤回。
Waterfall 模型类似 around-middleware:监听器拿到 (...args, next),调 next() 就把(可能被包装过的)结果交给下一个服务;不调 next() 就短路。单决策事件就应该短路——policy 监听器如果自己说了算,就直接返回。
真的是一切皆插件
DeepSeek Harness 首页 把插件能力清单列得很清楚:
- Models(模型)——LLM 后端:DeepSeek、OpenAI、Anthropic、Bedrock、Vertex、Azure、Codex,以及任意 OpenAI 兼容端点
- Tools(工具)——模型可调用的外部能力
- Skills(技能)——可复用的 prompt + 工具捆绑包
- Sessions(会话)——对话状态管理
- Sandboxes(沙箱)——代码运行地(PTY bash、
danger-full-access本地后端、基于 landlock 的原生沙箱) - Storage(存储)——会话持久化
- Loops(循环)——智能体每一轮的 turn 逻辑
- Scheduling(调度)——子代理、任务分发
- UI(界面)——默认跑在 3080 端口的 Web UI
开发者可以通过配置选择、替换、扩展任意一项,不用改 Harness 源码。Plugin Config Catalog 是由 scripts/gen-config-catalog.ts 自动生成、CI 校验新鲜度的,cordis.yml 里每个 config: 字段都精确匹配插件声明的配置类型。
四种运行模式
文档内置四种预设,各自对应不同场景:
Standard Mode(标准模式)——完整的编码智能体:文件编辑、shell、文件与网页搜索、技能、计划、目标、子代理、工作流。默认 Web UI 体验。
Code Mode(代码模式)——标准模式的一切都保留,但工具通过 Code Mode SDK 暴露给模型。模型可以写一段 TypeScript 程序来编排多步操作。一次程序执行取代多轮 tool call。
Minimal Mode(最小模式)——只保留两个工具:持久化的 bash shell 和 str_replace_editor。用来在极简环境里对模型做 benchmark。没技能、没计划、没子代理——纯原始模型能力面对真实仓库。
Creator Mode(创作者模式)——专门用来写自定义 agent preset 的。包含标准模式全部能力,外加运行时内省、内存内 Cordis 插件实验、preset 写作指引。未来的第五、第六、第七种模式就是在这里造出来的。
每次运行都可追踪回放
这是 Harness 和绝大多数 agent 工具拉开差距的地方。模型看到的所有东西都会被写进一条只追加(append-only)的会话日志:
- System prompt
- Reasoning 输出
- 工具调用与结果
- 子代理调度决策
- 每一次上下文注入
Web UI 里有一个 Trajectory 视图,可以按来源筛选查看。继续(resume)、分叉(fork)、搜索、回放——四种操作全部针对同一条事件流。没有单独的 trace 数据库,不用导出步骤。会话的 JSONL 文件本身就是 source of truth。
Python SDK 那边同理,session root 下存未压缩的 JSONL,里面是组装好的模型请求和工具调用。examples/jsonrpc-agent/minimal.py 走完整流程。
模型配置:DeepSeek + 任何你想接的
配置模型指南 分三层:
DeepSeek 官方。 打开设置 → 模型,粘贴 DeepSeek API key,保存。密钥是只写的。保存后 UI 只收到一个脱敏的描述符,永远拿不到明文。密钥存在 \$DSH_HOME/.credentials.yaml;settings 页面只保留凭据引用。
目录内提供方。 点「添加提供方」,选 Anthropic 或 OpenAI,粘贴 API key。走原生鉴权的提供方(Bedrock 用 AWS 凭据 + region;Vertex 用 ADC project;Azure 用 api-version;Codex 用 OAuth)不能只填 API key——各走各的鉴权路径。
自定义提供方。 给公司网关、自建服务、或目录里没有的提供方用。填一个小写 Provider ID(永久值——请求、保存的会话、模型默认值、凭据引用都会用到)、base URL、API 协议、凭据、至少一个模型。
视觉模型多一步。自定义端点不会宣告自己支持哪些模态,表单没法自动识别 vision 支持。要在 \$DSH_HOME/settings.yaml 给那个模型加上 input: [text, image]。如果你所有自定义模型都支持图,就在提供方层级写一次 defaultInput: [text, image] 省掉逐模型加。注意 input 字段是对端点的断言,不是实际检查——如果你说模型支持图但端点实际上不支持,报错来自提供方,不是 Harness 这边。
文档直接给出了排错表:
MISSING_CREDENTIAL→ 去模型页存提供方的密钥,或导出被引用的环境变量。UNKNOWN_MODEL→ 选一个已配置的模型,或在自定义提供方下补上这个模型。- “获取可用模型返回 401” → 检查密钥。模型发现走 OpenAI 兼容的
GET /models端点。你的服务没暴露这个接口?手动录入模型。 - “图片在发送前被拒绝” → 该模型没声明
image模态。加input: [text, image]。 - “提供方拒绝了带图片的请求” → 模型声称支持图片但端点实际上没有。从声明列表里拿掉
image,然后开新会话——旧图片留在会话日志里,同一个请求会不断重复。
三条上手路径
路径一:npx @deepseek-ai/dsh web
装好 Node.js,跑一条命令。Web UI 默认起在 http://127.0.0.1:3080。不用 clone,不用 build,不用 pnpm。
npx @deepseek-ai/dsh web接下来:设置 → 模型 → 粘贴 DeepSeek API 密钥。选择工作区(启动 dsh 的目录就行)。发起会话:
总结这个仓库,识别它主要的包。
智能体可以读写工作区文件、跑命令、委派工作、维护计划。任何在当前权限策略下需要审批的操作,Web UI 都会先弹窗再执行。
路径二:源码 clone + build
git clone https://github.com/deepseek-ai/deepseek-harness.gitcd deepseek-harnesspnpm installpnpm run buildpnpm dsh web路径三:Python SDK
要求:Python 3.10+、Linux x64 / Linux arm64 / macOS 14+ arm64、DeepSeek 兼容的端点与凭据。
git clone https://github.com/deepseek-ai/deepseek-harness.gitcd deepseek-harnesspython -m venv .venv. .venv/bin/activatepython -m pip install deepseek-harness-sdk设凭据:
export DEEPSEEK_API_KEY=sk-your-key-here# 可选:# export DSH_MODEL=deepseek-v4-flash# export DSH_SYSTEM_PROMPT='You are a helpful software engineer assistant.'对一个隔离工作区跑任务:
python examples/jsonrpc-agent/minimal.py \ --workspace /absolute/path/to/workspace \ --session-root /absolute/path/to/sessions \ --session-id example-001 \ "Inspect the repository and fix the failing tests."你自己的代码里,SDK 入口是作为 context manager 的 DeepSeekHarness:
from pathlib import Pathfrom deepseek_harness import DeepSeekHarness
config = Path("examples/jsonrpc-agent/minimal.cordis.yml").resolve()workspace = Path("/absolute/path/to/workspace").resolve()sessions = Path("/absolute/path/to/sessions").resolve()
with DeepSeekHarness( provider="deepseek-official", model="deepseek-v4-flash", max_tokens=49_152, cwd=str(workspace), session_root=str(sessions), cordis=str(config),) as harness: result = harness.run( "Inspect the repository and fix the failing tests.", session_id="example-001", ) print(result.final_response)DeepSeekHarness 懒启动内置 runtime,并在 with 块退出前一直复用它。同一个 session id 可以保留 Bash 进程(工作目录、环境变量、shell 函数全部继承)。要独立任务就换新的 session id。
jsonrpc-agent 的 minimal 组合刻意做得很精简:只暴露持久 bash 和 str_replace_editor 给模型。Bash 超时 300 秒,编辑器输出上限 16,000 字符,上下文压缩关闭。文件系统走裸本地后端——编辑器路径可以写进运行时进程能看到的任意位置。文档明确提醒:“只在一次性 checkout 或容器里跑。” 持久 PTY 后端还要求 POSIX 终端 substrate,Windows 不能用这套组合。
写你的第一个插件
教程 Your first plugin。一个 plugin 就是一个导出 apply 函数的 TypeScript 模块:
import type { Context } from '@deepseek-ai/cordis'
export const name = 'hello-plugin'
export function apply(ctx: Context) { console.log('[hello-plugin] plugin loaded!')}在 cordis.yml patch 里注册它:
- insert: - id: hello name: '/absolute/path/to/deepseek-harness/scratch-plugin/src/my-plugin.ts'带 overlay 启动:
pnpm dsh web --patch ./scratch-plugin/cordis.yml自动清理是杀手锏。通过 ctx 注册的一切——事件监听器、工具、定时器——plugin 卸载时通通自动撤回,不用手写 removeListener / clearInterval。需要显式清理的(网络连接之类),在 ctx.effect() 里返回 disposer 即可。
依赖通过 inject 声明:
export const name = 'my-tool-plugin'export const inject = ['tools']
export function apply(ctx: Context) { // ctx.tools 此时已经就绪}Cordis 等每一项依赖都就位才加载插件。
插件三种写法:函数式(上面)、带 apply 的对象、继承 Service 的 class。插件本身要向其他插件提供服务时用 class form。
写你的第一个工具
教程 Build a tool。用 @deepseek-ai/dsh-tools 的 defineTool:
import type { Context } from '@deepseek-ai/cordis'import { defineTool } from '@deepseek-ai/dsh-tools'
export const name = 'greet-tool'export const inject = ['tools']
export function apply(ctx: Context) { ctx.tools.register(defineTool({ name: 'greet', description: 'Greet someone by name.', parameters: { name: { type: 'string', required: true, description: 'The name to greet', }, }, output: { schema: { type: 'string' }, render: (_args, value) => [{ type: 'text', text: value }], }, async execute(args) { return `Hello, ${args.name}!` }, }))}defineTool 根据 parameters 推断并校验 args。execute 返回 output.schema 声明的规范值(canonical value)。output.render 把这个规范值转换成面向模型的内容。重启带 patch 后,在 Web UI 里问:“Use the greet tool to greet Ada.” 模型会调 greet 并收到 Hello, Ada!。
教程后续三个链接:插件配置、工具编写参考(嵌套 schema、规范值、后台执行、policy hook、Code Mode、UI 卡片)、能力分层(Service 定义 → Service Provider → Consumer 包三层拆分)。
CLI 入口模式
@deepseek-ai/dsh 命令是产品级启动器。四个入口:
| 命令 | 用途 |
|---|---|
dsh --profile <name> |
启动 \$DSH_HOME/profiles/<name> 下命名 profile |
dsh --profile headless "job" |
跑一次全新持久会话,打印最终答案然后退出 |
dsh web |
--profile web 的别名 |
dsh plugin --profile <name> <pnpm args> |
把 pnpm 命令转发到 profile 目录,管它的插件 |
启动时所在目录是默认工作区根目录。web 和 headless 两个 profile 在首次使用时会按内置模板自动初始化。其他 profile 必须用 dsh plugin 创建。
启动器只解析自己的 flag。第一个启动器不认的 token 就交给被 boot 的 profile。例子:dsh --profile web --port 8080 里 --port 8080 是 web app 的 flag,不是启动器的。
Profile 目录里放一个 package.json(外挂插件依赖 + profile manifest dsh.profile,内含有序的 bundles 列表)和一个 cordis.patch.yml(用户自己的 patch 层)。在空根上的组合顺序是:dsh.profile.bundles 顺序下各 bundle 的 patch → profile 的 cordis.patch.yml → 用户 home 级的 \$DSH_HOME/cordis.patch.yml → --patch overlay。用 --dump-default-config 和 --dump-config 可以不启动就查看组合完的树。
社区插件与生态
给自己的插件仓库打 GitHub topic dsh-plugin 就能被发现。官网直接链到这个 topic 页。还有一个 DeepSeek Harness Discord 社区 做日常讨论。
反馈和 bug 走 GitHub Discussions。开发流程看 CONTRIBUTING.md,系统设计看 architecture.md,智能体侧编码约定看 AGENTS.md。
开发者预览 = 会坏
README 直接写了全大写:“THERE WILL BE COMPATIBILITY-BREAKING CHANGES.”(会有破坏兼容性的变更。)
核心插件和 API 还在快速迭代。首页原话:“DeepSeek Harness remains in developer preview and is still being tested by developers building agent harnesses.”(Harness 仍然处于开发者预览阶段,正在被全世界构建智能体套壳的开发者们测试。)
如果你在它上面做东西:pin 住 commit hash、写插件时尽量贴着 config catalog 保持薄、每个 rc 升级后重新回归测试。虽然插件自动清理和依赖注入让回归比整体式框架舒服很多,但「开发者预览」这话就是字面意思。
它到底不一样在哪
今天大多数 agent 框架是先写 turn loop,再把可扩展性当成事后 feature 钉上去。Harness 反过来:可扩展性本身就是框架,turn loop 只是另一个 plugin。可观察到的三个差异,别家一般凑不齐:
- 不用 fork 就能换任何东西。 看不惯内置工具系统?换一个。想换 LLM 路由层?换 provider。全部走 Cordis service key 解析。
- 可追踪性是默认的。 只追加日志不是外加的可观测性,而是会话本身的工作方式。resume / fork / search / replay 都在同一条流上。
- 可组合的 preset,不是 feature flag。 四种模式(Standard / Code / Minimal / Creator)本质上就是一组有序的插件-bundle patch 层。你可以用 YAML 在上面叠自己的 preset,不用写代码。
这套方式能不能赢过整体式 SDK,要看插件生态能不能产出足够多的第三方工具和提供方,让「替换 / 重组」的故事真正成立。发布当天 1.6k star、1.2 万提交——势头是明确的。