1. 从 DeepSeek Harness 的插件化设计说起Agent Runtime 为什么需要重新理解DeepSeek Harness简称 dsh是 DeepSeek 官方开源的 Agent Harness目前处于 Developer Preview 阶段底层由 Cordis 驱动。它最核心的设计理念只有一句话Everything is a Plugin。这句话听起来像口号但落到架构上它意味着 Model Adapter、Tool Registry、Session Log、Agent Loop 这些传统 Harness 里被视为“内核”的组件全部都是 Plugin都可以通过配置替换。如果你之前用过 Claude Code 或 Codex你脑子里可能已经有一套稳定的 Harness 认知模型User Goal 进入 HarnessHarness 产生 InstructionInstruction 驱动 Skill / Agent / Tool再经过 Policy 和 Sandbox最终执行。在这套模型里通常存在一个相对稳定的 Harness Core然后围绕 Core 挂载 Skill、Plugin、MCP、Hook、Custom Agent。扩展模型大致是 Core 先存在Plugin 后加载。DeepSeek Harness 走了一条明显不同的路线。官方架构文档明确把 Model Adapter、Tool Registry、Session Log、Agent Loop 都纳入 Plugin 体系并说明运行中的 dsh 是启动阶段通过多层配置组合出来的一棵 Plugin Tree。也就是说不是 Runtime 先存在再加载 Plugin而是 Plugin 组合出 Runtime。这个区别看似微妙但它直接决定了你如何理解 Agent Runtime 的构建方式、如何做能力替换、如何设计企业级 Agent 环境。这篇文章面向的读者是正在研究 Agent Harness 架构的工程师、需要为企业搭建可组合 Agent Runtime 的技术负责人、以及想理解 Cordis 和 Composable Runtime 设计思路的开发者。我会从静态目录结构入手拆解 Plugin、Bundle、Profile 三层组合机制给出可复制的 Runtime 配置片段和插件注册示例最后通过 TaoToken 统一 Key/API 通道完成一次端到端调用验证。整个过程你可以跟着操作不需要提前理解 Cordis 的全部细节。2. TaoToken 前置准备统一 Key 与 API 通道配置在开始拆解 DeepSeek Harness 的 Runtime 配置之前需要先解决一个实际问题dsh 作为 Agent Harness最终要调用 LLM。而 LLM 调用需要 API Key、Base URL 和 Model ID 三件套。如果你同时使用多个模型提供商每个提供商一套 Key 和 Endpoint配置会变得非常分散。TaoToken 在这里的角色是提供统一的 Key 和 API 通道让你在 dsh 的 Model Adapter Plugin 里只需要配置一套凭据。TaoToken 的 API 地址是 https://taotoken.net/api官网是 https://taotoken.net/。你需要先在 TaoToken 控制台创建一个 API Key。创建完成后你会得到一个以 sk- 开头的 Key。这个 Key 将用于 dsh 的 Model Adapter 配置。在 dsh 的架构里Model Adapter 本身就是一个 Plugin。官方 dsh-base Bundle 里包含了 Model Adapters 和 Default Model Selection。这意味着你不需要修改 dsh 的核心代码只需要在 Profile 的 cordis.patch.yml 里覆盖或追加 Model Adapter 的配置即可。这正是 Everything is a Plugin 带来的实际好处换模型提供商不需要动 Runtime 内核只需要改一层 Patch。具体来说你需要在 dsh 的配置中设置三个值Base URL 指向 https://taotoken.net/apiAPI Key 使用你在 TaoToken 控制台创建的 KeyModel ID 填写你要调用的模型标识。这三个值会通过 Model Adapter Plugin 注入到 ctx.llm 这个 Service 中后续 Agent Loop 在 agent/request 阶段会通过 ctx.llm 发起请求。如果你还没有 TaoToken 的 Key可以先到控制台的 API Keys 页面创建一个。创建时建议给 Key 起一个可识别的名字比如 dsh-dev方便后续在多个 Harness 之间区分。Key 创建后只显示一次记得保存到安全的地方。接下来我们会把这个 Key 写进 dsh 的配置片段里。3. 可复制配置dsh 的 Profile、Bundle 与 Model Adapter 设置dsh 的 Runtime 组合由 Profile、Bundle 和 Patch 三层决定。Profile 是一个命名组合记录要堆叠哪些 Bundles、安装哪些额外 Plugin、以及用户自己的 cordis.patch.yml。官方目前提供 web 和 headless 两个模板。Bundle 是一个 npm package通过 package.json 中的 dsh.bundle 字段指向一个 cordis.patch.yml成为 Profile 可以加载的一层 Patch。官方当前有三个关键 Bundlebase、web-app、headless。启动时的层叠顺序是Empty Entry List → Profile 中声明的 Bundles → Profile cordis.patch.yml → Home cordis.patch.yml → --patch CLI Overlay。最终得到的 Effective Plugin Tree 是所有这些层叠加的结果。你可以用 dsh --profile web --dump-config 查看当前环境真正会启动的组合树。下面是一个可复制的 cordis.patch.yml 片段用于配置 Model Adapter 指向 TaoToken 的统一通道。这个文件可以放在你的 Harness Home 目录下也可以作为 Profile 的 patch 层# cordis.patch.yml # 配置 Model Adapter Plugin 使用 TaoToken 统一 API 通道 plugins: deepseek-ai/dsh-llm-openai: baseURL: https://taotoken.net/api apiKey: ${TAOTOKEN_API_KEY} defaultModel: deepseek-chat models: - id: deepseek-chat name: DeepSeek Chat contextWindow: 65536 - id: deepseek-reasoner name: DeepSeek Reasoner contextWindow: 65536这里有几个关键点。第一baseURL 指向 https://taotoken.net/api这是 TaoToken 的 API 入口。第二apiKey 使用环境变量 ${TAOTOKEN_API_KEY}避免把 Key 硬编码在配置文件里。你需要在启动 dsh 之前设置这个环境变量export TAOTOKEN_API_KEYsk-your-tao-token-key第三defaultModel 设置为 deepseek-chat这是 dsh 默认使用的模型。如果你需要更强的推理能力可以切换为 deepseek-reasoner。Model Adapter Plugin 会把这两个模型注册到 ctx.llm 这个 Service 中Agent Loop 在 agent/request 阶段会根据当前配置选择合适的模型。如果你使用 headless Profile配置结构类似但 Bundle Stack 不同。headless Profile 大致是 dsh-base dsh-headless user patch。你可以在 headless 的 cordis.patch.yml 里做同样的 Model Adapter 覆盖。区别在于 headless 没有 Web Host 层适合一次性任务运行。另外如果你需要同时配置多个 Model Adapter可以在 plugins 下追加多个条目。Cordis 的 Context 会管理这些 Service 的注册和发现。当多个 Plugin 提供同一个 Service 时后加载的会覆盖先加载的这就是 Patch 层叠机制的作用。4. 插件注册示例与端到端调用验证理解了配置之后我们来看一个实际的插件注册示例。dsh 的 Plugin 通过 Cordis Context 提供 Service、监听 Event、创建 Effect。下面是一个简化的 Plugin 注册示例展示如何向 Runtime 注册一个自定义 Tool// my-tool-plugin.ts import { Context, Plugin } from cordisjs/core; export const name my-tool-plugin; export const inject [tools]; export function apply(ctx: Context) { // 向 ctx.tools 注册一个自定义 Tool ctx.tools.register({ name: echo, description: Echo back the input text, parameters: { type: object, properties: { text: { type: string, description: Text to echo } }, required: [text] }, async execute(args: { text: string }) { return { content: Echo: ${args.text} }; } }); // 监听 tool/call 事件在 Tool 执行前介入 ctx.on(tools/pre-execute, async (event) { console.log([my-tool-plugin] Tool called: ${event.toolName}); }); }这个 Plugin 做了两件事第一通过 ctx.tools.register 向 Tool Registry 注册了一个名为 echo 的 Tool第二通过 ctx.on 监听了 tools/pre-execute 事件在 Tool 执行前打印日志。这就是 Cordis 的 Service Event 机制Plugin 不需要修改 Agent Loop 的核心代码只需要向共享 Context 注册能力或监听事件。注册完成后你需要把这个 Plugin 加入 Profile 的配置中。可以在 cordis.patch.yml 里追加plugins: ./my-tool-plugin.ts: enabled: true现在来做端到端调用验证。启动 dsh webnpx deepseek-ai/dsh web默认监听 http://127.0.0.1:3080。打开浏览器访问这个地址你会看到 dsh 的 Web UI。在对话框里输入一段话比如“请用 echo 工具回显 hello”然后发送。Agent Loop 会经历以下链路turn/start → claim input → assemble prompt tools → agent/pre-step → step/start → derive model history → agent/request → llm/stream → assistant/message → tool/call → tools/pre-execute → tools/execute → tools/post-execute → tool/result → step/end → turn/end。如果一切正常你会看到模型返回了 echo 工具的执行结果。同时终端里会打印出 [my-tool-plugin] Tool called: echo 这行日志说明你的 Plugin 成功介入了 Runtime。整个过程中LLM 请求是通过 TaoToken 的 https://taotoken.net/api 通道发出的Model Adapter Plugin 从环境变量读取了 API Keyctx.llm 在 agent/request 阶段完成了模型调用。如果你想验证模型切换可以把 cordis.patch.yml 里的 defaultModel 改为 deepseek-reasoner重启 dsh再次发送请求。你会看到 Agent Loop 使用了不同的模型但整个 Runtime 结构没有变化。这就是 Composable Runtime 的实际效果换模型不需要改 Runtime只需要改一层 Patch。5. 常见报错排查401、local proxy failed、reading choices、OAuth在配置 dsh 和 TaoToken 的过程中你可能会遇到几类典型报错。下面逐一排查。第一类401 Unauthorized。这通常意味着 API Key 没有正确传入。检查步骤确认环境变量 TAOTOKEN_API_KEY 已经设置可以用 echo $TAOTOKEN_API_KEY 查看确认 cordis.patch.yml 里的 apiKey 字段引用了正确的环境变量名确认 Key 没有过期或被撤销。如果使用 dsh --dump-config 查看配置检查 Model Adapter 的 apiKey 字段是否被正确解析。注意不要在配置文件里直接写 Key 明文也不要把 Key 提交到 Git 仓库。第二类local proxy failed。这个报错通常出现在网络请求层。dsh 的 Model Adapter 会向 baseURL 发起 HTTPS 请求。如果 baseURL 配置错误比如漏了 https:// 或者写成了 http://就会导致连接失败。确认 baseURL 是 https://taotoken.net/api不要添加多余的路径后缀。另外检查本地网络环境是否能正常访问该地址。如果你在企业内网可能需要确认出口策略。第三类reading choices 相关报错。这个报错通常意味着 API 返回的响应结构不符合预期。可能的原因包括Model ID 填写错误导致服务端返回了错误格式的响应或者请求参数不完整。检查 cordis.patch.yml 里的 defaultModel 是否与 TaoToken 支持的模型标识一致。你可以先通过模型对话页面单独验证模型是否可用确认 Key 和 Model ID 正确后再回到 dsh 配置。第四类OAuth 相关报错。dsh 的某些 Plugin 可能涉及 OAuth 流程比如 GitHub 集成或第三方服务授权。如果你在配置过程中看到 OAuth 报错检查对应的 Plugin 配置是否完整。对于 Model Adapter 来说通常不需要 OAuth只需要 API Key。如果你使用了需要 OAuth 的 Plugin确认回调地址和 Client ID 配置正确。排查时的一个实用技巧是先用最小配置启动 dsh只保留 dsh-base 和 Model Adapter确认 LLM 调用通路正常后再逐步追加其他 Plugin。这样可以快速定位是哪个 Plugin 或哪层配置引入了问题。另外dsh --dump-config 输出的 Effective Plugin Tree 是排查配置层叠问题的关键工具建议在每次修改配置后都运行一次确认最终生效的 Plugin 列表和参数值。6. 从 Plugin System 到 Composable Runtime下一步怎么走到这里你已经完成了 DeepSeek Harness 的 Runtime 配置、Plugin 注册和端到端调用验证。回过头看dsh 和传统 Harness 最大的区别在于传统 Harness 问的是“Harness 有哪些 Extension Point”而 dsh 进一步问“Harness 本身能不能就是一种 Composition”。Model Adapter、Tool Registry、Session Log、Agent Loop 都是 Plugin都可以通过 Profile Bundle Patch 三层机制替换和组合。这种设计带来的实际好处是你可以为不同的 Agent 场景组合不同的 Runtime。比如 Developer Agent 可以组合 Filesystem Write、Shell、LSP、Git、Skill、SubagentReviewer Agent 可以组合 Filesystem Read、Search、LSP但不给 Shell Write 和 NetworkProduction Agent 可以使用 Remote Sandbox、Strict Permission、Audited Tool Gateway。这已经不是简单的 Tool Permission 问题而是 Runtime Composition 问题。如果你要继续深入下一步可以研究 Cordis 的 Context、Service、Effect、Event、Inject、Isolate 和 Plugin Lifecycle 机制理解一个 Plugin 是如何进入 Cordis 的、Service 是如何注册和发现的、Plugin 为什么能够卸载、Event 为什么能够改写 Runtime。这些问题的答案才是 Everything is a Plugin 真正被拆开的地方。在实际操作层面建议你先把 TaoToken 的 Key 配置好确保 Model Adapter 通路稳定。然后尝试写一个最简单的自定义 Plugin注册一个 Tool 或监听一个 Event观察它如何介入 Agent Loop。最后尝试用不同的 Profile 组合不同的 Bundle感受 Runtime Composition 的实际效果。如果你需要长期运行编码 Agent 或构建复杂的 Agent 工作流可以考虑使用 Coding Plan 来获得更稳定的调用额度。验证模型可用性可以直接在模型对话页面操作接入文档里有完整的 Base URL、Key 和 Model ID 配置说明。