Java 版 deepseek-harness 支持纯 Java 编写的原生插件。插件以 JAR 包形式安装,在 harness JVM 内以隔离 ClassLoader 加载运行,无需 Node.js 或任何 sidecar 进程。
在支持 Codex Skills 的 AI 工具(Codex、Claude Code 等)中安装 dsh-java-plugin-skills 后,AI 可以自动生成正确的插件工程。
Skill 位置:docs/skills/dsh-java-plugin-skills/SKILL.md
AI 工具加载后即可:
- 生成标准插件骨架
- 编写工具实现
- 调用一键安装脚本
- 排查常见加载错误
最快的方式是用官方 archetype 生成插件工程骨架,自动配好 pom、基类继承、plugin.yaml、ServiceLoader 文件。
cd deepseek-harness-java
mvn -q -pl deepseek-harness-java-types install -DskipTests
mvn -q -pl plugins/plugin-archetype install -DskipTestsmvn archetype:generate \
-DarchetypeGroupId=cn.xiaofuge \
-DarchetypeArtifactId=deepseek-harness-plugin-archetype \
-DarchetypeVersion=1.0.0-SNAPSHOT \
-DgroupId=com.acme \
-DartifactId=acme-weather-plugin \
-Dversion=1.0.0-SNAPSHOT \
-Dpackage=com.acme.weather \
-DpluginId=acme-weather \
-DpluginName="Acme Weather Plugin" \
-DpluginClass=WeatherPlugin \
-DpluginDescription="Weather query plugin" \
-DpluginAuthor="Acme Team" \
-DinteractiveMode=false| 参数 | 说明 | 默认值 |
|---|---|---|
groupId / artifactId / version |
标准 Maven 坐标 | version 默认 1.0.0-SNAPSHOT |
package |
Java 包名 | 同 groupId |
pluginId |
插件唯一标识(plugin.yaml 的 id) | 同 artifactId |
pluginName |
插件显示名 | 同 artifactId |
pluginClass |
入口类名 | Plugin |
pluginDescription |
插件描述 | A Java harness plugin. |
pluginAuthor |
作者 | Unknown |
acme-weather-plugin/
├── pom.xml ← 已配好 types provided 依赖
└── src/main/
├── java/com/acme/weather/
│ ├── WeatherPlugin.java ← 继承 AbstractHarnessPlugin
│ └── ExampleTool.java ← 继承 AbstractTool 的示例工具
└── resources/META-INF/
├── plugin.yaml ← 已填好 id/name/entrypoint
└── services/
└── ...JavaHarnessPlugin ← 已填好入口类全限定名
cd acme-weather-plugin
mvn package
# 产出 target/acme-weather-plugin-1.0.0-SNAPSHOT.jar编译完成后使用 install-plugin.sh 自动安装并运行插件(无需手动 curl):
bash scripts/install-plugin.sh \
--jar target/acme-weather-plugin-1.0.0-SNAPSHOT.jar脚本自动从 JAR 内 META-INF/plugin.yaml 读取 pluginId、displayName 和 version,调用宿主 HTTP API 完成安装 + 运行。
| 参数 | 说明 | 默认值 |
|---|---|---|
--jar |
必填,插件 JAR 路径 | |
--id |
插件 ID | 从 plugin.yaml 读取 |
--name |
显示名 | 从 plugin.yaml 读取 |
--version |
版本 | 从 plugin.yaml 读取 |
--host |
宿主地址 | http://localhost:8090 |
--entrypoint |
JAR 文件名 | JAR 文件名 |
PLUGIN_HOST 可覆盖宿主地址,如 PLUGIN_HOST=http://remote:8090 bash scripts/install-plugin.sh --jar ...
deepseek-harness-java-types ← 插件开发契约包(SPI 接口 + 抽象基类 + 值对象)
↑
deepseek-harness-java-domain ← 领域层(依赖 types)
↑
deepseek-harness-java-case / infrastructure / app ...
插件作者只需依赖 deepseek-harness-java-types,这是唯一的轻量契约包,不含 Spring 和任何运行时实现。
my-plugin/
├── pom.xml
└── src/main/
├── java/
│ └── com/example/
│ ├── MyPlugin.java ← 继承 AbstractHarnessPlugin
│ └── MyTool.java ← 继承 AbstractTool
└── resources/
└── META-INF/
├── plugin.yaml
└── services/
└── cn.xiaofuge.deepseek.harness.domain.spi.JavaHarnessPlugin
在外部工程中开发插件时,可以直接从 Maven 仓库引入契约包:
<!-- Source: https://mvnrepository.com/artifact/cn.xiaofuge/deepseek-harness-java-types -->
<dependency>
<groupId>cn.xiaofuge</groupId>
<artifactId>deepseek-harness-java-types</artifactId>
<version>0.1.5</version>
<scope>compile</scope>
</dependency>之后可以参考插件案例源码,开发你需要的插件。开发完成后,可以在 DSH-Java 上传使用。
如果插件由 DSH-Java 宿主加载,也可以使用 provided,由宿主 JVM 提供契约包:
<dependency>
<groupId>cn.xiaofuge</groupId>
<artifactId>deepseek-harness-java-types</artifactId>
<version>1.0.0-SNAPSHOT</version>
<scope>provided</scope> <!-- 打包时不打入插件 JAR,由宿主 JVM 提供 -->
</dependency>id: my-plugin
name: My Plugin
version: 1.0.0
author: Jane Doe
description: A plugin.
entrypoint: com.example.MyPlugin # 可选,不填则用 ServiceLoader 发现文件:META-INF/services/cn.xiaofuge.deepseek.harness.domain.spi.JavaHarnessPlugin
内容为实现类全限定名。
public class MyPlugin extends AbstractHarnessPlugin {
public MyPlugin() {
super("my-plugin"); // 必须与 plugin.yaml 的 id 一致
}
@Override
public List<ToolDefinition> tools() {
return List.of(new MyTool());
}
// onStart() / onStop() 已有默认实现(带日志),需要时 override
}AbstractHarnessPlugin 提供:
pluginId()由构造参数锁定,不会与 plugin.yaml 漂移- 内置
protected final Logger log onStart()/onStop()默认日志实现toolList(...)辅助方法收集动态工具集
public class MyTool extends AbstractTool {
@Override public String name() { return "my-tool"; }
@Override public String description() { return "做什么用的"; }
@Override
public Map<String, Object> parameters() {
return objectSchema()
.prop("input", stringSchema("输入文本"))
.prop("count", integerSchema("重复次数"))
.required("input")
.build();
}
@Override
protected CompletableFuture<ToolExecutionResult> run(Map<String, Object> args, ToolRunContext ctx) {
String input = str(args, "input");
int count = intVal(args, "count", 1);
if (input.isBlank()) {
return fail("input 不能为空", "MISSING_INPUT");
}
return ok("结果: " + input.repeat(count));
}
}AbstractTool 提供:
| 能力 | 方法 |
|---|---|
| 参数解析 | run(Map, ctx) — 自动把 Object args 转为类型安全 Map |
| 字符串读取 | str(args, key) / str(args, key, default) |
| 数值读取 | dbl(args, key) / intVal(args, key[, default]) |
| 布尔读取 | bool(args, key) |
| 成功结果 | ok(text) / ok(List<ContentBlock>) |
| 失败结果 | fail(message, code) |
| Schema 构建 | objectSchema().prop(...).required(...).build() |
| Schema 属性 | stringSchema / numberSchema / integerSchema / booleanSchema / enumSchema |
| 并发标记 | override isConcurrencySafe(args) 返回 true |
| 超时设置 | override timeoutMs() 返回毫秒数 |
参考 plugins/example-java-plugin/(echo + calculator)和 plugins/sample-tools-plugin/(weather_query + file_summary)。
bash scripts/install-plugin.sh --jar target/my-plugin-1.0.0-SNAPSHOT.jar# 安装
curl -X POST http://localhost:8090/api/harness/plugins/install \
-H "Content-Type: application/json" \
-d '{"pluginId":"my-plugin","displayName":"My Plugin","pluginVersion":"1.0.0",
"runtimeType":"JAVA_NATIVE","sourcePath":"/path/to/my-plugin.jar",
"entrypoint":"my-plugin.jar"}'
# 运行
curl -X POST http://localhost:8090/api/harness/plugins/run \
-H "Content-Type: application/json" -d '{"pluginId":"my-plugin"}'
# 状态
curl http://localhost:8090/api/harness/plugins/my-plugin/statusharness:
extensions:
plugins:
install-root: ./plugins
preset:
- plugin-id: my-plugin
display-name: My Plugin
plugin-version: 1.0.0
runtime-type: JAVA_NATIVE
source-path: ./plugins/my-plugin.jar
entrypoint: my-plugin.jar
auto-start: true注册名格式:plugin__<pluginId>__<toolName>
安装(install) → 激活(activate) → 运行(run) → 停止(disable) → 卸载(uninstall)
| 维度 | JAVA_NATIVE | DSH_NODE_BRIDGE |
|---|---|---|
| 运行 | JVM 内进程 | Node sidecar |
| 通信 | 直接方法调用 | JSON-RPC stdio |
| 依赖 | 只需 JDK + types 包 | 需 Node.js |
| 隔离 | URLClassLoader | 进程隔离 |
| 开发 | 继承 AbstractHarnessPlugin / AbstractTool | 按 TS Cordis 插件开发 |