JOTO
Contact us
← AI 智库
大语言模型

DeepSeek Harness 的 Agent 运行时设计

2026 年 9 月 7 日

DeepSeek Harness 是一个面向长期运行 Agent 的可组合运行时,通过插件生命周期、追加式事件日志和能力接缝统一托管模型、工具、会话与外部协议。其核心设计包括:明确区分 SDK 与运行时边界;以插件为组成单位并支持动态卸载;通过 Profile/Patch 实现可复现的 Agent 配置;用 Turn/Step 划分可暂停、可追溯的执行单元;以 Session Event Log 作为模型上下文唯一事实来源;将能力接口、实现与安全策略解耦为三层 Capability Seam;Web/SDK/ACP 均为同一运行时的投影。

DeepSeek Harness 更像 Agent 运行时。它用插件生命周期、追加式事件日志和能力接缝统一托管模型、工具、会话与外部协议。

阅读时间:约 7 分钟

DeepSeek Harness 容易被误读成一个模型命令行工具:能发请求,能流式输出,能读写文件,能跑 shell。

顺着源码往下看,它关注的是一组运行时问题:

  • 长期运行的 Agent 如何使用真实工具
  • 用户如何中断或恢复任务
  • 历史节点如何分叉
  • 能力组合如何替换
  • 同一套执行语义如何投影到 Web、SDK 和外部协议

本文基于官方标签 dsh-v0.1.0-rc.7。这个版本仍是 Developer Preview,官方明确提示后续可能破坏兼容性。适合学习架构,不适合把内部类型直接当稳定 API 依赖。

DeepSeek Harness 架构概览图
DeepSeek Harness 架构概览图

先划清边界:SDK 只管请求,Harness 管运行时

模型 SDK 的职责相对窄:

Prompt -> HTTP Request -> Model -> Stream Chunks -> Response

Agent Harness 要覆盖的范围更大:

Input Queue -> Turn/Step Driver -> Prompt + Tools -> Model Stream
          -> Tool Execution -> Permission/Sandbox -> Session Log
          -> Continue/Stop/Fork/Resume -> UI/SDK/ACP

模型适配器只负责请求和流的归一化。Harness 还要管跨请求的不变量:

  • 工具调用和工具结果必须配对
  • 用户中途输入要进入正确的下一步
  • 取消请求要收敛到一致状态
  • 会话历史要能恢复和分叉
  • 文件系统、Shell、LSP 和终端必须落在同一个执行世界
  • 模型看见过的事实,之后要能从日志重建

这个边界决定了它不是普通 SDK。

官方根 package.json 把版本固定在 0.1.0-rc.7。Node.js 要求是 ^22.19.0 || >=24.0.0,包管理器是 pnpm@11.7.0

快速启动 Web 形态:

npx @deepseek-ai/dsh web

从源码运行:

git clone --branch dsh-v0.1.0-rc.7 \
 https://github.com/deepseek-ai/deepseek-harness.git
cd deepseek-harness
pnpm install
pnpm run build
pnpm dsh web

Web 和 Headless 启动的仍是同一套可组合运行时。区别在插件组合,不在核心执行语义。

插件是运行时的组成单位

DeepSeek Harness 用 Everything is a Plugin 描述运行时模型。

这里的 Plugin 是基础结构。模型适配器、Agent Loop、Session Store、工具注册表、持久化、审批策略和 Web Host 都由插件贡献。

核心主干可以按五个服务理解:

主干责任Cordis Context 键
core/session追加式会话事件日志与内存 Session Storectx.sessions
core/system-promptPrompt Section、动态上下文和工具 Schema 组装ctx.systemPrompt
core/tools有作用域的工具注册与受保护执行管线ctx.tools
core/agentAgent 接口、注册表、Inbox 与 agent/* 事件ctx.agents
core/agent-loop默认 Turn/Step 驱动器ctx.agentLoop

模型侧还有 llm/llm。它定义 Message、Content Block、StreamChunk 和 Adapter 接缝,通过 ctx.llm 暴露。

这几块组成一条主链:

DeepSeek Harness 主链结构图
DeepSeek Harness 主链结构图

Cordis 的关键点是生命周期。插件对 Context 的贡献必须能撤销。注册工具、监听事件、提供服务,都要通过 effect 或 disposer 表达。

教学伪代码如下:

export default function plugin(ctx: Context) {
  ctx.effect(() => {
    const disposeTool = ctx.tools.register(myTool);
    const disposeListener = ctx.on("agent/request", onRequest);

    return () => {
      disposeListener();
      disposeTool();
    };
  });
}

这带来几个结果:

  • Agent Loop 没有特权,可以替换
  • 工具和 Prompt Section 可以只对某个 Agent 生效
  • 配置热重载时,可以卸载受影响的插件子树
  • Provider 替换时,旧资源能按顺序清理

Fiber 状态机记录插件生命周期:

export const enum FiberState {
 PENDING,
 LOADING,
 ACTIVE,
 FAILED,
 DISPOSED,
 UNLOADING,
}

配置顺序不等于启动顺序。插件应该用 inject 声明依赖,不能假设某个 Provider 已经先执行。

Profile 和 Patch 决定一个 Agent 长什么样

DeepSeek Harness 不把 Web、Headless、工具集和权限策略写死在一个启动函数里。

运行中的 dsh 是多层配置叠出来的插件树:

概念作用
Profile用户选择的命名组合,声明要叠加哪些 Bundle
Bundle可分发的 Cordis 配置行和插件代码
Patch按稳定行 ID 替换或插入配置
Preset为某个 Session 选择 Agent 组合
Scope运行时隔离边界,让能力只对指定 Agent 可见

合并顺序如下:

empty tree
 -> base bundle
 -> web-app or headless bundle
 -> profile cordis.patch.yml
 -> home cordis.patch.yml
 -> --patch overlay
 -> effective plugin tree

调试真实运行行为时,应该先看最终配置:

dsh --profile web --dump-config

源码里的 Bundle 只是默认组合。用户机器上真正启动的树,还会受到本地插件、Profile Patch、Home Patch 和命令行 Patch 影响。

Patch 的覆盖粒度是稳定行 ID,目标行会整体替换。升级上游 Bundle 后,旧 Patch 还能解析,不代表新版安全默认仍然存在。

可复现部署至少要保存这些材料:

  • • Harness tag
  • • 依赖锁文件
  • • Profile manifest
  • • 全部 Patch
  • • Preset 文件
  • --dump-config 输出

Turn 和 Step 让一次对话可暂停、可继续、可追溯

Harness 对执行单位的定义很细。

Step 是一次模型请求,以及这次响应要求执行的工具。Turn 包含零到多个 Step,从第一批输入被领取开始,到没有待处理工作结束。

输入进入同一个 Inbox,但位置和唤醒语义不同:

followup(input); // 放入 next-turn,并唤醒
steer(input);    // 放入 next-step,并唤醒
inject(input);   // 放入 next-step,但不主动唤醒

主循环可以概括成:

private async kick(): Promise<void>

Turn 内部先准备请求:

  1. 1. 从 Inbox claim 输入
  2. 2. 组装 Prompt Section 和工具 Schema
  3. 3. 通过 agent/pre-step Waterfall 做准入判断
  4. 4. 写入 step/start

随后进入执行和收尾:

  1. 5. 记录用户消息、请求头、模型流、完整 assistant message
  2. 6. 执行工具并记录 tool call / result
  3. 7. 判断是否进入下一 Step
  4. 8. 写入 turn/end

被拒绝的输入也会留下记录。它会形成有 turn/startturn/end、但没有 Step 的持久 Turn。

这不是多余日志。它避免系统假装这次尝试从未发生。

rc.7 没有内建 Turn 步数上限。终止 Hook、Goal 和评价器必须自己限制轮次、token 或墙钟时间。

Session Event Log 是模型上下文的事实来源

DeepSeek Harness 有一条硬约束:Model-visible means logged

凡是进入模型请求的内容,都要能从 Session Log 重建。

核心事件包括:

interface SessionEventMap {
 "turn/start": { turn: number };
 "turn/end": { turn: number; reason: TurnEndReason };
 "step/start": { turn: number; step: number };
 "step/end": { turn: number; step: number };
 "user/message": UserMessage;
 "assistant/chunk": StreamChunk;
 "assistant/message": AssistantMessage;
 "tool/call": ToolCall;
 "tool/result": { message: ToolResultMessage };
}

模型历史不是直接维护一个可变的 messages[]。系统先追加事件,再通过 deriveMessages() 投影成模型可见历史。

这样可以同时服务三种视图:

视图读取内容
模型请求当前 Surface
人工 Transcript原始追加消息
Web 回放流式 Chunk

压缩也不会删除原始事件。普通 Surface 节点采用 Append,压缩会追加 Replacement 节点遮蔽连续范围。模型看见的是压缩后的当前表面,审计和回放仍能回到原始事件。

Fork 则复制指定边界之前的事件作为 seed,并在 Session Header 中记录父 Session 和 seedLength。

代价是迁移成本。当前预发布阶段 SESSION_FORMAT_VERSION = 0,官方不承诺兼容旧格式。开发者扩展模型可见输入时,需要同步更新事件、投影、TypeScript SDK、Python SDK 和快照输出。

Capability Seam 把能力、实现和安全策略拆开

Harness 没有把文件系统、Shell、Subprocess、Terminal、LSP、Web Search、Subagent 和 Workflow 写成一组互相直连的工具函数。

它把可替换能力拆成三层:

角色作用
Service Definition声明能力接口、请求类型和事件
Service Provider提供本地、沙箱、远程或第三方实现
Consumer把能力暴露给 Agent,通常是模型工具

以 Shell 为例,模型调用 bash tool 不代表 tool 直接 spawn()

更合理的路径是:

Tool Consumer -> Service Definition -> Provider
                  |                  |
             typed events      local / sandbox / remote

这样,Sandbox 插件可以包装命令参数,文件策略和审批事件可以在固定位置拦截,Provider 也可以从本地切到远程隔离环境。

这里有个重要一致性要求:Provider 必须处在同一个执行世界。

只把 Shell 放到远程环境,却让 FS Tool 继续读本地目录,模型会看到互相矛盾的文件视图。Terminal、LSP 和 Subprocess 也一样。

Tool Schema 只描述模型如何提出调用,不是安全策略。路径限制、命令包装、审批和外部副作用控制,必须落在 Tool Pipeline、Capability Event 或 Provider 层。

Web 按钮也不能作为唯一审批入口。Headless、SDK 和 Subagent 可能绕过页面,但仍会进入同一能力世界。

Web、SDK 和 ACP 都只是同一运行时的投影

Web 形态由 Host 和 Client 两个 TypeScript 编译聚合组成。

两侧都会通过 declaration merging 扩展 Cordis Context,但同名 key 可能指向不同服务。因此项目保留 tsconfig.host.jsontsconfig.client.json 两个 Program,避免把 Host-only 实现打进浏览器。

跨边界方法不靠手写 REST DTO。Host 服务用 @Remote@RemoteScope 标记可调用方法,Typert 在 Host 构建阶段分析类型图,生成给 Client 使用的类型声明和运行时描述。

链路可以简化为:

Host Service + @Remote
        -> Typert type graph
        -> generated declarations + runtime metadata
        -> API Gateway
        -> Client ctx.remote / agentCtx.remote

TypeScript SDK、Python SDK、JSON-RPC Server 和 ACP Server 也不另建 Agent Loop。

它们驱动 ctx.agents,订阅 session/event,把同一套会话和生命周期投影成外部协议。

跨 Worker 或网络后,进程内 Scope 身份会消失。外部调用必须携带明确的 Session 或 Agent 标识,并重新授权。ctx.agent 这种进程内上下文,不能当作跨网络凭据。

读源码要按因果链走

这个仓库包很多。按目录顺序读,很容易陷进 UI 组件、Provider 细节和测试辅助代码。

先读运行时主链:

  1. 1. docs/architecture.md
  2. 2. docs/cordis-primer.md
  3. 3. packages/core/agentpackages/core/agent-loop
  4. 4. packages/core/session
  5. 5. packages/core/system-promptpackages/core/tools

再追能力和外部投影:

  1. 6. packages/llm/llmpackages/llm/llm-deepseek
  2. 7. 选一个完整 Capability Seam,例如 fs 或 shell
  3. 8. session persistence、projection、query
  4. 9. api gateway、typert、client runtime
  5. 10. extensions、sdk、acp、hooks

每读完一层,用不变量检查理解是否站得住:

  • • 插件卸载后注册是否消失
  • • 两个 Preset 的工具是否串话
  • • 被拒绝输入是否留下零 Step Turn
  • • 模型请求能否从 Header 与 Surface 重建
  • • 工具崩溃后能否区分未开始和结果未知
  • • Host 重连是否只重建投影,而不重跑 Agent

收束

DeepSeek Harness 最值得学的,是四个架构判断:

  1. 1. 扩展性下沉成运行时本体
  2. 2. 追加日志统一模型上下文、UI 回放、持久化和恢复
  3. 3. Capability Seam 分离接口、实现和安全策略
  4. 4. Web、CLI、SDK、ACP 共享同一套 Agent 执行语义

风险也要放在同一张图里看。它仍处在 0.1.0-rc.7 Developer Preview 阶段,Session 格式和 SQLite Schema 都不承诺向后兼容。

插件能力越强,配置越能改写安全边界。FS、Shell、Sandbox 和 Approval Provider 组合错了,框架不会自动变安全。

研究这套系统,最有价值的收获是一组工程约束。

能力必须可撤销,模型可见内容必须可重建,工具世界必须一致。外部协议只能投影运行时,不能复制一套新语义。

JOTO 企业落地观察

  • 对企业部署意味着:运行时架构不再允许将工具调用、会话状态、权限控制等能力硬编码进业务逻辑。企业需建立插件治理流程,确保 FS/Shell 等高危能力的 Provider 实现始终处于同一执行世界,否则模型将获得不一致的系统视图,引发不可控行为。
  • 这类系统的取舍在于:追加式事件日志虽保障了模型上下文可重建与审计可追溯,但也使 Session 数据成为核心依赖项。企业若需长期运行 Agent,必须将 event log 的持久化、压缩、迁移与 schema 版本管理纳入基础设施方案,而非仅视为临时调试日志。
  • 对智能体工程而言,Turn/Step 的显式划分强制将‘用户意图’与‘模型决策’解耦。企业构建可中断、可恢复的生产级 Agent 时,不能再依赖隐式状态传递,而必须围绕 inbox、claim、steer 等原语设计任务调度与人机协同机制。
  • 对 AI 安全治理而言,Capability Seam 的三层分离(定义/实现/消费)将安全策略锚定在 Provider 和 Pipeline 层,而非工具 Schema。这意味着企业无法仅靠修改 LLM 提示词或工具描述来满足合规要求,必须在 Provider 注入审批钩子、沙箱封装与副作用拦截,且所有接入能力须统一经过该管道。

立即咨询 JOTO

JOTO 提供覆盖企业智能体规划与搭建、AI 平台私有化部署、RAG 知识工程、AI 安全治理、FDE 驻场共创及持续运营优化的全周期 AI 落地服务,帮助企业把验证中的 AI 能力转化为安全、可控、可持续迭代的生产力。 联系 JOTO 获取 AI 落地咨询

想把这些做法用到你的业务里?

留下你的场景和痛点,我们帮你判断从哪一步开始。

联系我们
Contact Us

Start your enterprise AI rollout

Tell us your industry, team, and current pain points. We'll get back to you within one business day to help you decide what to tackle first, what data to prepare, and which platform fits.

WeChat
Scan to add us for a 1:1 chat
JOTO WeChat consultation QR code

Tell us what you need

Once we receive your details, we'll be in touch within one business day.