新闻详情

新闻详情

首页 / 资讯中心 / 详情

DeepSeek Harness 插件化拆解:用 Cordis 给 Agent 框架留出第三条路

发布时间:2026/9/26 10:07:10来源:尧图网络
DeepSeek Harness 插件化拆解:用 Cordis 给 Agent 框架留出第三条路
1. 为什么我想给 Agent 框架留第三条路DeepSeek Harness 开源之后我第一时间把它 clone 下来跑了一遍。它不是新模型也不是套壳客户端而是一个面向智能体的运行框架官方给的公式很直白Agent Model Harness。模型负责聪明Harness 负责把聪明落到环境里——读文件、跑命令、调工具、管会话。对想自建 Agent 框架的开发者来说它最值得研究的不是功能列表而是插件化架构连 Agent Loop 本身都是插件整个运行时就是一个 Cordis Context。过去搭 Agent 框架基本只有两条路。第一条是全家桶LangGraph、AutoGen、OpenAI Agents SDK 这类开箱即用但你想改那 10% 不合口味的地方往往得 fork 源码升级时再痛苦地 merge。第二条是纯手写一个 while 循环加几个 if灵活是灵活可一旦要加并发、取消、会话恢复、权限控制循环会膨胀成几百行没人敢动的面条。DeepSeek Harness 想给的是第三条路微内核 插件核心保持稳定能力全部外挂改功能等于加载/卸载模块而不是重编译内核。这篇不聊模型能力只聊工程。我会用 Cordis 的依赖注入思路拆开它的插件注册机制给出一份可复制的插件骨架配一段 Harness 配置片段最后演示一次插件热加载验证。全程不改核心代码你跟着敲就能跑通。2. Cordis 前置把能力拆成接口、实现、消费者Cordis 是 Harness 的微内核理解它比理解任何单个插件都重要。它的心智模型很像 Linux 内核模块内核只提供加载机制和上下文具体功能由模块注册进来。运行中的 Harness 本质是一个 Cordis Context不同包往这个 Context 上注册服务、事件和能力最后由配置文件组合成可运行的智能体。文档里把典型能力拆成三层我拿 Bash 举例说明层级职责可替换性接口定义“执行命令”是什么稳定契约不随实现变实现真正创建进程、管理 PTY可换成远程容器、云端沙箱消费者把能力变成模型能理解的 schema随接口复用不关心实现这个“能力接缝”是整套架构的命门。你想把本地执行换成企业沙箱理论上只替换实现层Agent Loop、工具 schema、会话日志全都不用动。Cordis 的依赖注入负责把这三层在运行时接起来插件声明自己提供什么服务、依赖什么服务Context 负责解析和注入谁都不需要 import 谁的具体实现。注意Cordis 的注入是运行时解析不是编译期绑定。这意味着插件可以动态挂载和卸载也是后面热加载能成立的前提。3. 可复制配置Cordis 插件注册骨架先给一份最小可用的插件骨架。Harness 仓库是 pnpm workspace 结构插件通常放在 packages/ 下每个插件一个目录入口导出 apply 函数。下面这份骨架我实测能注册进 Context 并被 Agent 调用。// packages/plugin-weather/src/index.ts import { Context, Service } from cordis // 1. 声明插件元信息稳定 ID 依赖 export const name plugin-weather export const inject [tools] // 依赖 tools 服务由 core 提供 // 2. 定义服务接口层消费者只认这个 export class WeatherService extends Service { constructor(ctx: Context) { super(ctx, weather) } async query(city: string): Promisestring { // 实现层这里换成任意数据源都不影响消费者 return weather:${city}:sunny:26C } } // 3. apply插件入口注册服务与工具 export function apply(ctx: Context) { const weather new WeatherService(ctx) // 把能力暴露成模型可理解的工具 schema ctx.tools.register({ name: get_weather, description: 查询指定城市的天气, parameters: { type: object, properties: { city: { type: string } }, required: [city], }, // 消费者层只依赖接口不碰实现 execute: async (args: { city: string }) weather.query(args.city), }) }三个关键点。第一inject 声明依赖Cordis 会保证 tools 服务就绪后再执行 apply你不用手写初始化顺序。第二Service 子类把实现藏在接口后面将来换数据源只改 query 内部。第三ctx.tools.register 是消费者层的入口模型看到的只是 name、description、parameters完全不知道背后是本地函数还是远程沙箱。接着是 Harness 侧的配置片段。cordis.yml 决定当前 Agent 装载哪些插件列出插件名、稳定 ID 和参数# cordis.yml plugins: core: {} llm: provider: deepseek model: deepseek-chat shell: {} fs: {} plugin-weather: id: weather-local config: timeout: 3000这里有个我踩过的坑配置补丁替换的是目标插件的整个 config不是深度合并。如果你只想加一个 timeout 字段却把整个 config 重写了一遍原来的 API Key、base URL 会一起消失。正确做法是把原有字段完整带上或者用官方支持的覆盖层机制让 TUI 和 Web UI 共享基础配置再各自叠加。4. 验证请求一次插件热加载实测配置写好后先确认插件被正确装载。启动 Harnesspnpm install pnpm run build pnpm dsh web默认监听 http://127.0.0.1:3080。打开 Web UI在会话里直接问“北京天气怎么样”如果模型调用了 get_weather 并返回 weather:北京:sunny:26C说明插件注册链路通了。这一步验证的是接口、实现、消费者三层是否接对。真正体现插件化价值的是热加载。Harness 的 Creation 模式允许运行时检查插件树并动态挂载临时插件。我实测的动作是不重启进程往运行中的 Context 挂一个新插件然后立刻让 Agent 调用它。// 在 Creation 模式的会话里执行 const ctx harness.context const mod await ctx.loader.load(./packages/plugin-weather/src/index.ts) await ctx.loader.start(mod) // 此时 get_weather 已进入工具列表无需重启执行后我在同一个会话里再问一次天气Agent 直接调到了刚挂载的工具。整个过程核心代码零改动Agent Loop 也没重启。这就是“一切皆插件”的实际手感扩展工具链像插 U 盘而不是拆机箱。如果你更想先验证模型侧的调用行为可以先用模型对话把工具 schema 调通确认参数格式和返回结构没问题再回到 Harness 里做插件挂载。两条路都行看你是先调工具还是先调模型。5. 本篇常见错排查插件注册了但模型看不到工具。先查 inject 是否声明了 toolsCordis 不会在你没声明依赖时保证服务就绪。再查 apply 是否真的被执行可以在 apply 里打一行日志确认。热加载报模块找不到。loader.load 的路径是相对进程工作目录的不是相对当前文件。用绝对路径或确认 cwd 再传参能省掉大半调试时间。配置改了没生效。回到那个坑config 是整体替换不是深度合并。检查你是不是只写了新字段把原有字段覆盖没了。建议改配置前先备份一份 cordis.yml。工具被调用但结果为空。多半是 execute 返回了 undefined 或非字符串。模型侧对工具返回值有格式预期返回前做一次序列化别直接把对象丢回去。并发工具互相干扰。Harness 的调度器会让声明为并发安全的只读任务并行遇到修改状态或安全性不确定的调用会设屏障。如果你的插件会改状态却没声明可能被并行执行导致数据错乱。给这类工具显式标记屏障语义。6. 从插件骨架到长期编码工作流把上面的骨架跑通之后你会发现扩展 Harness 的成本主要不在写代码而在想清楚接口边界哪些是稳定契约哪些是可替换实现哪些只是消费者。想清楚这三层插件就能像积木一样拼。如果你打算把这条链路用在日常编码或 Agent 长任务上建议先把 API Key 和接入方式固定下来再谈插件扩展。API Key 在控制台创建接入文档里有各语言的调用示例照着配一次就能复用。工具链调通后长期跑编码任务可以考虑 Coding Plan把模型调用和插件运行时放在同一套工作流里省得每次手动拼环境。插件化的意义不是让你写更多代码而是让你在不动核心的前提下把 Agent 改造成自己需要的样子。第三条路能不能走通取决于你愿不愿意先把接口和实现分开——这一步做对了后面全是加载模块的事。
网站建设高端定制企业官网
RELATED

相关资讯

更多精彩内容,欢迎继续阅读

较早相关资讯

最新相关资讯

Trae、Cursor生成式AI,Builder智能体体验报告:TaoToken统一Key接入配置实战 2026/9/26 13:39:22

Trae、Cursor生成式AI,Builder智能体体验报告:TaoToken统一Key接入配置实战

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
AI 编程简历总卡在“交付”?用 TaoToken 统一 Key 打通权限与日志闭环 2026/9/26 13:39:15

AI 编程简历总卡在“交付”?用 TaoToken 统一 Key 打通权限与日志闭环

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
【开源】2 分钟在 Windows 上搭建 AI Agent 运行环境:MachineY Engine 使用指南(TaoToken 配置篇) 2026/9/26 13:39:15

【开源】2 分钟在 Windows 上搭建 AI Agent 运行环境:MachineY Engine 使用指南(TaoToken 配置篇)

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

阅读更多 →
洛谷P1125笨小猴:Python字符串统计与质数判断的边界陷阱 2026/9/26 13:39:09

洛谷P1125笨小猴:Python字符串统计与质数判断的边界陷阱

做洛谷P1125这道题的时候,我第一反应是“这不就是个字符串统计加质数判断嘛”,结果第一次提交就被WA打脸了。问题出在minn的取值上——我用了长度为26的数组统计每个字母出现次数,然后直接对整组数求最小值,完全没想过那些没出现过…

阅读更多 →
Spring Boot @Retryable与@Recover实战:优雅实现重试与降级 2026/9/26 13:39:09

Spring Boot @Retryable与@Recover实战:优雅实现重试与降级

1. 重试机制到底解决了什么问题 1.1 远程调用失败的常态与痛点 做后端开发的朋友应该都遇到过这种场景:调用第三方接口超时、数据库连接池暂时被占满、外部服务临时抖动返回500。这些状况在分布式系统里不是“会不会出现”的问题,而是“多久出现一次”的…

阅读更多 →
Spring Boot重试机制全解析:从@Retryable到@Recover的工程实践 2026/9/26 13:39:09

Spring Boot重试机制全解析:从@Retryable到@Recover的工程实践

1. 为什么需要重试机制?——从一次线上故障说起那天下午我的手机被运维瞬间打爆,原因是线上订单服务大面积超时,连带支付回调也攒了整整五千多条。事后翻日志才发现罪魁祸首是下游的库存服务在做一次全量缓存重建,偶尔返回 503&am…

阅读更多 →

今日资讯

本周资讯

本月资讯

看完文章仍有疑问?

联系尧图顾问,获取一对一建站咨询

立即免费咨询 📞 400-888-8888
📞 ✉