DeepSeek Harness(架构篇):为什么连 Agent Loop 都能替换?

AIAgentArchitectureDeepSeekHarness

常见插件机制通常先有固定核心流程,插件再增加主题、命令或工具。

DeepSeek Harness 的设计不同。

Agent Loop 是 Agent 的核心流程:它组织模型判断、工具执行和结果反馈,并决定继续还是结束。按照常见的插件思路,这部分会写在软件核心里,插件只能围绕它扩展。

但官方架构文档明确把 Agent Loop 与模型适配器、工具注册表、会话日志一样做成了插件。

连 Agent 的核心流程都能替换,正是 DeepSeek Harness 与常见插件机制最大的区别。

这里的"能力边界",可以理解为部件之间约定好的插座:它规定请求怎样传入、结果和错误怎样返回,却不限定背后必须接哪一个具体实现。插座不变,模型适配器、文件系统或 Agent Loop 就能更换。

一、这里的插件不是外挂,而是产品本身

常见的插件系统通常可以画成这样:

plaintext
固定 Agent Loop + 外围插件
主程序决定工作流程,插件只能在预留位置增加功能,很难换掉内部的模型适配器或执行循环。

DeepSeek Harness 更接近另一种结构:

plaintext
稳定接口 + 包含 Agent Loop 的可组合插件
模型调用、工具执行、会话记录、文件系统、沙箱和 Agent Loop,本身就是组成默认产品的插件。这里不再保留一条只有官方才能修改的 Agent 核心流程。

不过,"Everything is a Plugin"不等于系统没有公共规则。插件仍要遵守接口、依赖和运行约定。

真正被取消的,是某个默认实现天然不可替换的特权。

外围能力保持连接,连 Agent Loop 这块核心匣也能更换

二、插件树不是功能清单,而是一份 Agent 组装图

官方把运行中的 dsh 描述为一棵插件树。

它记录本次启动装入了哪些部件、由谁提供。

在 .dsh/profiles/ 目录中,可以看到 Web 与 Headless 两套 Profile:

两种入口分别维护自己的 Profile;具体插件组成以下方导出的配置为准

Web 配置里可以看到这些独立条目:

yaml
- id: llm
  name: '@deepseek-ai/dsh-llm'
- id: session
  name: '@deepseek-ai/dsh-session'
- id: tools
  name: '@deepseek-ai/dsh-tools'
- id: agent-loop
  name: '@deepseek-ai/dsh-agent-loop'
- id: web-runtime
  name: '@deepseek-ai/dsh-web-app'

Headless 配置仍然保留 llm、session、tools 和 agent-loop,但不再装入 Web 界面,结尾换成自己的启动器与运行器:

yaml
- id: headless-startup
  name: '@deepseek-ai/dsh-headless/startup'
- id: headless-runner
  name: '@deepseek-ai/dsh-headless'

这里的 Headless,指不启动网页和服务器的命令行入口。它接收一个任务,等待 Agent 完成,打印最终回复后退出。

它适合一次性脚本,但不等于官方所说的 SDK 方式。

Python SDK 是另一条程序化入口。调用方可以启动完整的 Harness 运行时,复用进程、管理会话、连续提交任务并订阅事件。

SDK 与运行时通过标准输入输出上的 JSON-RPC 通信,不使用 Headless 的一次性任务运行器。

三种入口可以这样区分:

入口场景
Web浏览器交互
Headless命令行提交一次任务,输出结果后退出
SDK由另一个程序持续控制 Harness 运行时

它们的共同点,是入口没有与模型、工具、会话和 Agent Loop 焊死。 Web 与 Headless 的配置对照已经显示,同一批底层插件可以接到不同入口;SDK 则进一步允许外部程序驱动另一套完整的插件组合。

三、能替换的前提,是把能力、实现和使用者分开

把代码拆成很多包,不等于实现可以替换。 上层模块直接绑定具体实现,换实现时仍要跟着改。

DeepSeek Harness 对一项可替换能力区分三个角色:

  1. **能力接口:**像插座一样,规定输入、输出和错误应该是什么样;
  2. **提供者:**负责真正实现这项能力;
  3. **使用者:**通过接口调用能力,完成更高层任务。

可以把关系压缩成一行:

plaintext
使用者 → 稳定能力接口 ← 当前提供者

接口像固定插座;提供者可以更换,使用者一侧不必跟着改

以文件操作为例。

上层工具只关心读取、写入和搜索文件。本地文件系统和远程沙箱都可以成为提供者;只要履行相同约定,上层工具就不需要为每种环境复制一套实现。

命令执行也是如此,真正运行命令的可以是本机 PowerShell、受限沙箱或远程环境。

可替换也不是随便互换。新的提供者仍要正确处理权限、路径、错误反馈和生命周期。

四、模型、工具和会话,是三条独立边界

理解了能力接口,再看模型、工具和会话,插件架构就不再抽象。

**模型边界:**负责接入不同模型提供方。Agent Loop 发出统一的模型请求,适配器负责把请求转换成具体提供方能够理解的协议。更换模型实现,不要求 Loop 理解每个厂商的接口细节。

**工具边界:**负责注册当前 Agent 能看到的工具,并管理调用真正执行前后的处理流程。文件、命令和其他能力可以分别加入,而不是把所有工具代码塞进 Agent Loop。

**会话边界:**负责记录用户消息、模型回复、工具调用和工具结果。恢复、分叉、回放等能力都可以从这份记录派生,而不是依赖 Web 页面里暂时显示的对话内容。

一次任务大致这样经过三条边界:

plaintext
Agent Loop 请求模型
  → 模型选择工具
  → 工具执行并返回结果
  → 结果写入会话
  → Agent Loop 判断是否继续

三条边界协作但互不绑定,更换其中一个,不必重写其余能力。

五、为什么连 Agent Loop 都能替换

按照常见的插件机制,Agent Loop 属于软件核心,插件只能在它周围增加能力。

DeepSeek Harness 则把**"外部怎样使用 Agent"与"Agent 内部怎样推进任务"**分开了。

Web、Headless 或 SDK 只需要知道怎样创建 Agent、提交任务和读取状态;收到任务后怎样推进,则由 Agent Loop 插件决定。源码中的 agent 包提供公共约定,@deepseek-ai/dsh-agent-loop 是官方给出的默认调度实现。

更换 Agent Loop 时,不必连界面、SDK、会话和工具系统一起重写。

另一套调度器只要遵守相同约定,就能继续使用这些能力。

"可替换"不是删除 Loop,而是允许换成不同的实现。替换者仍要处理能力依赖、状态一致性、错误和运行顺序;插件化只提供选择,不保证新 Loop 效果更好。

结语

真正开放的是能力边界,不是插件数量。

现在可以回答开头的问题:如果 Agent Loop 都是插件,DeepSeek Harness 还有没有核心?

有。

稳定的是能力接口与协作约定;可变化的是当前装入的具体实现。

以后再看到一个 Agent 框架声称"支持插件",可以先问三个问题:

  1. 能替换的是外围功能,还是模型、工具、状态和执行循环等关键能力?
  2. 上层模块依赖稳定接口,还是直接绑定默认实现?
  3. 替换一个提供者时,其他模块是否需要跟着复制或改写?

常见插件机制扩展 Agent Loop,DeepSeek Harness 连 Agent Loop 本身也能替换。这才是"Everything is a Plugin"最关键的区别。

下一篇,我会沿一条真实请求继续往里走,看看 turn、step、模型调用、工具执行和结果回传怎样串成一次完整任务。

参考资料

评论

登录后参与评论 登录

加载中…

返回博客列表