DeepSeek Harness 架构拆解:一个“一切皆插件“的 Agent Runtime

DeepSeek 开源了他们的 Agent Harness(dsh),这不是又一个 LangChain 翻版,而是一套从底座重新设计的插件化 Agent Runtime。本文拆解它最值得关注的 5 个架构决策。


一、它不是"又一个 Agent 框架"

市面上 Agent 框架的典型架构长这样:

框架核心(不可变)  ├── ModelClient(内置 OpenAI 适配器)  ├── ToolRegistry(内置工具注册)  ├── AgentLoop(内置 ReAct 循环)  └── 你的代码(调用框架 API)

核心是"上帝类",你的代码是外围。要改循环逻辑?继承重写。要换工具策略?包装代理。改多了就变成框架 fork。

DeepSeek Harness 走了另一条路:没有不可变的核心

dsh 启动  ├── 加载 profile(声明式配置)  │     ├── dsh-base bundle(基础插件层)  │     │     ├── agent-loop 插件      ← 循环是插件  │     │     ├── tools 插件           ← 工具系统是插件  │     │     ├── session 插件         ← 会话日志是插件  │     │     ├── llm 插件             ← 模型适配是插件  │     │     ├── sandbox 插件         ← 沙箱是插件  │     │     └── ...  │     ├── dsh-web-app bundle(Web UI 层)  │     └── cordis.patch.yml(你的覆盖)  └── 运行

agent-loop 本身是插件。这意味着你可以用一个完全不同的循环实现替换默认循环,不用 fork 任何代码,只在配置里换一行。


二、5 个独特设计

设计 1:Cordis —— 注册是可逆的副作用

大多数插件系统的"注册"是单向的:register(tool) 之后,工具就永远存在。卸载?没有这个概念。

dsh 底层的 Cordis 框架做了一个根本性的改变:注册是 effect(副作用),effect 有 disposer(清理器)

// 注册一个工具,返回清理函数const dispose = ctx.effect(() => {    ctx.tools.register(myTool);    return () => ctx.tools.unregister(myTool);  // 卸载时自动调用});// 热卸载插件时dispose();  // 所有注册自动回滚

这意味着:

  • 插件可以热加载:运行中加载一个新工具插件,立即可用
  • 插件可以热卸载:卸载时所有注册自动回滚,进行中的 Agent 不受影响
  • 插件可以热升级:先卸载旧版(注册回滚),再加载新版(重新注册)

你的 Agent 正在执行第 3 步,此时有人加载了一个新的搜索工具插件。Agent 在第 4 步就能看到这个新工具。不需要重启,不需要暂停。

设计 2:Session Log —— 事实的唯一来源

大多数 Agent 框架的"状态"是一个 mutable 对象:

// 典型做法class AgentState {    List<Message> messages;  // 不断追加    int currentStep;    Status status;}

dsh 把状态变成了 append-only 事件日志

turn/start          ← 一轮对话开始  user/message       ← 用户说了什么  step/start         ← 一步开始  assistant/chunk    ← 模型流式输出的一个片段  assistant/chunk  assistant/message   ← 模型完整回复  tool/call          ← 模型要调工具  tool/result        ← 工具执行结果  step/end  step/start         ← 下一步  ...turn/end

关键原则:Model-visible means logged(模型可见的必定被记录)。

任何到达模型请求的内容,都必须能从日志重建。这不是建议,是运行时断言——如果你往模型请求里塞了日志里没有的内容,直接报错。

这个设计带来 5 个能力:

能力说明
回放从日志重放整个对话,逐步查看状态变化
Fork复制一个会话到新分支,两个分支各自独立演进
Resume从日志断点恢复执行
审计谁、什么时候、做了什么,全有记录
可观测所有变化都是事件,监听事件就能看到一切

设计 3:Capability Seam —— 一个能力三个角色

这是 dsh 最精巧的设计模式。一个"能力"不是"一个接口 + 一个实现",而是三个角色:

Service Definition(声明接口)  "文件系统能做什么:读、写、编辑"Service Provider(实现接口)  "本地文件系统" or "沙箱文件系统" or "远程 E2B 文件系统"Consumer(使用接口)  "文件读写工具"(模型可调用的 tool)

为什么是三角色而不是一个接口?

因为"声明"、“实现”、"使用"的演进节奏不同:

  • • 声明很少变(文件系统操作就那几个)
  • • 实现经常换(本地 -> 沙箱 -> 远程)
  • • 使用可能增加(新工具消费同一个文件系统)

如果合成一个角色,任何一个变化都牵动另外两个。

实际效果:dsh 的文件系统 Provider 从 fs-local(本地)换成 fs-sandbox(沙箱隔离)或 fs-e2b(远程 E2B 云沙箱),所有消费文件系统的工具代码一行都不用改

ctx.fs(Service Definition)  ├── fs-local(Provider:本地文件系统)  ├── fs-sandbox(Provider:沙箱文件系统)  └── fs-e2b(Provider:E2B 远程文件系统)tool-fs(Consumer:文件读写工具)  -> 只依赖 ctx.fs,不关心背后是哪个 Provider

同样的模式用在整个产品上。换沙箱后端?Bash、终端、LSP 全跟着走,因为它们都通过 ctx.subprocess 消费子进程能力,而子进程的 Provider 从 subprocess-local 换成 subprocess-e2b 即可。

设计 4:Waterfall —— 运行时组合的中间件

传统装饰器是"编译时组合":你写代码时决定套几层、什么顺序。

dsh 用 Cordis 的 waterfall 事件实现"运行时组合":

// 拦截模型请求(在运行时动态注册)ctx.on('agent/request', (request, next) => {    // 前置:改写请求    request.metadata.traceId = generateId();    // 委托给下一个监听器    const response = next(request);    // 后置:记录响应    log(response);    return response;});// 另一个插件:给请求加 retryctx.on('agent/request', (request, next) => {    try {        return next(request);    } catch (e) {        if (isRetryable(e)) return next(request);        throw e;    }});// 又一个插件:注入上下文ctx.on('agent/request', (request, next) => {    request.messages.push({ role: 'system', content: '当前时间: ...' });    return next(request);});

三个插件互不知道对方存在,但它们会按注册顺序组成管道。不需要在 main 里手动套娃,每个插件独立注册,运行时自动组合。

和装饰器的区别

维度装饰器Waterfall
组合时机编译时(写代码时)运行时(插件加载时)
组合方式构造函数嵌套事件注册
动态增删不行可以(effect + disposer)
顺序控制构造顺序注册顺序 + prepend

设计 5:Turn / Step —— 事件驱动的循环

大多数 Agent 框架的循环是一个 while 循环加 if-else:

while (hasSteps && !done) {    response = model.chat(request);    if (response.hasToolCalls()) {        executeTools();    } else {        done = true;    }}

dsh 的循环是事件流,每一步都是事件,每个事件都是扩展点:

turn/start  │  ├── agent/pre-step          ← 插件可拦截/改写/拒绝  │     ↓  ├── step/start  │     ├── user/message       ← 用户消息写入日志  │     ├── agent/request      ← 插件可改写模型请求(waterfall)  │     ├── llm/stream         ← 插件可拦截模型调用(waterfall)  │     ├── assistant/chunk*   ← 流式片段写入日志  │     ├── assistant/message   ← 完整回复写入日志  │     │  │     ├── tool/call*         ← 工具调用写入日志  │     │   ├── tools/pre-execute   ← 策略/权限/沙箱检查(waterfall)  │     │   ├── tools/execute       ← 实际执行(waterfall,可包装 timeout/retry)  │     │   ├── tools/post-execute  ← 结果改写/审计(waterfall)  │     │   └── tool/result*        ← 结果写入日志  │     │  │     └── step/end  │  ├── agent/turn-stopping      ← 插件可决定是否继续(serial)  │  └── turn/end

关键区别:循环逻辑不写在代码里,而是散布在事件中。

想加"每次调模型前注入当前时间"?不用改循环代码,监听 agent/request 事件即可。想加"危险工具调用前需要审批"?不用改工具执行代码,监听 tools/pre-execute 事件即可。

工具执行管道本身就有 5 层:

tools/pre-execute  ← hooks、权限、沙箱策略  ↓monotonic guards    ← 不可重排序的安全检查  ↓tools/execute       ← timeout、retry、metrics 包装  ↓tools/post-execute  ← 接受/拦截/替换/追加上下文  ↓tools/result        ← 冻结最终结果,写入日志

三、对比:它比"主流方案"强在哪

vs LangChain / LangGraph

LangChain 的核心是"链"——预定义的调用序列。扩展靠继承和包装。

dsh 的核心是"插件树"——运行时组装的能力集合。扩展靠注册事件监听。

维度LangChaindsh
扩展方式继承/包装插件注册
循环可改不行(内置 ReAct)可以(agent-loop 是插件)
热加载不支持支持(effect + disposer)
状态管理内存对象append-only 事件日志
工具治理无内置pre-execute / guards / post-execute

vs Claude Code / Cursor

Claude Code 和 Cursor 是闭源产品。dsh 把同类架构开源了:

维度Claude Codedsh
沙箱内置插件化(landlock / E2B / Docker)
工具系统固定可扩展(Capability Seam)
模型适配只有 Claude多 Provider(DeepSeek / pi-ai / replay)
可定制配置文件插件 + YAML 配置
持久化内置插件化(JSONL / SQLite)

四、工程实践亮点

1. 声明式组合:Profile + Bundle

# cordis.yml —— 一个 profile 的声明plugins:  - name: dsh-llm-deepseek        # 用 DeepSeek 模型    config:      api-key: ${DEEPSEEK_API_KEY}  - name: dsh-tools               # 工具系统  - name: dsh-sandbox-local       # 本地沙箱  - name: dsh-agent-loop          # 循环驱动    config:      max-steps: 50  - name: my-custom-trace-plugin   # 你自己的插件    config:      endpoint: https://...

换模型 = 改一行配置。换沙箱 = 改一行配置。加自定义逻辑 = 加一个插件行。不写一行胶水代码

2. 补丁层叠

配置是分层叠加的:

bundle 层(dsh-base 声明的默认插件)  ↓ 覆盖profile 层(cordis.patch.yml)  ↓ 覆盖home 层(用户全局覆盖)  ↓ 覆盖命令行 --patch(一次性覆盖)

每一层都可以覆盖下层任何一行的配置。不需要 fork bundle,打补丁即可。

3. 不变量断言

dsh 不依赖"约定"保证一致性,而是用运行时断言

  • • “模型可见的必定被记录” → 运行时检查,违反直接报错
  • • “一个 Provider 只能有一个实现” → 加载时检查
  • • “插件注册必须有 disposer” → 编译时检查

这些不是文档里写的"最佳实践",是代码里强制执行的规则。


五、对自研 Agent 框架的启示

如果你在构建自己的 Agent Runtime,dsh 至少给了 5 个可以直接借鉴的设计:

1. 把循环变成事件流

不要写 while (true) { model.chat(); executeTools(); }。把每一步拆成事件,让扩展通过监听事件注入逻辑,而不是改循环代码。

2. 状态用事件日志,不用 mutable 对象

mutable state 不可回放、不可 fork、不可审计。事件日志天然支持这些。

3. 能力拆成三角色

不要只写 interface + impl。拆成 Definition(声明)+ Provider(实现)+ Consumer(使用)。换 Provider 不影响 Consumer。

4. 注册要有清理机制

register() 返回 disposer。支持热加载/卸载的前提是注册可逆。

5. 声明式配置替代胶水代码

最终用户不应该写代码来组装 Agent。YAML 配置 + 插件发现 + 补丁层叠,才是产品级的组装方式。


六、总结

DeepSeek Harness 的核心设计哲学可以用一句话概括:

没有不可变的核心。一切皆插件,注册皆可逆,模型可见皆被记录。

这不是"又造了一个轮子",而是重新定义了轮子的组装方式。从"框架核心 + 用户外围"变成"插件平铺 + 声明式组合"。这种架构的扩展成本极低——加任何能力都是"写一个插件 + 加一行配置",不需要理解、更不需要修改核心代码。

对于正在构建 Agent Runtime 的团队,dsh 是一份完整的参考实现。不用抄它的 TypeScript 代码,但它的 5 个设计决策值得逐个对标。

学AI大模型的正确顺序,千万不要搞错了

🤔2026年AI风口已来!各行各业的AI渗透肉眼可见,超多公司要么转型做AI相关产品,要么高薪挖AI技术人才,机遇直接摆在眼前!

有往AI方向发展,或者本身有后端编程基础的朋友,直接冲AI大模型应用开发转岗超合适!

就算暂时不打算转岗,了解大模型、RAG、Prompt、Agent这些热门概念,能上手做简单项目,也绝对是求职加分王🔋

在这里插入图片描述

📝给大家整理了超全最新的AI大模型应用开发学习清单和资料,手把手帮你快速入门!👇👇

学习路线:

✅大模型基础认知—大模型核心原理、发展历程、主流模型(GPT、文心一言等)特点解析
✅核心技术模块—RAG检索增强生成、Prompt工程实战、Agent智能体开发逻辑
✅开发基础能力—Python进阶、API接口调用、大模型开发框架(LangChain等)实操
✅应用场景开发—智能问答系统、企业知识库、AIGC内容生成工具、行业定制化大模型应用
✅项目落地流程—需求拆解、技术选型、模型调优、测试上线、运维迭代
✅面试求职冲刺—岗位JD解析、简历AI项目包装、高频面试题汇总、模拟面经

以上6大模块,看似清晰好上手,实则每个部分都有扎实的核心内容需要吃透!

我把大模型的学习全流程已经整理📚好了!抓住AI时代风口,轻松解锁职业新可能,希望大家都能把握机遇,实现薪资/职业跃迁~

这份完整版的大模型 AI 学习资料已经上传CSDN,朋友们如果需要可以微信扫描下方CSDN官方认证二维码免费领取【保证100%免费

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值