
字节笔记本
2026年10月6日 · 约 8 分钟读完
DeepSeek Harness 服务目录:核心与接缝全景
DeepSeek 开源的 agent 框架 dsh(DeepSeek Harness,仓库 deepseek-ai/deepseek-harness)信奉一切皆插件,整个运行时构建在 Cordis 插件框架之上。它的 docs 目录里有一份不太一样的文档:capability-seams,标题是能力 Seams 与核心服务。这张覆盖全部服务的依赖图由脚本 gen-doc-graphs.ts 从代码里的 Cordis 服务声明自动生成,共画出 56 个 ctx 服务、130 个包和它们之间的 214 条依赖边,再配上一张逐服务明细表。对想研究 agent harness 内部构造的人来说,这相当于一份整机零件清单。本文把它整理成一篇导读:先看清三种角色,再走读几条代表性接缝,最后挑几个值得借鉴的设计细节。

先看全景:56 个服务,三种身份
统计明细表的角色一列,56 个服务分成三类:
- core(核心主干服务)29 个:不设替换概念的中枢,比如 ctx.sessions 拥有仅追加的 Session 实例与持久事件流,ctx.tools 拥有工具注册表与守卫执行管线。
- seam(可替换接缝)26 个:接口稳定、实现可换的能力位,比如 ctx.shell 背后站着 bash-local、bash-sandbox 和 pwsh-local 三种执行器。
- bundle(组合包与组合点)仅 1 个:ctx.agentLoop,文档明确说它是唯一的具体循环插件,扩展包应当依赖上层的事件与服务,而不是直接依赖这个包。
这个比例本身就说明了架构态度:过半服务是核心,负责把事实收拢到唯一所有者手里;其余做成接缝,把换成另一个实现变成组合期的一行配置。
一个接缝:声明、实现、消费方
文档给每个服务登记了所属包、实现包与直接消费方。以 ctx.shell 为例:shell 包声明接缝,bash-local、bash-sandbox、pwsh-local 三个包提供实现,tool-bash、tool-pwsh 和两款钩子桥负责消费。三个角色凑齐才算接缝;一个包可以兼任多个角色。
替换的价值在依赖图里看得最清楚。ctx.subprocess 是所有进程创建的统一入口:bash 执行器、PTY 终端、LSP 宿主,以及进程外的 ACP、Codex 和 Claude Code 子代理后端,全都从这条接缝 spawn。它的实现只有两个:subprocess-local 与 subprocess-e2b。挂上后者,文件系统与子进程就共享同一个远程 Linux 运行时,整条执行链一起搬进远程沙箱,上层消费方一行不改。
代表接缝速览:
| ctx 键 | 角色 | 实现 | 消费方 |
|---|---|---|---|
| ctx.llm | seam | llm-deepseek、llm-pi-ai、llm-replay | agent-loop、compaction-basic |
| ctx.shell | seam | bash-local、bash-sandbox、pwsh-local | tool-bash、tool-pwsh、钩子桥 |
| ctx.subprocess | seam | subprocess-local、subprocess-e2b | bash、终端、LSP、子代理后端 |
| ctx.sandbox | seam | sandbox-local | bash-sandbox、terminal-bash |
| ctx.sessionPersistence | seam | jsonl、sqlite 两款后端 | agent-loop、session-query 等 |
| ctx.fs | seam | fs-local、fs-sandbox、fs-e2b | tool-fs |
| ctx.web | seam | exa、perplexity、deepseek 搜索与 http 抓取 | tool-web |
| ctx.subagents | seam | 进程内两种、acp、codex、claude-code、dsh-sdk | tool-subagent 等 |
| ctx.jobs | seam | jobs-local | 后台 bash、终端、委派与 tool-jobs |
| ctx.credentials | seam | credentials-local | llm 适配器与 apiproxy |
走读:一次 bash 调用穿过四层

把工具链放大看,一次 bash 调用要穿过四层。tool-bash 提供面向模型的稳定名称;ctx.shell 选出执行器;执行器再经由 ctx.subprocess 创建进程,进程树、stdio 与终止升级都归它管;若走沙箱路径,ctx.sandbox 会拿到即将执行的确切 argv,按每次调用的策略包装后交还,并报告强制执行情况。
链路旁边还有三条侧线。权限决策走 ctx.approval,以 approval/request 瀑布事件分派一次性决策,没有回答方时直接以 unavailable 关闭失败。沙箱策略收拢在 ctx.sandboxPolicy 一处:部署默认模式与工作区根目录只有一份,bash 与文件系统两类强制执行组件读同一服务,从机制上杜绝限制到两个不同根目录的分叉。后台工作则统一登记进 ctx.jobs:后台 bash、PTY 发送和子代理委派都算正在运行的工作,tool-jobs 提供读取、列出与终止的模型接口。
所有工具调用还共用同一条守卫管线:策略前处理、单调守卫、环绕分派、策略后处理、最终结果观测,五个阶段依次执行。
值得抄的五个细节
明细表的说明一列藏着不少可以直接搬走的设计:
- 凭据只存引用。ctx.credentials 的配置里携带的是对机密的引用,实际值由提供方保管,消费方按操作解析,轮换凭据后紧接着的下一次请求即生效;Web 网关只暴露不含实际值的视图和只写存储。
- 压缩不必惊动模型。ctx.toolResultPruner 在摘要压缩前,用可回放的单节点表层替换改写过大的工具结果,全程无模型参与;仍然过大的文本可经 ctx.spillStore 外置保存,只给模型留定位信息和取回提示。
- 列表读取不碰完整日志。ctx.sessionProjectionCache 按会话持久化投影检查点,读取走缓存行加持久化尾部回放的冷读取阶梯,会话列表因此永远不需要加载完整事件日志。
- 回放是一等公民。ctx.llm 的第三个实现 llm-replay 专供回放,配合 ctx.tokenMeter 按会话隔离的回放折叠区,压力消费方共享不可变且带修订版本的测量结果。
- 会话标题也有接缝。ctx.sessionTitle 负责确定性回退与最新标题折叠,是否用模型起标题、读首条还是全部提示词,交给两个可选的提供方包各自实现。
目录是怎么保鲜的
自动生成的文档最怕过时,这份目录的做法是混合维护:服务本身从 Cordis 声明中自动发现,接口、实现与消费方的角色分类写在 scripts/gen-doc-graphs.ts 里,并设有完整性守卫,图表与代码想漂移会被校验拦下。中文版按双语配对维护,英文更新后需运行配对校验重新登记。文档的准确性不靠自觉,靠流水线。
怎么用这份目录
想替换 dsh 的某个默认行为,先在这张表里查 ctx 键:看它是不是 seam,有哪些实现,消费方是谁,再决定是写一个实现包,还是挂一条事件。想读懂一个工业级 agent harness 的分层方式,这份 56 行的零件清单和它背后的依赖图,是公开资料里少见的完整标本。仓库以 MIT 协议托管在 github.com/deepseek-ai/deepseek-harness,可自行对照源码验证。



