Appearance
1.4 能力缝:可替换能力的三种角色
本章概览:DSH 宏观模块抽象的核心组织原则——capability seam(能力缝)。理解"一个可替换能力 = 定义 + 实现 + 消费方"三种角色,就掌握了 DSH 模块化的钥匙。
什么是能力缝
DSH 官方文档把 seam 定义为:
一个 seam 是一项可替换能力,包含三种角色:声明接口的 Service Definition、实现它的 Service Provider,以及使用它的 Consumer(通常是面向模型的工具)。一个包可以合并承担多个角色,但单一角色本身不是 seam;添加一项能力意味着把三者一并设计。
出处:
docs/architecture.md(deepseek-harness-src/docs/architecture.md)与docs/capability-seams.md
三种角色各司其职:
| 角色 | 职责 | 依赖限制 | 例子(shell 能力族) |
|---|---|---|---|
| Service Definition | 声明服务接口(服务方法 + 事件 + 词汇表) | 只依赖 cordis(+ 必要的基础类型) | dsh-shell:ctx.shell.exec(...) 契约 |
| Service Provider | 实现接口;可替换 | 实现 Definition 的接口 | dsh-bash-local、dsh-bash-sandbox、dsh-pwsh-local |
| Consumer | 消费接口,通常是面向模型的工具 | 通过服务方法而非 import 具体实现 | dsh-tool-bash(模型侧的 bash 工具) |
为什么"三者一体"设计
seam 的要点不是"有个接口",而是替换一个提供方就能改变整个产品:
- 文件系统与进程提供方共享同一个执行世界:把 fs/subprocess 提供方指向远程沙箱,Bash、PTY、LSP 就一并迁往远程,无需为每个能力写专用分支;
- subagent 提供方在同一个
ctx.subagents接口之后千差万别:从"新建一个进程内子代理"到"把一个轮次委派给另一个产品"(ACP / Claude Code / Codex 后端); - LLM 适配器注册到
ctx.llm,从 DeepSeek 换到任意 OpenAI 兼容端点,不改动 loop。
出处:
docs/architecture.md(deepseek-harness-src/docs/architecture.md)
Service Definition 的依赖纪律
DSH 对 Definition 有一条明确约束(capability-seams 文档的表格注释体现):Definition 只依赖 cordis(+ harness 错误基类),绝不依赖后端实现。例如:
dsh-sandbox定义ctx.sandbox.confine(argv, policy),依赖仅 cordis;- 例外被显式记录:
dsh-compaction的契约动词定义在Session与ContentBlock词汇上,必须依赖dsh-session与dsh-llm——该偏差在 compaction capability-seam Agent Note 中记录。
出处:
packages/compaction/compaction/README.md(deepseek-harness-src/packages/compaction/compaction/README.md)
seam 全景:50+ 个服务
docs/capability-seams.md(生成 + 维护模式)列出全部服务及其角色分类。以下是按角色观察的要点:
- seam 型服务(Definition/Provider 分离):
ctx.sessions持久化(JSONL/SQLite 后端)、ctx.settings(file 后端)、ctx.credentials(env/.env 后端)、ctx.shell、ctx.subprocess、ctx.terminals、ctx.sandbox、ctx.fs、ctx.compaction、ctx.subagents、ctx.jobs、ctx.web、ctx.spillStore、ctx.skills、ctx.llm、ctx.lsp、ctx.sessionQuery、ctx.sessionTitle、ctx.sessionTelemetry、ctx.directoryPicker、ctx.codeRuntime、ctx.approval、ctx.storage等; - core 型服务(单一实现,产品 API 脊柱):
ctx.sessions、ctx.systemPrompt、ctx.tools、ctx.agents、ctx.goals、ctx.commands、ctx.planMode、ctx.agentPresets、ctx.invariants、ctx.tokenMeter等; - bundle 型:
ctx.agentLoop是"唯一的具体 loop 插件"——官方明言"整个 harness 中只有这一个包包含具体 loop 逻辑,其他一切都是抽象服务或针对扩展点的插件"。
出处:
docs/capability-seams.md(deepseek-harness-src/docs/capability-seams.md)
选择器策略:Provider 的"能力"而非"工具"
seam 上往往有多个 Provider 并存(如 web 搜索有 Exa / Perplexity / DeepSeek 三个)。DSH 的选择策略有两个要点:
- Provider 注册"能力"(capabilities),不注册工具:模型侧工具名(如
web_search)归 Consumer(dsh-tool-web)独家所有; - 选择在执行时解析:显式配置 id(config 或环境变量)→ 未配置且恰好一个可用 provider → 自动选中;否则按歧义/缺失/不可用抛出结构化的
WebError码。available()是廉价本地检查(凭据存在性),不得发起网络调用。
出处:
packages/web/web/README.md(deepseek-harness-src/packages/web/web/README.md)
扩展点语义:新行为归属
官方架构文档给出了"新行为归属"映射(docs/architecture.md),其精神与 seam 一致:改变"能做什么"就注册提供方,改变"怎么做"就监听事件:
| 目标 | 机制 |
|---|---|
| 添加模型提供方 | 在 ctx.llm 注册适配器 |
| 添加面向模型的能力 | 在 ctx.tools 注册;schema 自动进提示词组装 |
| 让会话拥有不同能力集合 | 组装 agent preset |
| 添加 shell 执行 | 注册 ctx.shell 后端 |
| 限制所启动的进程 | 使用 ctx.sandbox 后端,消费方在 spawn 前包装 argv |
| 拦截请求/工具/轮次 | 相应 agent/* 或 tools/* 事件 |
小结
能力缝是 DSH 模块抽象的"母模式":定义、实现、消费三分离,让替换后端成为配置而非改码。后续 第三部分·系统架构 与 第四部分·模块精讲 的每一章,几乎都是"某个 seam 的三角色 + 内部策略"。
参考资料
- docs/capability-seams.md — 能力缝与核心服务全景(生成图 + 表格)(
deepseek-harness-src/docs/capability-seams.md) - docs/architecture.md — 能力 seam 与扩展归属(
deepseek-harness-src/docs/architecture.md) - packages/web/web/README.md — web seam 选择策略示例(
deepseek-harness-src/packages/web/web/README.md)