DeepSeek Harness(dsh):插件化 Agent Harness 的产品形态与运行原理

This article is extracted from the chat log with AI. Please identify it with caution.

AI 参与说明(Agent:/root/root/cordis_pi_research/root/doc_update_audit):本文由 Agent 根据 DeepSeek Harness 公开仓库、架构文档、Cordis / Pi 源码与 CLI 安全边界文档协助整理。资料核验于 2026-08-21;本文源码基线为 528c682。dsh 官方明确标注为 Developer Preview,兼容性破坏性变更是预期行为;通过 npx 安装到的 npm 发行物不应被假定与本文锁定的仓库提交完全一致。

先说结论#

DeepSeek Harness(dsh 是 DeepSeek 开源的、以 Everything is a Plugin 为设计核心的 Agent Harness。它不是 DeepSeek 模型本体,不是托管 SaaS,也不只是一个 Coding CLI;它更像一个让开发者拼装模型、会话、工具、权限、沙箱、subagent 和宿主界面的本地 Agent runtime。

dsh web 所启动的 Web UI 只是其中一种产品入口。另有 headless profile、Python SDK 和可由其他程序驱动的 runtime。根据它们共享的 dsh-base、Agent loop 和 session 组件,可以合理地把它们理解为同一运行时的不同组装方式,而不是三套互不相干的 Agent 实现。

这也是它与 Cloudflare OS 必须分开讨论的原因:Cloudflare OS 是带身份、协作、应用实例和 capability security 的公司级工作区产品;dsh 的核心产物是一个可替换部件很多的 Agent runtime。两者都会“模型调用工具”,但部署边界、抽象层和安全责任明显不同。

1. 产品形态:本地 Agent runtime,而非单一聊天产品#

官方 README 将 dsh 定义为由 Cordis 驱动的开源 Agent Harness。它的核心用户是希望深度改变 Agent 行为的开发者和团队:不仅配置一个模型,还可以替换工具注册、持久化、文件系统、shell、审批策略和 UI。

入口作用运行边界
dsh web本地 Web UI,选择 workspace 后与 Agent 对话默认只监听 loopback;Agent 可在获准范围内操作该 workspace。
headless profile一次性或自动化运行不带 HTTP server,适合脚本/编排入口。
Python SDK将 dsh runtime 嵌入 Python 程序由宿主明确选择 profile、工具和权限组合。
plugin / bundle扩展模型、工具、MCP、subagent、workflow 或产品 UI插件代码和被调用的 MCP server 都是本机信任边界的一部分。

这与 Pi Coding Agent 入门与社区玩法 这类“开箱即可在终端完成编码任务”的工具有重叠,但 dsh 更强调构造 Agent 本身。若只需稳定、轻量的编码交互,dsh 的配置面和 Preview 风险可能超过收益;若需要把 Agent 做成自有产品、内部工作台或高度定制的自动化系统,它的拆分方式才更有价值。README

2. “Everything is a Plugin” 到底是什么意思#

dsh 启动后不是一个固定功能集合,而是一棵插件树。Cordis 插件向共享 context 贡献三类东西:service、类型化 event 和可撤销的 effect。模型 adapter、工具注册表、session log,乃至默认 Agent loop 本身都是插件;没有一个需要通过 fork 或打补丁才能改变的“特权内核”。Architecture: Cordis

2.1 Cordis 的概念、原理与设计哲学#

Cordis 在 dsh 中不是一个“插件列表”,而是负责组合、依赖与生命周期的框架层。dsh 把它 vendored 到仓库并重新作用域为 @deepseek-ai/cordis;这意味着本文不应把它等同于任意时刻 npm 上的最新 Cordis。其目的是让这层框架保持锁定、可审计和可打补丁。dsh vendor policy

概念在 dsh 中的含义解决的问题
Context一个 scoped service repository,例如 ctx.toolsctx.llmctx.sessionsconsumer 依赖稳定的 capability 名称,而不直接 import 某个具体实现。
Plugin / Service插件是被挂载的功能单元;它可以向 context 提供稳定的 ctx.<key> service模型、工具、session、sandbox、Agent loop 都能成为可替换部件。
inject插件声明自己必须等待哪些 service 存在依赖关系成为配置的一部分,而不是依赖手工安排启动顺序。
Typed Eventservice 通过 TypeScript 声明 event;按 emitwaterfallparallelserial 分派hook 的执行顺序、是否等待、是否可返回 / 截断成为公共契约;waterfall 还可实现包装或 short-circuit。
Effect / Fiberctx.effect()ctx.on() 等注册与所属 plugin 的 Fiber 生命周期绑定卸载或依赖变化时可以撤销 listener、tool registration、timer 等副作用,而不是遗留半失效资源。

这套设计可概括为四个原则:以声明的依赖代替启动顺序,以 service seam 代替具体 import,以类型化 event 代替隐式 hook,以可撤销 effect 代替永久副作用。Fiber 会协调 pending、loading、active、unloading / disposed 等状态;当 provider 出现、消失或替换时,相关插件可以重新计算和装卸。这正是 Cordis 所说的 temporal / spatial composability:组件不仅能在结构上拼装,也能在时间维度上被可靠替换与回收。Cordis primer Cordis composability paper

需要划清边界:Cordis 管的是组合和生命周期,不是 sandbox、权限审批或网络隔离。插件若绕开 ctx.effect() 自行创建 socket、watcher 或 timer,仍须把清理函数纳入 effect;否则框架无法自动回收它。

2.2 dsh、Cordis 与 Pi:不是“二选一”#

没有发现 DeepSeek 公开说明“因为 Pi 的某项缺陷,所以选择 Cordis”的决策记录。因此,“为什么选择 Cordis”以下是基于源码结构的架构推断,而不是官方选型声明。首先要澄清一个可证实的事实:dsh 没有把完整 Pi Coding Agent 或 pi-agent-core 作为自己的 runtime;在本文锁定的版本中,@deepseek-ai/dsh-llm-pi-ai 只依赖 @earendil-works/pi-ai,作为多 Provider 的 LLM adapter。它复用 provider catalog、wire protocol 与流式请求能力,而 Agent loop、session、tools、sandbox 和 profile 组合仍是 dsh + Cordis 的职责。dsh pi-ai adapter adapter dependencies

Cordis(dsh 的组合、依赖与生命周期框架)
  └─ dsh plugins(Agent loop、session、tools、sandbox、profile)
       └─ dsh-llm-pi-ai(可选 LLM adapter)
            └─ pi-ai(Provider catalog、协议与 streaming)

Pi 本身也不是单一抽象:pi-coding-agent 是面向终端用户的 Coding Agent,pi-agent-core 提供 Agent loop / state,而 pi-ai 是统一 Provider API。Pi 支持 TypeScript extension、tool、command、hook 和 package,因此“dsh 不使用完整 Pi”绝不等于 Pi 缺少扩展能力。Pi package overview Pi agent core Pi extensions

关注点Cordis 在 dsh 中的位置Pi 的重心
首要抽象可重组的 application component 与 capability可直接使用的 Coding Agent,以及围绕 Agent 的 runtime / extension API
扩展粒度service、typed event、reversible effect、profile / bundle / patchextension module、tool、command、hook、package
生命周期Fiber 追踪依赖与 disposer;组件替换可触发 unload / reloadextension 可以订阅 session lifecycle 并自行清理资源
dsh 的实际关系承担整套 runtime 的组合只在 pi-ai 层复用多模型传输能力

由此得到的合理推断是:dsh 要把模型 adapter、工具、持久化、sandbox、subagent、Web / headless 入口乃至 Agent loop 都重组成不同 profile,因此更需要 Cordis 的 service seam、依赖重算和可撤销 effect;与此同时,pi-ai 已经解决了跨 Provider 的协议和 catalog 适配,复用它可以避免重复维护那一层。这是一种分层复用:Cordis 解决“运行时怎么组合和演进”,Pi 解决“模型请求怎样跨 Provider 传输”,而不是两个项目在同一层争夺同一职责。

启动组合按以下顺序叠加:

profile 指定的 bundles
  → profile 自己的 cordis.patch.yml
  → Harness home 的 patch
  → 命令行 --patch overlay

dsh-base 是每个 profile 的基础层,提供模型 adapter、tools、持久化、sandbox / approval policy、settings、credentials 和 telemetry;dsh-web-app 在其上增加浏览器应用,dsh-headless 则增加无 HTTP server 的一次性运行器。一个后层 patch 可以按 id 替换配置条目或插入新条目,因此“默认行为”必须始终理解为当前 profile + 当前 patch 的结果,而不是某个包的单独默认值。Profiles and bundles

可以用下面的只读命令检查机器实际上会启动什么:

dsh --profile web --dump-config

预期输出是生效的配置树;它是排查“某个工具、模型或权限策略为什么不同于文档示例”的首要证据,而不是猜测默认配置。

3. 运行原理:SessionEvent 驱动的 model → tool → model 循环#

下面是 dsh 的纵向数据流。它浓缩自官方 turn flow;其中的持久事件和实时事件不能混为一谈。

flowchart TD
    entry["Web / Headless / Python SDK"] --> composition["Profile + bundles + patches"]
    composition --> loop["Agent loop"]
    loop --> inbox["Session inbox:领取本轮输入"]
    inbox --> prompt["组装 system prompt、tool schema、派生历史"]
    prompt --> llm["LLM adapter / streaming provider"]
    llm --> calls["Assistant message / tool calls"]
    calls --> pipeline["Tool pipeline:policy → guard → execute → result"]
    pipeline --> log["Append-only SessionEvent log"]
    log --> history["deriveMessages() 生成下次模型历史"]
    history --> loop
    pipeline --> capabilities["fs、shell、subagent、MCP、workflow 等 capability"]

一次 turn 可以包含零个或多个 step;一个 step 是一次模型请求及其产生的工具调用。具体过程如下:

  1. Driver 从 inbox 领取下一步输入和一条队列消息,打开 turn/start
  2. agent/pre-step 可以接受、改写或拒绝本次输入;若接受,系统记录用户消息,组装 prompt 和当前可见的 tool schema。
  3. agent/request 进入 llm/stream,流式返回的 assistant chunks 和最终 assistant message 会进入 session log。
  4. 工具调用先记录 tool/call,再经过策略和守卫;完成后记录一个对模型可见的 tool/result
  5. 若工具结果或 inbox 仍欠下一次模型请求,就开始下一 step;没有待办时关闭 turn/end

SessionEvent 日志是这里的关键:模型所见的 history 由日志派生,assistant/chunk 还保留 UI 和回放所需的流式细节。项目的规则是“模型可见即已记录”;fork、resume、transcript、telemetry 与 persistence 都从这份事件流派生,而不是另维护一份容易漂移的聊天历史。Turn flow and session log

默认 JSONL + Zstd persistence 会将 session 放在 $DSH_HOME/sessions。这提供了崩溃后恢复和可重放性,但也意味着 session 文件本身应被视作敏感本地数据:它可能包含任务输入、工具结果、路径或模型可见上下文。Session persistence

4. 工具不是直接执行:先经过可插拔的策略管线#

dsh 不把模型产生的 tool call 直接等同于 shell 命令。默认管线可以概括为:

tool/call
  → tools/pre-execute(hooks、approval、sandbox)
  → 不可绕过的 monotonic guards
  → tools/execute(timeout、retry、metrics 等包装)
  → tool body
  → tools/post-execute(接受、阻断、替换、补充 context)
  → finalizeContent + frozen tool/result

pre-executeexecutepost-execute 是可扩展的 waterfall;guard 只能拒绝或弃权,不能放宽已经注册的限制。工具结果在最终写入 session 前会被规范化为可回放的模型输入。这让 hook、审批、计时、结果改写等横切逻辑能作用于不同工具,而不要求每个工具都自己实现同一套安全控制。Tool execution pipeline

从扩展者角度看,真正重要的不是“dsh 内置多少 tools”,而是 service seam:文件系统、subprocess、sandbox、LSP、MCP、subagent、workflow 都有 provider 与 consumer 的分离。替换 filesystem / process provider,就能连带改变 Bash、PTY 和 LSP 运行在哪个执行世界;替换 LLM adapter,则改变模型路由而无需改 Agent loop。Capability seams

模型也不是写死为 DeepSeek。仓库包含直接的 DeepSeek adapter,以及可接多 provider / OpenAI-compatible endpoint 的 pi-ai adapter;实际可用模型、认证方式和 tool-calling 兼容性仍由选择的 adapter、route 与目标 provider 决定,不能泛化成“任何模型都同等支持”。Provider guide

5. 安全边界:有 sandbox,不等于可把任何内容当作安全#

最容易误读 dsh 的地方是“有 permissions / sandbox”这几个词。以官方 shipped base profile 为准,默认权限预设是 workspace-write + ask:可以在 workspace 写入,但需要审批。可选预设还包括 read-onlyworkspace-writedanger-full-access;后者会让 approval 变为 never,不应作为日常默认值。Base profile permission configuration

还需要同时记住以下边界:

  • sandbox 主要约束文件效果,不约束网络访问或进程可见性。 Linux 优先使用 bwrap,再考虑 Landlock;macOS 使用仍可用但已废弃的 sandbox-exec;Windows 使用 restricted-token ACL。缺少可用 runner 时应 fail closed,但 Windows ACL 和旧版 Landlock 仍可能只有 partial enforcement。Sandbox subsystem
  • 默认 Web UI 不应暴露到局域网。 dsh web 默认绑定 127.0.0.1:3080,shipped CLI 会拒绝 --host 0.0.0.0,因为那会把能执行 workspace 工具的控制面暴露到网络。通用 web-server 组件本身不提供 TLS、认证或 origin policy;若自行绕开该限制,必须由部署者另行提供网络层防护。Web app safety boundary Web server
  • 第三方 plugin 和 MCP server 是可信本机代码。 dsh plugin … add 会通过 pnpm 安装 tree 外 bundle;MCP client 虽被随附,默认不会启用任何 MCP server,因为每个 server command 都在 Agent sandbox 之外执行。审查它们的源码、依赖与权限,不能把它们套进 dsh 文件 sandbox 的安全承诺。CLI reference
  • telemetry 默认本地且关闭。 主动设置 DSH_TELEMETRY_MODE=FULLFEEDBACK_ONLY 后,OTLP 导出内容可能包含消息文本、tool arguments/results 和 workspace 路径;base 组合默认没有 telemetry redaction rule。启用前要先做数据分类和脱敏验证。Telemetry notes

Provider credential 也要按这个边界处理:UI 中的 API key 是 write-only,凭据存于 $DSH_HOME/.credentials.yaml,settings 只保存引用。为自定义 endpoint 配置认证时,优先使用 apiKeyEnv,不要在 route 的 headers 中明文硬编码 Authorization 等 secret。Provider credential guidance

6. 最小试用与选型建议#

下面是官方 quick start;本文未在本机执行该安装命令,运行时下载到的实际 npm 版本以当时 tag 为准:

# 前提:已安装 Node.js
npx @deepseek-ai/dsh web

预期是在本机启动 Web UI 并打开 http://127.0.0.1:3080。第一次试用应选择无敏感信息的 disposable workspace,保留默认 loopback 与 approval,不要急于添加第三方 plugin、MCP server 或 danger-full-access。从源码运行时,官方路径是 pnpm installpnpm run build 后执行 pnpm dsh webRun dsh

目标判断
构造可替换模型、工具、sandbox、subagent、工作流的自有 Agent 产品dsh 的 plugin tree、typed events 和 service seams 很适合深入定制。
只需要一个稳定的本地编码助手应先评估 Pi Coding Agent 入门与社区玩法 等更成品化的工具;dsh 的 Developer Preview 和配置面是实际成本。
把 local Web UI 直接发布给团队使用不适合仅改 host;必须另行解决 TLS、身份认证、网络隔离、共享 storage 与审计。
需要一个保证隔离所有网络和本机进程的执行沙箱dsh 的默认 sandbox 不足以单独承担该承诺;需要额外的容器、VM 或受控远程执行设计。

资料与版本#

本文共 6176 字,创建于 Aug 21, 2026

相关标签: Tools, AI, Agent, CLI, ByAI