【deepseek-harness】DeepSeek Harness (dsh) 系统级架构分析之一
DeepSeek Harness (dsh) 系统级架构分析
本文档对 DeepSeek Harness 项目进行系统级深度架构分析,覆盖整体架构设计、54 个包的模块拆解、跨模块调用关系与数据流,以及关键运行时流程。所有架构图均使用 Mermaid 语法绘制。
目录
第一部分:整体架构与设计哲学
1.1 项目定位与核心命题
DeepSeek Harness(以下简称 dsh)是一个插件化 AI Agent 运行时,构建于 Cordis 框架之上。其核心命题是:
一切皆插件(Everything is a Plugin)——包括模型适配器、工具注册表、会话日志、甚至 Agent 循环本身,都是可从配置替换的插件。
这意味着 dsh 没有特权核心需要打补丁:扩展 dsh 的方式是在其他插件旁挂载一个新插件,而注册是可逆效应,卸载时自动回滚。
1.2 Cordis 框架基础
dsh 的底层是 Cordis——一个基于 TypeScript 的插件化框架,核心概念包括:
| 概念 | 说明 |
|---|---|
| Context | 全局共享上下文对象,插件通过 ctx 注册和消费服务 |
| Fiber | 插件的生命周期单元,6 状态机:PENDING → LOADING → ACTIVE → FAILED → UNLOADING → DISPOSED |
| Service | 可调用、可隔离、可拦截、可追踪的服务单元 |
| Registry | 3 种插件形式:函数式 / 构造式 / 对象式 |
| Events | 5 种派发模式:emit / parallel / serial / bail / waterfall |
| Reflect | Proxy 代理服务,实现服务调用的透明拦截 |
Cordis 的注册是效应:卸载插件时,该插件的所有注册自动回滚,保证系统状态一致性。
1.3 插件化架构总览
dsh 的整体架构可分为四层,自底向上:
1.4 Profile 与 Bundle 分层组合系统
dsh 的启动过程是一个有序分层叠加过程:
| 概念 | 定义 | 存储位置 |
|---|---|---|
| Profile | 命名组合,存储在 Harness home,列出 Bundle 列表 + 持有树外插件 + 用户 cordis.patch.yml | ~/.dsh/profiles/ |
| Bundle | 分发格式,包含 Cordis 配置行和对应代码,声明于 package.json 的 dsh.bundle 字段 | 各 package |
| Patch | 通过 id 定位配置行,替换整行或插入新行 | YAML 文件 |
叠加顺序(从底到顶):
内置 Profile 模板:
- web:浏览器应用模式,包含 dsh-base + dsh-web-app
- headless:无服务器模式,包含 dsh-base + dsh-headless
1.5 三类服务模型:核心服务 / 能力接缝 / 组合点
dsh 的 ctx 上注册的服务分为三类:
| 类型 | 特征 | 示例 |
|---|---|---|
| 核心服务(Core) | 系统运行必需的基础设施,不可替换 | ctx.sessions、ctx.agents、ctx.systemPrompt、ctx.tools |
| 能力接缝(Seam) | 可替换的能力接口,三方角色:定义/实现/消费 | ctx.llm、ctx.shell、ctx.fs、ctx.subprocess、ctx.web |
| 组合点(Bundle) | 具体的实现插件,注册到某个接缝 | ctx.agentLoop(唯一的循环驱动器) |
能力接缝的三方角色模型:
1.6 事件系统三域
dsh 的事件分为三个域,每个域有不同的持久性和派发语义:
| 事件域 | 持久性 | 派发模式 | 用途 | 示例 |
|---|---|---|---|---|
| Session 事件 | 持久(追加到日志) | emit | 必须在重载后存活的事实 | turn/start、user/message、assistant/chunk、tool/call、tool/result |
| Agent 事件 | 实时(不持久化) | emit / waterfall / serial | 观察或拦截进行中的工作 | agent/pre-step、agent/request、agent/status、agent/turn-stopping |
| Capability 事件 | 实时 | waterfall / emit | 附加策略和适配器到接缝 | fs/write-intent、tools/pre-execute、llm/stream、approval/request |
Waterfall 事件的监听器必须调用 next() 来委托给下一个监听器;Serial 事件没有 next(),按顺序执行所有监听器。
1.7 Turn/Step 运行时生命周期
dsh 的核心运行时由两个概念驱动:
| 概念 | 定义 |
|---|---|
| Step | 一次模型请求 + 该请求调用的工具 |
| Turn | 零或多个 Step:从第一个输入被认领开始,到不再欠任何东西时关闭 |
完整生命周期序列图:
1.8 会话日志作为真理之源
会话日志是模型所见上下文的唯一来源:
Model-visible means logged. 任何到达模型请求的内容必须可从日志重建,运行时不变式会断言这一点。
关键设计决策:
deriveMessages()从日志投影模型历史- 原始
assistant/chunk事件保留回放和 UI 保真度 - Fork、resume、transcript、telemetry、persistence 全部从事件流派生
- 新的模型可见输入需要新的 Session 事件:扩展
SessionEventMap并从日志渲染
1.9 工具执行管线
工具执行管线是 dsh 最精密的子系统之一,在七个阶段中运行策略、钩子、沙箱、文件系统守卫、结果重写、最终观察和 UI 渲染:
1.10 包依赖层次结构
dsh 包含 54 个包,按依赖关系可分为五层:
第二部分:核心脊柱模块群
以下为 dsh 核心脊柱模块群的深度分析,涵盖 agent、agent-loop、session、system-prompt、scope、agent-default-model、agent-tool-presentation 七个模块。
目录
- core/agent — Agent 接口与注册表
- core/agent-loop — 默认 Agent 驱动器
- core/session — 会话事件日志
- core/system-prompt — 系统提示词组装
- core/scope — 作用域注册
- core/agent-default-model — 默认模型
- core/agent-tool-presentation — 工具展示
- 核心脊柱整体协作
1. core/agent — Agent 接口与注册表
路径: packages/core/agent/src/
核心作用: 定义 Agent 的公共接口、运行时类型、事件词汇表,并通过 AgentRegistry 服务管理进程内所有活跃 Agent 的生命周期注册表;同时承载 Inbox(待处理消息队列投影)、模型选择(ModelSelection)、事件分发(Dispatch)与已消费工作核算(ConsumedWork)等关键子能力。
1.1 模块内部架构
1.2 关键类/函数/方法表格
| 名称 | 类型 | 职责 |
|---|---|---|
AgentRegistry | class (Service) | 进程内 Agent 注册表;管理 Agent 的创建(委托给 AgentFactory)、注册、公告(announce)、查询、销毁;通过 AsyncLocalStorage 维护 initiator 驱动链 |
AgentFactory | interface | Agent 创建工厂接口,由 agent-loop 插件实现;定义 createAgent 和 resume 两个异步创建路径 |
AgentHandle | interface | 持有者获得的 Agent 句柄,包含 Agent 引用和 dispose() 销毁能力 |
Agent | interface | Agent 公共接口;包含 id、options、session、inbox、status、ctx,以及 cancel、whenIdle、runMaintenance、send、followup、steer、inject 等方法 |
Inbox | class | Agent 待处理消息的增量投影;从 session 事件日志重建,维护 next-turn 和 next-step 两个有序列表,支持 append/prepend/replace/remove/claim/clear 操作 |
agentEvents | function | 构建融合作用域载体的事件分发器;将 Agent 主体与 scope carrier 绑定,确保事件中的 agent 字段与 scope key 不可分离 |
agentCarrier | function | 为 Agent 构建无状态的作用域载体(Scoped<Agent>) |
assembleContextFor | function | 构建提示词组装上下文,将 agent 和 scope 同时设置,确保 agent 作用域的提示词/工具贡献不会被遗漏 |
installModelSelection | function | 将可变模型选择绑定到 Agent 作用域的提示词组装和请求路由;在组装时快照当前选择,在请求时应用 provider/model/effort |
ModelSelection | interface | 完整的 provider、model 和可选 reasoningEffort 选择 |
ModelSelectionRef | interface | 可变选择引用,区分 current(下一步将用)和 assembled(当前步已组装) |
foldConsumedWork | function | 折叠 Agent 日志,核算已消费工作;返回最近结束的核算 turn 和是否有被取消而未运行的工作 |
AgentRegistry.register | method | 注册已构造的 Agent;发出 agent/created,在 fiber 销毁时发出 agent/disposed |
AgentRegistry.enter | method | 插入未公告的 Agent(高级原语,供工厂使用) |
AgentRegistry.announce | method | 公告已插入的 Agent,发出 agent/created 事件 |
AgentRegistry.create | method | 通过注册工厂创建并发布新 Agent |
AgentRegistry.resume | method | 通过注册工厂加载持久化会话并恢复 Agent |
AgentRegistry.withInitiator | method | 在指定 Agent 作为 initiator 的边界内执行操作 |
AgentRegistry.withoutInitiator | method | 在清除 initiator 的边界内执行操作(用于共享定时器/队列等) |
AgentRegistry.currentInitiator | method | 读取继承的 initiator Agent(可选) |
AgentRegistry.requireInitiator | method | 读取并要求 initiator 存在,否则抛错 |
1.3 与其他模块的调用关系
- → core/session:Agent 接口持有
Session引用;Inbox 从Session.events重建并使用Session.append记录持久化 splice 事件;AgentCancelCause、SessionId等类型从 session 模块导入 - → core/scope:通过
scopeTarget(agent, agent)构建 scope carrier,用于事件分发的作用域过滤;AgentRegistry 自身通过ctx.accessor('agent', ...)注册 DX 上下文访问器 - → core/system-prompt:
assembleContextFor构建传递给systemPrompt.assemble()的上下文;AssembleContext接口通过模块增强声明agent字段 - → core/agent-loop:AgentRegistry 不直接依赖 agent-loop,而是通过
AgentFactory接口反转依赖;agent-loop 在构造时调用ctx.agents.setFactory(this)注册自己 - → core/agent-default-model:
ModelSelection类型被 agent-default-model 模块导入并使用 - ← 被 agent-loop 调用:agent-loop 的
ReactLoopAgent实现Agent接口,使用agentEvents、Inbox、assembleContextFor等 - ← 被 ACP bridge 等消费者调用:通过
ctx.agents.create()/ctx.agents.resume()创建 Agent
2. core/agent-loop — 默认 Agent 驱动器
路径: packages/core/agent-loop/src/
核心作用: 实现 AgentFactory 接口,提供 ReactLoopAgent 作为默认的 Agent 驱动器;负责 Agent 的创建/恢复事务(prepare → setup → publish → drive)、Turn/Step 两级驱动循环、工具调用调度,以及配置驱动的声明式 Agent 启动。
2.1 模块内部架构
2.2 关键类/函数/方法表格
| 名称 | 类型 | 职责 |
|---|---|---|
AgentLoop | class (Service) | 插件主服务;实现 AgentFactory,管理配置驱动的 Agent 启动、prepare 事务、settings 集成(maxParallelToolCalls) |
ReactLoopAgent | class | 默认 Agent 驱动器实现;实现 Agent 接口,驱动 Turn/Step 两级循环,管理 idle/maintenance/running 三相状态机 |
FactoryOwnership | class | 工厂级生命周期追踪;追踪活跃 Agent 的 teardown、配置启动任务和公共 create/resume 延续;通过 AbortController 融合三种销毁源(调用者取消、owner fiber 卸载、工厂 teardown) |
RuntimeContextProjection | class | 运行时上下文投影;追踪上次保留的 runtime-context 快照,仅在值变化时生成新的 UserMessage |
executeToolCalls | function | 调度一个 assistant step 的工具调用;排他调用形成屏障,并行调用使用有界滚动池;结果和上下文按模型顺序提交 |
runGroup | function | 运行一个排他屏障或并行池;在启动前重新分类后续调用;abort 时排干已启动调用并记录合成结果 |
PreparedAgent | interface | 已准备但未发布的 Agent 资源;包含 agent、signal、publish(source) 和 dispose() |
AgentLoop.prepare | method | 构建驱动器、作用域和记忆化反向 teardown;在发布前注册到工厂和 owner fiber |
AgentLoop.createAgent | method | 创建 owned Agent 的公共路径;prepare → setup → publish |
AgentLoop.resume | method | 从持久化恢复 Agent;加载持久化 → prepare → setup → publish |
AgentLoop.setupAndPublish | method | 在已获取的 Session 上准备 Agent、运行 setup、发布 |
ReactLoopAgent.kick | method | 驱动器入口;循环执行 turn() 直到无需继续 |
ReactLoopAgent.turn | method | 开启一个 turn;循环执行 preStep → step → turn-stopping 判定 |
ReactLoopAgent.step | method | 执行一个 step;构建请求 → 流式调用 LLM → 组装消息 → 执行工具调用 |
ReactLoopAgent.buildRequest | method | 组装冻结的请求配置并绑定到 adapter 注册;处理 request/header 的 initial/resume/change 三种原因 |
ReactLoopAgent.preStep | method | 步骤前处理;claim inbox 消息、组装提示词、投影运行时上下文、触发 agent/pre-step waterfall |
ReactLoopAgent.wakeDriver | method | 启动驱动器或锁存 wake;idle 时开启 turn 边界,running/maintenance 时锁存 |
ReactLoopAgent.send | method | 路由消息到 inbox 边界并可选唤醒驱动器 |
ReactLoopAgent.cancel | method | 清空 inbox(除非 keepInbox)并中止活跃 turn |
ReactLoopAgent.runMaintenance | method | 在真实 idle 阶段运行非 turn 维护任务 |
2.3 与其他模块的调用关系
- → core/agent:实现
AgentFactory并通过ctx.agents.setFactory(this)注册;使用agentEvents、Inbox、assembleContextFor、emitAgentEvent;通过ctx.agents.enter/announce/register管理 Agent 生命周期 - → core/session:通过
ctx.sessions.prepare/enter/announce管理 Session 生命周期;使用SessionPreparation包装未发布的 Session;通过Session.append记录所有事件 - → core/system-prompt:在构造时注册
provider、model、cwd变量;在preStep中调用ctx.systemPrompt.assemble()组装提示词;使用renderPrompt、renderContextSections、joinContextSections - → core/scope:通过
createScope(loopCtx, this)创建 Agent 作用域;通过this.ctx = this.scope.ctx.extend({ agent: this })构建 Agent 作用域上下文 - → dsh-llm:通过
ctx.llm.stream(request)发起 LLM 请求;使用BlockAssembler组装流式响应;通过ctx.llm.prepareCall解析 adapter 默认值 - → dsh-tools:通过
ctx.tools.executionMode判断工具并发模式;通过ctx.tools[TOOL_RUNTIME_SCHEDULER]的prepare/dispatch/finalize/finish调度工具执行 - → dsh-session-persistence:在
resume路径中通过ctx.get('sessionPersistence')获取持久化服务 - → dsh-settings:通过
installSettingsSection注册agent-loopsettings 命名空间(maxParallelToolCalls)
3. core/session — 会话事件日志
路径: packages/core/session/src/
核心作用: 提供 Event-Sourced 的会话事件日志——一个只追加(append-only)的 SessionEvent 序列作为 Agent 交互的持久化真相来源;包含 Session 类(事件日志 + 派生消息历史)、SessionStore 服务(内存存储 + 生命周期管理)、Surface 层(有序消息表面)、请求头折叠、分块压缩存储编码、崩溃修复等子模块。
3.1 模块内部架构
3.2 关键类/函数/方法表格
| 名称 | 类型 | 职责 |
|---|---|---|
Session | class | Event-Sourced 会话;维护只追加事件日志、Surface 表面管理器、增量的请求头折叠和派生消息历史缓存;支持 create(新建)和 fromRestore(从持久化恢复)两种构造模式 |
SessionStore | class (Service) | 内存会话存储服务;管理 Session 的创建(create)、准备(prepare)、插入(enter)、公告(announce)、查询、fork 和 flush |
SessionPreparation | class (Disposable) | 未发布 Session 的所有权包装;确保在发布或回滚时释放提供者状态 |
SurfaceManager | class | 增量有序表面视图;管理 surface 节点序列和替换代数(replaceGeneration);验证下一个事件而不修改已提交状态 |
foldSurface | function | 纯函数完整表面折叠;重放事件日志,返回当前表面序列和替换历史 |
deriveEventMessage | function | 单节点投影规则;将一个 surface 事件投影为 LLM 消息或 null |
Session.append | method | 追加一个类型化事件到日志;同步通知观察者;验证 JSON 可序列化性和 surface 元数据 |
Session.deriveMessages | method | 从有序表面派生 LLM 消息历史;每个 surface 节点只投影一次,surface 重写时重建 |
Session.requestHeader | method | 增量折叠请求头事件,返回当前 EpochHeader |
Session.requestContext | method | 增量折叠 request/context 事件,返回当前路由元数据 |
SessionStore.prepare | method | 构建 Session 但不进入存储;验证 id/cwd,构造 Session 和 SessionHeader |
SessionStore.enter | method | 将 prepared Session 插入存储;安装发布钩子;返回 detach disposer |
SessionStore.announce | method | 发出 session/created 事件;与 enter 分离以支持回滚安全 |
SessionStore.fork | method | 从活跃源的稳定前缀创建子会话 |
SessionStore.flush | method | 派发 session/flush 持久化检查点 |
foldRequestHeader | function | 纯函数请求头折叠;从事件日志重建当前 EpochHeader |
canonicalHeader | function | 将 header 规范化为标准形式(空 system/tools 变为 absent) |
headerEquals | function | 规范头的字段级相等比较 |
packChunkRuns | function | 将连续的 delta chunk 事件打包为存储行;无损压缩(~56× 实测压缩比) |
decodeStorageRecord | function | 将存储行解码回原始事件 |
interruptedTurnClosers | function | 为崩溃中断的会话日志生成合成关闭事件;为未匹配的工具调用生成错误结果 |
KNOWN_SESSION_EVENT_TYPES | const | 本构建已知的事件类型集合;持久化读取路径拒绝未知类型(除非标记 ignorable) |
3.3 与其他模块的调用关系
- ← core/agent:Agent 接口持有
Session引用;Inbox 使用Session.append记录 inbox splice;AgentCancelCause、SessionId等类型从此模块导出 - ← core/agent-loop:agent-loop 通过
ctx.sessions.prepare/enter/announce管理 Session 生命周期;ReactLoopAgent通过Session.append记录所有 turn/step/chunk/message 事件 - → core/scope:SessionStore 使用
scopeTarget(session, scopeOf(ctx))和scopeOf构建 scope carrier - → dsh-llm:导入
Message、UserMessage、AssistantMessage、ToolResultMessage、LlmCallConfig、StreamChunk等类型;使用deepFreeze冻结事件数据 - ← dsh-session-persistence:持久化插件订阅
session/event和session/flush事件;使用packChunkRuns/decodeStorageRecord进行存储编解码 - ← 其他插件:通过
SessionEventMap的模块增强声明插件事件类型(如agent/inbox/spliced、compaction/*、todo/write等)
4. core/system-prompt — 系统提示词组装
路径: packages/core/system-prompt/src/
核心作用: 提供有序的系统提示词段落(Section)、动态上下文(Context)、工具 schema(Tools)和变量(Variable)的注册表服务;在每次模型调用前组装这些部分为完整的 PromptAssembly,经过 waterfall 中间件变换后输出。
4.1 模块内部架构
4.2 关键类/函数/方法表格
| 名称 | 类型 | 职责 |
|---|---|---|
SystemPrompt | class (Service) | 注册表服务;管理全局和作用域的段落、上下文、工具提供者和变量;在 assemble() 时合并所有层、排序、运行 waterfall |
PromptLayer | class (ScopeLayer) | 一个作用域层的全部注册;包含 sections、contexts、runtimeContextSuppressors、toolProviders、variables 五个表 |
PromptSection | interface | 命名段落注册项;包含 name、order、text(静态或函数)、可选 complete(声明为完整提示词) |
PromptContext | interface | 动态上下文注册项;包含 name、order、text(静态或函数) |
ToolProviderResult | interface | 工具提供者返回值;包含 schemas 和可选 knownNames |
PromptAssembly | interface | 组装结果;包含 sections、contexts、tools、variables 四个部分 |
AssembledSection | interface | 已解析的段落;name + 已解析但未插值的 text |
AssembledContext | interface | 已解析的上下文贡献 |
AssembleContext | interface | 组装上下文;包含可选 scope、signal,通过模块增强可携带 agent |
SystemPrompt.section | method | 注册有序段落;作用域段落阴影全局同名段落 |
SystemPrompt.context | method | 注册有序动态上下文 |
SystemPrompt.tools | method | 注册工具 schema 提供者 |
SystemPrompt.variable | method | 注册提示词变量 |
SystemPrompt.suppressRuntimeContext | method | 抑制调用作用域的所有动态运行时上下文贡献 |
SystemPrompt.assemble | method | 组装全局和作用域提供者的输出,应用排序和阴影规则,运行 waterfall,返回最终 PromptAssembly |
renderPrompt | function | 插值 {{variable}} 引用,丢弃空段落,用空行连接其余段落 |
renderContextSnapshot | function | 渲染完整动态上下文快照文本 |
renderContextSections | function | 渲染为命名贡献列表,用于归属展示 |
joinContextSections | function | 将已渲染的段落列表连接为快照文本 |
PERSONA_SECTION | const | 部署 persona 段落名(deployment:persona),order=0 |
TOOL_ORDER_REST | const | toolOrder 配置中的通配符标记(<unlisted-tools>) |
4.3 与其他模块的调用关系
- ← core/agent:
AssembleContext通过模块增强接受agent字段;dispatch.ts的assembleContextFor构建传入assemble()的上下文 - ← core/agent-loop:agent-loop 在构造时注册
provider、model、cwd三个变量;在preStep中调用ctx.systemPrompt.assemble();使用renderPrompt、renderContextSections、joinContextSections渲染组装结果 - → core/scope:使用
ScopedLayers管理全局和作用域层;使用scopeTarget(this, scope)构建 waterfall 的 scope carrier;通过scopeOf(ctx)确定注册的作用域 - ← core/agent/model-selection:
installModelSelection在system-prompt/assemblewaterfall 中注入模型选择变量 - ← 其他插件:工具插件通过
ctx.systemPrompt.tools()注册工具 schema;提示词插件通过ctx.systemPrompt.section()/.context()/.variable()注册贡献
5. core/scope — 作用域注册
路径: packages/core/scope/src/
核心作用: 提供作用域原语——通过 createScope 铸造一个标记了不透明身份的 Cordis 上下文,通过 scopeTarget 构建路由-only 事件载体;支持作用域父子链(parent binding)和作用域层叠继承(ScopedLayers),使 Agent 作用域的注册和事件分发能够精确过滤。
5.1 模块内部架构
5.2 关键类/函数/方法表格
| 名称 | 类型 | 职责 |
|---|---|---|
createScope | function | 在 ctx 下铸造一个作用域;通过 ctx.plugin(scope) 创建 backing fiber,通过 ctx.extend({ [kScope]: key }) 标记上下文;返回 Scope(ctx + rawDispose + dispose) |
scopeTarget | function | 构建路由-only 事件载体;保留 base 的 Cordis filter,接纳未标记监听器和匹配 key 及其祖先的标记监听器;事件沿作用域链向上流动 |
scopeOf | function | 读取上下文继承的最近 scope tag |
bindScopeParent | function | 绑定子作用域的父作用域;返回 ScopeParentBinding(唯一可重链接的句柄);环检测 |
scopeParentOf | function | 读取一个 key 的父作用域 |
scopeChainOf | function | 返回从 key 到根祖先的链(nearest-first) |
Scope | interface | 铸造的作用域;包含 ctx(注册上下文)、rawDispose(精确 Cordis disposer)、dispose()(共享销毁) |
ScopeKey | type | 不透明的、身份比较的作用域 key(object) |
Scoped<T> | type | 路由-only 事件接收器;类型参数记录主体类型 |
ScopedLayers<L> | class | 管理全局和作用域层;提供 peek(精确层)、chainLayers(链层)、merge(合并命名条目)、effect(注册+效果所有权) |
NamedEntries<V> | class | 插入有序的命名条目表;重复名抛错;返回幂等 undo |
AnonymousEntries<V> | class | 插入有序的匿名条目表;独立注册身份;返回幂等 undo |
isScopeCarrier | function | 测试值是否为 scope 载体 |
carrierKeyOf | function | 读取载体的路由 key |
5.3 与其他模块的调用关系
- ← core/agent:
AgentRegistry使用scopeTarget(agent, agent)构建 agent 事件分发的 carrier;agentCarrier直接使用此函数 - ← core/agent-loop:
ReactLoopAgent构造时调用createScope(loopCtx, this)创建 Agent 作用域;通过this.scope.ctx.extend({ agent: this })构建 Agent 上下文 - ← core/session:
SessionStore使用scopeTarget(session, scopeOf(ctx))和scopeOf(ctx)构建 session 事件的 scope carrier - ← core/system-prompt:
SystemPrompt使用ScopedLayers管理段落/上下文/工具/变量的全局和作用域层;使用scopeTarget(this, scope)构建 waterfall carrier;使用scopeOf(ctx)确定注册作用域 - → Cordis:基于
ctx.plugin()创建 backing fiber;使用ctx.extend()标记上下文;carrier 通过Context.filter实现事件过滤
6. core/agent-default-model — 默认模型
路径: packages/core/agent-default-model/src/
核心作用: 独立于 Host 或传输层管理 Agent 的默认模型选择(provider + model + 可选 reasoningEffort);通过 settings 服务支持运行时修改,为没有显式模型选择的 Agent 提供回退。
6.1 模块内部架构
6.2 关键类/函数/方法表格
| 名称 | 类型 | 职责 |
|---|---|---|
AgentDefaultModelConfig | class (Service) | 默认模型选择服务;持有可变 source 函数,通过 settings 实时读取;提供 currentSelection() 和 saveSelection() |
AgentDefaultModelSettings | interface | 存储和组合的默认模型设置;provider、model、可选 reasoningEffort |
Config | interface | 组合入口配置;provider、model(无 effort — 由 settings 提供) |
currentSelection | method | 读取当前默认模型选择;返回 ModelSelection |
saveSelection | method | 保存完整默认模型选择到 settings |
AGENT_DEFAULT_MODEL_SETTINGS_NAMESPACE | const | settings 命名空间(agent-default-model) |
AGENT_DEFAULT_MODEL_SETTINGS_SCHEMA | const | settings schema |
6.3 与其他模块的调用关系
- → core/agent:导入
ModelSelection类型;将选择投影为此类型 - → dsh-llm:使用
ReasoningEffortId品牌类型 - → dsh-settings:通过
installSettingsSection注册 settings 命名空间;通过ctx.get('settings')?.replace()保存选择 - ← 消费者:Agent 创建入口在没有显式
AgentOptions.provider/model时可读取ctx.agentDefaultModel.currentSelection()作为回退
7. core/agent-tool-presentation — 工具展示
路径: packages/core/agent-tool-presentation/src/
核心作用: Agent 预设层面的工具展示选择器;声明 Agent 的模型看到哪种形式的工具——native(原始 schema)、code(仅 run_code + 生成 SDK)或 both(两者皆有);一个组合一行声明,覆盖该预设下的所有 Agent。
7.1 模块内部架构
7.2 关键类/函数/方法表格
| 名称 | 类型 | 职责 |
|---|---|---|
apply | function (Cordis plugin) | 插件入口;根据 config.mode 调用 ctx.tools.presentAs();native 直接调用,code/both 等待 codeRuntime 服务后调用 |
Config | interface | 插件配置;mode: ToolPresentationMode(native | code | both),必填 |
name | const | Cordis 插件名(tool-presentation) |
inject | const | 依赖注入声明(['tools']);codeRuntime 不在列表中,按需等待 |
7.3 与其他模块的调用关系
- → dsh-tools:通过
ctx.tools.presentAs(mode)声明工具展示模式;导入ToolPresentationMode类型 - → dsh-code-runtime:在
code/both模式下通过ctx.inject(['codeRuntime'], ...)等待代码运行时服务 - ← dsh-agent-presets:由 Agent 预设组合加载;预设声明其工具展示模式
- ← core/agent-loop:间接通过
ctx.tools读取展示模式,影响工具 schema 的组装
8. 核心脊柱整体协作
8.1 协作链路总览
DeepSeek Harness 的核心脊柱由七个模块构成一个完整的 Agent 运行时骨架。从 Agent 创建到模型调用的完整链路如下:
- Agent 创建:
AgentLoop(agent-loop)作为AgentFactory通过ctx.agents.create()或配置驱动启动创建事务 - Session 准备:
SessionStore(session)通过prepare → enter → announce三步将 Session 插入存储 - 作用域铸造:
ReactLoopAgent通过createScope(scope)铸造 Agent 作用域上下文 - Setup 组合:在未发布状态下运行 setup 回调,通过 Agent 作用域上下文注册工具、提示词段落、变量等
- 发布:先公告 Session(
session/created),再公告 Agent(agent/created),最后发出agent/session-start - 驱动循环:
ReactLoopAgent.kick()启动 Turn/Step 两级循环 - 步骤执行:每个 Step 中:
- Inbox Claim:从
Inbox认领消息 - 提示词组装:调用
SystemPrompt.assemble()组装系统提示词(段落 + 上下文 + 工具 + 变量) - 运行时上下文投影:
RuntimeContextProjection判断是否需要更新动态上下文快照 - 请求构建:通过
agent/requestwaterfall 确定请求配置,记录request/header - LLM 调用:流式调用 LLM,逐 chunk 记录
assistant/chunk,完成后记录assistant/message - 工具调用:
executeToolCalls调度工具执行,记录tool/call+tool/result - Turn 停止判定:无工具调用且无 next-step 消息时触发
agent/turn-stopping
- Inbox Claim:从
- 销毁:
AgentHandle.dispose()或 owner fiber 卸载触发反向 teardown——停止驱动器 → 注销 Agent → 注销 Session → 解开作用域
8.2 完整协作序列图
8.3 关键设计模式总结
反转依赖与工厂委托
core/agent 定义 AgentFactory 接口但不实现它;core/agent-loop 实现该接口并通过 ctx.agents.setFactory(this) 注册。这使得消费者可以仅依赖 ctx.agents 而不需要直接依赖 dsh-agent-loop 包。
三阶段发布事务
Session 和 Agent 的发布都遵循 prepare → enter → announce 三阶段模式:
- prepare:构建对象但不插入存储
- enter:插入存储、安装钩子,但不公告
- announce:发出创建事件
这种分离确保了 setup 回调中的同步失败可以回滚(已 yield 的 disposer 在 throw 时被 Cordis 的 generator effect 自动销毁),而不会泄露部分配置的 Agent。
作用域继承与事件过滤
core/scope 实现了两个方向的继承:
- 向下继承(注册可见性):子作用域能看到祖先的注册(
ScopedLayers.chainLayers),SystemPrompt利用此机制让 Agent 作用域阴影全局段落 - 向上继承(事件分发):祖先的监听器能收到后代作用域的事件(
scopeTarget的 filter 逻辑),使得一个上层组合能观察其下所有 Agent 的事件
Event-Sourcing 与派生历史
core/session 的核心设计是 Event-Sourcing:所有交互以 SessionEvent 形式追加到不可变日志。LLM 消息历史不是存储的,而是通过 Surface 层从事件日志派生的。Surface 层维护一个有序的"消息产生事件"序列,支持 append(正常追加)和 replace(压缩替换)两种操作。这使得:
- 日志是完整的(包括 chunk、turn 边界等非消息事件)
- 消息历史是派生的(通过 Surface 投影)
- 压缩可以替换历史范围而不丢失原始日志
两级循环与三相状态机
ReactLoopAgent 使用 Turn/Step 两级循环和 idle/maintenance/running 三相状态机:
- Turn:一次完整的用户交互(从认领消息到 turn 结束)
- Step:一次模型调用 + 工具执行
- idle:无活跃驱动器
- maintenance:运行非 turn 维护任务
- running:活跃的 Turn/Step 驱动
wakeDriver 的锁存机制确保在 maintenance 或 aborted 活动期间的唤醒不会丢失,而是在收敛到 idle 时重放。
工具调用的有序调度
executeToolCalls 实现了精细的工具调用调度:
- 排他模式:形成屏障,必须单独执行
- 并行模式:有界滚动池,受
maxParallelToolCalls限制 - 模型顺序提交:无论执行顺序如何,结果按模型给出的顺序提交到会话日志
- abort 处理:中止时排干已启动调用,为未启动调用记录合成错误结果,保持重放有效性
崩溃恢复
interruptedTurnClosers 为崩溃中断的会话日志生成确定性合成事件:为未完成的工具调用生成错误结果,关闭打开的 step 和 turn。这使得恢复后的会话日志对 LLM 来说是有效的(没有悬挂的工具调用),同时保留了崩溃前的完整记录。
存储压缩
packChunkRuns 将连续的 delta chunk 事件打包为单个存储行,实测压缩比约 56×。编解码是确定性的——解码后的事件与原始事件完全一致。未知的事件形状原样存储,不丢失数据。
以上分析基于 DeepSeek Harness 项目源码,涵盖
core/agent、core/agent-loop、core/session、core/system-prompt、core/scope、core/agent-default-model、core/agent-tool-presentation七个核心脊柱模块的完整架构。
更多推荐


所有评论(0)