Skip to Content
一切皆插件 · DeepSeek Harness不做 agent 也用得上的四个模式

不做 agent 也用得上的四个模式

这一章不用写代码,是全书的回收章。

第 3 章列了 DeepSeek 的六个取舍。这一章逐条问一遍:你的项目该不该做同样的选择。

然后给三件更实际的事:按团队规模的裁剪方案、已有项目怎么渐进引入、以及什么时候不该学 dsh。

21.1 六个取舍,逐条问自己

dsh 的选择你该不该跟判据
没有特权内核多数项目不该只有当”主路径本身要被替换”是真需求时才值得。如果你的核心流程五年不变,付这个复杂度是亏的
日志是源不是产物多数项目该只要你有两个以上的需求要读同一份历史(回放、审计、恢复、统计),这条就回本
进程内类型化拦截看语言边界插件都是同语言同团队 → 该;要跨语言或者要故障隔离 → 用进程边界
配置整体替换多数项目该除非你的配置层数很少(两层以内),否则可追溯性比人体工学值钱
vendor 底层框架多数项目不该除非那个框架是你的核心竞争力所在,否则维护补丁的成本很快超过收益
富交互界面优先看产品形态你的 agent 需不需要展示复杂的中间状态

两条我认为绝大多数团队都该抄的:日志是源、配置整体替换。

它们的共同点是——成本前置,收益递增。一开始麻烦一点,但用得越久越省。

21.2 四个模式,不做 agent 也用得上

抽掉 agent 的外衣,dsh 里有四个东西是通用的软件设计模式。

模式一:注册即可撤销

问题:任何”能装能卸”的系统,最难的不是装,是卸干净。

做法:所有会改变系统状态的操作,都同时交出撤销它的方法。框架按逆序执行。

为什么逆序:复合的逆是逆序的复合,(g∘f)⁻¹ = f⁻¹∘g⁻¹。不是习惯,是定义。

配套条件:卸载集合必须在卸载开始时封闭——卸载中途不许再注册。

用在哪:插件系统、中间件、测试的 setup/teardown、任何有生命周期的资源管理。

判断你需不需要:问一句”这个东西能在运行中卸掉吗”。如果答案是”只能重启”,那你就还没有这个模式。

模式二:事件即扩展点,并区分策略型和观察型

问题:怎么让别人在你的流程里插一脚,而不用改你的代码。

做法:在流程的关键位置发事件。分发方式是契约的一部分——emit(观察)和 waterfall(可拦截)的监听器写法完全不同,不能混。

关键规矩:策略型监听器可以短路(它对这件事有决定权),观察型必须委托。违反的症状是沉默的——下游凭空收不到东西。

用在哪:任何有”扩展点”需求的系统。

判断你做对没有:看你的拦截器签名。如果它没有 next,那它就不是环绕式的,你没法在它里面做超时、重试、埋点这类”包住一次调用”的事。

模式三:接缝三角色

问题:怎么让一个能力真的可替换。

做法:Definition(声明是什么)+ Provider(实现)+ Consumer(使用)。三个角色齐全才算,单有 interface 不算。

判据(来自 Feathers 的原始定义):能在不改调用点的前提下换掉行为,而且有明确的启用点。

一条 dsh 自己没解决的教训:接缝的粒度应该切在**「可以独立替换」**的地方,不是「可以独立实现」的地方。fs 和 subprocess 能独立实现,但不能独立替换——换一个不换另一个就是错的,而这个约束在 dsh 里没有地方表达。

用在哪:存储层、执行环境、通知渠道、认证方式,任何”以后可能要换”的东西。

模式四:配置层合成,且预览和执行同源

问题:多层配置怎么保证”最终值是怎么来的”有唯一答案。

做法:整体替换而非深合并(结合律成立,来源唯一),记录每一行的来源,预览和实际执行调用同一个函数

最值钱的是最后半句。 一个”能预览最终配置”的命令,如果和实际加载走两条代码路径,它迟早会骗你。

用在哪:任何有环境覆盖、租户覆盖、用户覆盖的配置系统。

一句可以直接拿去问的话:你的配置预览命令,和真正启动时用的是同一段代码吗?

21.3 还有一条不算模式,但最该抄

把「这个模块让模型看到什么」写成必填的文档小节,并加机器门禁。

第 19 章给了脚本,不到 40 行。

它零迁移成本,而且解决的是一个真实痛点:在一个多人维护的 agent 项目里,没人知道改一个模块会怎么影响模型看到的东西和缓存命中。

如果你只从这本书抄一样东西,抄这个。

图 21-1:按收益和成本排的优先级。左上角那几个是三人团队就该抄的

21.4 按团队规模裁剪

3 人以内

抄两条:

  1. 注册返回 disposer(模式一的最小形态)
  2. ## Model Experience 文档小节(先靠自觉,不用上门禁)

别抄的:Agent Notes 那套四态分类、per-file 100% 覆盖、双语流水线、生成式文档。三个人的团队,这些的维护成本远大于收益——你们互相说一声就行了。

10 到 30 人

再加四条:

  1. 配置层合成,预览和执行同源
  2. 接缝三角形,用在你确实要换的那一两处(存储、执行环境)
  3. 事件即扩展点,把最容易被要求定制的那个流程开出来
  4. 两个机器门禁:模型可见面说明、注册必须返回 disposer

这个规模开始,“靠自觉”失效了。 十个人里总有一个不知道那条约定。门禁的价值从这时候开始体现。

30 人以上,或者代码库开始有 agent 参与维护

上剩下的:

  1. 决策记录 + 归档即冻结(比”写 ADR”这个倡议管用得多)
  2. 生成式文档,至少把最容易过期的那张图(依赖关系、事件流)生成出来
  3. pin + golden 的 prompt 漂移门禁——如果你在做 agent,这条的优先级应该往前提

永远别无脑抄的

  • per-file 100% 覆盖。dsh 敢这么干,是因为它的包切得极细(226 个包),单个包的表面积小。你的包如果是大模块,这个门槛会逼出一堆没意义的测试。
  • 中英双语流水线。除非你真的有两批读者。
  • vendor 一个框架。除非它是你的核心竞争力。

21.5 已有项目怎么渐进引入

不要重构。按这个顺序加,每一步都能单独止损。

第一步(一天):给每个模块写 Known Limitations。

在每个模块的 README 或者文件头加一段”这个模块目前做不到什么、什么是故意没做的”。

为什么从这里开始:它零风险、零依赖,而且写的过程中你会发现一堆之前没意识到的隐含约束。它还有个副作用——写不出来的模块,通常就是职责不清的那些。

第二步(一周):让所有注册返回 disposer。

从新代码开始,老代码不动。定一条规矩:任何 register*add*on* 方法必须返回撤销它的函数。

验收标准:你能在测试里装一个东西、跑一下、卸掉,然后断言系统回到了初始状态。做不到这一点,说明还有东西没交出逆操作。

第三步(一到两周):把最容易被要求定制的那个流程开成事件。

选一个真实被反复要求改的流程。定义好扩展点,把现有逻辑改成默认监听器。

关键判断:那个扩展点该是可拦截的(waterfall)还是只能观察的(emit)?给错了以后很难收回——放出去的短路能力,收回来就是破坏性变更。

第四步:接缝化你确实要换的那一个能力。

不要一次做多个。选那个你已经知道要换的(比如存储从本地要换成对象存储),完整做一遍三角色。做完之后你会对”什么该做成接缝”有体感,再看别的。

第五步:加门禁。

前四步的产物需要守住。第 19 章那两个脚本是起点。

21.6 什么时候不该学 dsh

诚实的部分。

你的核心流程稳定,没人要求定制。 那么”没有内核”就是纯成本。第 3 章那六个取舍里,五个的收益都建立在”要换”上。不换,全是账。

你的团队没有人愿意维护这套约束。 门禁需要有人加、有人修、有人在它误报时判断。没有 owner 的门禁三个月内会被 --no-verify 绕过。

你的项目周期短。 成本前置、收益递增的东西,在一个六个月就结项的项目上是纯亏。

你的团队正在快速扩张。 概念负担是招人成本的一部分。一个”服务可用性驱动的加载 + 环绕式分发 + 配置整体替换”的代码库,新人上手要两周;如果你三个月招十个人,这两周乘以十。

最后一条,也是最重要的一条这套架构的每一个好处,都对应一个”以后要改”的假设。 假设不成立时,它们全部变成负债。

先问清楚你的项目里哪些东西真的会变。 会变的那几处做成接缝,其余的写死。这比”全部做成插件”务实得多——而 dsh 之所以全部做成插件,是因为它是一个 harness,它的整个价值主张就是”每个部件都可能被别人换掉”。你的项目大概率不是。

21.7 你能改的东西,取决于别人把边界画在哪

这本书从一个改不动的 hook 开始。

绕了二十一章,答案其实很简单:你能改的东西,取决于别人把边界画在哪里。 Claude Code 把它画在几个预留的洞上,dsh 把它画在——没有边界,因为没有内核。

代价是我在第 3 章算过的六笔账,收益是你在第 13、14、18 章看到的那些事。这个交换划不划算,取决于你要改的东西有多少。

真正想留给你的不是 dsh 本身——它现在还是 0.1.0-rc,官方明说会有破坏性变更,可能一年后就长成另一个样子。留下的是那四个模式,和一个判断问题的方式:

你的系统里,哪些部件是”以后要换的”?它们现在能换吗?换的时候,旧的那个能干净地撤下来吗?

能回答这三个问题,这本书的目的就达到了。


全书完。

配套代码在 mini-dsh/examples/extensions/,实测数据和采集命令在 assets/。勘误维护在仓库 ERRATA.md


本章来自《一切皆插件》开源版 · 作者「递归客」
在线阅读完整书系:inferloop.dev
源码仓库:github.com/diguike/book-deepseek-harness

本书资源

继续阅读 · 同作者其他书

Last updated on