<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>插件系统 · AI Times</title><link>https://blog.havenice.day/tag/%E6%8F%92%E4%BB%B6%E7%B3%BB%E7%BB%9F/</link><description>AI 时代，中年人倔强的记录</description><language>zh-CN</language><lastBuildDate>Fri, 11 Sep 2026 10:38:05 +0800</lastBuildDate><atom:link href="https://blog.havenice.day/tag/%E6%8F%92%E4%BB%B6%E7%B3%BB%E7%BB%9F/index.xml" rel="self" type="application/rss+xml"/><item><title>92 页论文，讲给普通开发者听：DeepSeek Harness 的插件内核为什么是对的</title><link>https://blog.havenice.day/2026/09/11/92-ye-lun-wen-jiang-gei-pu-tong-kai-fa-zhe-ting/</link><pubDate>Fri, 11 Sep 2026 10:38:05 +0800</pubDate><guid>https://blog.havenice.day/2026/09/11/92-ye-lun-wen-jiang-gei-pu-tong-kai-fa-zhe-ting/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;精读对象：&lt;strong&gt;arXiv:2608.25512&lt;/strong&gt;《A Programming Paradigm for Spatiotemporal Composability》&lt;/p&gt;&#10;&lt;p&gt;作者：&lt;strong&gt;Yifan Shi&lt;/strong&gt;（北京大学 / DeepSeek-AI）、&lt;strong&gt;Wei Zhang&lt;/strong&gt;（北京大学）、&lt;strong&gt;Tianyi Cui&lt;/strong&gt;（DeepSeek-AI）&lt;/p&gt;&#10;&lt;p&gt;提交：2026-08-26 · 92 页 · 1 图 2 表 · cs.PL + cs.SE&lt;/p&gt;&#10;&lt;p&gt;前情提要：上一篇《DeepSeek Harness 精读》讲了 Cordis &lt;strong&gt;怎么用&lt;/strong&gt;，这一篇讲它&lt;strong&gt;为什么是对的&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;h2 id="0-一句话速览"&gt;0. 一句话速览&lt;/h2&gt;&#10;&lt;p&gt;&lt;strong&gt;这不是一篇 AI 论文，是一篇编程语言（PL）论文。&lt;/strong&gt; 它给 DeepSeek Harness 的插件内核 &lt;strong&gt;Cordis v4&lt;/strong&gt; 补上了完整的数学地基。&lt;/p&gt;&#10;&lt;p&gt;作者名单里的 &lt;strong&gt;Yifan Shi&lt;/strong&gt;，就是 Koishi / Cordis 的作者 &lt;strong&gt;Shigma&lt;/strong&gt; —— 现在在 DeepSeek。论文自己也交代了：Koishi 跑在 Cordis v3 上，论文呈现的是 v4，核心组合模型两版共享。&lt;/p&gt;&#10;&lt;p&gt;所以这不是「又一篇 Agent 论文」。它是一次&lt;strong&gt;工程实践的回头总结&lt;/strong&gt;：一个从 2019 年一路长起来的框架、被 4000+ 社区插件压测了四年，终于有人把「它为什么 work」讲清楚了。&lt;/p&gt;&#10;&lt;p&gt;三个你在 dsh 里天天见到的东西，论文都给了正式答案：&lt;/p&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;你在 dsh 里看到的&lt;/th&gt;&#10;&lt;th&gt;论文里的名字&lt;/th&gt;&#10;&lt;th&gt;它证明了什么&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.effect()&lt;/code&gt; 返回 disposer，卸载自动撤销&lt;/td&gt;&#10;&lt;td&gt;可回滚效应&lt;br/&gt;Revertible Effects&lt;/td&gt;&#10;&lt;td&gt;卸载一个组件时，它撤回的&lt;strong&gt;只有它自己的&lt;/strong&gt;贡献&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;inject&lt;/code&gt; 声明依赖，服务就绪才启动&lt;/td&gt;&#10;&lt;td&gt;响应式余效应&lt;br/&gt;Reactive Coeffects&lt;/td&gt;&#10;&lt;td&gt;provider 撤回绑定&lt;strong&gt;之前&lt;/strong&gt;，所有依赖方一定已经停用&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;reload&lt;/code&gt; 不重启进程&lt;/td&gt;&#10;&lt;td&gt;合流定理&lt;br/&gt;Confluence&lt;/td&gt;&#10;&lt;td&gt;中途怎么折腾都无所谓，&lt;strong&gt;最终状态只取决于最终配置&lt;/strong&gt;&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="1-问题动态组合为什么一直没有理论"&gt;1. 问题：动态组合为什么一直没有理论&lt;/h2&gt;&#10;&lt;p&gt;论文标题里那个拗口的词 —— &lt;strong&gt;时空可组合性（spatiotemporal composability）&lt;/strong&gt; —— 其实是把「运行时装卸组件」这件事拆成了两个正交的维度。&lt;/p&gt;&#10;&lt;p&gt;动态组合的两个正交维度&#10;时间可组合性关注卸载时能否完整撤销副作用，空间可组合性关注组件间依赖的声明与解析&lt;/p&gt;&#10;&lt;p&gt;动态组合&lt;/p&gt;&#10;&lt;p&gt;时间可组合性&#10;卸载时完整撤销副作用&lt;/p&gt;&#10;&lt;p&gt;空间可组合性&#10;依赖的声明与响应式解析&lt;/p&gt;&#10;&lt;p&gt;VSCode 前 100 扩展 · 87 个含代码&lt;/p&gt;&#10;&lt;p&gt;VSCode 前 100 扩展 · 仅 7 个声明依赖&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;时间可组合性&lt;/strong&gt;管的是：组件被卸载时，它对共享环境做的修改必须被完整、安全地撤销。每一次资源分配、事件注册、状态变更都要能被追踪和回收。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;空间可组合性&lt;/strong&gt;管的是：组件必须能声明、发现、解析彼此的依赖，并在依赖出现或消失时协调各自的生命周期。&lt;/p&gt;&#10;&lt;p&gt;静态场景下这两件事都有现成答案：时间维度退化成词法作用域（RAII、bracket 模式），空间维度退化成模块导入解析。&lt;strong&gt;但一旦组件能在运行时来去，两边同时崩掉&lt;/strong&gt; —— 没有哪个词法作用域能框住一个部署后才加载的插件，也没有哪个编译期上下文能预测运行时配置里冒出来的依赖。&lt;/p&gt;&#10;&lt;h3 id="论文拿-vscode-开刀数据很扎心"&gt;论文拿 VSCode 开刀，数据很扎心&lt;/h3&gt;&#10;&lt;p&gt;插件系统是动态组合最典型的场景。论文挑了 VSCode 做样本，因为它最普及、也最经典：&lt;/p&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;维度&lt;/th&gt;&#10;&lt;th&gt;VSCode 的现状&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;时间&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;所有扩展跑在同一个 extension host 进程里。&lt;strong&gt;安装量前 100 的扩展里 87 个含可执行代码&lt;/strong&gt;，禁用或卸载任何一个，都得重启整个 host，影响所有已加载扩展。&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;空间&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;虽然提供了 &lt;code&gt;extensionDependencies&lt;/code&gt;，但&lt;strong&gt;前 100 里只有 7 个&lt;/strong&gt;声明了非内置扩展依赖。&lt;code&gt;getExtension(...).exports&lt;/code&gt; 返回 &lt;code&gt;any&lt;/code&gt;，完全没有类型契约。&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;论文对 &lt;code&gt;deactivate&lt;/code&gt; 钩子的批评特别值得记一笔：它不只是「不彻底」，而是&lt;strong&gt;把效果的销毁（&lt;code&gt;deactivate&lt;/code&gt;）和效果的创建（&lt;code&gt;activate&lt;/code&gt;）拆到了两个地方&lt;/strong&gt;，违反了关注的局部性 —— 于是「清理完整吗」这个问题，变成了一件无法验证的事。&lt;/p&gt;&#10;&lt;p&gt;顺带，论文也点了现有变通方案的本质：&lt;strong&gt;操作系统在「进程」粒度给了时间可组合性，容器编排器在「服务」粒度给了空间可组合性。&lt;/strong&gt; 代价是每次重启丢掉全部进程内状态（缓存、连接、部分计算），重建要几秒到几分钟；容器编排还&lt;strong&gt;无法表达共享地址空间内组件之间的依赖&lt;/strong&gt;，给本可以是本地函数调用的交互硬塞进一层网络开销。&lt;/p&gt;&#10;&lt;p&gt;论文给它起了个名字：&lt;strong&gt;粒度错配（granularity mismatch）&lt;/strong&gt;。现代系统越来越在更细的粒度上组合，而现有机制只在进程和容器的边界上工作。&lt;/p&gt;&#10;&lt;p&gt;对 AI agent 来说这事更致命。论文把「自进化 harness」列为头号动机，并指出最危险的一条：&lt;strong&gt;没有时间可组合性，一次错误的自我修改可能让恢复所需的那个进程本身瘫痪。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="2-时间维度让每个函数自带逆"&gt;2. 时间维度：让每个函数自带「逆」&lt;/h2&gt;&#10;&lt;p&gt;经典 effect system 和 coeffect system 都是&lt;strong&gt;静态工具&lt;/strong&gt;：效应在词法固定的作用域内被追踪、由编译期的 handler 处理；余效应注解针对执行前就确定的上下文验证。&lt;/p&gt;&#10;&lt;p&gt;论文的关键判断是：&lt;strong&gt;与其给静态类型系统继续加注解，不如把效应和余效应的概念结构「具体化」（reify），让运行时能直接操作它们。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;落到时间维度上，成果简单到有点意外：&lt;strong&gt;一个效应不是「一个函数」，而是「一个函数 + 它自己的逆」。&lt;/strong&gt; 类型写成这样：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;e : Γ → Γ × (Γ → Γ)&#10; ↑ ↑&#10; 新状态 撤销这次变换的逆&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;运行时把每一步返回的逆累积保存起来（论文叫它&lt;strong&gt;累加器&lt;/strong&gt;）。于是：&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;「卸载一个组件」就退化成「把累积的逆跑一遍」。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;可回滚效应：每个效应携带自己的逆&#10;组件加载时依次执行效应，每个效应返回新上下文和它自己的逆；逆按应用顺序累积进累加器，卸载时按 LIFO 逆序执行即可回到初始状态&lt;/p&gt;&#10;&lt;p&gt;状态 0&lt;/p&gt;&#10;&lt;p&gt;状态 1&lt;/p&gt;&#10;&lt;p&gt;状态 2&lt;/p&gt;&#10;&lt;p&gt;状态 3&lt;/p&gt;&#10;&lt;p&gt;效应 1&#10;效应 2&#10;效应 3&lt;/p&gt;&#10;&lt;p&gt;累加器 = 逆 1 ∘ 逆 2 ∘ 逆 3　（每个效应自带逆，按应用顺序累积）&lt;/p&gt;&#10;&lt;p&gt;卸载 = 把累加器跑一遍，逆序执行自动回到初始状态&lt;/p&gt;&#10;&lt;p&gt;最漂亮的一点是：&lt;strong&gt;LIFO 顺序是白送的&lt;/strong&gt;。逆按应用顺序累积、按相反顺序执行，正好每一次撤销都拿到「当初自己造成的那一个状态」。论文用一条定理把这个说死了（每步撤销都精确回到它自己的起点，且中间每个状态都满足可靠性不变量），不需要额外规则。&lt;/p&gt;&#10;&lt;p&gt;论文还点出一个我很喜欢的类比：&lt;strong&gt;效应迭代器本质上就是一个「具体化的定界续体」，也就是主流语言用 &lt;code&gt;yield&lt;/code&gt; 暴露的那个结构&lt;/strong&gt;。所以这套模型不是要发明什么新语言特性 —— 它直接落在语言已经给的 generator 上。&lt;/p&gt;&#10;&lt;h3 id="翻译成-cordis-的写法就是你在-dsh-里天天见的东西"&gt;翻译成 Cordis 的写法，就是你在 dsh 里天天见的东西&lt;/h3&gt;&#10;&lt;pre&gt;&lt;code&gt;ctx.effect(() =&amp;gt; {&#10; const onSignal = () =&amp;gt; shutdown()&#10; process.on('SIGINT', onSignal) // ← 正向：做一件事&#10; // 这个返回值就是论文里的「逆」&#10; return () =&amp;gt; process.off('SIGINT', onSignal)&#10;})&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;你返回的那个 &lt;code&gt;() =&amp;gt; ...&lt;/code&gt;，在论文里是有严格类型的对象：&lt;strong&gt;运行时持有它，卸载时按 LIFO 跑它&lt;/strong&gt;。所以你不需要写 uninstall 路径，也不需要记得清理 —— 这不是「方便」，是&lt;strong&gt;有证明的结构性保证&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="3-空间维度依赖操作本身就是效应"&gt;3. 空间维度：依赖操作本身就是效应&lt;/h2&gt;&#10;&lt;p&gt;依赖这边，论文先用一张部分函数表来建模，也就是 &lt;code&gt;key → 值&lt;/code&gt; 的映射，叫&lt;strong&gt;余效应上下文&lt;/strong&gt;。用类型族保证每个 key 关联到具体的值类型，访问依赖时类型是安全的。&lt;/p&gt;&#10;&lt;p&gt;然后是全篇最「啊哈」的一步。注册一个依赖的操作签名长这样：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code&gt;set(k, v) : Σ ⇀ Σ × (Σ ⇀ Σ)&#10; ↑ ↑&#10; 新状态 撤销这次注册的逆&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;&lt;strong&gt;这个类型恰好就是第 2 节那个可回滚效应函数的类型。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;也就是说：&lt;strong&gt;注册一个依赖，本身就是一次可回滚效应&lt;/strong&gt;，它返回的逆就是「把 k 从表里删掉」。论文的结论是 —— 依赖注册的追踪和恢复，&lt;strong&gt;完全不需要新机制，直接从时间那一半白嫖过来&lt;/strong&gt;。原文把这称为两种机制之间的 synergy：&lt;em&gt;余效应操作就是效应，而效应是可回滚的。&lt;/em&gt;&lt;/p&gt;&#10;&lt;p&gt;在这之上才是「响应式」。每次上下文发生变化，都会被对照组件声明的依赖清单（specification）分类成三种之一：&lt;/p&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;分类&lt;/th&gt;&#10;&lt;th&gt;含义&lt;/th&gt;&#10;&lt;th&gt;后果&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;activating&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;依赖从「不满足」变成「满足」&lt;/td&gt;&#10;&lt;td&gt;执行组件的效应（自动被追踪）&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;deactivating&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;依赖从「满足」变成「不满足」&lt;/td&gt;&#10;&lt;td&gt;跑累加器回滚（自动撤销）&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;neutral&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;满足性没变&lt;/td&gt;&#10;&lt;td&gt;什么都不做&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;这就是为什么在 dsh / Cordis 里，插件&lt;strong&gt;不需要自己轮询依赖、也不需要自己接事件总线&lt;/strong&gt; —— 你 &lt;code&gt;inject&lt;/code&gt; 声明一下，系统在依赖满足性变化的瞬间驱动你的生命周期。&lt;/p&gt;&#10;&lt;p&gt;论文还顺手加了两个机制，都很实用：&lt;/p&gt;&#10;&lt;h3 id="隔离isolation同一个-key不同上下文解析到不同的值"&gt;隔离（isolation）：同一个 key，不同上下文解析到不同的值&lt;/h3&gt;&#10;&lt;p&gt;论文说它&lt;strong&gt;本质上实现了一个运行时的 ad-hoc 多态系统&lt;/strong&gt; —— 而且这种多态可以在运行时动态调整。多租户、测试环境、组件沙箱都用得上。比如同一份「数据库」依赖，给社区插件注入只读实例，给核心插件注入完整权限实例，而两份代码都不用改。&lt;/p&gt;&#10;&lt;h3 id="拦截interception给依赖访问挂横切元数据"&gt;拦截（interception）：给依赖访问挂横切元数据&lt;/h3&gt;&#10;&lt;p&gt;关键是它的合并规则是&lt;strong&gt;右偏的&lt;/strong&gt;：外层上下文可以覆盖组件自己的声明。这意味着&lt;strong&gt;外层可以约束一个组件「如何使用」某个依赖，而不修改那个组件的代码&lt;/strong&gt;。这个特性在权限控制里会变成主要卖点（第 6 节展开）。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="4-最深刻的一点恢复不等于原样恢复"&gt;4. 最深刻的一点：恢复不等于「原样恢复」&lt;/h2&gt;&#10;&lt;p&gt;前面说「卸载把累加器跑一遍就回到初始状态」，论文很快就自己拆台了。&lt;/p&gt;&#10;&lt;p&gt;它举了两个例子：&lt;code&gt;free&lt;/code&gt; 把内存块还给分配器，但&lt;strong&gt;不会恢复&lt;/strong&gt; &lt;code&gt;malloc&lt;/code&gt; 之前堆的布局；一个「生成名」被丢弃后也恢复不了，因为下次创建会取一个新的。&lt;/p&gt;&#10;&lt;p&gt;物理状态根本没法原样恢复。所以论文做了一件很诚实的事：&lt;strong&gt;把「相等」降级成「观察等价」&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;定义是这样的：两个状态相关，当且仅当&lt;strong&gt;没有观察者能区分它们&lt;/strong&gt;。而「观察者」的定义才是精髓 —— &lt;strong&gt;观察一个值，就是跑它那个 key 提供的操作、读它们返回的结果。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;p&gt;于是这个等价关系是被&lt;strong&gt;接口本身&lt;/strong&gt;生成的。推论非常实用：&lt;/p&gt;&#10;&lt;p&gt;接口发布什么决定了什么可回滚&#10;只发布必要结果的接口让变更不可观察，因而可交换可回滚；多发布一个结果就会暴露顺序差异，破坏可交换性&lt;/p&gt;&#10;&lt;p&gt;可交换 · 可回滚&#10;路由注册 / 事件监听器注册&#10;mmap — 可返回任意未用地址&#10;每次注册有自己的条目，顺序观察不到&lt;/p&gt;&#10;&lt;p&gt;不可交换 · 无法回滚&#10;中间件有序链&#10;open — 必须返回最低可用 fd&#10;多暴露一个结果，顺序差异就可见&lt;/p&gt;&#10;&lt;p&gt;接口少发布一个结果 → 观察等价更粗 → 更多变更变得不可观察&#10;接口设计因此可以直接当成可组合性设计来用&lt;/p&gt;&#10;&lt;p&gt;论文里那组 POSIX 对照我看了好几遍，实在太漂亮：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;mmap&lt;/code&gt; &lt;strong&gt;允许返回任何未使用的地址&lt;/strong&gt;，所以没有操作能观察到「用了哪个地址」，两次分配就是可交换的。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;open&lt;/code&gt; &lt;strong&gt;必须返回最低可用的文件描述符&lt;/strong&gt; —— 单这一条要求，就让两次描述符分配不再可交换。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;同一个内核里的两个系统调用，成败就取决于&lt;strong&gt;接口多发布了一个结果&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;论文还提到一个细节：关于「分配器发出的 handle」，如果它的接口不比较这些 handle，那么两个堆在「handle 重命名」下就是等价的 —— 这正是 &lt;strong&gt;CompCert&lt;/strong&gt; 关联一个程序及其编译结果的内存状态的方式。&lt;/p&gt;&#10;&lt;p&gt;这条洞察可以直接拿去用：&lt;strong&gt;如果你在设计一个可热插拔的接口，「少发布一个返回值」不只是减少耦合，它直接把更多变更变成了「不可观察」，从而变得可回滚。&lt;/strong&gt;&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="5-从单个组件抬到整个系统"&gt;5. 从单个组件，抬到整个系统&lt;/h2&gt;&#10;&lt;p&gt;单个组件能干净装卸还不够 —— 真实系统是一堆组件交错运行。论文为此搭了三层对象：&lt;/p&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;概念&lt;/th&gt;&#10;&lt;th&gt;是什么&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;组件（component）&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;一个三元组：它需要的依赖 &lt;code&gt;d&lt;/code&gt;、它可能提供的 key &lt;code&gt;p&lt;/code&gt;、以及带见证的效应函数 &lt;code&gt;e&lt;/code&gt;&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;纤程（fiber）&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;组件的一次实例化，带自己的生命周期状态，和一份 &lt;strong&gt;committed view&lt;/strong&gt;（记录它激活时每个 key 由谁提供）。你在 Cordis 里看到的 &lt;code&gt;fiber&lt;/code&gt; 就是这个&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;注册表（registry）&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;所有纤程按名字挂载，父指针构成一棵树&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;有个设计细节特别能体现作者的谨慎：&lt;strong&gt;整个依赖表是「派生」出来的，不是存储的&lt;/strong&gt; —— 它就是所有处于激活状态的纤程共同提供的东西。而且不同纤程的「可提供集合」&lt;strong&gt;必须不相交&lt;/strong&gt;，于是每个 key 恰好有一个 provider。&lt;/p&gt;&#10;&lt;p&gt;规则一共九条，分两类：&lt;strong&gt;编排规则&lt;/strong&gt;是外部能请求的动作（插入 / 退休 / 移除），&lt;strong&gt;生命周期规则&lt;/strong&gt;是只要前提成立就自发发生的步骤。&lt;/p&gt;&#10;&lt;p&gt;其中**「退休」（Retire）和「移除」（Remove）是刻意分开的**，理由很实在：退休是一个&lt;strong&gt;请求&lt;/strong&gt;，所以无条件；而一个已退休但仍处于激活态的纤程，&lt;strong&gt;必须先被停用才能移除&lt;/strong&gt; —— 提前移除会丢弃累加器，直接泄漏。&lt;/p&gt;&#10;&lt;p&gt;这套演算最终换来六个结果，我用大白话列一下：&lt;/p&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;定理&lt;/th&gt;&#10;&lt;th&gt;大白话&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;Preservation&lt;/td&gt;&#10;&lt;td&gt;系统不会「跑坏」：良构性在每一步之后都保持&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;Recovery exactness&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;任意交错之后跑某个纤程的累加器，&lt;strong&gt;它撤回的只有它自己的贡献&lt;/strong&gt;，别人的一丝不动&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;Ordering&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;纤程只在依赖就位的地方启动；provider 只在所有依赖方都停用之后，才撤回绑定&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;Resolution coherence&lt;/td&gt;&#10;&lt;td&gt;一次过渡所依据的依赖解析，不会在它自己脚下移动&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;Progress&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;不会死锁，而且一定会终止 —— 每个最长的步骤序列都终结于「静止状态」&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;Confluence&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;无论中途怎么折腾、什么顺序，最终静止状态&lt;strong&gt;只取决于最终配置&lt;/strong&gt;&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;前两个就是「时间可组合性」和「空间可组合性」的全局版本 —— 从「一个组件自己成立」升级成「任意交错的一堆组件之间都成立」。&lt;/p&gt;&#10;&lt;p&gt;而 &lt;strong&gt;Confluence 是最有工程价值的那个&lt;/strong&gt;，因为它直接回答了：&lt;strong&gt;「配置热更新为什么是对的？」&lt;/strong&gt; loader 在做增量调和的时候，中途怎么插入、怎么退休、以什么顺序执行，全都无所谓 —— 系统最终会停在「从零加载最终配置」本该在的位置。这就是 §5.2 那套实现的合法性来源。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="6-落地理论--代码的对照"&gt;6. 落地：理论 ↔ 代码的对照&lt;/h2&gt;&#10;&lt;p&gt;Cordis 的实现分三层：&lt;strong&gt;核心库&lt;/strong&gt;（效应 / 余效应原语）→ &lt;strong&gt;组件加载器&lt;/strong&gt;（声明式配置、调和、热模块替换）→ &lt;strong&gt;应用框架&lt;/strong&gt;（Koishi 在第三层）。&lt;/p&gt;&#10;&lt;p&gt;论文的 Table 2 是一张理论到代码的对照表，几个有意思的映射：&lt;/p&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;论文里的&lt;/th&gt;&#10;&lt;th&gt;Cordis 里的&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;累加器&lt;/td&gt;&#10;&lt;td&gt;&lt;code&gt;fiber.dispose&lt;/code&gt;&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;committed view&lt;/td&gt;&#10;&lt;td&gt;&lt;code&gt;fiber.committed&lt;/code&gt;&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;插入 / 退休&lt;/td&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.use&lt;/code&gt; 及其回调的逆&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;生命周期状态&lt;/td&gt;&#10;&lt;td&gt;&lt;code&gt;fiber.state&lt;/code&gt;（LOADING 对应 Reloading）&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="一个顺带做成的安全特性"&gt;一个顺带做成的安全特性&lt;/h3&gt;&#10;&lt;p&gt;访问依赖有两条路：&lt;code&gt;ctx.get(key)&lt;/code&gt; 是反射式查找，&lt;strong&gt;永远不失败&lt;/strong&gt;；而 &lt;code&gt;ctx[key]&lt;/code&gt; 走 TypeScript 的 Proxy，&lt;strong&gt;沿纤程链向上解析&lt;/strong&gt; ——&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;遇到第一个 committed view 里绑定了这个 key 的纤程 → 授权，返回&lt;/li&gt;&#10;&lt;li&gt;遇到一个&lt;strong&gt;声明了但还没加载&lt;/strong&gt;的纤程 → 访问失败&lt;/li&gt;&#10;&lt;li&gt;一路走到 root 都没人声明 → 直接拒绝&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;这&lt;strong&gt;本身就是一层能力式访问控制&lt;/strong&gt;：组件只能访问它声明过的东西。而且因为声明是静态的，&lt;strong&gt;完整的权限集合在组件运行之前就已知&lt;/strong&gt; —— 编排器可以在加载的时候审查，而不是等到访问发生才发现。&lt;/p&gt;&#10;&lt;h3 id="koishi-的四年就是这套理论的对照组"&gt;Koishi 的四年，就是这套理论的对照组&lt;/h3&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;四年开发，积累了 &lt;strong&gt;4000+ 社区插件&lt;/strong&gt;（IM 适配器、数据库驱动、管理控制台、终端功能）&lt;/li&gt;&#10;&lt;li&gt;论文自己交代：Koishi 目前跑在 Cordis v3 上，论文里的 v4 精炼了效应/余效应语义并重写了 loader，核心组合模型两版共享&lt;/li&gt;&#10;&lt;li&gt;最有说服力的验证是**「时间可组合性没有认知开销」**：因为效应被自动追踪、逆被自动组合，&lt;strong&gt;一个没经验的插件作者也能拿到有序清理，完全不用写 uninstall 路径&lt;/strong&gt;&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;论文说，这才补上了 VSCode 那种「靠每个作者自己勤勉」的缺失 —— 正确性从「每个人的责任心」变成了&lt;strong&gt;由抽象一次性结清&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;p&gt;空间侧的验证同样实在：Koishi 的生态里有&lt;strong&gt;真实的依赖拓扑&lt;/strong&gt;。运行时切换存储后端，只会重新激活那些「解析结果真的变了」的依赖方；依赖暂时缺失的插件保持不活动、&lt;strong&gt;但不报错&lt;/strong&gt;。而关键在于，&lt;strong&gt;这一切跨独立作者成立&lt;/strong&gt; —— 插件和它的依赖通常由不同人写，除了连接它们的那个 key 之外，谁也不认识谁。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="7-作者自己承认的局限"&gt;7. 作者自己承认的局限&lt;/h2&gt;&#10;&lt;p&gt;这部分我挺欣赏，写得非常实在，没有硬撑：&lt;/p&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;局限&lt;/th&gt;&#10;&lt;th&gt;具体说明&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;案例研究是「存在性」的，不是定量的&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;只有 Koishi 一个生态、TypeScript 一种宿主语言，是观察性的，没有受控对照。抽象带来的&lt;strong&gt;开销、以及对开发效率的影响，论文没有测量&lt;/strong&gt;，明确留作未来工作&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;「无环」是假设，不是结论&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;Progress 和 Confluence 两条定理都建立在依赖优先关系无环的假设上。有环的后果只是相关组件永远不激活（好处是&lt;strong&gt;从声明就能提前预测&lt;/strong&gt;，不像并发死锁必须在运行时检测），但「拆环」会让集成组件的数量&lt;strong&gt;随组件数二次增长&lt;/strong&gt;&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;版本问题完全开放&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;形式模型只有&lt;strong&gt;按名字链接&lt;/strong&gt;，没有版本或结构化链接。于是有&lt;strong&gt;接口漂移&lt;/strong&gt;（provider 改了接口，消费者还声明同一个 key，依赖「满足」了但值不对）和 &lt;strong&gt;key 碰撞&lt;/strong&gt;（两个独立 provider 用同名 key 表示无关接口，消费者不做检查就接受）。Cordis 现在靠 peer dependencies 兜着，但这依赖大家遵守 semver，而包管理器通常只解析单一版本&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;边界外的东西回不了滚&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;论文把环境划成边界内 / 外。一次外部操作分两个阶段：&lt;strong&gt;获取&lt;/strong&gt;在边界内（装描述符、注册条目 —— 是可回滚效应），&lt;strong&gt;发射&lt;/strong&gt;跨到边界外（写出去的字节、发出去的消息 —— 表现为恒等变换）。事后要恢复只能靠&lt;strong&gt;扣留&lt;/strong&gt;（推迟发射，即经典的 output commit 问题）或&lt;strong&gt;补偿&lt;/strong&gt;（退款、删文件），而补偿「&lt;strong&gt;元理论不传递&lt;/strong&gt;」—— 交换性是针对观察等价证的，换成更粗的等价得重新证一遍&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;沙箱需要语言之外的机制&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;语言级的访问控制挡不住恶意组件（它能直接够到底层对象），必须靠软件故障隔离、独立运行时、沙箱进程或容器&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="8-可借鉴清单"&gt;8. 可借鉴清单&lt;/h2&gt;&#10;&lt;h3 id="认知层"&gt;认知层&lt;/h3&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;「注册即副作用，卸载即撤销」值得当成一条设计纪律。&lt;/strong&gt; 不只是 Cordis 的做法，而是一个可以迁移的原则：任何「装上去」的东西，都应该在安装的那一刻就定义好「怎么拆下来」，并且让框架替你拆。凡是把清理代码写在另一个地方的设计，迟早会漏。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;给「接口发布什么」这件事加一层思考。&lt;/strong&gt; 想让一个组件更容易被替换、被回滚，第一步不是加抽象，而是&lt;strong&gt;检查它的接口有没有发布不必要的返回值&lt;/strong&gt;。发布得越少，可观察的差异越少，能安全替换的实现就越多。POSIX 里 &lt;code&gt;mmap&lt;/code&gt; 和 &lt;code&gt;open&lt;/code&gt; 的对比是最好的教材。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;依赖用「声明」而不是「查找」。&lt;/strong&gt; 组件说「我需要什么」，而不是「我去哪里找什么」。声明可以静态审查、可以推导加载顺序、可以在依赖消失时自动停用 —— 查找做不到这些。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="架构层"&gt;架构层&lt;/h3&gt;&#10;&lt;ol start="4"&gt;&#10;&lt;li&gt;&lt;strong&gt;把「撤销」做成一等公民，而不是异常路径。&lt;/strong&gt; 如果你的系统有任何形式的动态加载（插件、工具、技能、子 agent），先保证两件事：每次注册都返回一个 disposer，且框架在卸载时&lt;strong&gt;逆序&lt;/strong&gt;执行它们。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;「退休」和「移除」分开。&lt;/strong&gt; 一个想下线的组件，应该先被标记、等它自然停用，再真正删除。直接删会丢掉它持有的撤销信息 —— 这是论文专门用一条规则强调的坑。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;热更新要有「最终状态只取决于最终配置」这个性质。&lt;/strong&gt; 如果你的增量更新做出来的结果，和「拿最终配置重启一次」不一样，那这个增量就是不可信的。Cordis 用一条合流定理把这个性质钉死了，自研系统至少应该把它当成测试断言。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;能力集合在加载前可知，比在访问时才拦截强得多。&lt;/strong&gt; 声明式的依赖清单天然就是一张权限表，可以在组件装载前审查。这是「声明式」相对「运行时反射」被低估的一个收益。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="可以直接去读的东西"&gt;可以直接去读的东西&lt;/h3&gt;&#10;&lt;ol start="8"&gt;&#10;&lt;li&gt;论文第 3.4.2 节关于「可交换性」的讨论，是全文最可迁移到日常接口设计的部分，配合 §6.6 一起读。&lt;/li&gt;&#10;&lt;li&gt;Cordis 源码只有 9 个模块（context / registry / fiber / events / service / reflect / logger / utils / index），&lt;code&gt;fiber.ts&lt;/code&gt; 是核心 —— 生命周期状态机加 effect 系统都在里面。&lt;/li&gt;&#10;&lt;li&gt;论文的 Table 2（理论↔实现对照表）值得单独保存，它是一张「读源码时该看哪里」的地图。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="9-风险与观望点"&gt;9. 风险与观望点&lt;/h2&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;点&lt;/th&gt;&#10;&lt;th&gt;说明&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;论文没有性能数据&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;全文没有 benchmark。效应追踪和依赖解析的运行时开销是多少，只能自己压测&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;单一生态验证&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;所有实证来自 Koishi + TypeScript，范式本身和其他语言实现的优劣还没有横向对比&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;「无环」需要自己保证&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;它不是被证明的，是假设。你的组件设计得自己盯着别写出环&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;版本语义还缺一块&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;这是论文明确列为「开放问题」的部分。生态越大，接口漂移和 key 碰撞的代价越明显&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="10-延伸阅读"&gt;10. 延伸阅读&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;论文原文：&lt;code&gt;arxiv.org/abs/2608.25512&lt;/code&gt;（92 页，但 §3 和 §4 的定理陈述部分读下来就够了）&lt;/li&gt;&#10;&lt;li&gt;Cordis 源码：&lt;code&gt;github.com/cordiverse/cordis&lt;/code&gt;（MIT）&lt;/li&gt;&#10;&lt;li&gt;DeepSeek Harness 里 vendor 的版本：&lt;code&gt;vendor/cordis&lt;/code&gt;，发布为 &lt;code&gt;@deepseek-ai/cordis&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;官方插件入门：&lt;code&gt;docs/cordis-primer.zh.md&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;前文：《DeepSeek Harness 精读：一个「一切皆插件」的 Agent 运行时》&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;p&gt;**一句话总结：**它把 effect 和 coeffect 从编译期的类型注解，变成运行时可操作的一等对象，让「运行时装卸组件」第一次有了完整的理论保证 —— 而这一切，已经被一个 4000+ 插件的生产系统验证了四年。&lt;/p&gt;&#10;</description></item><item><title>DeepSeek Harness 精读：一个「一切皆插件」的 Agent 运行时</title><link>https://blog.havenice.day/2026/08/26/deepseekharness-jing-du-yi-ge-yi-qie-jie-cha-jian-de-agent/</link><pubDate>Wed, 26 Aug 2026 18:25:59 +0800</pubDate><guid>https://blog.havenice.day/2026/08/26/deepseekharness-jing-du-yi-ge-yi-qie-jie-cha-jian-de-agent/</guid><description>&lt;blockquote&gt;&#10;&lt;p&gt;精读对象：github.com/deepseek-ai/deepseek-harness（dsh），2026-08-26 克隆自 master 分支&lt;br&gt;&#10;版本：0.1.x 开发者预览（rc 阶段）· MIT 许可&lt;br&gt;&#10;精读重点：&lt;strong&gt;轨迹日志（事件溯源）&lt;/strong&gt; 与 &lt;strong&gt;插件系统（Cordis / seam）&lt;/strong&gt; 两套核心设计&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="0-一句话速览"&gt;0. 一句话速览&lt;/h2&gt;&#10;&lt;p&gt;&lt;strong&gt;dsh 不是又一个 AI 编程工具，而是一个”Agent 外壳”的插件平台。&lt;/strong&gt; 它的核心命题是：&lt;code&gt;Agent = 模型 + Harness&lt;/code&gt;——模型只负责推理，Harness 负责把模型接进文件、命令、工具、会话、权限与界面。而它赌的架构是：&lt;strong&gt;Harness 本身没有特权内核，一切能力都是可插拔的插件&lt;/strong&gt;，包括模型适配器、工具、沙箱、会话日志，甚至 Agent 循环本身。&lt;/p&gt;&#10;&lt;p&gt;两套最值得读的设计：&lt;/p&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;设计&lt;/th&gt;&#10;&lt;th&gt;一句话概括&lt;/th&gt;&#10;&lt;th&gt;杀手锏&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;轨迹日志&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;会话 = 一条仅追加的事件日志，是唯一真源&lt;/td&gt;&#10;&lt;td&gt;“模型可见即已记录”——模型看到的一切都能从日志重建&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;插件系统&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;Cordis 微内核只管装配，能力按 seam（缝）三件套组织&lt;/td&gt;&#10;&lt;td&gt;换掉一个提供方就能改变整个产品，不用改源码&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="1-轨迹日志事件溯源式会话精读重点-1"&gt;1. 轨迹日志：事件溯源式会话（精读重点 #1）&lt;/h2&gt;&#10;&lt;h3 id="11-设计哲学模型可见即已记录"&gt;1.1 设计哲学：模型可见即已记录&lt;/h3&gt;&#10;&lt;p&gt;这是 dsh 的第一条铁律，由&lt;strong&gt;运行时不变量&lt;/strong&gt;强制断言：&lt;/p&gt;&#10;&lt;blockquote&gt;&#10;&lt;p&gt;&lt;strong&gt;抵达模型请求的一切都必须能从日志重建。&lt;/strong&gt; 新增任何一项模型可见输入，就必须新增一个会话事件类型。&lt;/p&gt;&#10;&lt;/blockquote&gt;&#10;&lt;p&gt;也就是说：日志不是”聊天记录的副本”，而是&lt;strong&gt;唯一真源&lt;/strong&gt;。LLM 的消息历史是从日志&lt;em&gt;派生&lt;/em&gt;出来的（&lt;code&gt;deriveMessages()&lt;/code&gt;），&lt;strong&gt;从不单独存储&lt;/strong&gt;。回放 = 用同一组事件重新派生一遍。&lt;/p&gt;&#10;&lt;p&gt;&lt;img src="https://blog.havenice.day/wp-content/uploads/2026/08/dsh-dataflow.png" alt="会话事件溯源数据流"&gt;&lt;/p&gt;&#10;&lt;p&gt;派生的好处：&lt;strong&gt;历史永远不会和日志不一致&lt;/strong&gt;——不存在”存了一份消息数组、又改了日志”的双写问题。所有下游消费方（UI 转录、遥测、会话标题、搜索索引）都从同一份事件流派生，各取所需。&lt;/p&gt;&#10;&lt;h3 id="12-事件词汇表日志里有什么"&gt;1.2 事件词汇表：日志里有什么&lt;/h3&gt;&#10;&lt;p&gt;&lt;code&gt;SessionEventMap&lt;/code&gt; 定义了事件类型，&lt;strong&gt;插件可以通过 TypeScript 声明合并扩展&lt;/strong&gt;（见 §2.4）。核心事件如下：&lt;/p&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;事件&lt;/th&gt;&#10;&lt;th&gt;作用&lt;/th&gt;&#10;&lt;th&gt;说明&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;turn/start&lt;/code&gt; / &lt;code&gt;turn/end&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;轮次边界&lt;/td&gt;&#10;&lt;td&gt;轮次 = 一次排空已接纳输入的过程；&lt;code&gt;turn/end&lt;/code&gt; 带结束原因&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;step/start&lt;/code&gt; / &lt;code&gt;step/end&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;步骤边界&lt;/td&gt;&#10;&lt;td&gt;步骤 = 一次模型请求 + 它触发的工具执行&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;user/message&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;用户输入&lt;/td&gt;&#10;&lt;td&gt;普通提示词、注入上下文（&lt;code&gt;agent.inject()&lt;/code&gt;）、目标续行共用一个类型，靠 &lt;code&gt;source&lt;/code&gt; 区分&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;assistant/chunk&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;&lt;strong&gt;原始流分片&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;token 级回放保真——UI 能逐字重现输出过程&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;assistant/message&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;组装后的模型回复&lt;/td&gt;&#10;&lt;td&gt;携带 &lt;code&gt;usage&lt;/code&gt;（token 记账随消息走）；中断的回复标记 &lt;code&gt;interrupted&lt;/code&gt;&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;tool/call&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;工具调用&lt;/td&gt;&#10;&lt;td&gt;&lt;strong&gt;保留模型产出的原始 JSON 参数&lt;/strong&gt;（未解析），&lt;code&gt;callId&lt;/code&gt; 与结果配对&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;tool/result&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;工具结果&lt;/td&gt;&#10;&lt;td&gt;可选携带 &lt;code&gt;error&lt;/code&gt; 和工具私有 &lt;code&gt;meta&lt;/code&gt;（如文件 diff 卡片）&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;todo/write&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;待办全量快照&lt;/td&gt;&#10;&lt;td&gt;整表替换、last-write-wins，故意不做成带 id 的条目&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;request/header&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;&lt;strong&gt;请求完整信封&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;调用配置 + 系统提示词 + 工具 schema 全量快照，每次变化记一份&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;request/context&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;路由元数据&lt;/td&gt;&#10;&lt;td&gt;提供方/模型/上下文窗口，容量变化时记录&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;session/end-seed&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;种子边界&lt;/td&gt;&#10;&lt;td&gt;标记”哪些事件是恢复/fork 继承的、哪些是本进程新写的”&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;几个细节非常见功力：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;&lt;code&gt;seq&lt;/code&gt; 必须连续&lt;/strong&gt;（&lt;code&gt;seq = log.length&lt;/code&gt;），因此不能从规范日志里过滤分片——连 &lt;code&gt;assistant/chunk&lt;/code&gt; 都必须无损保存。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;所有 &lt;code&gt;data&lt;/code&gt; 必须是可无损 JSON 序列化的&lt;/strong&gt;。&lt;code&gt;Session.append()&lt;/code&gt; 在写入前做一次递归校验（BigInt、函数、循环引用、Map/Set 一律拒绝），&lt;strong&gt;坏事件在源头就失败&lt;/strong&gt;，绝不让错误进入日志。这对”日志即真源”是底线保障。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;热路径不阻塞 I/O&lt;/strong&gt;：追加是同步进内存，持久化插件异步批量落盘。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="13-surface-机制如何从日志长出模型历史"&gt;1.3 Surface 机制：如何从日志”长”出模型历史&lt;/h3&gt;&#10;&lt;p&gt;不是所有事件都投影成消息。只有 3 种”产生消息”的事件（&lt;code&gt;user/message&lt;/code&gt;、&lt;code&gt;assistant/message&lt;/code&gt;、&lt;code&gt;tool/result&lt;/code&gt;）携带 &lt;code&gt;surfaceOp&lt;/code&gt;，声明自己如何加入有序的派生 surface：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;code&gt;append&lt;/code&gt;：普通尾部追加。&lt;/li&gt;&#10;&lt;li&gt;&lt;code&gt;replace&lt;/code&gt;：&lt;strong&gt;遮蔽&lt;/strong&gt;从 start 到 end 的一段旧节点，在原位插入新事件。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;&lt;code&gt;replace&lt;/code&gt; 是&lt;strong&gt;压缩（compaction）&lt;/strong&gt; 的落点：上下文太长时，压缩插件把一段旧历史折叠成一条摘要，用 &lt;code&gt;replace&lt;/code&gt; 遮蔽旧节点——&lt;strong&gt;日志本身一个字不删&lt;/strong&gt;，只是”模型视野”里那一段被摘要替代了。这就是”日志永远可审计、只被遮蔽、不被删除”。&lt;/p&gt;&#10;&lt;p&gt;每个 surface 事件还携带 &lt;code&gt;sourceEventSeqs&lt;/code&gt;（引用了哪些早期事件），比如 &lt;code&gt;assistant/message&lt;/code&gt; 会引用构成它的 &lt;code&gt;assistant/chunk&lt;/code&gt; 序号。压缩时被遮蔽的节点也必须在 &lt;code&gt;sourceEventSeqs&lt;/code&gt; 里列全——&lt;strong&gt;血缘可追溯&lt;/strong&gt;。&lt;/p&gt;&#10;&lt;h3 id="14-持久化与崩溃恢复"&gt;1.4 持久化与崩溃恢复&lt;/h3&gt;&#10;&lt;p&gt;持久化本身是一个 &lt;strong&gt;seam&lt;/strong&gt;（见 §2.3）：&lt;code&gt;ctx.sessions&lt;/code&gt; 只做内存事件存储，持久化由插件订阅 &lt;code&gt;session/event&lt;/code&gt; 完成。&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;flush 检查点&lt;/strong&gt;：&lt;code&gt;session/flush&lt;/code&gt; 是显式耐久屏障；日常写入走异步批量缓冲（固定时间窗，窗口内事件不重置截止时间）。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;两个可互换后端&lt;/strong&gt;：JSONL（逐会话追加日志，默认 Zstandard 压缩 + checksum，原子写入）和 SQLite（schema 17，同一分片块内字段完全匹配的 delta 段做有界物理存储）。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;崩溃恢复的优雅之处&lt;/strong&gt;：重新加载时发现一个”开了 &lt;code&gt;turn/start&lt;/code&gt; 却没有 &lt;code&gt;turn/end&lt;/code&gt;“的轮次，&lt;strong&gt;不截断日志&lt;/strong&gt;（长任务里一个轮次可能很大，删了就是丢数据），而是合成一个 &lt;code&gt;turn/end { kind: 'interrupted' }&lt;/code&gt; 把它配平——这是唯一一个不由循环发出的结束原因。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;格式拒绝&lt;/strong&gt;：遇到版本更新的日志、或未知的&lt;em&gt;必需&lt;/em&gt;事件类型（没有 &lt;code&gt;ignorable&lt;/code&gt; 标记），后端&lt;strong&gt;拒绝加载而不是静默跳过&lt;/strong&gt;——因为”跳过一条可能改变整体解读的事件”比”拒绝”危险得多。新格式明确提示”由更新的 harness 写入，请升级”。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;fork / resume&lt;/strong&gt;：可以从任意稳定轮次间位置 fork；恢复时元数据里存了 &lt;code&gt;agentPreset&lt;/code&gt;——因为 preset 决定工具和提示词，&lt;strong&gt;恢复成不同的组合等于让模型回放一段它无法再行动的历史&lt;/strong&gt;。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;h3 id="15-为什么说这是杀手锏"&gt;1.5 为什么说这是杀手锏&lt;/h3&gt;&#10;&lt;p&gt;对跑 Agent 的人来说，最贵的成本是”&lt;strong&gt;它到底为什么搞砸了&lt;/strong&gt;“。dsh 的答案：日志里什么都有，且保证能重建。调试一个跑了 50 步的 Agent 任务，可以回放、定位到出错的那一步、看当时模型看到的完整上下文、连原始流分片都在。这同时是审计、基准测试（同一任务换模型对比）、以及多 Agent 协作排障的基础设施。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="2-插件系统cordis-微内核--能力-seam精读重点-2"&gt;2. 插件系统：Cordis 微内核 + 能力 seam（精读重点 #2）&lt;/h2&gt;&#10;&lt;h3 id="21-五个核心概念cordis-入门"&gt;2.1 五个核心概念（Cordis 入门）&lt;/h3&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;概念&lt;/th&gt;&#10;&lt;th&gt;含义&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;插件&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;实现 Service 的对象（函数 + &lt;code&gt;apply(ctx)&lt;/code&gt; 或 Service 子类），生命周期由 Cordis 管理&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;上下文&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;服务的容器。服务占据稳定的 &lt;code&gt;ctx.&amp;lt;key&amp;gt;&lt;/code&gt;（如 &lt;code&gt;ctx.llm&lt;/code&gt;、&lt;code&gt;ctx.tools&lt;/code&gt;），其他插件&lt;strong&gt;按 key 查找服务，绝不 import 具体实现&lt;/strong&gt;&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;inject 声明依赖&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;插件声明所需服务后，会等待服务就绪才启动——加载顺序由依赖表达，而非手动编排&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;类型化事件&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;服务通过声明合并注册事件名，以 4 种模式分发（见下）&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;注册是可逆副作用&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;所有注册（提示词片段、工具 schema、监听器）都是副作用，&lt;strong&gt;插件卸载时自动撤销&lt;/strong&gt;&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="22-事件分发模式一鱼四吃"&gt;2.2 事件分发模式：一鱼四吃&lt;/h3&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;模式&lt;/th&gt;&#10;&lt;th&gt;语义&lt;/th&gt;&#10;&lt;th&gt;典型用途&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;emit&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;监听器按注册顺序观察，不等待、无返回值&lt;/td&gt;&#10;&lt;td&gt;广播事实（如 &lt;code&gt;session/event&lt;/code&gt;）&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;waterfall&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;&lt;strong&gt;环绕中间件&lt;/strong&gt;：监听器收到 &lt;code&gt;(...args, next)&lt;/code&gt;，可包装、改写，&lt;strong&gt;不调 next 直接返回 = 短路&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;拦截/决策（如 &lt;code&gt;agent/pre-step&lt;/code&gt;、&lt;code&gt;tools/pre-execute&lt;/code&gt;）&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;parallel&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;所有监听器并行，await 全部&lt;/td&gt;&#10;&lt;td&gt;耐久检查点（如 &lt;code&gt;session/flush&lt;/code&gt;）&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;serial&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;按序执行、有返回值&lt;/td&gt;&#10;&lt;td&gt;顺序决策（如 &lt;code&gt;agent/turn-stopping&lt;/code&gt;）&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;code&gt;waterfall&lt;/code&gt; 是最聪明的：&lt;strong&gt;策略监听器拥有决策权时可以短路&lt;/strong&gt;（比如”这条工具调用禁止执行”），而只做观察的监听器必须调 &lt;code&gt;next()&lt;/code&gt; 委托下去。拦截、审批、限流、改写提示词全部可以用事件挂上去，不碰核心。&lt;/p&gt;&#10;&lt;h3 id="23-能力-seam可替换能力的三件套"&gt;2.3 能力 seam：可替换能力的”三件套”&lt;/h3&gt;&#10;&lt;p&gt;一个 &lt;strong&gt;seam&lt;/strong&gt; 包含三种角色：&lt;/p&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;Service Definition&lt;/strong&gt;：声明接口，拥有自己的 &lt;code&gt;ctx.&amp;lt;key&amp;gt;&lt;/code&gt;（如 &lt;code&gt;ShellExecutor&lt;/code&gt; 抽象类）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Service Provider&lt;/strong&gt;：实现该接口（可以有多个，可互换）&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;Consumer&lt;/strong&gt;：消费该服务的插件（通常是面向模型的工具）&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;p&gt;规范范例——shell 能力：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-text"&gt;ctx.shell（Service Definition）&#10;├── dsh-bash-local （Provider：本地 bash）&#10;├── dsh-bash-sandbox （Provider：沙箱 bash）&#10;├── dsh-pwsh-local （Provider：本地 PowerShell）&#10;└── dsh-tool-bash （Consumer：面向模型的 bash 工具）&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;&lt;strong&gt;替换一个提供方就能改变整个产品&lt;/strong&gt;：把 &lt;code&gt;bash-local&lt;/code&gt; 换成 &lt;code&gt;bash-sandbox&lt;/code&gt;，所有消费 &lt;code&gt;ctx.shell&lt;/code&gt; 的消费方（bash 工具、钩子桥接）自动获得沙箱保护，&lt;strong&gt;消费方零改动&lt;/strong&gt;。文件系统、子进程、沙箱、搜索、凭据、存储、技能……整个平台都是按这个模式组织的。&lt;/p&gt;&#10;&lt;p&gt;seam 生态（部分代表性服务）：&lt;/p&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;ctx 键&lt;/th&gt;&#10;&lt;th&gt;类型&lt;/th&gt;&#10;&lt;th&gt;可换提供方&lt;/th&gt;&#10;&lt;th&gt;说明&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.llm&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;seam&lt;/td&gt;&#10;&lt;td&gt;deepseek / pi-ai / replay&lt;/td&gt;&#10;&lt;td&gt;模型适配器注册表，agent loop 提供方无关地调流式服务&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.sessionPersistence&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;seam&lt;/td&gt;&#10;&lt;td&gt;jsonl / sqlite&lt;/td&gt;&#10;&lt;td&gt;会话持久化，应用组合时选后端&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.shell&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;seam&lt;/td&gt;&#10;&lt;td&gt;bash-local / bash-sandbox / pwsh-local&lt;/td&gt;&#10;&lt;td&gt;Bash 执行器&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.fs&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;seam&lt;/td&gt;&#10;&lt;td&gt;fs-local / fs-sandbox / fs-e2b&lt;/td&gt;&#10;&lt;td&gt;文件系统&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.subagents&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;seam&lt;/td&gt;&#10;&lt;td&gt;6 个提供方&lt;/td&gt;&#10;&lt;td&gt;从进程内 fork，到委派给 Claude Code / Codex 进程&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.web&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;seam&lt;/td&gt;&#10;&lt;td&gt;exa / perplexity / deepseek / http-fetch&lt;/td&gt;&#10;&lt;td&gt;搜索与抓取&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.skills&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;seam&lt;/td&gt;&#10;&lt;td&gt;badge / filesystem&lt;/td&gt;&#10;&lt;td&gt;&lt;strong&gt;技能注册表&lt;/strong&gt;——&lt;code&gt;tool-skill&lt;/code&gt; 渲染会话前缀目录并加载 skill 正文&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.approval&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;seam&lt;/td&gt;&#10;&lt;td&gt;acp&lt;/td&gt;&#10;&lt;td&gt;一次性权限决策&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.credentials&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;seam&lt;/td&gt;&#10;&lt;td&gt;credentials-local&lt;/td&gt;&#10;&lt;td&gt;凭据&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.storage&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;seam&lt;/td&gt;&#10;&lt;td&gt;json / sqlite&lt;/td&gt;&#10;&lt;td&gt;非会话存储&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.sessions&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;core&lt;/td&gt;&#10;&lt;td&gt;—&lt;/td&gt;&#10;&lt;td&gt;仅追加事件日志（真源）&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.tools&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;core&lt;/td&gt;&#10;&lt;td&gt;—&lt;/td&gt;&#10;&lt;td&gt;工具注册表 + 带把关的执行流水线&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.agents&lt;/code&gt; / &lt;code&gt;ctx.agentLoop&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;core&lt;/td&gt;&#10;&lt;td&gt;—&lt;/td&gt;&#10;&lt;td&gt;Agent 注册表 + 唯一具体循环驱动&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.invariants&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;core&lt;/td&gt;&#10;&lt;td&gt;—&lt;/td&gt;&#10;&lt;td&gt;配套不变量注册表（运行时自检）&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;h3 id="24-无特权内核的两个关键机制"&gt;2.4 无特权内核的两个关键机制&lt;/h3&gt;&#10;&lt;p&gt;&lt;strong&gt;① Map → derived-union 扩展模式。&lt;/strong&gt; 几乎所有可扩展的联合类型都遵循同一模式：接口以判别标签为 key（&lt;code&gt;ThingMap&lt;/code&gt;），联合类型由 &lt;code&gt;keyof&lt;/code&gt; 派生。插件通过 &lt;strong&gt;TypeScript 声明合并&lt;/strong&gt;添加变体——&lt;strong&gt;不需要修改拥有该类型的包&lt;/strong&gt;：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-ts"&gt;declare module '@deepseek-ai/dsh-llm' {&#10; interface ContentBlockMap {&#10; 'c': { kind: 'c'; /* … */ }&#10; }&#10;}&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;六个规范 map（含 &lt;code&gt;SessionEventMap&lt;/code&gt;、&lt;code&gt;TurnEndReasonMap&lt;/code&gt;）都这么干。代价是约定：对这类联合类型做 &lt;code&gt;switch&lt;/code&gt; 时禁止 &lt;code&gt;assertNever&lt;/code&gt;——插件添加的变体是合法的未知值，&lt;code&gt;default&lt;/code&gt; 分支必须放行。&lt;/p&gt;&#10;&lt;p&gt;&lt;strong&gt;② 注册即副作用，卸载即撤销。&lt;/strong&gt; 扩展 dsh 的方式就是”把插件挂载到其他插件旁边”，不存在需要打补丁的特权内核。每个注册要么从 &lt;code&gt;ctx.effect()&lt;/code&gt; 返回一个 disposer，要么用 Cordis 辅助方法自动处理——&lt;strong&gt;reload 和 teardown 时按预期撤销&lt;/strong&gt;。连 Agent 循环本身都是可换的。&lt;/p&gt;&#10;&lt;h3 id="25-装配profile-与组合包"&gt;2.5 装配：profile 与组合包&lt;/h3&gt;&#10;&lt;p&gt;运行中的 dsh 是一棵&lt;strong&gt;插件树&lt;/strong&gt;，由启动时按序叠加的各层组成：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;profile&lt;/strong&gt;（web / headless）：具名组装，列出叠放的组合包，保存用户的 &lt;code&gt;cordis.patch.yml&lt;/code&gt;。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;组合包&lt;/strong&gt;（bundle）：配置项 + 挂载代码的分发格式；&lt;code&gt;dsh-base&lt;/code&gt; 是第一层（模型/工具/持久化/沙箱/审批/设置/凭据/遥测），&lt;code&gt;dsh-web-app&lt;/code&gt; 加浏览器应用。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;patch 覆盖&lt;/strong&gt;：任何条目都可以被上层 patch 替换——&lt;code&gt;dsh --profile web --dump-config&lt;/code&gt; 打印真实配置树，&lt;strong&gt;打印出的任何条目都能被你的 patch 替换&lt;/strong&gt;。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;p&gt;这就是”配置层可换任意能力”的落点：换模型端点、换执行工作流、换 UI，都不碰源码，只改 YAML。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="3-agent-循环轮次--步骤--scope--inbox"&gt;3. Agent 循环：轮次 / 步骤 / scope / inbox&lt;/h2&gt;&#10;&lt;p&gt;一个轮次按同一条循环流经 6 个核心包：&lt;/p&gt;&#10;&lt;pre&gt;&lt;code class="language-text"&gt;认领输入 → 开轮次(turn/start) → 组装提示词+工具schema → 从日志派生历史&#10;→ 模型流式请求(llm/stream) → 工具执行(tools/*) → 每个模型可见事实追加回日志 → 关轮次&#10;&lt;/code&gt;&lt;/pre&gt;&#10;&lt;p&gt;值得抄的设计点：&lt;/p&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;&lt;strong&gt;scope（作用域）&lt;/strong&gt;：按 agent 划分注册单位，只有”全局”和”恰好属于一个 agent”两层。&lt;strong&gt;shadowing 机制&lt;/strong&gt;——带作用域的工具/提示词片段在该 scope 内替换同名全局项，这是”按 agent 定制 persona 和工具集”的机制。过滤掉的工具既不出现在提示词里、也拒绝执行，&lt;strong&gt;与不存在的工具无法区分&lt;/strong&gt;（安全特性）。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;inbox（收件箱）&lt;/strong&gt;：agent 拥有两条有序待处理列表——&lt;code&gt;next-turn&lt;/code&gt;（普通续问）和 &lt;code&gt;next-step&lt;/code&gt;（steering 中途引导）；&lt;code&gt;inject()&lt;/code&gt; 注入上下文&lt;strong&gt;不唤醒&lt;/strong&gt;驱动，留到下一个步骤边界。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;拦截决策&lt;/strong&gt;：&lt;code&gt;agent/pre-step&lt;/code&gt; 是请求派生前唯一的串行监听器链，可改写甚至&lt;strong&gt;拒绝&lt;/strong&gt;进入步骤的消息（拒绝仍会记录一个空轮次——日志记录这次尝试本身）；&lt;code&gt;agent/request-error&lt;/code&gt; 监听器可以返回 &lt;code&gt;{ kind: 'retry' }&lt;/code&gt; 拥有失败恢复。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;取消&lt;/strong&gt;：&lt;code&gt;cancel(cause)&lt;/code&gt; 带类型化原因（user / parent / hook / disposed），持久日志保留粗粒度 &lt;code&gt;aborted&lt;/code&gt;，&lt;strong&gt;谁请求的取消不塞进终态结果&lt;/strong&gt;（那是另一类持久事件的职责）。&lt;/li&gt;&#10;&lt;/ul&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="4-与-workbuddy-对照同行不同路"&gt;4. 与 WorkBuddy 对照：同行不同路&lt;/h2&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;能力&lt;/th&gt;&#10;&lt;th&gt;dsh 的答案&lt;/th&gt;&#10;&lt;th&gt;WorkBuddy 的答案&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;扩展机制&lt;/td&gt;&#10;&lt;td&gt;Cordis 插件树，&lt;strong&gt;配置层可换任意能力&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;Skill 技能 + Expert 专家 + Connector 连接器（MCP）&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;会话记忆&lt;/td&gt;&#10;&lt;td&gt;&lt;strong&gt;事件溯源日志&lt;/strong&gt;，模型可见即已记录，可回放&lt;/td&gt;&#10;&lt;td&gt;三层记忆（云端画像 / 用户级 / 工作区日志）+ 会话历史检索&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;子 Agent&lt;/td&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.subagents&lt;/code&gt; 6 个提供方（进程内 / Claude Code / Codex）&lt;/td&gt;&#10;&lt;td&gt;子 Agent + Team 多智能体协作&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;技能系统&lt;/td&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.skills&lt;/code&gt; + tool-skill 从文件系统加载技能目录&lt;/td&gt;&#10;&lt;td&gt;&lt;code&gt;~/.workbuddy/skills/&lt;/code&gt; 技能目录（同构！）&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;权限&lt;/td&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.approval&lt;/code&gt; + permission-presets 预设表&lt;/td&gt;&#10;&lt;td&gt;权限系统 + 沙箱&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;斜杠命令&lt;/td&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.commands&lt;/code&gt;（不经过模型轮次）&lt;/td&gt;&#10;&lt;td&gt;/ 命令体系&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;后台任务&lt;/td&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.jobs&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;后台任务 / 自动化&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;计划模式&lt;/td&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.planMode&lt;/code&gt;&lt;/td&gt;&#10;&lt;td&gt;Plan 模式&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;沙箱&lt;/td&gt;&#10;&lt;td&gt;&lt;code&gt;ctx.sandbox&lt;/code&gt; / &lt;code&gt;ctx.fs&lt;/code&gt; / &lt;code&gt;ctx.shell&lt;/code&gt; 三 seam&lt;/td&gt;&#10;&lt;td&gt;Bash 沙箱&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;形态&lt;/td&gt;&#10;&lt;td&gt;开源 MIT，&lt;code&gt;npx @deepseek-ai/dsh web&lt;/code&gt; 一行起&lt;/td&gt;&#10;&lt;td&gt;商业产品，桌面 IDE 开箱即用&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;最有趣的发现：&lt;strong&gt;dsh 的 &lt;code&gt;ctx.skills&lt;/code&gt; 与 WorkBuddy 的 skill 目录是同一种东西&lt;/strong&gt;——都是”技能提供方注册表 + 从文件系统加载技能正文 + 渲染进会话前缀”。你在 WorkBuddy 里积累 skill 的路线，被 dsh 印证为行业共识。&lt;/p&gt;&#10;&lt;p&gt;而 WorkBuddy 目前&lt;strong&gt;没有&lt;/strong&gt;的是 dsh 的”事件溯源级完整轨迹”：WorkBuddy 有记忆沉淀，但不是”每次工具调用、每个原始 chunk 都可回放”的完整日志。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="5-可借鉴清单结合你的项目"&gt;5. 可借鉴清单（结合你的项目）&lt;/h2&gt;&#10;&lt;h3 id="51-认知层直接吸收"&gt;5.1 认知层：直接吸收&lt;/h3&gt;&#10;&lt;ol&gt;&#10;&lt;li&gt;&lt;strong&gt;轨迹复盘习惯&lt;/strong&gt;：给 teammate 的每个投资决策、每篇博客内容生产，养成”过程可留痕”的习惯——关键节点（判断、工具结果、中途修改）记成结构化条目，事后可回放、可归因。WorkBuddy 的会话记忆 + 工作区日志已经是雏形，把它用得更狠。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;“模型可见即已记录”是调试的底线&lt;/strong&gt;：多 agent 协作（teammate 6 个 agent）出问题，最贵的是”不知道哪一步错了”。任何 AI 交互系统，&lt;strong&gt;先保证输入输出有完整留痕，再谈别的&lt;/strong&gt;。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;场景化运行模式&lt;/strong&gt;：dsh 有 Standard / Code / Minimal / Creator 四模式，WorkBuddy 有 Craft / Plan / Ask——”按任务类型切换运行形态”已是行业共识，你现在的用法是对的。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="52-架构层可落到自己的代码"&gt;5.2 架构层：可落到自己的代码&lt;/h3&gt;&#10;&lt;ol start="4"&gt;&#10;&lt;li&gt;&lt;strong&gt;事件溯源代替”直接存消息数组”&lt;/strong&gt;：如果你给《族谱》小程序或投资系统做 AI 会话持久化，参考 dsh 的模式——只追加事件日志（&lt;code&gt;user&lt;/code&gt; / &lt;code&gt;assistant_chunk&lt;/code&gt; / &lt;code&gt;assistant&lt;/code&gt; / &lt;code&gt;tool_call&lt;/code&gt; / &lt;code&gt;tool_result&lt;/code&gt; / &lt;code&gt;header&lt;/code&gt;），历史由投影派生。收益：永不双写、可回放、可 fork、压缩只遮蔽不删除。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;seam 三件套组织扩展&lt;/strong&gt;：定义接口 / 提供方实现 / 消费方分离，&lt;strong&gt;消费方只依赖接口&lt;/strong&gt;。teammate 的 6 个 agent 如果共享接口定义，换模型、换数据源都不动其他 agent。这是 dsh 全文最值得抄的组织模式。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;崩溃恢复”不截断、合成结束标记”&lt;/strong&gt;：长任务中断后恢复，别删尾部，合成一个 &lt;code&gt;interrupted&lt;/code&gt; 结束标记配平——数据永远不丢。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;坏数据在源头拒绝&lt;/strong&gt;：写日志前做序列化校验（拒绝不可 JSON 序列化的 payload），宁可在写入时报错，也不让坏事件进入真源。&lt;/li&gt;&#10;&lt;li&gt;&lt;strong&gt;waterfall 事件做策略&lt;/strong&gt;：需要做”拦截/审批/改写”的地方，用”可短路的环绕中间件”而不是硬编码 if-else——策略与主流程解耦，还能按需叠加。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;h3 id="53-生态层可抄的现成组件"&gt;5.3 生态层：可抄的现成组件&lt;/h3&gt;&#10;&lt;ol start="9"&gt;&#10;&lt;li&gt;dsh 的技能、子 agent 多后端、session-query（会话全文搜索）、compaction（上下文压缩）都是独立包，&lt;strong&gt;概念可以直接移植&lt;/strong&gt;到你自己的架构里，不用抄代码。&lt;/li&gt;&#10;&lt;/ol&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="6-风险与观望点"&gt;6. 风险与观望点&lt;/h2&gt;&#10;&lt;table&gt;&#10;&lt;thead&gt;&#10;&lt;tr&gt;&#10;&lt;th&gt;风险&lt;/th&gt;&#10;&lt;th&gt;说明&lt;/th&gt;&#10;&lt;/tr&gt;&#10;&lt;/thead&gt;&#10;&lt;tbody&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;0.1.x 开发者预览&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;8/13 发布，API 与磁盘格式都在快速演进，&lt;code&gt;SESSION_FORMAT_VERSION&lt;/code&gt; 明确&lt;strong&gt;不做迁移&lt;/strong&gt;——旧日志可能打不开&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;Star 数有水分&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;一周 17 万 star 明显含大量”先收藏再说”，真实工程采纳率未验证&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;生态起步期&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;&lt;code&gt;dsh-plugin&lt;/code&gt; npm 话题刚形成，成熟插件少；Cordis 是 vendor 进来的第三方内核，上游风险要看 cordiverse/cordis 的维护&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;定位窄&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;它只是 harness（外壳），不提供模型、不做训练、不做 RAG 中间件——别指望开箱即用的”完整 Agent 应用”&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;tr&gt;&#10;&lt;td&gt;&lt;strong&gt;对普通用户不友好&lt;/strong&gt;&lt;/td&gt;&#10;&lt;td&gt;是给开发者/平台构建者的积木，日常用户仍应待在 WorkBuddy 这类成品里&lt;/td&gt;&#10;&lt;/tr&gt;&#10;&lt;/tbody&gt;&#10;&lt;/table&gt;&#10;&lt;p&gt;&lt;strong&gt;结论：&lt;/strong&gt; 值得读源码和文档（尤其是 &lt;code&gt;docs/subsystems/&lt;/code&gt; 和 &lt;code&gt;docs/cookbook/&lt;/code&gt;），作为”下一代 Agent 平台”的免费教材；但&lt;strong&gt;别急着上生产&lt;/strong&gt;，等它到 1.0 或生态稳定再考虑作为自建底座。&lt;/p&gt;&#10;&lt;hr&gt;&#10;&lt;h2 id="7-延伸阅读"&gt;7. 延伸阅读&lt;/h2&gt;&#10;&lt;ul&gt;&#10;&lt;li&gt;架构总览：&lt;code&gt;docs/architecture.zh.md&lt;/code&gt;（含轮次流程图）&lt;/li&gt;&#10;&lt;li&gt;轨迹日志：&lt;code&gt;docs/subsystems/session.zh.md&lt;/code&gt; → &lt;code&gt;docs/subsystems/persistence.zh.md&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;插件系统：&lt;code&gt;docs/cordis-primer.zh.md&lt;/code&gt; → &lt;code&gt;docs/capability-seams.zh.md&lt;/code&gt; → &lt;code&gt;docs/event-producer-consumer.zh.md&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;Agent 循环：&lt;code&gt;docs/subsystems/core.zh.md&lt;/code&gt;&lt;/li&gt;&#10;&lt;li&gt;术语表：&lt;code&gt;docs/glossary.zh.md&lt;/code&gt;（seam / scope / turn / step 的规范定义）&lt;/li&gt;&#10;&lt;li&gt;扩展实操：&lt;code&gt;docs/cookbook/extension-cookbook.zh.md&lt;/code&gt;（加工具 / 加 LLM 适配器 / 加 Chat 节点分步指南）&lt;/li&gt;&#10;&lt;li&gt;本地源码：本仓库已克隆至 &lt;code&gt;dsh-src/&lt;/code&gt;（&lt;code&gt;packages/core/session&lt;/code&gt; 是轨迹日志实现，&lt;code&gt;packages/shell&lt;/code&gt; 是 seam 规范范例）&lt;/li&gt;&#10;&lt;/ul&gt;&#10;</description></item></channel></rss>