核心服务地图
本教程共 32 篇 · 第 28 篇 · 更新于 2026-08-15 · 约 8 分钟阅读
本节目标:拿到一张能查的「服务地图」——哪些包提供哪些
ctx.*服务、去哪个文档查细节、以及一项能力到底怎么被替换。
上一章说「换一个 Provider 就换整个产品行为」。这一章把地图画出来:服务有哪些、谁拥有谁、去哪查、怎么换。看完你会知道 --dump-config 打出的树里每个名字大概管什么。
服务的三种形态
官方能力图把服务分成三类,先分清形态再看清单:
| 形态 | 含义 | 例子 |
|---|---|---|
| 核心主干(core) | 系统运转必需,通常不可替换 | ctx.sessions、ctx.tools |
| 能力缝(seam) | 可替换能力,有 Definition / Provider / Consumer 三角色 | ctx.fs、ctx.sandbox、ctx.llm |
| 组合包/组合点(bundle) | 具体实现或装配入口 | ctx.agentLoop |
一个包可以合并承担多个角色,但单一角色本身不是 seam。判断标准只有一个:这几个角色是否需要独立演进或替换。
核心包与 ctx 键清单
下表来自官方 capability-seams 参考,是「谁能换谁」的权威来源。先记住高频的:
| 包 | 职责 | ctx 键 | 形态 |
|---|---|---|---|
| core/session | 仅追加的会话事件日志与内存存储 | ctx.sessions | core |
| core/system-prompt | 提示词片段与工具 schema 组装 | ctx.systemPrompt | core |
| core/tools | 作用域化工具注册表 + 把关执行流水线 | ctx.tools | core |
| core/agent | Agent 接口、活跃 Agent 注册表、agent/* 事件 | ctx.agents | core |
| core/agent-loop | 唯一的默认循环驱动器 | ctx.agentLoop | bundle |
| core/scope | 按 Agent 划分作用域的注册原语 | 库,无键 | 库 |
| llm/llm | 消息/流式词汇 + 适配器缝 | ctx.llm | seam |
| attachment | 附件持久存储缝 | ctx.attachments | seam |
| sandbox | 进程沙箱缝 | ctx.sandbox | seam |
| approval | 一次性审批缝 | ctx.approval | seam |
| credentials | 凭据缝(配置只存引用,不存值) | ctx.credentials | seam |
| settings | 用户设置缝 | ctx.settings | seam |
| session-telemetry | 会话遥测缝(输出离开进程) | ctx.sessionTelemetry | seam |
| session-persistence | 会话持久化缝(JSONL / SQLite 后端) | ctx.sessionPersistence | seam |
| storage | 非会话存储枢纽缝(json / sqlite) | ctx.storage | seam |
| session-query | 会话读取、过滤、检索缝 | ctx.sessionQuery | seam |
| session-title | 会话标题缝 | ctx.sessionTitle | seam |
| token-meter | Token 回放计量 | ctx.tokenMeter | core |
| invariants | 运行时不变量注册表 | ctx.invariants | core |
| typert-registry | 运行时类型注册表 | ctx.typert | core |
| api-gateway | Typert Host 调用网关 | ctx.typertGateway | core |
| apiproxy | 与传输无关的 Host 网关接口 | ctx.apiProxy | core |
再往后还有一批缝值得眼熟:ctx.fs(文件系统)、ctx.shell(bash 执行)、ctx.subprocess(子进程)、ctx.terminals(PTY)、ctx.subagents(子 Agent)、ctx.compaction(上下文压缩)、ctx.skills(技能)、ctx.commands(人类命令)、ctx.goals(目标)、ctx.jobs(后台任务)、ctx.web(搜索/抓取)、ctx.permissionPresets(权限预设)、ctx.agentPresets(Agent 预设)、ctx.sessionProjections(会话投影)、ctx.codeRuntime(代码执行)。
Note第三方汇总里流传的
ctx.apiGateway写法,官方能力图中的对应键是ctx.typertGateway(api-gateway 包,Typert Host 调用网关);另一个易混的是ctx.apiProxy(apiproxy 包,Host 网关接口)。查文档以官方 capability-seams 表为准。
子系统参考怎么用
ctx 键只告诉你「服务在哪」,细节要去 subsystems/ 目录查。官方把每个子系统做成一页,回答三个问题:它是什么、它操作哪些数据结构、它由哪些服务/事件支撑。
| 你想查什么 | 去哪个页面 |
|---|---|
| 会话事件有哪些类型 | session.md |
| 工具定义完整字段 | tools.md |
| 消息与流式词汇 | llm-streaming.md |
| 沙箱/审批/权限预设 | sandbox.md / approval.md / permission-presets.md |
| 文件系统与凭据 | filesystem.md / credentials.md |
| 持久化与查询 | persistence.md / session-query.md |
| 遥测与 Token | session-telemetry.md / token-meter.md |
| 后台任务/子 Agent | jobs.md / subagent.md |
每页末尾通常有一段生成的 Cordis API 小节,承载该页的服务与事件参考。这些页面上的类型声明与源码等价,由 verify-type-equiv 门禁防止漂移——也就是说文档里抄的类型定义,不会悄悄落后于源码。
一项能力怎么被替换
审计任何一项能力,三步走:
- 契约由谁定义:找 Service Definition 包(接口与类型)。
- 当前装了哪个 Provider:看
dsh --profile web --dump-config配置树。 - Consumer 在哪个作用域激活:看工具注册与 preset 组合。
以 shell 为例,官方把三组件拆成独立包:shell(Definition,ctx.shell)、bash-local / bash-sandbox / pwsh-local(Provider)、tool-bash / tool-pwsh(Consumer)。想从本地执行换成沙箱执行,替换 Provider 即可,Consumer 和 Definition 都不用动。
# cordis.patch.yml:按 id 替换 bash 执行器的 Provider
# 先运行 dsh --profile web --dump-config 查实际条目 id 与配置字段,再照抄修改
- id: <bash 执行器条目的实际 id>
config:
# 换成沙箱后端;tool-bash 依旧通过 ctx.shell 调用
provider: '@deepseek-ai/dsh-bash-sandbox'
Note上面的 patch 是替换思路的示意,不是可直接照抄的成品:不同版本里 bash 执行器条目的 id 和字段名可能不同。动手前先
dsh --profile web --dump-config看本机实际条目,再按 id 替换。
文件系统与进程提供方共享同一个执行世界。把 ctx.fs 指向远程沙箱,Bash、PTY、LSP 会一起搬过去——因为它们的 Consumer 都只认接口,不认具体 Provider。这正是 seam 设计的威力。
核心主干为什么不能随便换
ctx.sessions、ctx.tools、ctx.invariants 这类 core 服务没有实现包——不是漏写,是故意的。它们是整个系统的地基:事件日志、工具注册、不变量检查如果被替换,其它所有插件的行为约定都会失去锚点。官方文档因此给它们标了 core 角色:可以扩展(比如往 ctx.tools 注册新工具),但不提供「换一个 Provider」的缝。反过来说,凡是标了 seam 的服务,就是官方认可的可替换边界,替换它是被支持的操作,不会破坏组合约定。
这也解释了为什么「选对形态」那么重要:自己写插件时,如果一项能力未来可能被替换(比如换个存储后端),就应该把它设计成 seam 的三角色结构,而不是把实现焊死在消费方里。
怎么读官方能力图
capability-seams 文档顶部的 mermaid 图是服务地图的源头。读图三步:先看服务节点(ctx.xxx 加一句英文职责说明),再看箭头方向——从实现包指向服务的箭头表示「这个包实现了它」,从服务指向消费方的箭头表示「谁在用」。一眼就能看出某个服务有没有多实现(说明它真的可换)、哪些包在直接消费它(替换前要评估的影响面)。
这张图由脚本 gen-doc-graphs.ts 从 Cordis 声明中生成,并设有完整性守卫:接口、实现和消费方角色分类不对时,门禁会失败。所以图不会过时,可以放心把它当权威地图。
新行为归属哪里
想加东西先查表,别自己发明位置。官方架构文档给出了一份完整映射,摘几条高频的:
| 目标 | 机制 |
|---|---|
| 添加模型提供方 | 在 ctx.llm 上注册适配器 |
| 添加面向模型的能力 | 在 ctx.tools 上注册,schema 自动进入提示词组装 |
| 添加 shell 执行 | 注册 ctx.shell 后端 |
| 添加文件系统访问或策略 | 注册 ctx.fs Provider,或监听 fs/* 事件 |
| 限制所启动的进程 | 使用 ctx.sandbox 后端,消费方启动前包装 argv |
| 拦截请求、工具或轮次 | 用 agent/* 或 tools/* 事件 |
| 生成会话标题 | 注册唯一的 ctx.sessionTitle Provider |
| 添加持久会话状态 | 扩展 SessionEventMap,从日志渲染和回放 |
Tip官方 capability-seams 页顶部有一张完整的服务图(mermaid),展示每个服务声明的包、已知实现包与直接消费方。它是「谁能换谁」的终极答案。维护模式是混合式:服务从 Cordis 声明中发现,接口/实现/消费方角色由脚本分类并设完整性守卫,图不会过时。
小结
服务分 core / seam / bundle 三形态;查细节去 subsystems/ 对应页面;换能力三步走(Definition → Provider → Consumer);加功能先查归属表。地图在手,--dump-config 的树就不再是黑盒。