DeepSeek Harness 深度架构全解析_deepseek harness 解析-CSDN博客
本文对 DeepSeek Harness(以下简称 DSH)进行全面的技术架构剖析,全文由Claude Code + GLM-5.2撰写后小范围调整。文中将从"如何让 Agent 框架的每个部分都可替换"这个最核心的设计问题出发,逐步展开其插件系统、Agent 生命周期、工具执行管线、LLM 抽象、会话模型、双端架构和构建体系。旨在提供一份学习DSH的阅读指南,适合对 AI Agent 框架设计感兴趣的中高级开发者阅读。
DeepSeek Harness 于 昨天(2026年8月13日) 正式发布并开源。具体发布情况如下:
- 发布版本:v0.1 开发者预览版(本文基于v0.1.0-rc.5),面向全球开发者开放测试。
- 开源协议:采用 MIT 协议在 GitHub 平台全量开放源代码。
注:部分媒体和报道在8月14日对其进行了跟进报道或称其为“8月14日发布”,这主要是因为该框架在13日晚间发布后,于14日迅速引发了广泛关注并登顶GitHub涨星榜,但官方实际的开源发布时间为8月13日。
一、Agent框架要解决什么问题
在构建 AI Agent 应用时,开发者通常面临几个核心挑战:
- 模型适配:不同的 LLM 提供商(DeepSeek、OpenAI、Anthropic)有不同的 API 和流式协议,如何统一?
- 工具扩展:如何让 Agent 安全地调用 Bash、读写文件、搜索网页,同时允许用户自定义工具?
- 上下文管理:对话越来越长,token 窗口有限,如何压缩历史而不丢失关键信息?
- 会话持久化:如何保存和恢复 Agent 的完整状态,包括多轮对话、工具调用结果?
- UI 集成:如何将 Agent 能力暴露给 Web 前端,同时保持前后端解耦?
DeepSeek Harness 的答案简洁而彻底:将所有功能都设计为可替换的插件,包括 Agent 循环本身。项目基于 Cordis 插件框架构建,代码完全开源(MIT)。
技术栈速览
| 维度 | 技术选型 |
|---|---|
| 语言 | TypeScript 6.0+,编译目标 ES2024 |
| 运行时 | Node.js ≥22.19 / ≥24.0 |
| 包管理 | pnpm 11.7 Workspace Monorepo |
| 构建 | tsc -b(项目引用增量编译)+ tsdown(Rolldown 打包)+ vite(Web 前端) |
| 前端 | React 18 + Vite 6 |
| 测试 | Vitest 4.x(单元 / Web / E2E / 快照 / 性能测试) |
| 代码检查 | Oxlint + ESLint |
| 文档站点 | VitePress |
| 通信协议 | 自研 Typert 类型化 RPC + JSON-RPC 2.0 |
二、项目结构:一个 Monorepo,两个编译面
DSH 使用 pnpm workspace 管理 50+ 个功能包,按领域分在 packages/<group>/<pkg>/ 下。整个项目在编译时被分为两个独立的 TypeScript 程序——Host(Node.js 后端) 和 Client(浏览器前端)——它们永远不会在同一个类型系统中相遇。
deepseek-harness/
├── vendor/ # 第三方源码(vendored),Cordis 框架核心
│ ├── cordis/ # 插件系统:Context, Service, Fiber, Events
│ ├── loader/ # 从 YAML 配置文件加载插件的运行时
│ └── ...
├── packages/
│ ├── core/ # 核心骨架——Agent、会话、工具、系统提示词
│ ├── host/ # Host 端:Web 服务器、API 代理、目录选择器
│ ├── client/ # Web UI 组件(30+ 个包)
│ ├── llm/ # LLM 抽象层:适配器注册 + 流式协议
│ ├── sdk/ # JSON-RPC 协议定义 + 服务端 + TypeScript 客户端
│ ├── shell/fs/terminal/ # 系统能力:Shell 执行、文件系统、终端
│ ├── skill/commands/ # 扩展机制:技能注册表、斜杠命令
│ ├── compaction/ # 上下文压缩(解决 token 窗口限制)
│ ├── subagent/workflow/ # 编排:子代理委派、工作流
│ ├── hooks/mcp/acp/ # 外部协议:Claude Code/Codex Hook、MCP、ACP
│ ├── sandbox/ # 沙箱策略(进程隔离、Windows ACL)
│ ├── typert/ # 类型化 RPC 系统(类型图生成 + 运行时注册表)
│ ├── session/ # 会话持久化(JSONL / SQLite 两种后端)
│ ├── interaction/ # 用户审批、权限、AskUserQuestion
│ ├── plan/todo/goal/ # 高级 Agent 行为:计划模式、待办、目标
│ ├── bundle/ # 分发包(base / headless / web-app)
│ ├── preset/ # Agent 预设配置
│ ├── boot/ # 应用启动引导
│ └── util/ # 零依赖工具库
├── apps/
│ ├── cli/ # `dsh` 命令行入口
│ └── web/ # Web 前端 Vite 入口
├── python/ # Python SDK + 运行时
├── native/ # C 原生模块
├── examples/ # 可运行的 Cordis 配置示例
└── docs/ + website/ # 架构文档 + VitePress 文档站点
三、Cordis 插件系统:“一切皆插件"的基础
Cordis 是 DSH 的插件框架,被完整 vendored 在 vendor/cordis/ 下。它解决的核心问题是:如何让几十个功能模块在不互相 import 的情况下协作,并且每个模块都能被独立替换?
3.1 服务定位:通过 Context 而不是 import
在传统架构中,模块 A 要使用模块 B 的功能,通常会直接 import B:
| |
这种方式的问题是:B 被替换时,A 的代码必须修改。Cordis 的做法是:所有模块将自身注册到一个共享的 Context 对象上,其他模块通过 Context 的属性访问它们。
| |
ctx 是一个 Proxy 对象,当你访问 ctx.tools 时,它实际上通过服务解析器查找名为 tools 的注册服务。inject 声明告诉 Cordis:“只有在这两个服务都可用时,才启动这个插件;如果任何一个服务被卸载,先停掉这个插件,等它重新可用后再启动。”
这意味着:加载顺序不需要手动编排。 你只需要声明依赖关系,Cordis 自动处理启动和卸载的时序。
3.2 插件的三种写法
Cordis 接受三种插件形态,选择哪种取决于你需要多复杂的生命周期管理:
| |
3.3 事件系统:四种分发模式满足不同场景
Cordis 的事件系统不是简单的 pub/sub。它提供了四种分发模式,每种对应不同的协作场景:
| 模式 | 行为 | 典型场景 |
|---|---|---|
emit | 同步触发所有监听器,不等待,不收集返回值 | 通知类事件:“某件事发生了” |
parallel | 并行触发所有监听器,等待全部完成 | 独立的后处理:“所有人都处理一下” |
serial | 按注册顺序依次触发,返回值传递给下一个 | 有序决策链:“依次审批” |
waterfall | 每个监听器可调用 next() 委托给下游,不调用则短路 | 中间件:“包装或拦截” |
Waterfall 是最重要的模式,它实现了"围绕中间件"语义。来看一个具体例子——工具执行前的审批:
| |
3.4 Fiber:每个插件的独立生命周期
每次调用 ctx.plugin() 都会创建一个 Fiber,它代表这个插件实例的完整生命周期。Fiber 最重要的特性是可撤销的副作用:
| |
所有通过 ctx.effect() 注册的副作用,在插件卸载时会按注册的逆序自动清理。这保证了即使插件在运行中被热替换,也不会留下资源泄漏。
3.5 从配置文件到运行中的插件树
DSH 的插件不是硬编码的,而是通过 YAML 配置文件声明:
| |
Loader 的加载过程:
- 解析 YAML 为 Entry 节点树
- 通过 Node.js 的动态
import()加载每个插件的模块 - 用插件声明的 schema 校验用户配置
- 调用
ctx.plugin()创建 Fiber 并启动 - 配置变更时,如果只改了 config 值,则热更新 Fiber 而不重建;如果改了模块名或依赖声明,则重建整个 Fiber
这种机制实现了配置即架构:修改一个 YAML 文件就能替换任何功能模块,无需重新编译。
四、Agent 的完整生命周期
4.1 两个核心概念:Step 和 Turn
在理解 Agent 循环之前,需要先厘清两个关键概念:
- Step:一次 LLM 请求 + 该请求触发的所有工具调用。例如,用户说"帮我创建一个文件”,Agent 可能调用
write_file工具——这是一次 LLM 请求 + 一个工具调用 = 一个 Step。 - Turn:一个完整的用户交互周期。一个 Turn 包含零个或多个 Step。当模型说"还需要更多信息"并调用工具时,Step 结束,但 Turn 继续;当模型给出最终回复且没有更多待处理的工作时,Turn 结束。
4.2 一次 Turn 的完整流程
下面是从用户发送消息到 Agent 完成回复的完整事件序列。我们将事件分为两类:带 session/event 前缀的是持久化事件(写入会话日志),带 agent/* 或 tools/* 前缀的是运行时事件(只在内存中传递,不持久化)。
用户发送消息 "帮我分析 app.ts"
│
▼
turn/start(持久化) ← 新 Turn 开始
│
├─ 从 inbox 中认领用户的输入消息
│
├─ agent/pre-step(waterfall) ← 运行时决策点
│ │ 插件可以在这里:
│ │ · 拒绝进入(turn 关闭,不消耗 step)
│ │ · 改写消息内容
│ │ · 注入额外上下文
│ │
│ └─ 进入 →
│
├─ step/start(持久化) ← 新 Step 开始
│ │
│ ├─ user/message(持久化) ← 记录用户消息
│ │
│ ├─ 从会话日志派生模型历史 ← 将持久化事件转为 LLM 消息格式
│ │
│ ├─ 组装系统提示词 + 工具 schema ← 注入当前可用的工具列表
│ │
│ ├─ agent/request(waterfall) ← 发送前最后修改机会
│ │ └─ llm/stream(waterfall) ← 流式 LLM 调用
│ │ ├─ assistant/chunk(持久化)← 每个流式块
│ │ ├─ assistant/chunk
│ │ └─ assistant/message(持久化)← 完整回复
│ │
│ ├─ 模型决定调用工具
│ │ │
│ │ ├─ tool/call(持久化) ← 记录工具调用
│ │ ├─ tools/pre-execute(waterfall) ← 允许/拒绝/询问
│ │ ├─ tools/execute(waterfall) ← 实际执行(可被超时/重试包装)
│ │ ├─ tools/post-execute(waterfall)← 检查/替换/丰富结果
│ │ └─ tool/result(持久化) ← 记录工具结果
│ │
│ └─ step/end(持久化)
│ │
│ ├─ 工具调用指示需要继续?→ 回到 step/start
│ └─ 模型给出最终回复 → 进入 turn 结束流程
│
├─ agent/turn-stopping(serial) ← 最终检查点
│
└─ turn/end(持久化) ← Turn 结束
4.3 Agent 接口
ReactLoopAgent(位于 packages/core/agent-loop/src/agent.ts)是 Agent 接口的具体实现。它暴露了以下编程接口:
| |
几个值得注意的设计:
- 双目标 Inbox:消息被路由到
next-turn或next-step两个队列。next-turn的消息在新 Turn 开始时认领,next-step的消息在当前 Step 结束后立即认领。这允许插件在不同时机注入不同优先级的上下文。 - 独立的子 Context:每个 Agent 拥有自己的子 Context,意味着可以为不同会话注册不同的工具集、不同的审批策略,互不干扰。
- AbortController 三合一:取消信号来自三个可能的来源——用户主动取消、插件被卸载、Agent 工厂被销毁。Agent 实现将这三个信号融合为一个统一的 AbortController。
五、工具执行管线:每一层都可以拦截
工具系统是 DSH 最精密的设计之一。每个 工具调用 不是简单地"执行然后返回结果",而是经过一个四阶段管线,每个阶段都是一个可以被插件拦截的 waterfall 事件:
tool/call 被记录
│
▼
tools/pre-execute(waterfall)
插件可以在这里决定:允许、拒绝、或弹出用户审批对话框
如果拒绝,整个调用在此终止,记录一个拒绝结果
│
▼
tools/execute(waterfall)
实际执行工具。插件可以在这里包装超时控制、重试逻辑、性能指标收集
执行环境与调用者的身份和权限绑定
│
▼
tools/post-execute(waterfall)
执行完成后。插件可以检查结果、替换内容、丰富元数据、或阻止敏感信息返回
│
▼
tools/result(emit)
最终结果冻结。这是纯通知事件,监听器不能修改结果
│
▼
tool/result 被持久化
并行工具调用的调度策略
当 LLM 一次返回多个工具调用时,DSH 的调度器会分析每个调用的执行模式:
- 独占调用:形成屏障,所有其他调用必须等待。例如,
write_file和read_file对同一文件操作时必须串行。 - 并行调用:使用有界滚动池(大小由
maxParallelToolCalls配置控制),允许同时执行。
关键约束是:结果必须按模型返回的顺序最终化,不能因为并行执行而打乱顺序。这保证了重放时的一致性——如果因取消而跳过了某个调用,调度器会记录一个合成的错误结果,而不是留下一个空洞。
Code Mode:在沙箱中执行代码
DSH 支持一种特殊的"代码模式":当 Agent 选择使用 run_code 工具时,它会提交一段代码(TypeScript 或 Python),这段代码在沙箱中执行,并且代码内部可以访问所有其他工具。换句话说,run_code 是唯一直接暴露给模型调用的工具,文件读写、Shell 执行等能力都通过 ctx.codeRuntime 从程序内部访问。
六、LLM 抽象层:一套流式协议适配所有模型
6.1 适配器模式
DSH 将所有 LLM 提供商的差异封装在 LlmAdapter 抽象类之后:
| |
注册适配器是全或无的操作:如果尝试注册一个已有提供商的适配器,会直接抛出错误。这种设计防止了"哪个适配器在生效"的歧义。适配器的生命周期与注册它的 Fiber 绑定,Fiber 卸载时适配器自动注销。
6.2 统一的流式协议
DSH 定义了一套与提供商无关的流式块类型系统。无论底层是 DeepSeek、 OpenAI 还是 Anthropic 的 API,最终都转换为这种统一格式:
| |
每个内容块有独立的 index,支持多模态输出(例如同时生成文本和工具调用)。reasoning-delta 类型专门用于承载模型的推理过程(如 DeepSeek-R1 的思维链)。
6.3 流式调用的拦截
每个 LLM 调用都流经 llm/stream waterfall 事件。这意味着你可以在不修改适配器代码的情况下插入中间件:
| |
prepareCall() 方法在适配器注册状态下"锁定"一次调用,返回 PreparedLlmCall 句柄。这防止了在热更新(HMR)期间,一次调用的不同阶段使用不同版本的适配器。
七、双端架构:Host 与 Client 的彻底分离
7.1 为什么需要分离
DSH 的 Host 端运行在 Node.js 中,拥有文件系统、子进程、网络等完整能力;Client 端运行在浏览器中,只负责渲染 UI 和转发用户输入。两者通过 WebSocket 通信。这种分离意味着:
- Host 端可以访问敏感资源,Client 端不能
- 可以在不重启 Host 的情况下热更新前端
- 第三方可以通过 SDK 直接与 Host 通信,而不需要浏览器
7.2 编译时分离
两个 TypeScript 程序通过项目引用定义:
tsconfig.json → 解决方案文件,files: [],不包含任何源码
├── tsconfig.host.json → Host 端项目引用图
└── tsconfig.client.json → Client 端项目引用图
tsc -b tsconfig.host.json 和 tsc -b tsconfig.client.json 分别编译。这意味着 Host 端的类型(如 node:http、node:fs)永远不会泄漏到 Client 端,反之亦然。
7.3 运行时通信
┌────────────────────── Host (Node.js 进程) ──────────────────────┐
│ │
│ WebServer (ctx.webServer) │
│ ├─ HTTP API: /api/* 路由 │
│ ├─ WebSocket: 多路复用事件流 + Host 事件流 │
│ └─ 安全策略:DNS-rebinding 防护、特权接口仅限 loopback │
│ │
│ AgentLoop ──→ LLM ──→ Tools ──→ Session Log │
│ │ │
│ └── session/event ──→ WebSocket ──→ 推送到浏览器 │
│ │
└──────────────────────────────────────────────────────────────────┘
│ WebSocket / JSON-RPC
┌────────────────────── Client (浏览器) ───────────────────────────┐
│ │
│ ConnectionController │
│ ├─ 双流连接:mux(多路复用事件)+ host(Host 事件) │
│ ├─ 指数退避重连:500ms → 1s → 2s → ... → 10s(带随机抖动) │
│ └─ 严格就绪握手:describe() 单向可达 + onOpen 流建立 │
│ │
│ SessionRuntime ──→ ConversationView ──→ SlotRenderer │
│ │
└──────────────────────────────────────────────────────────────────┘
7.4 前端的两阶段启动
Web 前端启动时经历两个阶段:
- Module Face:解析 Host 注入的
window.__DSH_BOOT__清单,预加载 React、Cordis 核心和 UI 基础组件。这些是固定的、不会因配置而变化的模块。 - Plugin Face:挂载 Cordis Loader,为每个插件行创建 Entry 并启动。所有 Entry 启动完成后执行全量 Fiber 扫描——任何处于 PENDING 或 FAILED 状态的 Entry 都会导致启动失败,并在界面上展示详细的诊断信息(哪个插件、缺失哪个服务)。
Shell 组件(app-shell)是唯一内置的前端模块。它只做一件事:提供 React Slot 渲染器。整个 UI 布局树挂在 'root' slot 上——Shell 不参与任何 UI 组合决策,所有布局由 Host 端的插件 bundle 通过 Slot 注册来决定。
八、会话模型:事件溯源而非状态快照
8.1 核心设计
DSH 的会话不是"当前状态的快照",而是只追加的类型化事件日志。每一次用户消息、每一个 LLM 流式块、每一次工具调用和结果,都作为不可变事件追加到日志末尾。
这个设计有一个硬性约束:任何要发送给模型的内容,必须能从日志中重建。 运行时不变量会强制执行这一点——如果你试图向模型发送日志中没有记录的内容,系统会抛出错误。
| |
事件溯源带来的直接好处:
- Fork 会话:从任意事件序号切出一个子会话,两个会话共享分叉前的历史
- 断点续传:应用重启后从日志恢复完整状态
- 审计:每个决策的前因后果都有完整记录
- 重放:Telemetry 和调试都可以通过重放日志实现
8.2 两种持久化后端
| 后端 | 格式 | 特点 |
|---|---|---|
| JSONL | 每会话一个追加文件 | Zstandard 压缩,每个帧可独立解码,崩溃恢复只需截断尾部 |
| SQLite | 每会话的行映射 | WAL 日志模式,原子追加事务,可通过 SQL 查询特定事件范围 |
两者共享 PersistenceCoordinator,它负责写批合并(可配置延迟,减少磁盘 I/O)、会话缓存(避免重复加载)和修订追踪。
九、Typert:跨进程的类型安全 RPC
9.1 问题:前后端分离后如何保证类型安全
当 Host 和 Client 是两个独立的 TypeScript 程序时,它们无法共享类型定义。DSH 的解决方案是 Typert——一个运行时类型注册表,在构建时从 Host 端代码中提取类型信息,生成反射 schema,然后在运行时供 Client 端查询。
9.2 工作原理
| |
typertKey(package, name) 生成全局唯一键(格式为 <package>#<name>),注册表负责解析和路由。构建时,tsdown 的 Typert 插件扫描 Host 编译产物,自动生成反射数据。
十、扩展机制:Skill、Command 与 Hook
10.1 Skill 技能系统
Skill 是 Agent 可动态加载的能力模块。每个 Skill 由一个 SkillProvider 提供:
| |
每个 Skill 有两个可见性标志:
modelInvocable:是否出现在模型的工具目录中(模型可以主动调用)userInvocable:是否出现在用户的命令目录中(用户可以通过/skill-name调用)
Skill 使用作用域分层机制:全局注册 + 每个 Agent 作用域可覆盖。同一层内,同名 Skill 先注册的生效;不同层之间,更近的作用域优先。
Skill 的内容被渲染为规范的 XML 格式,传给模型:
| |
10.2 Command 命令系统
Command 是不经过模型的用户直接操作,通过斜杠命令触发(如 /clear、/compact):
| |
Command 的执行生命周期是:command/run(持久化,记录调用)→ handler 执行 → command/done(持久化,记录结果)。成功时可以通过 sourceEventSeq 指向一个领域事件,让前端做更丰富的展示。
10.3 Hook 系统
DSH 通过 Hook 系统与外部 Agent 工具( Claude Code、OpenAI Codex)集成。packages/hooks/ 下的包实现了与这些工具的桥接协议,允许 DSH 作为中间层统一管理多个 Agent 工具的会话、权限和资源。
十一、上下文压缩:在 Token 限制下保持对话连贯
11.1 为什么需要压缩
每次 LLM 调用都需要把历史对话作为上下文发送。随着对话增长,token 消耗线性增加,最终超出模型的上下文窗口限制。压缩的目标是:用一段简短的摘要替换早期的对话内容,在保持关键信息不丢失的前提下减少 token 消耗。
11.2 压缩策略
DSH 的 CompactionEngine(ctx.compaction)定义了压缩的抽象接口,BasicCompactionEngine 是默认实现。一次压缩的完整流程:
- 触发判断:通过
ctx.tokenMeter测量当前上下文压力。达到阈值(thresholdRatio)时触发压缩。 - 范围选择:
selectCompactableRange()从对话历史中选出一个"可压缩范围"。选择时会尊重工具调用配对——如果一对tool/call和tool/result被压缩,它们必须一起被压缩,否则模型会看到一个不完整的工具调用。 - 摘要生成:用一个专门的 LLM 调用(可以使用不同的模型,比如用更便宜的模型做摘要)生成压缩范围的摘要。
- 替换事务:用一个
user/message事件(携带摘要内容)替换选定的表面范围。压缩本身的事件(compaction/start、compaction/summary、compaction/end)只写入日志,不进入模型可见的表面。
这套机制支持两种所有权模式:
'current-turn':仅压缩当前 Turn 内的内容'whole-surface':压缩整个对话表面
十二、构建体系
12.1 构建流程
pnpm build
├── build:lib:host → tsc -b tsconfig.host.json # Host 端类型检查
│ → tsdown --env.DSH_BUILD_FACE host # Host 端打包 + Typert 类型生成
│
├── build:lib:client → tsc -b tsconfig.client.json # Client 端类型检查
│ → tsdown --env.DSH_BUILD_FACE client # Client 端打包
│
└── build:web → pnpm --filter @deepseek-ai/dsh-web-frontend run build
→ vite build # Web 前端 Vite 构建
tsdown 基于 Rolldown(Rust 编写的打包器,与 Rollup 兼容),通过 tsdown.config.ts 统一管理 workspace 级别的打包配置。typertPlugin 在 Host 面构建时运行,从 TypeScript 编译产物中提取类型信息并生成运行时反射 schema。
12.2 代码质量工具链
- Oxlint + ESLint:双轨 lint。Oxlint 处理快速检查,ESLint 处理 Stylistic 和 SonarJS 等需要 AST 分析的规则
- Lefthook:管理 Git hooks,确保提交前通过检查
- Knip:检测未使用的文件和依赖
- publint:在发布前验证每个包的
package.json配置
十三、SDK:将 Agent 能力嵌入你的应用
13.1 TypeScript SDK
| |
DeepSeekHarness 是高级 API,在内部管理一个 DSH 运行时子进程,跨多个会话复用。底层 HarnessClient 通过子进程的 stdio 进行 JSON-RPC 2.0 通信,包含完整的错误处理:传输层错误(TransportClosedError)、超时错误(RequestTimeoutError)和协议错误(SdkProtocolError)。
13.2 扩展点速查
当你需要扩展 DSH 时,以下是各场景对应的机制:
| 你想做什么 | 在哪里做 |
|---|---|
| 接入新的 LLM 提供商 | 实现 LlmAdapter,注册到 ctx.llm |
| 添加新的工具 | 定义 ToolDefinition,注册到 ctx.tools |
| 在工具执行前插入审批 | 监听 tools/pre-execute waterfall 事件 |
| 添加新的 Shell 后端 | 注册 ctx.shell 提供商 |
| 添加用户命令 | 注册到 ctx.commands |
| 添加文件系统策略 | 监听 fs/* 事件 |
| 拦截每次 LLM 请求 | 监听 agent/request 或 llm/stream waterfall 事件 |
| 添加前端聊天节点 | 注册 ConversationNodeDefinition + 渲染器 |
| 扩展会话事件类型 | 扩展 SessionEventMap 接口 |
| 添加新的持久化后端 | 实现 SessionPersistence 抽象类 |
十四、设计原则总结
回顾全文,DSH 的架构体现了几个鲜明的设计原则:
1. 一切皆可替换。 没有"特权核心"。Agent 循环、工具注册表、LLM 适配器、会话持久化——全部是插件,全部可以从 YAML 配置替换。文件系统和子进程提供商共享一个执行世界,将它们指向远程沙箱即可同时移动 Bash、PTY 和 LSP 的能力。
2. 声明式依赖。 插件通过 inject 声明自己需要什么服务,框架自动处理加载顺序和卸载。不存在"确保 X 在 Y 之前初始化"的样板代码。
3. 多阶段拦截。 工具执行管线(pre-execute → execute → post-execute → result)和 LLM 调用流(request → stream)都设计为多阶段 waterfall 事件链,每个阶段都可以被插件拦截、包装或重写。
4. 事件溯源。 所有会话状态来自可重放的只追加日志。Fork 会话、断点续传、审计和调试都是这一设计的自然结果。
5. 编译时分离。 Host 和 Client 是两个独立的 TypeScript 程序,通过 Typert 生成的反射 schema 在运行时保证类型安全,而不是通过共享类型文件。
本文基于 DeepSeek Harness v0.1.0-rc.5 源码分析,架构细节可能随版本迭代变化。
- 原文作者:知识铺
- 原文链接:https://index.zshipu.com/ai002/post/20260818/DeepSeek-Harness-%E6%B7%B1%E5%BA%A6%E6%9E%B6%E6%9E%84%E5%85%A8%E8%A7%A3%E6%9E%90_deepseek-harness-%E8%A7%A3%E6%9E%90-CSDN%E5%8D%9A%E5%AE%A2/
- 版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 4.0 国际许可协议进行许可,非商业转载请注明出处(作者,原文链接),商业转载请联系作者获得授权。
- 免责声明:本页面内容均来源于站内编辑发布,部分信息来源互联网,并不意味着本站赞同其观点或者证实其内容的真实性,如涉及版权等问题,请立即联系客服进行更改或删除,保证您的合法权益。转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。也可以邮件至 sblig@126.com

