<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>潘锦的空间 &#187; Agent Harness</title>
	<atom:link href="https://www.phppan.com/tag/agent-harness/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.phppan.com</link>
	<description>SaaS SaaS架构 团队管理 技术管理 技术架构 PHP 内核 扩展 项目管理</description>
	<lastBuildDate>Sun, 23 Aug 2026 03:36:05 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>DeepSeek Harness 的 Cordis 插件架构</title>
		<link>https://www.phppan.com/2026/08/deepseek-harness-cordis/</link>
		<comments>https://www.phppan.com/2026/08/deepseek-harness-cordis/#comments</comments>
		<pubDate>Sun, 23 Aug 2026 03:36:05 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[架构和远方]]></category>
		<category><![CDATA[Agent]]></category>
		<category><![CDATA[Agent Harness]]></category>
		<category><![CDATA[AIAgent架构]]></category>
		<category><![CDATA[DeepSeek]]></category>
		<category><![CDATA[DeepSeekHarness]]></category>
		<category><![CDATA[harness]]></category>

		<guid isPermaLink="false">https://www.phppan.com/?p=2531</guid>
		<description><![CDATA[DeepSeek Harness 把模型、工具、会话、沙箱、文件系统、Agent 循环、调度和 UI 都交给插 [&#8230;]]]></description>
				<content:encoded><![CDATA[<section id="nice" style="color: #000000;" data-tool="mdnice编辑器" data-website="https://www.mdnice.com">
<p data-tool="mdnice编辑器">DeepSeek Harness 把模型、工具、会话、沙箱、文件系统、Agent 循环、调度和 UI 都交给插件。</p>
<p data-tool="mdnice编辑器">系统没有一块承载业务能力的固定内核，Cordis 只维护上下文、服务注册、事件分发、依赖激活和副作用回收；Agent 能做什么，由启动时挂入的一棵插件树决定。</p>
<p data-tool="mdnice编辑器">传统的插件有注册容易，撤销困难；初始化容易，失败回滚困难；全局单例容易，局部覆盖困难等问题，而 Cordis 把这些困难收进了运行时语义，Harness 再用 session、agent 和 preset 的业务约束补齐它。</p>
<p data-tool="mdnice编辑器">今天聊了一下 DeepSeek Harness 的核心 Cordis 架构以及 Cordis 所谓「时空可组合」，究竟怎样落到代码里，又为何适合 Agent Harness 这类持续变化的运行时。</p>
<h1 data-tool="mdnice编辑器"><span class="content">插件的历史</span></h1>
<p data-tool="mdnice编辑器">插件架构的历史并不短。Eclipse 在二十多年前已经把 IDE 拆成插件、扩展点和扩展，宿主声明可扩展位置，其他插件通过清单贡献菜单、编辑器和处理逻辑。</p>
<p data-tool="mdnice编辑器">OSGi 更进一步，给 bundle 配置安装、启动、停止、更新和卸载生命周期，再通过共享服务注册表完成发布、查找和绑定。服务离开注册表时，依赖方必须跟着处理动态变化。</p>
<p data-tool="mdnice编辑器">今天看 Cordis，能找到这些设计的清晰痕迹：动态服务、生命周期、注册表、声明式依赖、事件通知都已有成熟先例。</p>
<p data-tool="mdnice编辑器">Cordis 没有发明插件系统。</p>
<p data-tool="mdnice编辑器">它简化并重新组合了这些概念，让它们适合 TypeScript 应用内的细粒度组装。OSGi 的部署单元是 bundle，模块、生命周期、服务和安全各有一层；Cordis 的执行单元是 Fiber，一个函数或一个 <code style="color: #ef7060;">Service</code> 子类就能成为插件。Eclipse 的扩展点通常由宿主定义结构化清单，Cordis 让服务和类型化事件直接成为扩展面。Agent 运行时里的工具、提示词片段、模型适配器和审批策略变化频繁，如果每次扩展都要引入重量级模块边界，团队很快会绕过框架，重新写回几个全局数组。</p>
<p data-tool="mdnice编辑器">Cordis 官方仓库把自己定位为「Meta-Framework of Spatiotemporal Composability」。</p>
<p data-tool="mdnice编辑器">从源码看，「元框架」表示它不规定 Agent、Web 服务或机器人该有什么组件，只提供构造框架所需的基础语义。DeepSeek Harness 在其上定义 <code style="color: #ef7060;">sessions</code>、<code style="color: #ef7060;">tools</code>、<code style="color: #ef7060;">llm</code>、<code style="color: #ef7060;">agents</code> 等服务，又用这些服务组装产品。Cordis 与 Harness 的关系更接近运行时机制和领域框架，而非通用插件平台与插件集合。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 还把 Cordis 源码直接放进 <code style="color: #ef7060;">vendor/</code>，固定在明确的上游提交，并将包名重映射到 <code style="color: #ef7060;">@deepseek-ai</code> 命名空间。</p>
<p data-tool="mdnice编辑器">项目维护的本地修改包含 Fiber 重入卸载加固、配置更新事务、HMR 精确监听、延迟配置解析等。这增加了维护成本，也换来了框架层的可审计性。Agent 能执行 Shell、修改文件、访问网络，插件生命周期出错会留下进程、监听器、终端模式或权限状态。</p>
<p data-tool="mdnice编辑器">此时依赖一个本地的代码白盒，会让人放心一些。</p>
<h1 data-tool="mdnice编辑器"><span class="content">调用链路图</span></h1>
<p data-tool="mdnice编辑器">简单的调用图如下所示：</p>
<figure data-tool="mdnice编辑器"><img src="https://files.mdnice.com/user/36365/c8ef3798-50e3-40a7-810e-c68c5f71ca03.png" alt="" /></figure>
<h1 data-tool="mdnice编辑器"><span class="content">最小内核</span></h1>
<p data-tool="mdnice编辑器">Cordis 的根对象是 <code style="color: #ef7060;">Context</code>。它同时承担依赖容器、插件挂载入口和事件入口。</p>
<p data-tool="mdnice编辑器">服务通过稳定名称出现在 <code style="color: #ef7060;">ctx</code> 上，例如 <code style="color: #ef7060;">ctx.tools</code>、<code style="color: #ef7060;">ctx.llm</code>、<code style="color: #ef7060;">ctx.sessions</code>。插件声明 <code style="color: #ef7060;">inject</code> 后，Cordis 只有在所需服务可用时才激活它；服务消失，依赖插件也会进入卸载或等待状态。配置文件中条目的先后顺序因此不承担启动顺序，依赖关系才承担。</p>
<p data-tool="mdnice编辑器">这种处理解决了传统插件系统的第一个顽疾：隐含初始化顺序。</p>
<p data-tool="mdnice编辑器">常见实现会遍历插件数组，依次调用 <code style="color: #ef7060;">init</code>。当工具依赖文件系统、文件系统依赖沙箱、UI 又依赖会话时，数组顺序就变成一套没有类型、没有诊断的依赖图。后来插入一个插件，顺序约束可能跨越几十个文件。</p>
<p data-tool="mdnice编辑器">Cordis 把需求写进 <code style="color: #ef7060;">inject</code>，Fiber 会为每项依赖保存当前实现；缺少依赖时保持 <code style="color: #ef7060;">PENDING</code>，依赖齐备后进入 <code style="color: #ef7060;">LOADING</code> 和 <code style="color: #ef7060;">ACTIVE</code>。启动失败则进入 <code style="color: #ef7060;">FAILED</code>。状态机至少让故障有了准确位置。</p>
<p data-tool="mdnice编辑器"><code style="color: #ef7060;">Context</code> 还是一个代理对象。</p>
<p data-tool="mdnice编辑器">插件直接读取 <code style="color: #ef7060;">ctx.tools</code> 时，反射层会检查它是否声明过依赖，并沿 Fiber 父链解析实现。未声明就读取会抛错；声明了但当前上下文不可用，也会抛出另一类错误。这种约束防止依赖藏在任意函数深处。源码里依然提供 <code style="color: #ef7060;">ctx.get(name)</code> 读取可选服务，区别在于调用方显式接受服务可能不存在。</p>
<p data-tool="mdnice编辑器">这里的「服务定义、服务提供方、消费方」三种角色被完整建模。比如文件系统能力不能只写一个接口，也不能只挂一个本地实现。定义方稳定调用协议，提供方接入本地目录或远程沙箱，消费方把能力变成模型可见工具。Harness 把这组关系称为 capability seam。替换沙箱时，Shell、PTY、LSP 只要依赖同一能力面，就能整体迁移到新的执行环境，消费方无需知道提供方运行在本机还是远端。</p>
<p data-tool="mdnice编辑器">「一切皆插件」有一个前提是：一切产品能力皆由插件贡献，Cordis 自身仍保留插件得以存在的机制。上下文代理、Fiber 状态机、服务存储、事件总线和 Loader 属于元层。</p>
<p data-tool="mdnice编辑器">这并不是系统里没有内核，更准确的说，应该是，内核不拥有模型、工具和循环等产品特权。</p>
<h1 data-tool="mdnice编辑器"><span class="content">空间组合</span></h1>
<p data-tool="mdnice编辑器">同一个进程里，服务名称必须稳定，实例又不能全局唯一。两个 Agent 可能选择不同模型、不同工具集、不同 persona 和不同沙箱。如果 <code style="color: #ef7060;">ctx.llm</code> 永远指向一个全局对象，插件替换只发生在进程级，无法满足多会话并存。</p>
<p data-tool="mdnice编辑器">Cordis 的 <code style="color: #ef7060;">Context.isolate</code> 为指定服务名创建一个 realm 标签。服务注册和查找都以该标签定位，同名服务可以在不同子上下文里各自存在。两个 <code style="color: #ef7060;">isolate</code> 调用传入同一标签时会加入同一 realm；使用新标签时彼此隔离。子上下文通过原型继承父上下文，隔离映射按层遮蔽，因此局部配置不需要复制整棵容器。</p>
<p data-tool="mdnice编辑器">这解释了「空间可组合」的第一层：组合具有位置。插件挂在哪个上下文，决定它提供的服务、注册的监听器和持有的副作用在哪个范围可见。传统依赖注入容器也有 singleton、request、session 等 scope，Cordis 的差异在于作用域与插件树、事件过滤、资源所有权使用同一个 Context 表达。开发者无需在四套 API 之间同步身份。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 又增加了 <code style="color: #ef7060;">dsh-scope</code>。它用不透明对象作为 scope key，维护父子关系，并创建带路由身份的事件 receiver。注册视图沿父链向下继承：Agent 能看到所属 preset 的提示词和工具。事件则沿链向上接纳：preset 级监听器能收到其下 Agent 的事件，兄弟 Agent 互不串线。这是第二层空间结构，解决的是领域身份，而非单个服务名的 realm。</p>
<p data-tool="mdnice编辑器">为何需要两层？<code style="color: #ef7060;">isolate</code> 处理「哪个 <code style="color: #ef7060;">tools</code> 服务实例」，<code style="color: #ef7060;">dsh-scope</code> 处理「同一工具注册表里，哪些注册项对当前 Agent 可见」。前者适合替换提供方，后者适合对注册内容分层。把所有差异都做成独立服务实例，会放大内存和初始化成本；把所有差异都塞进一个全局注册表，又会让过滤规则散落在调用点。这两层模型把实例隔离和内容路由分开了。</p>
<p data-tool="mdnice编辑器">Agent preset 是空间组合的完整应用。一个 preset 的 Cordis 配置会挂在一个长期存在的 scope 下，Agent 创建时把自己的 scope key 绑定到该 preset。相同 preset 的并发首次使用通过 single-flight 共享一次挂载，后续 Agent 复用这份组合。文件变化后，新会话加入新一代组合，已有会话保留原来的代际。这个策略避免会话运行中途突然更换工具或提示词，代价是旧代际要保留到整棵运行时退出，配置频繁变化时内存会按代际增长。</p>
<p data-tool="mdnice编辑器">源码还专门审计 preset 子树是否把服务发布到了 root realm。发生这种泄漏时，第二个会话挂载同一 preset 会与第一个冲突，所谓会话级组合也会退化成进程全局状态。DeepSeek Harness 在发布 Agent 前拒绝这种配置。空间隔离若只靠约定，迟早会被一个没有 <code style="color: #ef7060;">isolate</code> 的 provider 穿透；运行时审计比文档警告可靠。</p>
<p data-tool="mdnice编辑器">这套空间模型存在认知成本。插件作者要同时理解 Context 父链、服务 realm、业务 scope 父链和事件过滤方向（当然，在当前 Vibe Coding 盛行的时代，也可以作者不理解，直接让 AI 来搞）。</p>
<p data-tool="mdnice编辑器">在认知不清楚的时候，常见的错误往往表现为某项能力「看不见」或意外泄漏，类型系统无法证明运行时挂载位置。DeepSeek Harness 用 preset 挂载审计、包级 invariant 和真实组合测试降低风险，却没有消除模型复杂度。团队若只需要单进程单 Agent，直接引入整套空间语义会显得过重。</p>
<h1 data-tool="mdnice编辑器"><span class="content">时间组合</span></h1>
<p data-tool="mdnice编辑器">插件能挂载只是静态组合。运行期间服务上线、配置改变、插件失败或上下文销毁，系统还要回到一致状态。Cordis 用 Fiber 和 effect 管理这条时间轴。</p>
<p data-tool="mdnice编辑器">每次插件应用都会产生一个 Fiber。Fiber 记录父上下文、原始配置、解析后配置、依赖实现快照、生命周期状态和 disposables。插件调用 <code style="color: #ef7060;">ctx.effect()</code> 注册副作用，effect 的执行结果返回 disposer。事件监听、服务提供、子插件和访问器最终都进入这套所有权体系。Fiber 卸载时按注册的逆序执行清理，并等待异步清理达到静止状态。</p>
<p data-tool="mdnice编辑器">逆序本身不是一个特别要讲的事情，因为这是必须的。</p>
<p data-tool="mdnice编辑器">若插件先启动子进程，再注册输出监听，最后暴露服务，销毁时应先撤销服务，停止新请求，再移除监听，最后结束进程。资源创建顺序的反向通常就是依赖安全的拆卸顺序。</p>
<p data-tool="mdnice编辑器">传统插件常给出一个 <code style="color: #ef7060;">deactivate()</code> 钩子，把所有清理责任推给作者；漏掉一个定时器或事件监听，热加载几次便出现重复执行。Cordis 让每次注册同时产生撤销动作，框架持有所有权。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 的 vendor 版本进一步处理了重入场景：effect 在执行 setup 前先登记所有者包装；插件发布事件时，观察者可能同步卸载它；异步 cleanup 已经开始后，其他调用者仍能等待同一次清理；Fiber 处于 <code style="color: #ef7060;">UNLOADING</code> 时拒绝创建新 effect。这些代码看起来全是繁琐的边界处理，但为了保证生命周期并发的安全，一个都不能少。否则插件的热卸载就只是个玩具，没法真正落地。</p>
<p data-tool="mdnice编辑器">依赖变化也属于时间组合。某个服务被提供后，反射层通知所有声明该依赖的 Fiber 重新检查；条件满足便激活。服务撤销后，依赖方会卸载并回到等待。OSGi 早已采用动态服务注册表，Cordis 的新意主要在于把动态依赖、作用域上下文和 effect 所有权压进一个很小的进程内模型。代价同样继承自 OSGi：任何持有服务引用越过生命周期的代码，都可能在提供方撤销后继续调用过期对象。Cordis 保存加载时的实现快照，却无法替业务代码管理逃逸引用。</p>
<p data-tool="mdnice编辑器">Loader 把时间组合延伸到配置。DeepSeek Harness 的 profile 由多层 bundle patch 叠加：基础 bundle、模式 bundle、profile patch、home patch、命令行 overlay。patch 按 id 定位条目，配置采用整块替换。整块替换要求用户重述保留字段，使用上稍显笨重，却避免深度合并规则在数组、表达式和删除语义上制造歧义。</p>
<p data-tool="mdnice编辑器">配置热更新时，Loader 先导入候选插件，再卸载旧实例并应用候选；候选失败会恢复旧插件或旧配置。Group 对一批子条目并发启动，收集全部结果，只要一项失败就删除新增项并重建旧配置。Include 读取候选文件、在副本上应用 patch、完成树协调后才提交缓存。用户 patch 语法错误或新插件启动失败时，最后一棵可用树继续运行。</p>
<p data-tool="mdnice编辑器">这已经接近配置事务，却不能等同于数据库事务。</p>
<p data-tool="mdnice编辑器">插件 effect 可能调用外部 API、创建远端资源、发送消息；disposer 只能做补偿，无法保证外部世界回滚。Loader 能保证自己管理的树和服务注册恢复，无法撤回所有不可逆副作用。插件开发规范仍要限制初始化期行为，把外部写入延迟到真正的业务请求，或者设计幂等键和补偿路径。</p>
<p data-tool="mdnice编辑器">时间组合还带来可观的测试面积。挂载成功只是第一条路径，还要覆盖依赖晚到、依赖撤销、初始化失败、卸载重入、异步清理、热更新失败、回滚再次失败。DeepSeek Harness 要求注册项证明 disposal，产品可见插件还要通过真实 Loader 组合测试。这个成本无法靠框架消失，只能被框架集中暴露。相比线上出现幽灵监听器和半更新状态，还是愿意支付这部分测试费用。</p>
<h1 data-tool="mdnice编辑器"><span class="content">事件契约</span></h1>
<p data-tool="mdnice编辑器">插件之间只靠服务调用，会把所有扩展都变成接口方法。宿主每增加一项策略，就要修改服务定义。Cordis 同时提供类型化事件，并区分 <code style="color: #ef7060;">emit</code>、<code style="color: #ef7060;">parallel</code>、<code style="color: #ef7060;">serial</code>、<code style="color: #ef7060;">bail</code> 和 <code style="color: #ef7060;">waterfall</code>。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 最依赖的是 waterfall。它的监听器拿到 <code style="color: #ef7060;">next</code>，调用后把控制权交给下一层，不调用就截断链条。模型请求、工具执行和轮次控制都能被插件包裹。审批策略可以在工具执行前拒绝，重试插件可以包围模型流，日志插件可以观察前后状态。它与 Koa 一类中间件链相似，但事件名和 Context 过滤让同一个分发器覆盖多个能力域。</p>
<p data-tool="mdnice编辑器">waterfall 也最容易出错。一个只想记录日志的监听器忘记调用 <code style="color: #ef7060;">next()</code>，整条能力链便被短路。DeepSeek Harness 把「必须调用 <code style="color: #ef7060;">next()</code>」写进项目级规则，并在事件文档里记录 dispatch mode。类型能保证参数，却很难保证 continuation 一定执行。代码评审和组合测试仍是主要防线。</p>
<p data-tool="mdnice编辑器">事件的持久性也被刻意分层。<code style="color: #ef7060;">agent/*</code> 和 <code style="color: #ef7060;">tools/*</code> 事件用于活跃运行时的拦截；会话事件追加到日志，承担恢复、fork、UI 回放和模型历史投影。DeepSeek Harness 规定「模型可见即已记录」：进入模型请求的输入必须能从 session log 重建。插件若偷偷修改 prompt 却不产生会话事实，重放结果会漂移，问题也无法审计。</p>
<p data-tool="mdnice编辑器">这条约束说明，一切皆插件并不意味着一切皆事件。直接能力调用放进 Service，策略和拦截放进实时事件，需要持久化的事实进入 session log。三类通信各自承担调用、扩展和历史。将它们混成一个全局 event bus，短期代码更少，长期会失去时序语义和数据权威。</p>
<h1 data-tool="mdnice编辑器"><span class="content">Agent 适配</span></h1>
<p data-tool="mdnice编辑器">Agent Harness 比普通 Web 服务更需要动态组合。模型供应商会变，工具权限随工作区变化，子 Agent 的执行环境可能与父 Agent 不同，UI 还要消费同一份流式过程。如果主循环直接 import 每个能力，任何替换都会改循环；循环逐渐成为依赖最多、风险最高的文件。</p>
<p data-tool="mdnice编辑器">DeepSeek Harness 的默认 agent loop 仍然存在，但它也是一个服务提供方。循环读取 session log 生成历史，组装插件贡献的 prompt 和 tool schema，通过 <code style="color: #ef7060;">agent/request</code> 进入模型适配器，再经过工具流水线记录结果。扩展点围绕步骤、请求、工具和停止阶段布置。新功能通常挂到这些事件或注册表，项目规则甚至要求修改 agent loop 时同步更新架构文档。</p>
<p data-tool="mdnice编辑器">我赞成这种限制。循环承担控制流，频繁承载产品策略后会迅速腐化。压缩上下文、重试、审批、工具超时、计划模式、子 Agent 调度都可以有自己的生命周期与配置。它们进入循环的接口必须少且稳定。插件化不会自动获得解耦，真正起作用的是 DeepSeek Harness 为能力选择了明确的 seam，并拒绝消费方特有逻辑污染定义层。</p>
<p data-tool="mdnice编辑器">UI 作为插件也有实际意义。Web 和 headless profile 在共享 base bundle 上增加不同条目，后者可以完全不启动服务器。UI 驱动 <code style="color: #ef7060;">ctx.agents</code>，订阅 <code style="color: #ef7060;">session/event</code> 渲染状态，没必要成为循环的一部分。服务端、CLI、ACP 和浏览器界面可以共享会话及 Agent 语义，同时保留自己的传输和展示逻辑。</p>
<p data-tool="mdnice编辑器">插件树还提供自省基础。Fiber 保留名称、状态、依赖和 effect 元数据，DeepSeek Harness 能实现查看、挂载、卸载自身插件的能力。对 Agent 而言，这比普通应用更敏感：模型可以通过工具改变运行时，错误配置可能直接扩大权限。源码中的 sandbox 和 approval 仍是独立能力，插件架构没有天然安全性。自修改必须受工具权限、配置校验和作用域审计约束。</p>
<h1 data-tool="mdnice编辑器"><span class="content">架构代价</span></h1>
<p data-tool="mdnice编辑器">第一项代价是启动与运行时开销。每个插件产生 Fiber，服务访问经过 Proxy 和反射解析，事件分发要执行作用域过滤，注册项还要保存 disposer 与诊断元数据。对于 LLM Agent，单次模型请求通常以百毫秒到秒计，这些 JavaScript 调度开销很难成为主要瓶颈；高频 token chunk、文件扫描或终端字节流若全部穿过通用事件总线，成本会被放大。DeepSeek Harness 把流式模型输出定义为能力语义，但大量数据处理仍应留在具体 provider 内，事件只承载必要扩展点。</p>
<p data-tool="mdnice编辑器">第二项代价是故障面扩大。插件初始化可以同步抛错、异步拒绝、等待缺失服务，也可能在 disposer 中失败。Group 并发启动缩短时间，却会带来多个兄弟同时失败的 AggregateError。DeepSeek Harness 的 boot 会等待 Loader 结算，审计所有启用条目是否加载与激活，失败时先 dispose 部分构造的上下文，再退出。少做任何一步，都可能让终端停留在 raw mode，或者让后台 watcher 继续运行。</p>
<p data-tool="mdnice编辑器">第三项代价是配置成为编程接口。<code style="color: #ef7060;">cordis.yml</code> 支持 <code style="color: #ef7060;">!!js</code> 表达式，条目可以按环境禁用，配置会在依赖激活后求值。灵活性很高，静态分析能力随之下降。表达式读取服务时，求值时机与上下文位置都会影响结果。DeepSeek Harness 只允许 <code style="color: #ef7060;">config</code> 和 <code style="color: #ef7060;">disabled</code> 使用插值，其他元数据保持字面量，并让错误尽早暴露。这仍要求运维人员理解插件依赖和 patch 覆盖语义，配置文件已经超出普通 YAML 参数表的复杂度。</p>
<p data-tool="mdnice编辑器">第四项代价是生态兼容。Cordis 的服务名和事件类型提供了源码级协议，插件版本升级仍可能修改配置、事件 payload 或生命周期假设。DeepSeek Harness 目前处于预发布阶段，仓库规则允许直接拒绝旧磁盘格式，也没有承诺 session 格式兼容。现在的可组合性主要服务于同一发行版内的替换和扩展，尚不能推导出跨版本插件 ABI 稳定。</p>
<p data-tool="mdnice编辑器">第五项代价是组织治理。一切都能成为插件后，团队容易把每段十几行逻辑都拆成包，形成依赖图膨胀、文档分散和测试启动缓慢。DeepSeek Harness 用 package 分组、Service Definition/Provider/Consumer 角色、每包 README、运行时 invariant 和真实组合测试控制边界。这些规范本身就是成本。小团队若没有维护扩展生态或多 profile 的需求，模块化函数加显式依赖可能更合适。</p>
<h1 data-tool="mdnice编辑器"><span class="content">历史对照</span></h1>
<p data-tool="mdnice编辑器">从 OSGi 看 Cordis，动态服务和生命周期联动已有先例。服务注册、发现、撤销后触发依赖变化，这条主线几乎一致。Cordis 值得学习的新点，是把资源清理统一成 effect，并让子插件、服务、监听器都归属于同一个 Fiber。OSGi 的 bundle 生命周期更完整，也更重；Cordis 选择应用内细粒度对象，失去了类加载隔离、标准版本解析和安全层，获得了低门槛组合。</p>
<p data-tool="mdnice编辑器">从 Eclipse 看 DeepSeek Harness，profile 与 bundle patch 很像部署时组装，Service 和事件类似扩展点。差异在于 Eclipse 扩展通常围绕稳定宿主能力，DeepSeek Harness 连 agent loop 和 UI 都可替换，核心插件与第三方插件共享同一挂载机制。这个平权减少了特权内核，风险也更集中到协议治理：循环能被替换，不代表任何替代循环都遵守 session log、权限和工具时序约束。</p>
<p data-tool="mdnice编辑器">从依赖注入容器看，Cordis 的服务解析并不陌生。新的组合来自 DI 与生命周期的绑定。普通容器负责构造对象，定时器、监听器和子进程仍由业务代码清理；Cordis 把注册动作收敛成 effect。空间 scope 与时间 ownership 同时存在，插件才能在某个 Agent 范围内挂载，并随该 Agent 完整撤销。</p>
<p data-tool="mdnice编辑器">从微内核看，DeepSeek Harness 的内核确实很轻，但其 Loader 和配置协调已经承担不少平台职责。它要解析模块、等待依赖、处理 HMR、执行事务式更新、保存最后可用树、输出诊断。这提醒我，微内核减少的是业务特权，不会减少生命周期复杂度。能力越动态，内核对失败语义的要求越高。</p>
<p data-tool="mdnice编辑器">Cordis 的贡献可以概括为一种紧凑的组合坐标：Context 决定插件位于哪里，Fiber 决定插件在何时有效，Service 负责直接能力，Event 负责横切协作，effect 负责撤销。DeepSeek Harness 在这个坐标系上加入 Agent scope、持久会话事件和配置事务，使其能承载多会话、多 profile 与热更新。</p>
<h1 data-tool="mdnice编辑器"><span class="content">工程取舍</span></h1>
<p data-tool="mdnice编辑器">当我想要用类似架构时，会先确认三个条件，基于这三个条件判断来是否采用。</p>
<p data-tool="mdnice编辑器">其一，能力确实需要独立替换，至少存在两个生产提供方或明确的外部扩展需求。</p>
<p data-tool="mdnice编辑器">其二，同一进程需要多套组合并存，或者运行期间需要可靠更新。</p>
<p data-tool="mdnice编辑器">其三，团队愿意为卸载、回滚和真实组合测试持续付费。</p>
<p data-tool="mdnice编辑器">缺少这些条件，插件框架容易沦为复杂的工厂模式。</p>
<p data-tool="mdnice编辑器">能力切分要从消费方开始。先列出谁调用、调用时需要哪些稳定语义，再设计 Service Definition；随后实现 provider，最后把面向模型的 schema、展示和错误文本留给 consumer。接口只有一个内部调用者时，保留私有闭包，不急着升格为公共 service。可替换性必须由真实替代者证明。</p>
<p data-tool="mdnice编辑器">所有注册都要有明确所有者。注册工具、提示词片段、适配器、监听器时同步返回 disposer；卸载测试要观察注册项确实消失。涉及异步资源时，dispose 完成的定义要包含子进程退出、队列排空和 watcher 关闭，不能只发出取消信号。DeepSeek Harness 对 Fiber quiescence 的处理值得照搬。</p>
<p data-tool="mdnice编辑器">配置更新要区分内存一致性和外部副作用。Loader 可以恢复旧树，插件初始化若已经创建云资源，回滚需要业务补偿。规则可更保守一些：挂载阶段只做校验和本地注册，外部写操作放到带幂等标识的运行阶段。确实要在初始化创建资源时，必须让 disposer 能识别部分完成状态。</p>
<p data-tool="mdnice编辑器">作用域要控制在两种以内。实例隔离与注册可见性已经足够表达多数 Agent 场景，再增加租户、请求、工作区、角色四套独立 scope，调试成本会失控，需要根据实际业务需求和必要性来判断。当需要新增维度时，先判断它属于服务实例选择、注册过滤、持久数据权限还是请求参数。很多所谓新 scope，其实只是一次显式参数传递。</p>
<p data-tool="mdnice编辑器">事件也要克制。需要唯一返回值的调用用 Service，需要持久恢复的事实写 session log，需要多个插件观察或包裹的阶段才用事件。waterfall 必须把短路当成公共协议，监听器顺序也要有测试。事件名虽然能降低导入耦合，却会增加时序耦合；后者通常更难排查。</p>
<h1 data-tool="mdnice编辑器"><span class="content">小结</span></h1>
<p data-tool="mdnice编辑器">DeepSeek Harness 选择 Cordis，解决的主要矛盾是 Agent 能力变化速度与运行时一致性之间的冲突。模型、工具、沙箱和 UI 都可以替换并不稀奇；这些能力可以在局部作用域内共存，能随依赖变化启停，能在配置失败后保留旧树，卸载时还能回收监听器、服务和子插件，才构成可用的插件架构。</p>
<p data-tool="mdnice编辑器">它也没有抹平工程风险。Proxy 隐藏了查找路径，双层 scope 增加理解成本，热更新无法回滚任意外部副作用，预发布阶段也缺少跨版本兼容承诺。团队采用这套思路时，应复制它的生命周期纪律和能力边界，别只复制「一切皆插件」的目录结构。</p>
<p data-tool="mdnice编辑器">源码给我们一些启发，把插件设计的评审顺序倒过来：先问如何撤销，再问如何注册；先证明局部挂载不会泄漏，再讨论全局复用；先定义失败后保留哪一棵树，再讨论热更新速度。做到这些，时空可组合才是一组可以验证的运行时语义。</p>
<p data-tool="mdnice编辑器">这套架构个人理解是想往 Agent 的实时「自生长」，通过 AI 的能力在使用过程中让自己更强大。</p>
<p data-tool="mdnice编辑器">逼逼这么多，主要还是在这个过程中学习一下，说实话，有了 DeepSeek Harness，想自己开发一个专属的 Agent ，快捷方便了很多，eg且这是 MIT 协议的。</p>
<p data-tool="mdnice编辑器">以上。</p>
<h2 data-tool="mdnice编辑器"><span class="content" style="color: #ffffff;">参考资料</span></h2>
<ul data-tool="mdnice编辑器">
<li>
<section style="color: #010101;"><a style="font-weight: bold; color: #ef7060;" href="https://github.com/deepseek-ai/deepseek-harness/blob/master/docs/architecture.zh.md">DeepSeek Harness 架构文档</a></section>
</li>
<li>
<section style="color: #010101;"><a style="font-weight: bold; color: #ef7060;" href="https://github.com/cordiverse/cordis">Cordis：Meta-Framework of Spatiotemporal Composability</a></section>
</li>
<li>
<section style="color: #010101;"><a style="font-weight: bold; color: #ef7060;" href="https://osgi.github.io/osgi/core/framework.service.html">OSGi Service Layer</a></section>
</li>
<li>
<section style="color: #010101;"><a style="font-weight: bold; color: #ef7060;" href="https://www.osgi.org/resources/architecture/">OSGi Architecture</a></section>
</li>
<li>
<section style="color: #010101;"><a style="font-weight: bold; color: #ef7060;" href="https://www.eclipse.org/articles/Article-Plug-in-architecture/plugin_architecture.html">Eclipse Plug-in Architecture</a></section>
</li>
</ul>
</section>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2026/08/deepseek-harness-cordis/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
