Files
deepseek-harness/.agents/notes/implemented/architecture/2026-06-13-capability-seams.zh.md
2026-07-24 13:57:16 +08:00

3.3 KiB
Raw Blame History

Agent Note: 能力 seam——接口实现消费方三分

Status: implemented

English | 中文

问题

harness 具有可替换的能力:当前是 bash 执行,未来会有沙箱化/远程执行器和替代模型提供方。一项能力涉及三个关注点,它们以不同速率、因不同原因变化:契约(这项能力是什么)、实现(它如何运行)、消费方接口模型和其他插件面向什么编程。将三者捆绑在一个包package中会耦合这些变化速率——把本地执行器换成沙箱化执行器时模型看到的工具 schema 也会被搅动,尽管面向模型的契约从未改变。

这与「谁在运行时提供、谁需要一项能力」是不同的问题,后者 Cordis 已通过服务 + inject 解决(提供方注册 ctx.bash;消费方声明 inject: ['bash'],其 fiber 挂起直到服务存在)。该机制是必要的,但不决定包的边界;本 Agent Note 决定的是包的边界。

决策

一项可替换的能力由三个包构成:

  1. 接口——一个抽象服务加词汇类型,拥有 ctx.<key>,仅依赖其词汇依赖(例如 dsh-bashBashExecutorBashRunResultBashProcess)。
  2. 实现——一个具体子类,以插件形式加载(例如 dsh-bash-local:子进程、进程组 kill、溢出文件截断。沙箱化远程后端是实现同一接口的兄弟包。
  3. 消费方——模型和插件看到的内容(例如 dsh-tool-bashbash schema后台句柄注册到通用任务运行时。消费方 inject 接口键,从不导入实现类型。

实现与消费方由此独立演进:沙箱化执行器替换 dsh-bash-local 时无需触碰任何工具 schema。

当各部分确实属于同一个关注点时三分并非强制LLM大语言模型 seam 将接口 + 消费方合并为 dsh-llm(消费方是 agent loop智能体循环本身而非可替换的 schema 表面),适配器作为实现包。不要预防性地拆分——如果一项能力只有一种可设想的实现和一个消费方,就保持为一个包,直到第二种出现。

曾考虑的替代方案

  • 单一合并包:否决。因为它重新耦合了三分设计本要分离的三种变化速率(这正是拆分的意义所在)。
  • @cordisjs/plugin-capability:这是完全不同的维度。它是一个权限/能力安全服务(具名权限加继承,通过 ctx.capability.test 对会话进行检测),是延后的权限/沙箱工作(tools/pre-execute deny/ask seam的候选方案不是替换实现的机制。混淆这两个「能力」概念正是本 Agent Note 所指出的陷阱。

后果

每项能力需要更多包和更多样板代码(一组 package.json/tsconfig/README加上 inject 接线)。换来的是:实现与消费方独立发布和版本管理,新后端永远不会波及面向模型的契约。该规则记录在 AGENTS.md § Conventions「Capability seams are three packages」architecture.md §「Capability seams」中bash 三件套是参考模板。何时合并、何时拆分是一个判断问题,架构文档对此有详细说明——本 Agent Note 记录的是为什么默认选择拆分。