DeepSeek Harness插件开发:把重复操作固化为面板与Agent工具
发布时间:2026/10/29 7:18:12 锦皓数字建站

最近我写了一个 DeepSeek Harness 插件把组里跑得最频繁的那批重复操作全部做成了面板入口和 Agent 工具。这个插件不是用来做提示词优化不是用来加个侧边栏皮肤而是把我每天在项目里要反复敲的那几十步操作——跑测试、生成 changelog、打标签、做代码检查、整理依赖清单——固化成两个稳定入口一个在 Harness 的界面上点按钮就能执行另一个注册成 Agent 工具让 Agent 在对话里自己按需调用。这个东西解决的核心问题是项目里的“标准操作”永远是散落在文档、聊天记录和个人肌肉记忆里的。每次新同事来了要重新教每次换电脑要重新配每次 Agent 有任务就得把一大段上下文塞给它。我把这些操作统一成插件之后手动场景有面板自动化场景有工具两边走的还是同一套实现不重写、不维护两套逻辑这个收益比我想象中大得多。这篇就把整个插件的设计、实现过程、以及上线之后踩过的坑都写出来。如果你也在用 DeepSeek Harness 这类带 Agent 编排能力的工具正准备把团队里的重复工作流沉淀下来这篇文章应该能让你少走不少弯路。1. 为什么写这个插件被重复操作逼出来的效率缺口1.1 每天重复的“高频操作”到底有多费按理说一个工程团队里最不该浪费的时间就是重复劳动。但我自己统计了一下一个普通的迭代里我至少有这些操作每天都要来一遍本地跑全量测试、跑静态检查、根据 git log 生成 changelog 草稿、核对依赖版本、执行数据库迁移脚本、清理临时分支。这里面有些是命令行有些是我自己封装的脚本有些得开一个编辑器临时写一段。每项单独看花不了几分钟但它们有两个很恶心的特性一是上下文切换成本高跑完测试要看一眼结果跑完检查又要换一个工具信息散落在好几个终端窗口里二是每次执行都得重新解释同事找我帮忙跑某一步我得先回忆那条路径是什么再检查环境变量对不对还要确认当前分支是不是正确的。我一开始的解决方案是写脚本集合把常用命令包成 bash 函数。但脚本集合有一个天然缺陷它只是给“人”用的。我把脚本封得再好Agent 不会主动去找它。Agent 只知道它调用的工具列表里有哪个工具不会知道你有个/home/me/scripts/run_all.sh。后来我干脆想与其继续堆脚本不如直接给 DeepSeek Harness 写一个插件。DeepSeek Harness 本身是个把模型能力和项目工作流串起来的框架它允许外部插件注册两类东西一类是 UI 面板入口一类是 Agent 工具。同一段逻辑注册成面板按钮给人点注册成工具给 Agent 调这样两个场景都覆盖了。1.2 为什么是“面板 Agent 工具”双形态而不是只做一种只做面板入口当然简单但那样的话 Agent 还是用不上只做 Agent 工具的话我自己手动点的时候也没有一个稳定的视觉入口每次还得通过对话把 Agent 唤醒再让它干活。这两种场景我每天都会遇到缺一个都别扭。但这里有个很现实的技术问题如果面板调用和 Agent 调用走两套代码那等于又回到了维护两套逻辑的老路上。所以我做插件时定的一个死规矩是——操作逻辑必须只有一个实现面板和 Agent 都只是“调用层”。面板按钮按下之后内部还是走工具注册的那个执行函数Agent 拿到工具描述之后调用的也是同一个函数。这样带来的直接好处是你只需要修复一次 bug两个入口就同时修好了你只需要做一次日志埋点两个入口的调用记录就都在同一份日志里。开发量不会因为双形态而翻倍反而因为抽象层清晰了后面加新操作的速度快了很多。2. 前置知识DeepSeek Harness 插件机制速览2.1 Harness 的扩展点到底在哪些位置动手之前得先搞清楚 DeepSeek Harness 到底开放了哪些扩展点。我是从插件清单文件开始看起的。Harness 插件的基本形态是一个带plugin.json的目录里面声明插件名称、版本、入口文件、SDK 版本要求然后通过一个contributes数组声明你要往 Harness 里塞什么东西。常见的扩展点有几种面板类扩展注册到工作台的某个位置工具类扩展给 Agent 增加可调用的工具还有一类是周期任务扩展比如定时清理缓存。我主要用了前两个面板和工具。理解这套机制的关键是搞清楚插件和 Harness 主进程之间是怎么通信的。Harness 会启动一个插件沙箱插件入口文件在这个沙箱里运行它不能直接改项目文件也不能直接读取任意路径它只能通过 Harness 提供的 API 来申请权限、读写工作区、执行子进程。这跟我以前写 VS Code 扩展的感觉很像本质上是一种宿主应用 插件进程的模型。我强烈建议你在写第一个插件之前先花点时间把它 SDK 里的类型定义读一遍。你会发现它早就把“工具输入 schema”“面板渲染数据”“沙箱权限申请”这些东西都抽象好了很多需求直接用现有类型就能表达根本不用自己发明轮子。2.2 插件的注册、激活与生命周期插件不是一装上就立刻跑起来的。Harness 的插件生命周期大体是加载清单 → 校验依赖 → 注册贡献点 → 按需激活 → 去激活。按需激活这点特别重要。设计得好的插件应该是懒加载的比如一个插件声明了“当打开 Python 项目时激活”那 Harness 就不会在打开 JavaScript 项目时浪费时间去加载它。我的插件注册的时候会在清单里写when条件。这样项目里没有对应文件时面板都不会显示Agent 的工具列表里也不会出现这些工具整个生命周期非常干净。如果插件逻辑出错了怎么办Harness 的处理方式是让插件在沙箱里崩溃宿主进程不会跟着挂掉。沙箱会把异常信息回传你可以直接在插件的输出通道里看到堆栈。这种隔离设计让我开发插件的时候放心很多不至于因为一个工具实现写得有 bug把整个 Harness 主界面搞瘫痪。3. 插件设计与信息建模3.1 先把“反复跑的操作”抽象成配置写插件之前我第一步不是写代码而是把所有要固化的操作列了一张表。我建议你也这么做把你想固化的操作写成一个表格每一行填上“操作名称、触发场景、执行命令或脚本、需要的权限、执行超时时间、输出内容”。我当时的表格大概是这样的操作名触发场景底层执行方式需要权限超时跑全量测试迭代提测前npm run test:coverage工作区读取执行300s生成变更日志发版前解析 git log 模板渲染git 读取60s检查依赖许可证安全合规审计扫描 package-lock 后查库网络请求120s清理过期分支每周清理调用 git branch 删除git 写权限60s这张表就是插件的“信息模型”。后面写清单文件时每一项基本都能映射到工具声明的name、description、inputSchema映射到面板上的一个按钮。我踩过的第一个坑也在这里一开始我直接写代码没有先做这张表结果好几个操作的边界是模糊的说不清它到底应该暴露为什么参数后面重构了一次浪费了大半天。还有一点要提前想清楚哪些操作适合固化成“工具”哪些操作只适合留在面板里。我的判断标准是如果这个操作纯粹依赖当前编辑器里的可见状态不适合 Agent 调用因为 Agent 拿不到那些视觉信息如果这个操作输入输出都可以用结构化参数表达那就适合做成工具。适合做工具的操作描述文字要写得清楚不然模型根本不知道什么时候该用它。3.2 面板与 Agent 工具怎么分工面板入口的设计思路和工具设计不太一样。面板上是“人”在点人看按钮名称能理解它是干什么的所以按钮文案可以带一些团队内部的行话而 Agent 工具不一样模型没有你的团队背景知识它只能依赖工具描述里的文字来理解。我给同一个操作经常准备两种名称面板上的按钮叫“跑回归”工具的名称却是run_full_regression_tests工具描述里认认真真写“在提交发版前运行完整回归测试包含单元测试和覆盖统计执行时间较长可能超过三分钟”。这两种形态的背后是同一个函数只是“接口视图”不同。另外一个重要的分工是面板提供反馈、工具提供数据。人点击面板按钮后想要看到的是进度条、日志流、结果摘要Agent 调用工具后想拿到的是一份可以被进一步加工的结构化结果。所以我的工具执行函数返回的类型都是 JSON 对象面板则负责把 JSON 渲染成带样式的结果卡片两者各司其职。3.3 设计工具返回协议先说清楚成功和失败工具返回协议这一块如果设计不好插件上线后 Agent 会频繁出错。我一开始以为只要返回字符串就行后来发现完全不行。模型判断“这个工具到底有没有完成任务”完全依赖返回内容的清晰度。如果你只返回一行“failed”模型并不知道失败原因是什么也不知道下一步该不该重试。我最后定的返回协议长这样一个对象包含ok布尔值、error可读错误信息、data业务数据、logs截取过的日志尾巴、durationMs耗时。这个设计对 Agent 极其友好——ok为什么 false错误在哪执行了多久所有判断需要的信息都齐了。面板端渲染的时候也直接消费同一份返回协议。拿到ok: false就渲染红色错误卡片拿到ok: true就渲染成功摘要。因为返回协议统一了我才真正做到了“面板和 Agent 共用一个实现”。4. 从零实现关键代码与接入步骤4.1 插件脚手架一分钟起DeepSeek Harness 的 SDK 提供了一个脚手架命令可以快速生成一个最小插件工程。我用的是 TypeScript 模板生成的目录大概是这样的src/index.ts是入口文件plugin.json是清单scripts里放着构建和打包脚本。我比较推荐用 TypeScript 来写插件。因为 SDK 的类型定义非常完整你在写配置的时候 IDE 就会提示你哪些字段漏了、哪些类型写错了。一个几行的插件定义写的时候就能发现大部分拼写问题比运行时报错好排查得多。脚手架生成后我做的第一件事是把插件名字改成有辨识度的名字然后加上一个workspace.hasPackageJson之类的激活条件保证它只在前端项目里出现。这个条件在清单里写一遍面板和工具自动都会遵循不用每个贡献点重复写。4.2 把面板入口注册进去下面这段是我最初版本的面板注册逻辑。我注册了一个挂在工作台侧边栏的面板里面放了好几个按钮每个按钮绑到一个操作上。核心思路是面板组件不直接实现业务逻辑它只通过一个bus把事件发出去业务逻辑在工具执行函数里处理。import { definePlugin } from deepseek-harness-sdk; export default definePlugin({ id: repo-ops, panel: { id: repoOps, title: Repo Ops, when: workspace.hasPackageJson, render({ bus, workspace }) { return ( div classNamerepo-ops-panel button onClick{() bus.emit(tool:run, { name: run_full_regression_tests })} 跑回归 /button button onClick{() bus.emit(tool:run, { name: generate_changelog })} 生成变更日志 /button /div ); }, }, });这段代码里有几个不能忽视的点。第一when条件改成workspace.hasPackageJson之后插件打开非 Node 项目时这些按钮都不会出现这个细节让插件体验好了很多。第二面板按钮的事件走的是tool:run这个统一事件这就保证了我前面说的“面板只是调用层”。第三workspace对象可以拿到当前项目的上下文比如项目根路径用在哪里后面会提到。运行面板不用重新打包整个插件SDK 有热重载机制。我改完面板样式后在 Harness 界面里按一次刷新就能看到新布局开发效率非常高。4.3 把操作包成 Agent 工具面板有了接下来是重头戏把同样的操作注册成 Agent 工具。工具注册有几个关键字段name、description、inputSchema和execute。很多插件开发新人会在description上偷懒写得很短我强烈建议你不要这么做。模型判断是否调用工具靠的是description里的描述和当前用户请求的语义匹配度。如果描述写得太短太模糊模型就可能在一个完全不应该调用它的场景里错误调用或者在应该调用的时候完全想不起来它。我给每个工具写的 description 都是完整的两三句话包含“什么时候用、什么时候不用、大概耗时会多长”。import { definePlugin } from deepseek-harness-sdk; export default definePlugin({ id: repo-ops, tools: [ { name: run_full_regression_tests, description: 在提交或发版前运行项目完整回归测试包含单元测试和覆盖率统计。 当用户需要验证代码改动是否安全、准备提测或发版时使用。 执行时间通常超过 3 分钟请通过 summary 中的 passed/failed 字段判断结果。, inputSchema: { type: object, properties: { filter: { type: string, description: 只运行包含该字符串的测试用例可选, }, withCoverage: { type: boolean, description: 是否生成覆盖率统计默认 false, }, }, }, async execute(args, { workspace }) { const start Date.now(); try { const result await workspace.exec( npm run test${args.filter ? -- args.filter : } ); return { ok: result.exitCode 0, data: { passed: result.exitCode 0, summary: result.stdout.slice(-2000), }, durationMs: Date.now() - start, }; } catch (err) { return { ok: false, error: err.message, logs: err.stdout?.slice(-1000) ?? , durationMs: Date.now() - start, }; } }, }, ], });注意看execute的返回它严格遵循了我前面设计的返回协议。ok、data、error、logs、durationMs五个字段全都在。这样一来Agent 收到返回值后可以立刻判断测试是否通过不需要再去解析一大段文本日志。我自己试过用一句话总结输出看似对模型友好实际上完全不行结构化才是正道。这里还有一个容易被忽略的细节workspace.exec这个方法不是单纯执行命令它会自动捕获输出、限制超时时间并且给命令注入项目环境变量。而不是直接使用 Node 的child_process。项目里如果用了私有的 npm registryexec 会自动带上用户的配置如果直接用child_process大概率因为环境变量缺失而失败。这也是我后来排查了很久才发现的一个坑后面细说。4.4 构建发布与更新写完之后就要构建发布。Harness 插件的构建产物通常是一个打包后的 JS 文件加上plugin.json清单。因为我的需求要先在组内试用所以我暂时用本地安装的方式把插件目录放到 Harness 的插件目录里在配置里声明启用重启后插件就加载了。发布到团队共享有一个好处是其他人也能用。如果你打算分享出去记得在清单里写上版本号和最低 Harness 版本要求。更新插件的机制是Harness 加载插件时会对比线上版和本地版线上版新就自动拉取。所以版本号管理要认真一点我吃过一次亏——测试时改了本地代码但忘了升版本结果 Harness 一直加载旧版本我还以为热重载坏了。构建步骤里的一个必备操作是清理构建产物。TS 编译过后的dist目录有时候会残留旧文件导致新版本还是旧的 bug。我后来在构建脚本里加了rm -rf dist这一行一劳永逸。5. 实操过程中最常见的问题和处理清单5.1 高频问题排查速查表插件开发完了真正头疼的问题都在运行阶段浮出来。我用一张表把遇到的高频问题整理了一下后面你如果也遇到类似的可以直接对照排查问题现象可能原因排查方法插件装了但面板不显示激活条件没满足检查when表达式是否匹配当前项目看插件的激活日志Agent 从不调用工具工具描述不够明确梳理 description明确“何时用”和“何时不用”工具执行报权限错误没有申请对应权限在清单中补上权限声明如需写入 git 则申请workspace.git.*面板按钮点了没反应事件名拼写不一致检查按钮bus.emit的name与工具注册的name是否一致执行结果被截断返回了很多日志使用 SDK 提供的日志截断方法只返回最后若干字符插件代码更新不生效版本号没升级或缓存清理构建产物提升插件版本号后重新加载这张表看着简单但每一条都是我实实在在花时间查出来的。最让我头大的是权限问题。5.2 几个必须避开的坑越早看到越好第一个坑事件名和工具名不一致。Harness 的面板按钮通过bus.emit(tool:run, {name: xxx})去调用工具如果 name 写错按钮点了之后什么事都不会发生也没有任何报错提示。我第一次遇到这个问题时面板刷了几遍都找不到原因最后是打开控制台看到了事件日志才发现是大小写问题。第二个坑不要直接在工具函数内部用全局的child_process执行命令。我之前提到过用 SDK 提供的workspace.exec会继承项目环境变量和权限约束直接裸调 child_process 看似能跑通但用户换一台机器可能就挂了而且会有权限绕过问题。我后来把之前写的所有工具都改成了workspace.exec调用这个改动花了我一个下午但之后几乎没再出现过环境相关的问题。第三个坑工具描述不要用团队黑话。我之前给生成 changelog 的工具写的描述是“生成提测材料”Agent 完全不知道这跟发版有什么关系。后来我改成“根据 git 提交记录生成从上次标签到当前提交之间的变更日志 Markdown 文本”模型立刻就会用了。描述的目的不是给人类看是给模型看所以一定要“中性、具体、场景化”。第四个坑权限申请不要一刀切。插件声明了太多权限Harness 安装时会吓到用户因为那意味着插件可以读任意文件。最好按需申请最小权限比如我只申请了 git 读取和 workspace 执行权限没有申请文件系统任意读写。这样用户安装时看到权限列表干净也更愿意放心用。第五个坑日志里不要输出敏感信息。工具返回日志切片时如果日志里包含内网地址或密钥会被 Agent 拿到并可能写进对话上下文。我在封装工具时加了一层脱敏逻辑把疑似 token、password 的字段替换成***。这是这个插件上线后安全侧同事提出来的属于那种不在第一版考虑到、后面补起来就很麻烦的问题。结尾前的一点个人体会写这个插件的整个过程最大的体会是把操作固化下来不是一个写代码的问题而是一个抽象与表达的问题。代码部分大部分时间都花在写工具描述、设计返回协议、调权限边界这些看起来不太起眼的环节上。但恰恰是这些环节决定了插件好不好用。如果你准备给自己的项目也写一个类似的 DeepSeek Harness 插件我的建议是先从一张操作清单开始把每一项的高频度、输入输出、权限要求列清楚然后挑三个最常用的操作先做成工具跑通面板和 Agent 双入口之后再慢慢补充其余的操作。千万不要一上来就想着把所有操作都做成插件那样你只会得到一个庞大的、没有人愿意装的怪物。现在这个插件已经在组里跑了一个月我自己已经不用再记那些命令了。新同事来了看一眼面板就知道有哪些标准操作Agent 发版前会主动调用回归测试工具不再需要我把测试命令塞进提示词里。这种“一次配置处处复用”的感觉确实是写插件最爽的部分。
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。