Skip to content

01 · Agent Harness 与「一切皆插件」

这一章回答三个问题:什么是 Agent Harness?为什么 DeepSeek 选择了"一切皆插件"的架构?这套架构和我们熟悉的 Web 框架有什么本质区别?

1.1 从一个真实场景说起

假设你接到一个需求:做一个"帮我改代码"的 AI 助手。它要能读文件、跑命令、用模型思考、把结果流式地显示在网页上。

你打开 DeepSeek Harness 的官网,看到的第一句话就是:

DeepSeek Harness (dsh) is an open-source agent harness developed by DeepSeek AI. It uses an architecture where everything is a plugin — 一切都由插件组成。

你可能会想:"插件架构不新鲜啊,VS Code 不也是插件架构吗?" 没错,但大多数"插件架构"其实长这样:

内核是特权中心:它决定什么时候调用插件、给插件什么数据。插件只能"挂在"内核预留的钩子上。如果你想让模型调用工具的方式改一改?对不起,那是内核代码,改不了。想换掉会话存储?那是内核的一部分,也改不了。

DeepSeek Harness 的做法是反过来:连"内核"都不留特权。 官方架构文档的原话是:

Every part of the product is a plugin, including the model adapter, the tool registry, the session log, and the agent loop itself, so every part is replaceable from configuration.

产品的每个部分都是插件——包括模型适配器、工具注册表、会话日志,甚至 agent 循环本身——因此每个部分都可以从配置中替换。

模型适配器是插件,工具注册表是插件,会话日志是插件,连 Agent 的思考循环本身都是一个插件。这就是"一切皆插件"的字面含义:没有任何一段代码因为"它很重要"就享有不可替换的地位。

1.2 什么是 Agent Harness

先把术语对齐。

  • Agent(智能体):一个能"感知 → 思考 → 行动"循环往复的运行时实体。它持有模型、工具和一段持续的记忆。
  • Harness(挽具/马具):这个词来自马具。马有力气(模型能力),但你需要一套挽具把力传导到车上,才能把车拉走。Harness 就是那套"把模型能力装配成可用产品"的装置。

所以 Agent Harness = 装配和驱动 Agent 的框架。它要解决的实际问题有:

  1. 怎么跟各种模型对话? 每家提供方的协议、流式格式、错误码都不一样。
  2. 模型怎么调用工具? 工具声明、参数校验、执行、把结果喂回模型,这套循环谁来做?
  3. 对话历史怎么存? 多轮上下文、流式输出、断点续聊、分支(fork)。
  4. 中间过程谁能干预? 审批、权限、审计、压缩上下文……这些横切关注点加在哪?
  5. 产品怎么组合? 有的用户要 Web UI,有的要命令行一次性任务,有的要 API——同一个内核怎么长出这么多形态?

一个"普通"的框架会把这五个问题分别硬编码在五个模块里。DeepSeek Harness 的回答是:这五个问题各自对应一类插件,而装配它们的"内核"本身薄到几乎不存在。

1.3 一切皆插件意味着什么

我们逐条看官方架构文档列出的对应关系,每条都是一个"你原来以为要改内核、其实注册个插件就行"的场景:

你想做的事在 dsh 里的做法
接入一个新的模型提供方写一个 LlmAdapter 子类,注册到 ctx.llm
给模型一个会调工具的能力(比如读写文件)注册到 ctx.tools,schema 自动进入提示词装配
给某个会话换一套能力组合一个 agent preset(服务行加 isolate 作用域)
加 shell 执行能力注册一个 ctx.shell 后端
加一个不用模型的人机命令注册到 ctx.commands
加后台任务注册到 ctx.jobs,配套的 job_* 工具自动出现
加文件系统访问或策略注册 ctx.fs 提供方,或监听 fs/* 事件
拦截一次请求 / 工具调用 / 轮次监听对应的 agent/*tools/* 事件
给模型注入上下文agent.inject(),内容进入下一次请求
加 UI 或编辑器集成驱动 ctx.agents,从 session/event 渲染
生成会话标题注册唯一的 ctx.sessionTitle 提供方
管理一个同会话的目标ctx.goals,通过 agent/* 继续
给单个 agent 局部注册用该 agent 自己的 agent.ctx

注意最后一列里反复出现的 ctx.*上下文(Context)是这套架构的枢纽:它既不是全局单例,也不是手动传参,而是一个"服务容器"。我们下一章会细讲,这里先记住一个心智模型:

每个插件都站在同一个 Context 面前:往上面挂服务、监听事件、注册可逆的副作用。谁也不知道"整个系统"长什么样,它们只知道自己在跟谁协作。这就是 dsh 的可替换性来源:功能之间的耦合不是代码里的 import,而是运行时的注册。

1.4 为什么这么设计:一个思维实验

你可能想问:把 agent 循环做成插件,会不会过度设计?我们做个思维实验来体会它解决了什么真问题。

问题一:模型调用工具的方式是"正确答案"吗?

2023 年 OpenAI 定义了 Function Calling 协议,2024 年 Anthropic 的 tool use 又不一样,2025 年各家的"原生工具调用"继续演化。如果你把工具循环硬编码在内核里,每一次协议演进都是一次内核手术。

dsh 的做法:工具循环(agent-loop)是插件,工具的执行管线(tools 服务)也是插件,模型与工具的交互协议定义在 llm 插件层。哪个环节变了就换哪个插件,其余全部原样保留。

问题二:产品形态能枚举完吗?

Web UI、CLI 一次性任务、ACP(Agent Client Protocol)服务器、Python SDK、JSON-RPC……每个形态都想要"同一个内核"。如果你为每个形态 fork 一份代码,维护成本是乘法。

dsh 的做法:一个 profile 就是一份"插件清单"(bundle 列表 + patch 覆盖层)。webheadless 只是两份不同的清单——产品形态从"代码"变成了"配置"

text
dsh --profile web        # Web UI:base bundle + web-app bundle
dsh --profile headless   # 一次性任务:base bundle + headless bundle,不装 HTTP 服务器

问题三:用户的个性化需求怎么落地?

用户 A 想把所有工具调用都记录到自己的审计系统;用户 B 想在模型请求发出前自动切换路由;用户 C 要给某个会话单独挂一个沙箱。这三件事在传统框架里都需要"提 PR、等发版"。

dsh 的做法:A 监听 tools/result 事件,B 监听 agent/request 瀑布事件,C 用 isolate 作用域。三个需求都是局部的、可独立发布的插件,核心仓库一行都不用改。

1.5 关键概念速览

在进入下一章之前,先把整个教程会用到的核心名词过一遍(完整版见术语表):

概念一句话解释
Plugin(插件)实现服务的对象:一个函数、一个类、或带 apply(ctx) 的对象。
Context(上下文)服务的容器:一个服务占据稳定的 ctx.<key>,其他插件按键查找。
Service(服务)挂在 Context 上的命名能力,比如 ctx.llmctx.toolsctx.sessions
inject(依赖注入)插件声明自己需要哪些服务,服务就绪前不启动;加载顺序由依赖决定,而非手动编排。
Event(事件)插件间通信:emit(广播)、waterfall(可拦截的中间件链)、parallel(并发扇出)、serial(顺序执行)。
Effect(可逆副作用)所有注册(监听器、工具、适配器)都是 effect,插件卸载时自动按逆序撤销。
Profile / Bundle产品的"配方":profile 是命名组合,bundle 是可分发的插件集(npm 包)。
Session(会话)一次持续对话;其日志是"可回放的事实源"。
Turn / Step一次唤醒叫 turn;turn 内的"一次模型请求 + 它调用的工具"叫 step。
Seam(接缝)可替换的能力点:接口声明 + 提供方 + 消费方,三位一体。

1.6 本章小结与练习

这一章的核心只有一句话:dsh 没有特权内核,一切皆插件,功能之间的耦合发生在运行时的注册里,而不是代码的 import 里。

小练习:给"一切皆插件"找反例

打开你熟悉的任意一个框架(Express、Django、Spring Boot……),问自己:如果我想替换它的"路由匹配逻辑"或"请求日志格式",需要改哪里?是注册一个中间件,还是改框架源码?

然后把同样的问题问一遍 dsh:替换模型适配器(插件)、替换工具执行策略(事件)、替换会话持久化(服务提供方)。体会一下两者在"可替换边界"上的差别。

关于本章的事实来源

"Everything is a plugin"、"Every part of the product is a plugin, including the model adapter, the tool registry, the session log, and the agent loop itself" 均出自官方 READMEarchitecture 文档。dsh 的插件机制由 Cordis 提供,其设计思想见论文 A Programming Paradigm for Spatiotemporal Composability

基于 DeepSeek Harness(开发者预览版 0.1.0-rc.6)与 Cordis 撰写