DeepSeek Harness插件开发全流程:从设计到发布

DeepSeek Harness插件开发全流程:从设计到发布 最近在做 DeepSeek Harness 的二次开发时经常遇到同事问“插件到底怎么写是不是直接把 .py 文件丢进去就能跑” 实际上一个能放进插件目录、能被 Harness 正确识别、还能发布到 GitHub 给别人使用的插件远不止一个 .py 文件那么简单。它需要遵循插件协议、有清晰的目录结构、能优雅处理配置和异常并且需要完整的项目元信息。这篇文章就把这套流程完整拆开手把手带大家写一个正式的插件从设计、落成文件、装进插件目录再到发布到 GitHub全程走一遍。如果你正准备基于 DeepSeek Harness 做二次开发或者看了一圈教程却不知道插件文件到底该怎么组织那么这篇内容会比较适合你。文中的示例插件我会使用一个纯本地的“笔记工具”插件不依赖第三方服务方便你直接复制运行。1. DeepSeek Harness 插件机制是什么1.1 Harness 解决什么问题DeepSeek Harness 可以理解为一条连接“大模型能力”和“实际业务动作”的通道。它把 DeepSeek 的对话、推理、函数调用等能力包装成可编排的工作流让开发者可以像搭积木一样组合不同的“工具”。但在实际使用中任何人都不可能只靠内置工具满足所有业务场景于是插件机制成了扩展能力的关键入口。所谓插件就是一段符合 Harness 插件协议、能被 Harness 在运行时动态加载的代码。通过插件你可以往 Harness 里加入新的工具函数、新的模型接入、新的存储方式甚至新的执行器逻辑。写插件的过程本质上是把“业务能力”封装成 Harness 能理解的结构。1.2 插件的常见类型从插件的作用范围来看DeepSeek Harness 生态中常见的插件有几种插件类型作用典型场景Tool 插件向模型暴露一个可被调用的函数查天气、查数据库、读写文件Provider 插件接入新的模型服务商接入不同厂商的大模型 APIMemory 插件自定义上下文存储方式把对话记录存到 MySQLExecutor 插件自定义任务执行流程在工具调用前后增加审计逻辑本文将以 Tool 插件为例因为这是最简单、也最能体现插件开发完整链路的一种类型。Tool 插件写好后DeepSeek 模型在对话过程中可以根据用户意图自动触发这个工具并把工具返回结果融入到回答中。1.3 插件生命周期理解插件生命周期能帮你更快定位问题。一个插件从加载到被调用大致经过几个阶段Harness 启动时扫描指定插件目录。读取插件元信息名称、版本、类型、入口。动态导入插件入口模块。将插件中注册的工具函数加入工具列表。模型在对话中决定调用某个工具。Harness 执行对应插件代码并返回结构化结果。其中第 2、3 步最容易被忽略。很多同学只是把 .py 文件丢进插件目录却没有提供元信息Harness 自然无法识别。接下来写插件时我们会专门把这一步做完整。2. 环境准备与版本约定2.1 基础环境本文示例以 Python 3.10 为前提建议使用虚拟环境隔离依赖。操作系统方面Windows、macOS、Linux 均可但命令示例以 macOS/Linux 为主。如果你在 Windows 下操作注意把export换成set路径分隔符也要对应调整。需要准备的工具Python 3.10并确保pip可用。Git用于本地版本管理和推送到 GitHub。GitHub 账号用于创建远程仓库。一个支持 Python 的 IDE 或文本编辑器推荐 VS Code。2.2 安装 DeepSeek HarnessDeepSeek Harness 的版本迭代速度比较快具体安装方式建议以官方仓库 README 为准。如果官方提供了 pip 安装包一般命令是pip install deepseek-harness如果尚未发布 pip 包也可以从 GitHub 源码安装git clone https://github.com/your-name/deepseek-harness.git cd deepseek-harness pip install -e .这里我们重点演示插件开发思路并不依赖 Harness 内部的某个特定类名或函数名所以即使你的 Harness 版本与文中示例有差异核心流程依然可以复用。需要说明的是本文示例代码不会硬编码 Harness 源码里的私有 API而是以通用的插件协议思路实现保证可迁移性。2.3 创建项目根目录后续所有文件都放在同一个根目录下便于管理和发布。我先规划一个目录名比如dsh-notes-tool进入这个目录开始初始化mkdir dsh-notes-tool cd dsh-notes-tool git init这里初始化 Git 仓库的时机比较早目的是让后续每个文件的创建和修改都能被 Git 跟踪避免发布前才发现漏掉了某个文件。3. 设计一个正式的插件3.1 明确插件职责写插件之前先想清楚插件到底做什么。我这里的示例需求是做一个“笔记工具”插件让 DeepSeek 模型能帮用户记录笔记、读取笔记、列出所有笔记。选择这个方向有几个原因不依赖外部网络服务本地即可运行。有明确的输入输出结构适合演示 Tool 插件的数据契约。存储层可以替换为数据库适合后续扩展。插件具备三个能力新增一条笔记。根据标题查询笔记内容。列出当前所有笔记标题。3.2 定义工具的数据契约Tool 插件本质上是在向模型暴露函数。为了让模型理解“什么时候调用这个函数、参数怎么填”我们需要给每个函数定义一个结构化的描述包括函数名、函数描述、参数类型、参数说明等。这个格式通常与 OpenAI 的 function calling 风格兼容DeepSeek 也支持类似的声明式工具描述。TOOLS [ { type: function, function: { name: notes_add, description: 保存一条新的笔记根据标题和正文内容写入本地存储, parameters: { type: object, properties: { title: { type: string, description: 笔记标题 }, content: { type: string, description: 笔记正文 } }, required: [title, content] } } }, { type: function, function: { name: notes_get, description: 根据标题读取一条笔记的完整内容, parameters: { type: object, properties: { title: { type: string, description: 需要查询的笔记标题 } }, required: [title] } } }, { type: function, function: { name: notes_list, description: 列出当前所有笔记的标题列表, parameters: { type: object, properties: {} } } } ]这段声明就是模型与插件之间的“契约”。模型看到这段声明后会在合适的时候生成一个 JSON 格式的工具调用请求Harness 再把这个请求转发给插件执行。3.3 确定插件入口Harness 需要知道“如何加载这个插件”。通常做法是插件目录中必须有一个入口模块入口模块暴露一个名为register的函数或等价约定Harness 调用该函数后获得插件注册信息。由于不同版本的 Harness 约定可能不同我这里采用一种保守而通用的做法在插件入口中提供register()函数返回一个包含插件元信息与工具列表的字典。def register(): return { plugin_name: dsh-notes-tool, plugin_version: 0.1.0, plugin_type: tool, tools: TOOLS, handlers: { notes_add: handle_add, notes_get: handle_get, notes_list: handle_list } }handlers中把工具名映射到具体的处理函数。Harness 在执行工具调用时会根据工具名找到对应处理函数并把模型生成的参数传给该函数。4. 把插件落成文件4.1 推荐的项目目录结构一个正式插件不能只有一个入口文件。为了让项目可维护、可测试、可发布我建议使用下面的目录结构dsh-notes-tool/ ├── .env.example ├── .gitignore ├── LICENSE ├── README.md ├── pyproject.toml ├── src/ │ └── dsh_notes_tool/ │ ├── __init__.py │ ├── config.py │ ├── plugin.py │ └── storage.py └── tests/ └── test_storage.py每个文件的职责文件作用pyproject.toml项目元信息、依赖声明、构建配置.env.example环境变量示例方便使用者复制.gitignore忽略本地生成文件避免误传LICENSE开源许可证README.md使用说明src/dsh_notes_tool/init.py标记 Python 包src/dsh_notes_tool/config.py配置读取如存储路径src/dsh_notes_tool/storage.py笔记存储逻辑src/dsh_notes_tool/plugin.py插件入口与工具处理函数tests/test_storage.py存储层单元测试4.2 创建 pyproject.tomlpyproject.toml是 Python 项目标准的工程化配置文件。这里声明插件名称、版本、依赖以及构建信息。需要注意插件名使用了dsh-notes-tool而 Python 包名使用了下划线dsh_notes_tool这是因为 pip 包名规范中短横线更常见而 Python import 语句中不能包含短横线。[build-system] requires [setuptools68.0] build-backend setuptools.build_meta [project] name dsh-notes-tool version 0.1.0 description A DeepSeek Harness tool plugin for local note management. readme README.md requires-python 3.10 license { text MIT } authors [ { name Your Name, email your.emailexample.com } ] dependencies [] [project.optional-dependencies] dev [ pytest7.0.0 ] [tool.setuptools.packages.find] where [src]这里dependencies留空是因为我们的插件只用 Python 标准库。如果你的插件需要调用 requests、httpx 等库就在这个列表里声明这样用户安装插件时会自动拉取依赖。4.3 创建配置读取模块插件在真实环境中运行不能写死路径。我通常用一个config.py统一读取环境变量并给出合理的默认值。这样用户可以通过.env或系统环境变量覆盖默认配置无须修改插件代码。# 文件路径src/dsh_notes_tool/config.py import os from pathlib import Path def get_storage_path() - Path: 从环境变量获取笔记存储路径默认使用用户目录下的 .dsh_notes_tool/data.json raw os.getenv(DSH_NOTES_STORAGE, ) if raw: return Path(raw).expanduser() home Path.home() default_dir home / .dsh_notes_tool return default_dir / data.json设计要点使用Path.expanduser()处理~开头的路径提升兼容性。存储目录放在用户目录下避免插件运行目录不可写。环境变量名带插件前缀DSH_NOTES_降低与其他插件冲突的概率。4.4 实现存储层存储层负责笔记的持久化。这里使用 JSON 文件存储简单直观。生产环境中你可以替换为 SQLite、MySQL 或对象存储只要保留同样结构的方法即可。# 文件路径src/dsh_notes_tool/storage.py import json from pathlib import Path from typing import Dict, List, Optional class NoteStorage: 基于本地 JSON 文件实现的笔记存储 def __init__(self, file_path: Path): self.file_path file_path self.file_path.parent.mkdir(parentsTrue, exist_okTrue) self._notes: Dict[str, str] self._load() def _load(self) - Dict[str, str]: if not self.file_path.exists(): return {} try: with open(self.file_path, r, encodingutf-8) as f: data json.load(f) if isinstance(data, dict): return data return {} except json.JSONDecodeError: # 文件损坏时不要直接崩溃返回空字典 return {} def _save(self) - None: with open(self.file_path, w, encodingutf-8) as f: json.dump(self._notes, f, ensure_asciiFalse, indent2) def add(self, title: str, content: str) - None: if not title or not title.strip(): raise ValueError(笔记标题不能为空) self._notes[title.strip()] content.strip() self._save() def get(self, title: str) - Optional[str]: return self._notes.get(title.strip()) def list_all(self) - List[str]: return list(self._notes.keys())在_load方法中我特别处理了 JSON 文件损坏的情况。插件在长期运行中很可能遇到磁盘写入中断、文件被误编辑等问题如果加载失败直接抛异常会让整个 Harness 崩溃反之返回空字典并把问题写入日志更符合生产环境的容错思路。4.5 实现插件入口与处理函数plugin.py是 Harness 加载插件的关键文件。它负责四件事声明TOOLS工具列表。提供register()入口函数。实现三个处理函数。将工具名与处理函数关联。# 文件路径src/dsh_notes_tool/plugin.py from typing import Any, Dict from .config import get_storage_path from .storage import NoteStorage TOOLS [ { type: function, function: { name: notes_add, description: 保存一条新的笔记根据标题和正文内容写入本地存储, parameters: { type: object, properties: { title: {type: string, description: 笔记标题}, content: {type: string, description: 笔记正文} }, required: [title, content] } } }, { type: function, function: { name: notes_get, description: 根据标题读取一条笔记的完整内容, parameters: { type: object, properties: { title: {type: string, description: 需要查询的笔记标题} }, required: [title] } } }, { type: function, function: { name: notes_list, description: 列出当前所有笔记的标题列表, parameters: { type: object, properties: {} } } } ] def handle_add(args: Dict[str, Any]) - str: storage NoteStorage(get_storage_path()) title args.get(title, ) content args.get(content, ) try: storage.add(title, content) return f笔记保存成功标题{title} except ValueError as e: return f笔记保存失败{str(e)} def handle_get(args: Dict[str, Any]) - str: storage NoteStorage(get_storage_path()) title args.get(title, ) content storage.get(title) if content is None: return f未找到标题为 {title} 的笔记 return content def handle_list(args: Dict[str, Any]) - str: storage NoteStorage(get_storage_path()) titles storage.list_all() if not titles: return 当前没有任何笔记 return 笔记列表\n \n.join(f- {t} for t in titles) def register() - Dict[str, Any]: return { plugin_name: dsh-notes-tool, plugin_version: 0.1.0, plugin_type: tool, tools: TOOLS, handlers: { notes_add: handle_add, notes_get: handle_get, notes_list: handle_list } }这里有一个容易被忽略的细节handle_add内部的NoteStorage(get_storage_path())每次都会重新读取文件。这种写法虽然简单但在高频调用场景下效率不高。我在示例中刻意保持简单是为了让核心逻辑更清晰在后面的最佳实践章节会介绍如何用单例或缓存优化。4.6 创建init.py__init__.py让src/dsh_notes_tool成为一个 Python 包。我们可以在这里导出一部分常用对象方便其他模块引用# 文件路径src/dsh_notes_tool/__init__.py from .plugin import register __all__ [register]4.7 创建环境变量示例与忽略文件.env.example告诉用户这个插件支持哪些环境变量复制为.env即可使用# 可选配置默认值~/.dsh_notes_tool/data.json DSH_NOTES_STORAGE.gitignore用来避免把本地数据、缓存和虚拟环境文件推送到 GitHub__pycache__/ *.py[cod] .env .venv/ venv/ dist/ build/ *.egg-info/ .DS_Store notes_data.json这里把.env加入忽略列表非常重要。.env中经常包含个人路径或密钥绝不能被推送到公开仓库。4.8 编写存储层单元测试正式插件应当有最小限度的测试。我们写一个针对NoteStorage的测试覆盖新增、查询、列出三个核心行为# 文件路径tests/test_storage.py import tempfile from pathlib import Path from dsh_notes_tool.storage import NoteStorage def test_add_and_get_note(): with tempfile.TemporaryDirectory() as tmpdir: storage NoteStorage(Path(tmpdir) / data.json) storage.add(标题A, 内容A) assert storage.get(标题A) 内容A def test_list_all_notes(): with tempfile.TemporaryDirectory() as tmpdir: storage NoteStorage(Path(tmpdir) / data.json) storage.add(标题A, 内容A) storage.add(标题B, 内容B) assert storage.list_all() [标题A, 标题B] def test_get_missing_note(): with tempfile.TemporaryDirectory() as tmpdir: storage NoteStorage(Path(tmpdir) / data.json) assert storage.get(不存在的笔记) is None运行测试命令pip install -e .[dev] pytest tests/ -v看到类似输出说明测试通过test_add_and_get_note PASSED test_list_all_notes PASSED test_get_missing_note PASSED4.9 编写 README 与 LICENSEREADME 是插件能否被其他人快速用起来的关键。一个正式插件至少要在 README 里写清楚插件简介、环境要求、安装方式、使用方法、配置项、开发调试方式。这里给一个参考模板# dsh-notes-tool 一个用于 DeepSeek Harness 的本地笔记工具插件支持新增笔记、按标题查询笔记、列出全部笔记。 ## 功能 - 新增笔记 - 根据标题查询笔记 - 列出所有笔记标题 ## 环境要求 - Python 3.10 - 已安装 DeepSeek Harness ## 安装 将本插件目录放入 Harness 的插件目录中然后在 Harness 配置中启用即可。 ## 配置 | 环境变量 | 说明 | 默认值 | | --- | --- | --- | | DSH_NOTES_STORAGE | 笔记 JSON 文件路径 | ~/.dsh_notes_tool/data.json | ## 开发 bash pip install -e .[dev] pytest tests/ -vLICENSE 文件直接采用 MIT 许可证文本这里不再重复粘贴全部内容。你可以到开源许可证网站复制 MIT 模板替换作者名与年份后放入项目根目录。 ## 5. 装进插件目录并验证 ### 5.1 理解插件目录加载机制 Harness 启动时会扫描一个或多个插件目录。具体目录名取决于你的 Harness 版本常见的有 plugins/、~/.harness/plugins/或在配置文件中指定。为了通用我们可以通过环境变量或配置文件来指定插件目录例如 bash export HARNESS_PLUGIN_DIR./pluginsHarness 对插件目录中的内容有约定它通常会识别满足条件的 Python 包并导入入口模块。因此把插件项目文件放进插件目录后需要确保 Harness 的 Python 环境能 import 到dsh_notes_tool这个包。5.2 安装到插件目录官方插件目录安装方式有几种这里提供一种比较稳妥的做法把整个项目目录作为插件目录并在 Harness 的 Python 环境中以可编辑模式安装。# 假设 Harness 项目位于 ~/deepseek-harness cd ~/deepseek-harness/plugins # 把你的插件目录克隆或复制过来 cp -r /path/to/dsh-notes-tool . # 进入插件目录并安装 cd dsh-notes-tool pip install -e .如果 Harness 支持纯目录扫描而非 pip 安装也可以直接把src/dsh_notes_tool符号链接到 Harness 识别的插件目录中ln -s /path/to/dsh-notes-tool/src/dsh_notes_tool /path/to/harness/plugins/dsh_notes_tool强调一点不同版本的 Harness 对插件目录的感知方式可能不同。如果你的 Harness 版本没有自动发现插件优先阅读 Harness 源码中关于插件加载的模块找到它定义的入口函数名和工具注册约定。5.3 配置并启动验证启动 Harness 前先设置插件需要的环境变量export DSH_NOTES_STORAGE~/.dsh_notes_tool/data.json然后启动 Harness并在对话中尝试让模型调用测试用户帮我记录一条笔记标题是“购物清单”内容是“牛奶、面包、鸡蛋”。 模型调用 notes_add 工具...如果 Harness 支持命令行直接测试工具也可以写一段简单的 Python 脚本来模拟工具调用链路验证插件是否被正确加载from dsh_notes_tool.plugin import register plugin_info register() print(插件名称:, plugin_info[plugin_name]) for tool in plugin_info[tools]: print(可用工具:, tool[function][name])如果输出类似下面内容说明插件入口和工具列表已经被正确加载插件名称: dsh-notes-tool 可用工具: notes_add 可用工具: notes_get 可用工具: notes_list接下来可以再手动验证存储层是否正常工作from pathlib import Path from dsh_notes_tool.storage import NoteStorage storage NoteStorage(Path.home() / .dsh_notes_tool / data.json) storage.add(购物清单, 牛奶、面包、鸡蛋) print(storage.get(购物清单))预期输出牛奶、面包、鸡蛋6. 发布到 GitHub6.1 完成本地 Git 提交在推送之前我们先创建一次干净的本地提交。回到插件根目录检查状态并提交git add . git commit -m feat: 初始化 dsh-notes-tool 插件这里建议先看一遍git status确认没有把.env、__pycache__等文件加进来。如果发现误加文件可以用git rm --cached移除。6.2 在 GitHub 创建远程仓库登录 GitHub点击右上角“”号选择“New repository”填写Repository namedsh-notes-toolDescriptionDeepSeek Harness tool plugin for local note management可见性Public如果你想公开初始化选项不要勾选 README因为我们本地已经有 README创建完成后GitHub 会给出远程仓库地址通常有两种格式https://github.com/your-name/dsh-notes-tool.git gitgithub.com:your-name/dsh-notes-tool.git我们选择 HTTPS 地址即可。6.3 关联并推送代码在本地仓库中执行git remote add origin https://github.com/your-name/dsh-notes-tool.git git branch -M main git push -u origin main推送成功后在 GitHub 仓库页面就能看到全部代码。这里需要注意如果你的网络环境访问 GitHub 不稳定请使用正常的网络连接重试不要在文章或代码中引入任何非官方加速手段。6.4 创建 Release正式插件最好在 GitHub 上创建一个 Release打上版本标签。这样使用插件的人可以下载稳定版本的压缩包而不是每次克隆 main 分支。git tag v0.1.0 git push origin v0.1.0然后在 GitHub 仓库页面点击 “Releases” - “Draft a new release”选择标签v0.1.0填写发布说明## v0.1.0 - 新增 notes_add 工具 - 新增 notes_get 工具 - 新增 notes_list 工具 - 使用 JSON 文件本地存储点击 “Publish release” 后Release 就正式发布了。后续插件更新时可以递增版本号并重新打标签。6.5 写好仓库首页仓库发布后别人第一眼看到的是 README。README 要让人快速知道这个插件是干什么的、怎么装、怎么用、配置项是什么。平时我建议把 README 分成几个固定板块插件简介、功能列表、环境要求、安装方式、配置说明、开发调试、许可证声明。一个容易被忽略的点README 尽量不要贴大段没有输出的命令。如果写了安装命令最好把命令行运行后的预期输出也写出来这样使用者能对照判断是否安装成功。7. 常见问题与排查思路插件开发过程中最让人头疼的不是写业务逻辑而是“Harness 不认我的插件”。下面整理了几个高频问题按排查顺序排列。问题现象常见原因解决思路Harness 启动后工具列表中没有插件工具插件目录未被正确扫描确认插件目录环境变量或配置项是否正确提示找不到模块dsh_notes_tool插件包未安装到 Harness 的 Python 环境执行pip install -e .后重新启动工具能列出但调用时报handler not found插件入口中 handlers 映射缺失检查 register() 中处理函数是否与工具名一致插件读取不到配置环境变量名称拼写错误比较.env.example中的变量名与服务端设置JSON 文件读取后内容为空文件损坏或首次运行没有创建文件查看日志确认_load()是否返回空字典模型不调用插件工具工具描述不够明确模型无法判断何时使用优化description增加具体触发条件7.1 工具列表能看到但调用报错这个问题通常出在 handlers 映射上。比如工具名称是notes_add但 handlers 中写成了handle_addHarness 按工具名取处理函数时就会失败。排查时先在本地调用 register()检查返回的handlers字典键是否与TOOLS中的function.name一一对应。7.2 插件目录扫描不到如果 Harness 配置了多个插件目录请确认把插件安装到了正确的那个目录。有一个通用技巧在插件入口文件开头加一行日志例如print(loading dsh-notes-tool plugin)启动时观察是否打印。没有打印说明插件目录没有被扫描到优先检查目录路径配置。7.3 模型长期不触发工具很多时候模型不调用工具不是插件代码的问题而是工具描述写得不够清楚。模型需要从description中理解工具的作用和触发条件。比如notes_add的 description 可以进一步写成“当用户需要记录、保存、备忘一段文字时使用。该工具会把标题和正文保存到本地存储。” 描述越具体模型越容易做出正确决策。8. 最佳实践与工程建议8.1 插件命名与版本管理插件名建议使用dsh-前缀表明它属于 DeepSeek Harness 生态例如dsh-notes-tool、dsh-weather-tool。版本号遵循语义化版本规范主版本号在不兼容变更时递增次版本号在向后兼容的功能增加时递增修订号在 bug 修复时递增。同时在pyproject.toml和__init__.py中维护版本号避免手写多处不一致。8.2 配置与安全边界插件中不要硬编码路径和密钥。所有可变配置都应通过环境变量或配置文件读取并在.env.example中留下说明。对于需要访问外部服务的插件要明确限制敏感操作的授权范围遵循最小权限原则。本文示例中只使用本地 JSON 文件不需要额外权限但如果你扩展为数据库或云存储务必在 README 中说明需要哪些权限。另外要注意如果插件接受模型生成的参数不能直接信任这些参数并拼接到系统命令或 SQL 中。应当做白名单校验例如笔记标题长度限制、特殊字符过滤等防止模型被恶意提示词劫持后触发非法操作。8.3 日志与异常处理插件代码应当记录关键操作日志。简单场景下可以使用 Pythonlogging模块import logging logger logging.getLogger(__name__) def handle_add(args): ... logger.info(note added, title%s, title)日志不仅能帮助你排查问题也能帮助 Harness 使用方理解插件行为。异常处理上所有对外的处理函数都应当捕获已知异常并返回可读的错误信息给 Harness而不是让异常直接冒泡导致整个工作流中断。8.4 性能优化思路前面提到每次调用都重新创建NoteStorage会频繁读写文件。在正式插件中可以使用模块级缓存或依赖注入来复用存储实例。例如_storage None def _get_storage(): global _storage if _storage is None: _storage NoteStorage(get_storage_path()) return _storage这样在 Harness 长期运行中第一次调用后存储实例会被复用。如果你的插件依赖数据库连接池也应当使用类似生命周期管理方式。8.5 插件发布前的检查清单发布到 GitHub 之前建议逐项检查[ ].env是否被.gitignore忽略[ ]__pycache__是否被忽略[ ]pyproject.toml中的版本号与 Git tag 是否一致[ ] README 是否包含安装和使用说明[ ] LICENSE 文件是否存在[ ] 单元测试是否全部通过[ ] 是否在干净环境执行过pip install .验证安装[ ] 是否在 Harness 中实际跑过一次完整工具调用这八项检查并不复杂但能避免很多发布后才发现的问题。尤其是“干净环境安装验证”这一步我们经常会因为当前环境已经安装过旧版本而忽略新的依赖声明缺失问题。9. 结语本文从概念讲到落地完整走了一遍 DeepSeek Harness 插件的开发与发布流程。核心要点可以总结成四句话插件开发要先定义清晰的工具契约插件文件要按标准 Python 工程结构组织插件目录要配合 Harness 的加载机制来配置发布 GitHub 要同时管理好本地 Git、远程仓库、版本标签和 README。如果你正在做 Harness 二次开发可以先从本文的dsh-notes-tool示例入手跑通后再加入自己的业务逻辑。遇到 Harness 版本差异时优先阅读源码中插件加载模块的入口函数以官方实现为准。如果这篇文章对你有帮助可以收藏备用后续我会继续写更多关于 DeepSeek 生态的实战教程。