diff --git a/content/posts/deepseek-harness-architecture-evaluation.md b/content/posts/deepseek-harness-architecture-evaluation.md index 34dbf2e..8f6e2be 100644 --- a/content/posts/deepseek-harness-architecture-evaluation.md +++ b/content/posts/deepseek-harness-architecture-evaluation.md @@ -80,6 +80,36 @@ Fiber 常见状态为 `PENDING → LOADING → ACTIVE → UNLOADING`。插件声 | 依赖图 | 谁必须等待哪项能力 | `tool-bash` 等待 `tools` 和 `shell` | | 调用链 | 一次请求经过哪些活跃组件 | Agent loop → LLM → Tools Runtime → shell → LLM | +### 1.5 插件规模与关系 + +在当前提交中,仓库包含 219 个 DSH package,其中 170 个可以由 `cordis.yml` 直接加载。其余 15 个是不能单独挂载的抽象 Service 定义包,34 个是供其他包导入的普通库包。因此,219 是仓库包数量,170 是可加载插件数量。 + +| 口径 | 数量 | 含义 | +|---|---:|---| +| DSH package | 219 | 排除 7 个测试 fixture 后的仓库包 | +| 可加载 Cordis 插件 | 170 | 105 个有配置,65 个无配置 | +| Web 根配置行 | 129 | Base Bundle 78 行,加上 Web Bundle 新增的 51 行 | +| ACTIVE Fiber | 动态值 | 由操作系统、`disabled`、Profile、patch、Agent Preset 和运行时挂载共同决定 | + +129 不是 Web Profile 启动后的 ACTIVE Fiber 数量。它只是用户 patch 生效前的根配置行数;条件分支、禁用项、Realm 和运行时动态挂载都会继续改变实际插件树。 + +插件关系需要按四种口径分别观察: + +| 关系 | 当前规模 | 回答的问题 | +|---|---:|---| +| Package 依赖 | 1,089 条边 | 哪个 package 在代码层依赖哪个 package | +| Service 协作 | 56 项 Service、213 条角色关系 | 谁定义、谁提供、谁使用一项能力 | +| 运行时硬依赖 | 101 个插件、198 条 `inject` 关系 | 哪项 Service 缺失会让插件无法激活 | +| Event 协作 | 56 个事件名 | 谁发布事件、谁监听,以及使用哪种分发语义 | + +正文以 Service 关系作为主图,因为它最能回答“插件怎样接入已有能力”。箭头含义固定为:Definition 声明接口,Provider 注册实现,Consumer 依赖并调用 Service。 + +![三条 Service 能力边界展示定义、提供与使用关系](/articles/deepseek-harness-architecture-evaluation/dsh-service-seams.svg) + +这张图只呈现三条代表性的 Service 能力边界;移动端可横向滑动查看。 + +完整关系可以继续查阅仓库自动生成的 [Plugin Catalog](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/config-catalog.md)、[Module Graph](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/module-graph.md)、[Capability Seams](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/capability-seams.md)和 [Event Producer/Consumer](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/event-producer-consumer.md)。这些清单来自代码扫描,比手工维护一张总图更适合作为完整索引。 + ## 二、插件协作的三类接口 ![插件通过三类接口协作](/articles/deepseek-harness-architecture-evaluation/dsh-interaction-contracts.png) @@ -135,11 +165,13 @@ TypeScript 接口只提供编译期检查,运行时会被擦除。交互由四 只有前四类可能构成跨插件或外部契约。是否公开还要看它是否从 Definition package 导出,并在 subsystem 文档中出现。 -## 三、服务提供方的配置机制 +## 三、Service 的实现与选择 -### 3.1 shell 服务的分层结构 +Provider 不是一种独立的 dsh 组件类型,而是插件相对于某项 Service 承担的角色。一个插件可以为一项 Service 提供实现,同时使用另一项 Service。例如,`@deepseek-ai/dsh-bash-local` 是 `shell` 的 Provider,也是 `subprocess` 的 Consumer。 -官方 shell 链路可以完整说明插件之间怎样协作。它分为 Definition(契约)、Provider(提供方)和 Consumer(使用方)三层。 +### 3.1 Service 的定义方、提供方与使用方 + +官方 shell 链路包含三种角色:Definition(定义方)声明接口,Provider(提供方)实现接口,Consumer(使用方)调用接口。这些名称描述插件与 Service 的关系,不是三种固定的插件类型。 Definition 包 `@deepseek-ai/dsh-shell` 定义 `ctx.shell`: @@ -159,7 +191,7 @@ export abstract class ShellExecutor extends Service { } ``` -Provider 实现这项服务。默认基础 Bundle 在非 Windows 环境挂载 `@deepseek-ai/dsh-bash-sandbox`;`@deepseek-ai/dsh-bash-local` 是另一种实现。两者最终都注册名为 `shell` 的 Service。 +Provider 实现这项服务。`@deepseek-ai/dsh-bash-sandbox` 和 `@deepseek-ai/dsh-bash-local` 都继承 `ShellExecutor`,最终都把自己注册为名为 `shell` 的 Service。 Consumer `@deepseek-ai/dsh-tool-bash` 不导入具体 provider。它只导入 Definition 包中的类型,并声明服务依赖: @@ -175,7 +207,11 @@ ctx.tools.register(defineTool({ })) ``` -默认 Profile 的关键配置是: +因此,`@deepseek-ai/dsh-tool-bash` 只知道 `ctx.shell` 的接口,不知道当前实现来自 `dsh-bash-local` 还是 `dsh-bash-sandbox`。 + +### 3.2 Profile 对 Service 实现的选择 + +Profile 不直接把 `shell` 绑定到某个类名,而是挂载一个会注册 `shell` 的 Provider 插件。默认基础 Bundle 在非 Windows 环境选择 `@deepseek-ai/dsh-bash-sandbox`。其关键配置是: ```yaml - id: bash-sandbox @@ -185,9 +221,11 @@ ctx.tools.register(defineTool({ name: '@deepseek-ai/dsh-tool-bash' ``` -这条链路可以读成一句话:Profile 选择 provider,provider 注册 `shell`,Cordis 让 consumer 等待 `shell`,consumer 只调用 `ctx.shell`。因此它没有硬编码 `dsh-bash-local` 或 `dsh-bash-sandbox`。 +这条链路可以读成:Profile 挂载 Provider → Provider 注册 `ctx.shell` → Cordis 激活依赖 `shell` 的 Consumer → Consumer 调用 `ctx.shell`。如果 Profile 改为挂载 `@deepseek-ai/dsh-bash-local`,Consumer 的代码不需要改变。 -### 3.2 服务提供方的追查方法 +同一个 Context 只能注册一个同名 Service。若 Profile 在同一作用域同时挂载两个 `shell` Provider,Cordis 会因重复注册而报错,不会静默选择其中一个。 + +### 3.3 实际 Service 实现的确认 用户可以查看实际挂载结果,但目前没有一条命令直接输出完整的 `Service → Provider → 配置来源` 映射: @@ -276,19 +314,56 @@ HMR 的行为是卸载旧 Fiber、加载新模块,再重建依赖方。前端 - 模型、协议或用户行为增加 `test:snapshot`。 - 真实 provider 才选择带密钥的 `test:e2e`。 -### 6.3 提交、合并与发布流程 +### 6.3 Issue 与 PR 的关联规则 + +内部 PR 的关联采用“作者显式声明、程序自动校验”的方式。PR 作者或编码 Agent 必须在正文中写明关联关系,自动化不会根据代码内容寻找 Issue,也不会替作者创建 Issue。 + +1. 解决型关联。 + - 写法:`Fixes #123`、`Closes #123`、`Resolves #123`。 + - 含义:该 PR 用于解决 Issue,会进入解决型关联和状态同步。 +2. 信息型关联。 + - 写法:`Related to #123`、`#123`。 + - 含义:只记录关联关系,不表示合并后关闭 Issue。 + +当非 Draft、非 Bot 的 PR 请求评审或收到 Review 后,`issue-policy.yml` 会从默认分支检出可信规则并执行 `node .github/issue-management/policy.mjs pr`。脚本解析同仓引用,排除指向其他 PR 的编号,再校验 Issue 关联、唯一的 `kind/*`、至少一个 `area/*` 和 Priority 一致性。[PR 模板](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/.github/pull_request_template.md) [Issue policy](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/.github/workflows/issue-policy.yml) [规则实现](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/.github/issue-management/policy.mjs) + +`issue-lifecycle.yml` 使用 `dsh-issue-management` GitHub App 同步解决型 Issue 的 Project 状态。PR 开始开发后可进入 `In progress`,请求评审后进入 `In review`,Review 要求修改时退回 `In progress`。这套组件执行固定 JavaScript 规则,不是负责理解需求和评审代码的 LLM Agent;语义评审、合并和发布授权仍属于维护者。[Issue lifecycle](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/.github/workflows/issue-lifecycle.yml) [项目配置](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/.github/issue-management/config.json) + +项目配置指向 `deepseek-harness/deepseek-harness`,而公开仓库是 `deepseek-ai/deepseek-harness`。结合公开仓库当前不接受外部 PR,更合理的解释是这套 Issue/PR 流程主要服务内部仓库。该判断来自配置与公开政策的交叉推断,官方没有公开内部仓库的完整协作说明。 + +### 6.4 开发参与者的公开规模 + +截至 2026 年 8 月 14 日,GitHub Contributors API 返回约 30 个非 Bot 贡献记录。Contributor 记录可能包含匿名作者、同一人的多个提交身份或历史导入,因此不能直接当作员工人数。15 个记录的贡献数不少于 100;前 10 个记录约占全部贡献的 90%,前 5 个约占 73%。这支持“代码主要由约十几名高频贡献者完成”的判断,不支持“100 多人共同开发”的说法。[Contributors API](https://api.github.com/repos/deepseek-ai/deepseek-harness/contributors?per_page=100&anon=1) + +1. 内测用户。 + - 职责:使用产品并反馈问题。 + - 规模:官方仓库与文档没有公布人数;百人级说法未获官方证据确认。 +2. 开发贡献者。 + - 职责:领取 Issue、修改代码、提交内部 PR。 + - 规模:高频贡献者约为 10~15 个公开记录;包含零星贡献后约为 20~30 个记录。 +3. 维护者。 + - 职责:进行语义评审,决定合并和发布。 + - 规模:GitHub Team、仓库权限和审批名单不公开,无法确认人数。 +4. 自动化账号。 + - 职责:校验元数据、同步状态、执行 CI。 + - 边界:GitHub Actions 和 GitHub App 不等同于开发者或 LLM Agent。 + +内测规模、代码贡献规模和维护权限规模属于三个不同口径。即使存在百人级内测,测试者也不必拥有仓库写权限;从反馈到内部 Issue 的转化入口没有出现在公开代码中。公开证据只能说明:反馈面可能较宽,持续代码生产集中在十几名贡献者,最终写入和发布权限进一步收窄。 + +### 6.5 合并与发布的权限边界 1. Git hooks 先检查翻译、lint、空白、生成文件和 typecheck。 -2. 内部 PR 拆分独立改动;非 Draft PR 关联同仓 Issue,并填写变更、验证和标签。 -3. CI 覆盖 static、逐文件 100% coverage、snapshot、Node 兼容、Python、Wine 和 Windows。 -4. `all checks passed` 聚合通过后,改动才能进入 master 工作流。 -5. 发布先构建和打包全部 DSH 成员,再验证安装产物;tag 和 environment 由人工触发。 +2. 开发者或编码 Agent 在 PR 正文中显式关联 Issue,并填写变更、验证和标签。 +3. GitHub Actions 自动校验 Issue 关联、元数据以及 static、逐文件 100% coverage、snapshot、Node 兼容、Python、Wine 和 Windows 等检查。 +4. `all checks passed` 聚合通过后,改动才具备进入 master 的技术条件。 +5. 维护者完成语义评审并决定是否合并;自动检查通过不能代替这项判断。 +6. 发布先构建和打包全部 DSH 成员,再验证安装产物;tag 和受保护 environment 由有权限的维护者触发。 逐文件 100% coverage 只是一项仓库门槛。行为质量还依赖真实组合测试和 keyless snapshot。真实 API e2e 使用密钥,只在可信事件运行;fork 和 Dependabot 会跳过,避免泄露 secret。[开发指南](https://github.com/deepseek-ai/deepseek-harness/blob/47f943859bef60e4160492346772ded9b24f765a/docs/development.md) -公开工作流只能证明 CI 已配置。required checks、reviewer 数量、merge method 和发布 environment 审批名单没有从公开仓库设置中取得,本文将它们标为未知。 +公开工作流只能证明 CI 已配置。required checks 是否已在 Branch Protection 或 Ruleset 中设为强制、reviewer 数量、merge method 和发布 environment 审批名单均无法从公开仓库文件确认。 -本轮按要求没有重新运行 Harness 本地测试。上表描述冻结仓库定义的开发流程,不代表本轮测试已经通过。 +本轮按要求没有重新运行 Harness 本地测试。以上内容描述冻结仓库定义的开发流程,不代表本轮测试已经通过。 ## 七、外部插件的发布方式 diff --git a/public/articles/deepseek-harness-architecture-evaluation/dsh-service-seams.svg b/public/articles/deepseek-harness-architecture-evaluation/dsh-service-seams.svg new file mode 100644 index 0000000..adbced2 --- /dev/null +++ b/public/articles/deepseek-harness-architecture-evaluation/dsh-service-seams.svg @@ -0,0 +1,139 @@ + + DeepSeek Harness 的三条 Service 能力边界 + shell、subagent 和会话持久化三项能力分别由 Definition 声明接口、Provider 注册实现、Consumer 调用 Service。 + + + + + + + + + Service 能力边界:定义接口、注册实现、依赖调用 + + Definition + Provider + Service + Consumer + + + + + shell 能力 + + + dsh-shell + Definition + + + dsh-bash-local + Provider + + + dsh-bash-sandbox + Provider + + + ctx.shell + + + dsh-tool-bash + Consumer + + + + + + + + + + subagent 能力 + + + dsh-subagent + Definition + + + dsh-subagent- + spawn-in-process + Provider + + + dsh-subagent- + fork-in-process + Provider + + + ctx.subagents + + + dsh-tool-subagent + Consumer + + + dsh-tool-subagent- + control + Consumer + + + + + + + + + + + 会话持久化能力 + + + dsh-session- + persistence + Definition + + + dsh-session- + persistence-jsonl + Provider + + + dsh-session- + persistence-sqlite + Provider + + + ctx.session + Persistence + + + dsh-agent-loop + Consumer + + + dsh-session-query + Consumer + + + + + + + + + Definition 声明接口;Provider 注册实现;Consumer 通过具名 Service 调用能力。 + diff --git a/src/styles/global.css b/src/styles/global.css index bd7f50f..f815ebf 100644 --- a/src/styles/global.css +++ b/src/styles/global.css @@ -151,6 +151,7 @@ button, input { font: inherit; } .prose h2:first-child { margin-top: 0; } .prose h3 { margin-top: 2.3em; font-size: 25px; font-weight: 500; } .prose p, .prose li { color: #2f3c41; } +.prose a { overflow-wrap: anywhere; } .prose strong { color: var(--ink); } .prose blockquote { margin: 2.2em 0; padding: 20px 26px; border-left: 3px solid var(--rust); background: rgba(178, 72, 45, .06); } .prose pre { overflow-x: auto; padding: 22px; border-radius: 2px; font-size: 13px; line-height: 1.6; } @@ -233,6 +234,8 @@ button, input { font: inherit; } .prose table { display: block; overflow-x: auto; white-space: normal; font-size: 12px; } .prose th, .prose td { min-width: 112px; padding: 10px 8px; } .prose img, .prose svg { width: calc(100vw - 28px); } + .prose p:has(> img[src$="dsh-service-seams.svg"]) { width: 100%; margin: 2.6em 0; overflow-x: auto; scrollbar-width: thin; } + .prose p > img[src$="dsh-service-seams.svg"] { width: 1080px; max-width: none; margin: 0; transform: none; } } @media (prefers-reduced-motion: reduce) {