前两周有个朋友跟我吐槽:他们的Agent平台已经把Skill、专家、连接器、项目全铺齐了,文档写得漂漂亮亮,架构图也画得清清楚楚,可真遇到线上问题,居然没有一条快速通道能动手。他说这话的时候,客户那边的工单系统已经崩了——外部CRM接口改了字段名,连接器还按老格式解析,一条工单都同步不进来。走正规流程改连接器、提交PR、跑回归、发版本,最快也要半天。我当时给他递了个建议:你们需要的不是第五个抽象层,而是DSH插件。
这个事让我越想越觉得值得展开聊。Skill编码、专家角色、连接器架构、项目级配置,这些概念已经是Agent落地的基本叙事,社区里搜这些词的人也越来越多。但越是把成熟基建铺得满满当当,越会暴露一个尴尬的空白:等你真的碰到“线上临时改个行为”这种需求时,居然找不到一个合适的工具。本文将围绕Skill、专家、连接器、项目与DSH插件的边界与关系展开,适合正在搭建Agent平台、或已经在使用这套体系但总感觉“差点什么”的工程师参考。
1. 工具齐了,问题还在:Agent基建的“最后一公里”空白
1.1 我遇到的那个“什么都齐全但做不了事”的时刻
先说说那次线上事故的细节。客户的CRM对接使用的是标准的REST连接器,连接器里有严格的字段映射,把CRM返回的mobile字段映射到内部的phone属性。某天CRM做了一次接口升级,mobile直接改成了workPhone,正常流程下这属于连接器版本迭代,需要修改映射表、重新构建镜像、走发布单,整套流程顺利的话也要两三个小时。但当时工单同步已经中断,每多一分钟客户那边的人工客服就得多手抄一批工单。
这种时候你回头看自己的基建:Skill有没有?有。连接器有没有?有。项目隔离有没有?有。可它们全都指向“稳定的长期需求”,没有一个指向“此刻、立即、只针对当前异常做局部修正”。我当时在线上环境里临时写了一个DSH脚本,订阅了tool_finished事件,判断工具名是crm_query时,把返回结果里的workPhone字段改回phone再交给下游。整个过程没动连接器、没发版、没重启进程,改完文件立即生效,10分钟恢复了数据同步。
这个案例特别典型——它不是DSH插件在炫技,而是现有体系无法覆盖的应急场景。Skill、专家、连接器、项目解决的是“结构化、长期、可复现”的问题,DSH插件解决的是“突发、临时、跨层”的问题。
1.2 正式链路为什么这么重
很多人会觉得,临时逻辑做成一个Skill不就行了吗?我自己以前也这么干过,把临时补丁命名为temp_patch_20250118,放到项目里跑通后再删掉。但用过几次就会发现,一个Skill从定义到真正可用,至少要经过注册、加载、版本依赖检查这几道程序。这套流程是为了稳定性设计的,不是为应急设计的。
连接器更不用说了,它天生是要跟外部系统长期打交道的适配层,任何字段变更都意味着要重新走协议测试。专家角色的调整则通常意味着提示词变更、记忆配置变更,如果只是想在某个会话里临时加一句“当前咨询量大请耐心等待”,走专家配置发布流程也是杀鸡用牛刀。项目级的配置管理更偏环境层,它负责告诉你“这套东西跑在哪、谁能访问”,它根本不适合承载动态行为。
DSH插件的定位恰恰相反。它刻意绕开了Skill的注册校验、连接器的协议测试、专家的提示词发布流程,直接在运行时事件上做钩子。它的设计哲学就是:临时的事,就用临时的工具干,干完就撤。
1.3 热搜背后藏着的真实诉求
最近我翻了一下社区热词,很多人搜“skill怎么用”“连接器分类”“workbuddy skill”“cursor有哪些skill推荐”“dsh好用的插件”。表面上看都是教程需求,但一个工程师不会平白无故去搜这些词,他多半是遇到了实际问题——要么Skill太多不知道该怎么组织,要么连接器对接外部系统时出了问题,要么就是手头有个线上问题需要快速处理。
我一直觉得,技术热词的背后是需求缺口。如果Skill、专家、连接器、项目已经能覆盖所有场景,就不会有人专门去搜“dsh插件”。那个搜索动作本身就说明:大家发现了一条用现有分层体系绕不过去的路,于是想要一个更轻、更快的解决方式。DSH插件正好填补了这个缝隙,这也是我觉得值得专门写一篇长文把它讲透的原因。
2. 各司其职但都够不着“运行时”:四个机制的边界分析
2.1 Skill、专家、连接器、项目到底在做什么
为了说清楚DSH插件的位置,得先把已有的四个机制掰开揉碎看一遍。
Skill是能力层。它封装的是Agent“会做什么”——发邮件、写代码、查天气、操作数据库。Skill有明确的输入输出定义,有实现逻辑,通常以声明式配置加回调函数组合出现。Skill解决的问题是能力的可复用性,同一套翻译能力可以被多个项目引用,不用重复开发。
专家是角色层。它定义的是Agent“以什么身份、什么风格做事”。一个客服专家可能包含语气规范、处理流程、知识边界和工具白名单。专家解决的问题是行为的一致性,让Agent在特定领域内像一个训练有素的专业人员。
连接器是触达层。它负责和外部系统通信,处理认证、加密、协议转换、字段映射。连接器解决的问题是“Agent能跟谁说话”,它把外部系统不稳定的接口细节隔绝在统一接口后面。
项目是环境层。它把Skill、专家、连接器、数据库、配置、API Key都组织到一个独立命名空间里。项目解决的问题是“这套东西跑在哪、给谁用、用什么资源”,它更像一个沙箱,保证不同业务线之间互不干扰。
这四个机制本身没有问题,它们合起来确实覆盖了一个Agent从能力到角色到外部触达到运行环境的完整描述。问题是,四个机制都属于“声明式”设计,它们的共同特征是把Agent的行为固化成一种静态配置,然后在运行的时候解释执行。
2.2 声明式的共同盲区:运行时动作
声明式设计解决的是“是什么”的问题,不太擅长解决“现在立刻改一下怎么办”的问题。一个Skill在注册表里躺着,它不会自动感知外部字段变更;一个连接器的映射关系已固定,它不会因为你线上出了故障就重新协商协议;一个专家的提示词定义好了,它不会在流量突增时主动加上限流话术。
这些变化都发生在运行过程中,且都带有“临时性”。正常拍脑袋想一想,临时变化不该污染正式配置——难道因为一次字段变更,就把它做成一个永久的Skill吗?当然不行,但你要是不处理,线上就是会挂。
这就是我在日常实操中对项目体系感受最深的点:Skill、专家、连接器、项目这四个机制天然是面向长期稳定性的,对“短期行为调整”存在结构性盲区。而这个盲区恰恰就是DSH插件的出生地。DSH插件订阅的是运行时事件,操作的是实时数据,它可以作为临时的“行为补丁”存在,而不需要去修改任何正式声明配置。
2.3 一张表看清五个概念的边界
用一张表整理一下这五个东西的差异,比光用文字描述直观得多。
| 概念 | 核心职责 | 定义方式 | 生效时机 | 修改成本 | 典型场景 |
|---|---|---|---|---|---|
| Skill | 封装可复用的能力 | 声明式配置 + 实现函数 | 被调用时 | 中(需注册、加载、依赖检查) | 翻译、写代码、数据分析 |
| 专家 | 定义角色风格与边界 | 提示词 + 记忆 + 工具白名单 | 会话级别生效 | 中(需过发布流程) | 客服、导师、行业顾问 |
| 连接器 | 对接外部系统 | 协议配置 + 字段映射 | 调用外部服务时 | 高(需重测接口) | CRM、数据库、消息队列 |
| 项目 | 组织人与资源 | 命名空间 + 权限 + 配置 | 创建后持续生效 | 低(但只影响环境) | 业务隔离、权限管理 |
| DSH插件 | 运行时临时行为钩子 | 轻量脚本,订阅事件 | 事件触发时即时生效 | 极低(改文件即生效) | 应急修复、临时适配、调试注入 |
这张表可能会颠覆一些人直觉:DSH插件看起来最“不正规”,但它恰恰是五个概念里唯一一个面向运行时动态调整的。其他四个概念负责“正规军作战”,DSH负责“特种兵突袭”。战场需要前面四个,但真要出状况的时候,你总不能跟敌人说“我方正规军还在跑审批流程”。
3. DSH插件的真实身份:挂在运行时上的脚本化钩子
3.1 先给DSH一个清晰定义
DSH,全称Dynamic Script Handler,动态脚本处理器。它是一个通用的运行机制,在Agent启动时会初始化事件总线,把请求处理过程中的关键节点暴露成事件,DSH插件允许开发者用脚本方式订阅这些事件并在事件前后插入逻辑。
很多平台、框架里都有类似的东西,叫法不一:有的叫hook,有的叫middleware,有的叫插件扩展点。DSH插件只是这类机制的一个规范化包装。它的核心特征有三个。
第一,DSH是进程内嵌入的。它不是单独的微服务,不需要走网络通信协议,它和Agent运行时共享内存和上下文对象,这意味着它的延迟极低,可以在主处理链路上同步执行。
第二,DSH是脚本化的。它不要求你写完整的类库、提交注册,而是直接放一段脚本,通常就是Python或JavaScript,文件放入指定目录即被加载。对这种轻量的临时逻辑来说,脚本是最短路径,不需要编译,不需要构建镜像。
第三,DSH是事件驱动的。它不负责处理完整请求,它只根据订阅的事件名决定自己要不要执行。它不做决策,它在大流程中做局部调整。这也决定了DSH插件的责任边界非常清晰——“我不替你干活,我只在你干活的时候搭把手”。
3.2 工作机制:加载、绑定、执行、释放
一个DSH插件从被放到服务器上到真正生效,大致经过四个步骤。
加载阶段:插件管理器扫描指定目录,读取脚本文件,提取插件名、版本、订阅事件列表,并计算文件的哈希值用于审计。加载时如果发现语法错误,会记录告警并跳过这个插件,不影响其他插件的加载。
绑定阶段:插件管理器把插件的回调函数注册到事件总线的对应事件上。比如一个插件声明订阅tool_finished事件,那么当Agent运行到“工具执行完毕”这个节点时,事件总线就会把这个插件的回调函数加入调用链。
执行阶段:事件触发时,DSH执行器会构造一个上下文对象,里面包含当前请求的关键数据,比如用户ID、会话ID、原始消息、解析结果、工具返回值等。然后按照注册顺序依次调用插件回调。每个回调可以修改上下文里的数据,可以记录日志,也可以设置中断标志来阻断当前流程。
释放阶段:插件更新或下线时,管理器会从事件总线上摘除对应的订阅关系,清理缓存。这一步对应到实际运维中就是告诉服务“我不用这个补丁了”,从摘除那一刻起,后续请求就不再经过这段临时逻辑。
这四个步骤像极了给你的车临时装一个外挂传感器——装上能用,拔掉还原。正是这种可插拔特性,Solid了DSH插件作为“临时行为补丁”的定位。也会有人问,这不就跟写个脚本跑一下完事?差得远,下面展开讲。
3.3 它和“写个脚本”的区别在哪
很多人第一次接触DSH插件时,会觉得它不过是“线上执行一段脚本”而已。确实,如果只是跑个一次性脚本,完全不需要插件机制,SSH上去执行python命令就行。但DIFF在几个地方。
一次性脚本是脱离系统的,它跑完了就完了,结果不会自动融入后续流程。DSH插件则是长驻的、可订阅的、有上下文的。它可以持续挂载在某个事件上,在每个请求经过时都被执行,并实时修改发给下游的数据。上面提到的CRM字段适配就是典型——那不是跑一次就结束的临时脚本,而是需要一直纠正到连接器的正式修复版本上线为止。
另外,一次性脚本没有灰度概念、没有回滚概念、没有过程审计,谁跑了什么脚本在哪个会话上产生了影响,事后很难追溯。DSH插件则天然支持版本编号、超时控制、白名单校验、审计日志。它严格说是“介于正式代码和临时脚本之间的一种中间形态”,既保留了脚本的轻量,又具备了基建级的基本管理能力。
那些说“DSH插件不重要,脚本搞定一切”的人,大概率是自己没有线上救过火。真在客户环境里操作过一次,你就知道审计和回滚比执行本身重要得多——你不需要代码多花哨,你需要的是出问题时能被问“跑了哪个版本、影响哪些请求、怎么一键撤下”。
4. 哪些场景值得动用DSH,哪些场景坚决不要用
4.1 值得用的五类场景
结合我自己的线上实操经验,DSH插件最值得用的场景大致有五类,每一类都有明显特征可以对照。
外部协议临时适配。连接器对接的外部接口临时变更了字段名、返回值结构、或分页方式,正式连接器修复需要排期,DSH插件可以先顶上。这类用法最关键的是要记录清楚临时适配的时间和原因,避免正式修复上线后补丁还在。
线上行为热修复。某个工具在特定输入下返回了不符合预期的数据,或者某个节点的处理逻辑出现边界错误,但全量修复走release流程太慢,DSH插件可以直接hook到出错点,对异常数据做纠正或过滤。注意一定是“局部纠正”,不是大范围逻辑重写。
批量数据订正。线上库里有一批脏数据,需要根据业务规则实时清洗,比如把历史数据里缺失的默认值补上,或者把编码不统一的字段做归一化。DSH插件订阅工具返回事件,在数据进入业务层之前就完成订正。
调试与观测注入。排查线上问题时,经常需要临时打印某个上下文变量、统计某个分支的命中次数、对特定用户ID打标签。这些临时观测代码不需要走正式发布,直接写个DSH插件订阅对应事件,把观测结果输出到日志或监控指标里。
业务策略微调。比如临时提高某个风险操作的拦截阈值,或者针对某个活动的文案做临时替换。这类策略调整有一个特点——持续时间短,只是为了应对某个活动窗口或风控事件,写死到配置里反而需要后续再改回来,用DSH插件挂着到期摘除更干净。
这五类场景的共同点是:临时、跨层、需要立即生效。它们不像独立的项目需求,它们像是正式系统上的一层“临时涂层”,到期就要刮掉。
4.2 坚决不要碰的四类场景
DSH插件好归好,但它不是万能钥匙。在同样经历过线上踩坑之后,我整理了几条“红线”,一旦踩中就别用DSH。
正式的、长期的业务能力积累。如果你发现某个补丁逻辑实际上很有价值,值得长期使用,那就应该把它固化成正式的Skill或连接器配置,而不是让它在DSH里一直躺着。长期功能写在DSH里就是技术债,后期几乎没有人记得它为什么存在。
性能敏感的核心链路。虽然DSH插件是进程内同步执行,理论上延迟很低,但脚本引擎本身有调用开销,且不可控的用户自定义逻辑可能拖慢主流程。凡是QPS很高、延迟要求极严格的主链路,不要让DSH插件参与,万一一个插件逻辑写得稀烂,会把整条链路拖垮。
安全与权限关键操作。涉及支付、用户隐私数据读取、权限变更等操作的逻辑,不应该用轻量级DSH脚本来承载。安全关键路径需要有完整的安全评审、权限校验和回归测试,DSH过高的灵活性对它是风险,而不是便利。
需要依赖特定内部模块/类库的复杂逻辑。DSH运行在受限的沙箱环境里,它对内部API的访问通常是有白名单限制的。如果某个补丁逻辑重度依赖内部代码结构和版本,一旦内部代码升级,这个补丁很容易失效甚至抛异常。复杂逻辑应该走正式代码,让它接受正常的版本控制。
4.3 判断该不该用的三条原则
后来我给自己总结了一套快速判断方法,遇到问题先过这三道关卡。
频率:这个问题是经常性的,还是偶发应急的?经常性的最终都要固化成正式配置或代码,偶发性才考虑DSH。
范围:改动是局部的还是全局的?DSH擅长局部数据修正、局部流程插入;全局性的架构调整或协议重写,应该走正式链路。
生命周期:这个逻辑打算活多久?计划内活不超过半衰期的,DSH完全合适;计划内在线上存续一年半载的,及早考虑到正式系统里去。
这三条原则看起来朴素,但在线上做决策时很管用。它把“能不能用DSH”这个问题从技术层面提升到了工程治理层面——你不是在问“技术上能不能实现”,而是在问“这活到底该不该干、干完之后怎么收场”。
5. 把一个DSH插件做出来:最小可用实现思路
5.1 插件挂在哪里:事件总线的侧翼
在Agent运行时里,DSH插件不介入核心业务流程,它挂在事件总线的侧翼。一次典型的Agent请求流程大概是这样:收到用户消息、解析意图、选择工具、调用工具、组装回复、发送回复。这中间每个环节都可以暴露一个事件。
我实际搭建时比较推荐把DSH执行器和事件总线放在同一层,插件管理器独立目录,通过事件驱动解耦。用到的核心对象包括:上下文对象,用来承载当前请求状态;事件总线,负责将事件分发到订阅的插件;插件管理器,负责脚本的加载、绑定、释放和审计。
5.2 接口与上下文设计
DSH执行器的核心接口其实可以很精简。重点是把上下文对象做厚,把回调接口做薄。下面是我在项目里使用的简化版接口设计。
# runtime/dsh/context.py class DSHContext: def __init__(self, event_name, user_id, session_id, payload): self.event_name = event_name self.user_id = user_id self.session_id = session_id # payload包含当前事件的所有有效数据,事件不同结构不同 self.payload = payload self.interrupt = False # 置为True可阻断当前流程 self.notes = [] # 记录审计日志 # runtime/dsh/base.py class DSHPlugin: name = "base_plugin" version = "1.0.0" events = [] # 要订阅的事件列表 def handle(self, ctx: DSHContext): raise NotImplementedError插件类的设计有几个细节值得注意。name和version不是装饰性的,它们直接进入审计日志,后期排查线上问题时靠这两个字段区分插件实例与版本。events声明了插件关心的所有事件,事件总线只给这个插件分发列表内的事件,通常一个插件只会订阅一两个事件。interrupt标志位要谨慎使用,它意味着阻塞Agent的后续流程,一般只用于安全拦截或错误处理。
5.3 一个真实可跑的最小插件示例
下面这个示例是我拿来应急处理CRM字段适配的原型和真实用法。它订阅tool_finished事件,发现工具是crm_query时,把返回结果里的workPhone字段改回phone。
# plugins/crm_field_adapter.py from runtime.dsh.base import DSHPlugin class CrmFieldAdapter(DSHPlugin): name = "crm_field_adapter" version = "1.3.0" events = ["tool_finished"] def handle(self, ctx): # 只处理crm_query这一个工具的结果 if ctx.payload.get("tool_name") != "crm_query": return records = ctx.payload.get("result", []) if not isinstance(records, list): ctx.notes.append("crm_field_adapter: skipped, result is not list") return fixed = [] for item in records: if isinstance(item, dict) and "phone" not in item and "workPhone" in item: item["phone"] = item.pop("workPhone") fixed.append(item) ctx.payload["result"] = fixed ctx.notes.append( "crm_field_adapter: normalized workPhone -> phone, " f"records={len(fixed)}" )这个示例只有不到三十行,但已经体现了DSH插件的完整价值:定向订阅、局部修改、审计记录。放在生产环境中,插件管理器会自动扫描这个文件,注册到tool_finished事件。从文件落地到生效,不需要任何额外操作。
5.4 接入与发布流程
插件文件放进去之后,事件总线那边需要有一个执行器负责调用。执行器统一处理超时、异常、指标上报。这样即使某个插件本身写得有问题,也不会把Agent主线拖垮。
# runtime/dsh/executor.py from contextlib import contextmanager import time class PluginExecutor: def __init__(self, manager): self.manager = manager def emit(self, event_name, payload): ctx = DSHContext(event_name, **payload) plugins = self.manager.get_plugins_for_event(event_name) for plugin in plugins: started = time.time() try: plugin.handle(ctx) except Exception as exc: # 插件异常必须隔离,不影响主流程 self.manager.log_failure(plugin, ctx, exc) continue elapsed_ms = (time.time() - started) * 1000 self.manager.record_metrics(plugin, event_name, elapsed_ms) if ctx.interrupt: break return ctx这个执行器设计里有几个点我认为值得解释。插件异常被捕获后继续,而不是中断整个事件循环,是因为DSH是辅助性机制,它的失败不应影响Agent主流程。interrupt标志是唯一的主动打断机制,只能由上而下显式设置。elapsed_ms指标非常重要,它可以用来发现某个插件是不是变成了性能瓶颈。
接入流程在实际工程中通常还会包含权限校验:插件在加载时检查自身文件的所有者、路径、哈希值是否在白名单中。这一步在多人共用的生产环境里非常关键,否则一个普通工程师就能往线上塞一段无限制的脚本,想想就头皮发麻。白名单之外的文件一律拒绝加载,加载失败的信息进入审计日志,留给平台管理员处理。
6. 线上跑了一个月,我捞到的几条实操经验
6.1 脚本也要做版本管理,不能“改完就算”
一开始我自己也犯过懒,觉得DSH脚本既然是临时补丁,直接改线上文件就行,没必要纳入版本管理。结果有一次改完文件后忘了记录变更,一周之后出了问题,怎么也想不起来最初版本是什么样。那之后我把所有DSH插件文件全部纳入独立的Git仓库,每条变更写commit信息,文件和线上目录之间用符号链接指向当前版本。
这种做法带来的好处是:确认问题时可以随时对比当前线上版本和上一版本的差异,临时逻辑救完火之后,也能清楚地知道哪个补丁可以摘除、哪个补丁已经被正式方案取代。版本管理花不了多少时间,但它在应急场景下提供的回溯能力是无价的。
6.2 沙箱与白名单:限制脚本能碰到的东西
DSH插件自由度很高,但高自由度也意味着高风险。我给DSH执行器做了一层白名单限制,插件代码里可以调用的内部API、可以读取的环境变量、可以访问的文件路径,全部在注册表里显式声明。脚本里使用未注册的调用会被执行器拒绝并记录告警。
有人会觉得这个限制太多,拖慢了“临时处理”的初衷。但我的真实感受是,恰恰是这些限制让DSH插件可以更大胆地去“临时”。正因为沙箱保证了它影响不到系统核心,它的上线审批才敢那么快。如果没有沙箱,每次上线都要仔细评审它能访问什么,那还是回到正式发布的效率水平上了。
6.3 审计日志:DSH最容易被忽略的配套
第一次用DSH时我只关注功能是否生效,没太在意审计日志。后来团队复盘一次线上变更时,发现DSH插件执行了数千次,却完全不知道是谁在什么时刻触发的、影响了哪些请求。从那以后,我把审计日志提到了和功能同等重要的地位。每次执行至少记录:插件名、版本、事件名、会话ID、用户ID、变更摘要、执行耗时、结果。
这些日志除了用于事后复盘,还有一个实用价值:它可以帮你判断一个DSH补丁是否已经被“遗忘”。如果连续十四天没有任何会话触发某个插件,我建议直接把它摘除,因为它大概率已经失去作用或已被正式方案覆盖。审计日志因此成为驱动DSH插件生命周期管理的核心依据。
6.4 秒级回滚:必须预设一键下线机制
DSH插件最大的卖点是即时生效,但如果只想到了正面、没想到反面,那是要吃亏的。临时补丁既然是临时写的,就有概率出现新问题。因此,每一个DSH插件在接入的时候,就应该配套定义好它的“一键下线”方案。
我的做法是把每个插件独立成一个文件,摘除插件时只需删掉或移动文件即可。加上前面的白名单机制,被摘除的插件在下一轮加载扫描时就不会再被绑定。从摘除到全部请求不再经过这段逻辑,时间窗口通常是秒级。这个操作在线上真的救过我——有个插件在处理某个边界数据时写出了一个明显有问题的中间值,我直接移除了插件文件,立即止损,然后才从容地去分析根本原因。
6.5 性能底线:把插件引擎隔离在主线之外
DSH执行器的性能开销主要来自脚本解析、方法调用、上下文序列化。我实际测过,一个简单插件单次执行大约在0.1毫秒到1毫秒之间,对于Agent这种以自然语言处理为主的系统来说,这个开销几乎可以忽略。但要注意的是,如果单个事件上挂了多个插件,或者插件逻辑里写了循环遍历大数据集,延迟就会显著上升。
我给自己定了一条底线:尽量让DSH插件执行时间不超过主流程单步耗时的5%。做到这一点的方法是把插件设计成“只修改数据、不做重计算”,复杂计算交给正式代码,DSH只负责判断和搬运。此外,事件总线侧我会对单插件设置超时上限,比如100毫秒,超过就中断该插件并记录告警,保证最坏情况下DSH也不会拖垮主链路。
6.6 心态校准:救火工具不能变成盖楼工具
这一条放在最后说,但我觉得它才是最重要的。DSH插件本质上是救火工具,是用来应急的,它的定位决定了它不应该成为日常开发的主要手段。如果在你的平台上,DSH插件越来越长、越来越多、存续时间越来越久,那一定说明你的正式链路出了问题。
我现在每周固定会做一次DSH插件“清理会”,把存续超过一个月、没有被固化为正式能力的插件全部揪出来,挨个讨论:要么尽快转成正式Skill或连接器,要么确认已无用直接下掉。这个过程不是为了消灭DSH插件,而是为了保持它的“应急”属性不失真。它之所以有价值,正是因为它是一个可以被迅速部署、迅速回收的轻量机制,一旦它被当成了常备力量,反而会变成架构里最不稳定的灰色地带。
我个人的习惯是:把DSH插件当作“最后一道手动阀门”,平时不用,但知道它在,线上出问题的时候心里就不慌。每一次使用都尽量在当天更新排期文档,标记“临时方案预计下线时间”,然后倒排日期推动正式修复落地上线。这半年下来,DSH插件在里面扮演的角色始终是“应急补丁”,没有升级成“长期依赖”,Agent平台的整体稳定性也一直保持在比较健康的水平。如果你也正在搭建Agent平台,我建议在定义Skill、专家、连接器、项目的同时,认真给DSH插件留一个位置——不是因为它多高级,而是因为你迟早会需要一条能秒级生效、用完即撤的应急通道。