ByteNoteByteNote
DeepSeek Harness 服务目录:核心与接缝全景
字

字节笔记本

2026年10月6日 · 约 8 分钟读完

DeepSeek Harness 服务目录:核心与接缝全景

API中转
¥120

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 内部构造的人来说,这相当于一份整机零件清单。本文把它整理成一篇导读:先看清三种角色,再走读几条代表性接缝,最后挑几个值得借鉴的设计细节。

DeepSeek Harness 服务目录全景:接缝三角色与 56 个服务的身份分布

先看全景: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.llmseamllm-deepseek、llm-pi-ai、llm-replayagent-loop、compaction-basic
ctx.shellseambash-local、bash-sandbox、pwsh-localtool-bash、tool-pwsh、钩子桥
ctx.subprocessseamsubprocess-local、subprocess-e2bbash、终端、LSP、子代理后端
ctx.sandboxseamsandbox-localbash-sandbox、terminal-bash
ctx.sessionPersistenceseamjsonl、sqlite 两款后端agent-loop、session-query 等
ctx.fsseamfs-local、fs-sandbox、fs-e2btool-fs
ctx.webseamexa、perplexity、deepseek 搜索与 http 抓取tool-web
ctx.subagentsseam进程内两种、acp、codex、claude-code、dsh-sdktool-subagent 等
ctx.jobsseamjobs-local后台 bash、终端、委派与 tool-jobs
ctx.credentialsseamcredentials-localllm 适配器与 apiproxy

走读:一次 bash 调用穿过四层

一次 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 提供读取、列出与终止的模型接口。

所有工具调用还共用同一条守卫管线:策略前处理、单调守卫、环绕分派、策略后处理、最终结果观测,五个阶段依次执行。

值得抄的五个细节

明细表的说明一列藏着不少可以直接搬走的设计:

  1. 凭据只存引用。ctx.credentials 的配置里携带的是对机密的引用,实际值由提供方保管,消费方按操作解析,轮换凭据后紧接着的下一次请求即生效;Web 网关只暴露不含实际值的视图和只写存储。
  2. 压缩不必惊动模型。ctx.toolResultPruner 在摘要压缩前,用可回放的单节点表层替换改写过大的工具结果,全程无模型参与;仍然过大的文本可经 ctx.spillStore 外置保存,只给模型留定位信息和取回提示。
  3. 列表读取不碰完整日志。ctx.sessionProjectionCache 按会话持久化投影检查点,读取走缓存行加持久化尾部回放的冷读取阶梯,会话列表因此永远不需要加载完整事件日志。
  4. 回放是一等公民。ctx.llm 的第三个实现 llm-replay 专供回放,配合 ctx.tokenMeter 按会话隔离的回放折叠区,压力消费方共享不可变且带修订版本的测量结果。
  5. 会话标题也有接缝。ctx.sessionTitle 负责确定性回退与最新标题折叠,是否用模型起标题、读首条还是全部提示词,交给两个可选的提供方包各自实现。

目录是怎么保鲜的

自动生成的文档最怕过时,这份目录的做法是混合维护:服务本身从 Cordis 声明中自动发现,接口、实现与消费方的角色分类写在 scripts/gen-doc-graphs.ts 里,并设有完整性守卫,图表与代码想漂移会被校验拦下。中文版按双语配对维护,英文更新后需运行配对校验重新登记。文档的准确性不靠自觉,靠流水线。

怎么用这份目录

想替换 dsh 的某个默认行为,先在这张表里查 ctx 键:看它是不是 seam,有哪些实现,消费方是谁,再决定是写一个实现包,还是挂一条事件。想读懂一个工业级 agent harness 的分层方式,这份 56 行的零件清单和它背后的依赖图,是公开资料里少见的完整标本。仓库以 MIT 协议托管在 github.com/deepseek-ai/deepseek-harness,可自行对照源码验证。

相关文章

分享: