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.tools、ctx.llm、ctx.sessions | consumer 依赖稳定的 capability 名称,而不直接 import 某个具体实现。 |
| Plugin / Service | 插件是被挂载的功能单元;它可以向 context 提供稳定的 ctx.<key> service | 模型、工具、session、sandbox、Agent loop 都能成为可替换部件。 |
inject | 插件声明自己必须等待哪些 service 存在 | 依赖关系成为配置的一部分,而不是依赖手工安排启动顺序。 |
| Typed Event | service 通过 TypeScript 声明 event;按 emit、waterfall、parallel 或 serial 分派 | hook 的执行顺序、是否等待、是否可返回 / 截断成为公共契约;waterfall 还可实现包装或 short-circuit。 |
| Effect / Fiber | ctx.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 / patch | extension module、tool、command、hook、package |
| 生命周期 | Fiber 追踪依赖与 disposer;组件替换可触发 unload / reload | extension 可以订阅 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 overlaydsh-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 是一次模型请求及其产生的工具调用。具体过程如下:
- Driver 从 inbox 领取下一步输入和一条队列消息,打开
turn/start。 agent/pre-step可以接受、改写或拒绝本次输入;若接受,系统记录用户消息,组装 prompt 和当前可见的 tool schema。agent/request进入llm/stream,流式返回的 assistant chunks 和最终 assistant message 会进入 session log。- 工具调用先记录
tool/call,再经过策略和守卫;完成后记录一个对模型可见的tool/result。 - 若工具结果或 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/resultpre-execute、execute、post-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-only、workspace-write 和 danger-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 仍可能只有partialenforcement。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=FULL或FEEDBACK_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 install、pnpm run build 后执行 pnpm dsh web。Run 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 或受控远程执行设计。 |
资料与版本#
- DeepSeek Harness README(定位、Quick Start、Developer Preview)
- Architecture(Cordis、profiles、turn flow、session log、capability seams)
- Cordis primer(Context、inject、typed events 与 reversible effects)
- dsh vendor policy(锁定且可打补丁的 Cordis framework layer)
- dsh pi-ai adapter Pi project / extension docs
- Tool execution pipeline
- Sandbox subsystem
- CLI reference(plugins、MCP、telemetry)